[
  {
    "path": ".gitignore",
    "content": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\n\n# Architecture specific extensions/prefixes\n*.[568vq]\n[568vq].out\n\n*.cgo1.go\n*.cgo2.c\n_cgo_defun.c\n_cgo_gotypes.go\n_cgo_export.*\n\n_testmain.go\n\n*.exe\n*.test\n*.prof\n\n# WebStorm\n*.iml\n\n# Directory-based project format:\n.idea/\n.idea/workspace.xml\n**/.idea/workspace.xml\n\n# mac hidden files\n.DS_Store\n\n#other\nnode_modules/\nbower_components/\n.tmp\n.sass-cache\nbuilds/**/images/*\n*.ogg\n*.mp3\n*.mp4\n*.png\n*.jpeg\n\n# security / ssl\n*.pem\n*.xxjson"
  },
  {
    "path": "01_getting-started/01_helloWorld/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(\"Hello world!\")\n}\n"
  },
  {
    "path": "01_getting-started/02_numeral-systems/01_decimal/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(42)\n}\n"
  },
  {
    "path": "01_getting-started/02_numeral-systems/02_binary/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Printf(\"%d - %b \\n\", 42, 42)\n}\n"
  },
  {
    "path": "01_getting-started/02_numeral-systems/03_hexadecimal/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\t//\tfmt.Printf(\"%d - %b - %x \\n\", 42, 42, 42)\n\t//\tfmt.Printf(\"%d - %b - %#x \\n\", 42, 42, 42)\n\t//\tfmt.Printf(\"%d - %b - %#X \\n\", 42, 42, 42)\n\tfmt.Printf(\"%d \\t %b \\t %#X \\n\", 42, 42, 42)\n}\n"
  },
  {
    "path": "01_getting-started/02_numeral-systems/04_loop/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfor i := 1000000; i < 1000100; i++ {\n\t\tfmt.Printf(\"%d \\t %b \\t %x \\n\", i, i, i)\n\t}\n}\n"
  },
  {
    "path": "01_getting-started/03_UTF-8/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfor i := 60; i < 122; i++ {\n\t\tfmt.Printf(\"%d \\t %b \\t %x \\t %q \\n\", i, i, i, i)\n\t}\n}\n"
  },
  {
    "path": "02_package/icomefromalaska/name2.go",
    "content": "package winniepooh\n\n// MyName will be exported because it starts with a capital letter.\nvar BearName = \"Pooh\"\n"
  },
  {
    "path": "02_package/main/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/GoesToEleven/GolangTraining/02_package/stringutil\"\n\t\"github.com/GoesToEleven/GolangTraining/02_package/icomefromalaska\"\n\t//someAlias \"github.com/GoesToEleven/GolangTraining/02_package/icomefromalaska\"\n)\n\nfunc main() {\n\tfmt.Println(stringutil.Reverse(\"!oG ,olleH\"))\n\tfmt.Println(stringutil.MyName)\n\tfmt.Println(winniepooh.BearName)\n}\n"
  },
  {
    "path": "02_package/stringutil/name.go",
    "content": "package stringutil\n\n// MyName will be exported because it starts with a capital letter.\nvar MyName = \"Todd\"\n"
  },
  {
    "path": "02_package/stringutil/reverse.go",
    "content": "// Package stringutil contains utility functions for working with strings.\npackage stringutil\n\n// Reverse returns its argument string reversed rune-wise left to right.\nfunc Reverse(s string) string {\n\treturn reverseTwo(s)\n}\n\n/*\ngo build\n\tgo build reverse.go reverseTwo.go\n \twon't produce an output file.\n\ngo install\n \twill place the package inside the pkg directory of the workspace.\n*/\n"
  },
  {
    "path": "02_package/stringutil/reverseTwo.go",
    "content": "package stringutil\n\nfunc reverseTwo(s string) string {\n\tr := []rune(s)\n\tfor i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {\n\t\tr[i], r[j] = r[j], r[i]\n\t}\n\treturn string(r)\n}\n\n// this demonstrates how an unexported function\n// can be used by an exported function in the same package\n"
  },
  {
    "path": "03_variables/01_shorthand/01/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\ta := 10\n\tb := \"golang\"\n\tc := 4.17\n\td := true\n\te := \"Hello\"\n\tf := `Do you like my hat?`\n\tg := 'M'\n\n\tfmt.Printf(\"%v \\n\", a)\n\tfmt.Printf(\"%v \\n\", b)\n\tfmt.Printf(\"%v \\n\", c)\n\tfmt.Printf(\"%v \\n\", d)\n\tfmt.Printf(\"%v \\n\", e)\n\tfmt.Printf(\"%v \\n\", f)\n\tfmt.Printf(\"%v \\n\", g)\n}\n"
  },
  {
    "path": "03_variables/01_shorthand/02/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\ta := 10\n\tb := \"golang\"\n\tc := 4.17\n\td := true\n\te := \"Hello\"\n\tf := `Do you like my hat?`\n\tg := 'M'\n\n\tfmt.Printf(\"%T \\n\", a)\n\tfmt.Printf(\"%T \\n\", b)\n\tfmt.Printf(\"%T \\n\", c)\n\tfmt.Printf(\"%T \\n\", d)\n\tfmt.Printf(\"%T \\n\", e)\n\tfmt.Printf(\"%T \\n\", f)\n\tfmt.Printf(\"%T \\n\", g)\n}\n"
  },
  {
    "path": "03_variables/02_var_zero-value/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tvar a int\n\tvar b string\n\tvar c float64\n\tvar d bool\n\n\tfmt.Printf(\"%v \\n\", a)\n\tfmt.Printf(\"%v \\n\", b)\n\tfmt.Printf(\"%v \\n\", c)\n\tfmt.Printf(\"%v \\n\", d)\n\n\tfmt.Println()\n}\n"
  },
  {
    "path": "03_variables/03_less-emphasis/01_declare-variable/var.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar message string\n\tmessage = \"Hello World.\"\n\tfmt.Println(message)\n}\n"
  },
  {
    "path": "03_variables/03_less-emphasis/02_declare-many-at-once/var.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar message string\n\tvar a, b, c int\n\ta = 1\n\n\tmessage = \"Hello World!\"\n\n\tfmt.Println(message, a, b, c)\n}\n"
  },
  {
    "path": "03_variables/03_less-emphasis/03_init-many-at-once/var.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tvar message = \"Hello World!\"\n\tvar a, b, c int = 1, 2, 3\n\n\tfmt.Println(message, a, b, c)\n}\n"
  },
  {
    "path": "03_variables/03_less-emphasis/04_infer-type/var.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tvar message = \"Hello World!\"\n\tvar a, b, c = 1, 2, 3\n\n\tfmt.Println(message, a, b, c)\n}\n"
  },
  {
    "path": "03_variables/03_less-emphasis/05_infer-mixed-up-types/var.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tvar message = \"Hello World!\"\n\tvar a, b, c = 1, false, 3\n\n\tfmt.Println(message, a, b, c)\n}\n"
  },
  {
    "path": "03_variables/03_less-emphasis/06_init-shorthand/var.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\t// you can only do this inside a func\n\tmessage := \"Hello World!\"\n\ta, b, c := 1, false, 3\n\td := 4\n\te := true\n\n\tfmt.Println(message, a, b, c, d, e)\n}\n"
  },
  {
    "path": "03_variables/03_less-emphasis/07_all-together/variables.go",
    "content": "package main\n\nimport \"fmt\"\n\nvar a = \"this is stored in the variable a\"     // package scope\nvar b, c string = \"stored in b\", \"stored in c\" // package scope\nvar d string                                   // package scope\n\nfunc main() {\n\n\td = \"stored in d\" // declaration above; assignment here; package scope\n\tvar e = 42        // function scope - subsequent variables have func scope:\n\tf := 43\n\tg := \"stored in g\"\n\th, i := \"stored in h\", \"stored in i\"\n\tj, k, l, m := 44.7, true, false, 'm' // single quotes\n\tn := \"n\"                             // double quotes\n\to := `o`                             // back ticks\n\n\tfmt.Println(\"a - \", a)\n\tfmt.Println(\"b - \", b)\n\tfmt.Println(\"c - \", c)\n\tfmt.Println(\"d - \", d)\n\tfmt.Println(\"e - \", e)\n\tfmt.Println(\"f - \", f)\n\tfmt.Println(\"g - \", g)\n\tfmt.Println(\"h - \", h)\n\tfmt.Println(\"i - \", i)\n\tfmt.Println(\"j - \", j)\n\tfmt.Println(\"k - \", k)\n\tfmt.Println(\"l - \", l)\n\tfmt.Println(\"m - \", m)\n\tfmt.Println(\"n - \", n)\n\tfmt.Println(\"o - \", o)\n}\n"
  },
  {
    "path": "03_variables/03_less-emphasis/08_exercise_your-name/01_oneSolution/myNameVar.go",
    "content": "package main\n\nimport \"fmt\"\n\nvar name = \"Todd\"\n\nfunc main() {\n\tfmt.Println(\"Hello \", name)\n}\n"
  },
  {
    "path": "03_variables/03_less-emphasis/08_exercise_your-name/02_anotherSolution/myNameVar.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar name = \"Todd\"\n\tfmt.Println(\"Hello \", name)\n}\n"
  },
  {
    "path": "03_variables/03_less-emphasis/08_exercise_your-name/03_anotherSolution/myNameVar.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tname := \"Todd\"\n\tfmt.Println(\"Hello \", name)\n}\n"
  },
  {
    "path": "03_variables/03_less-emphasis/08_exercise_your-name/04_anotherSolution/myNameVar.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tname := `Todd` // back-ticks work like double-quotes\n\tfmt.Println(\"Hello \", name)\n}\n"
  },
  {
    "path": "04_scope/01_package-scope/01/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nvar x = 42\n\nfunc main() {\n\tfmt.Println(x)\n\tfoo()\n}\n\nfunc foo() {\n\tfmt.Println(x)\n}\n"
  },
  {
    "path": "04_scope/01_package-scope/02_visibility/main/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/GoesToEleven/GolangTraining/04_scope/01_package-scope/02_visibility/vis\"\n)\n\nfunc main() {\n\tfmt.Println(vis.MyName)\n\tvis.PrintVar()\n}\n"
  },
  {
    "path": "04_scope/01_package-scope/02_visibility/vis/name.go",
    "content": "package vis\n\n// MyName is exported because it starts with a capital letter\nvar MyName = \"Todd\"\nvar yourName = \"Future Rock Star Programmer\"\n"
  },
  {
    "path": "04_scope/01_package-scope/02_visibility/vis/printer.go",
    "content": "package vis\n\nimport \"fmt\"\n\n// PrintVar is exported because it starts with a capital letter\nfunc PrintVar() {\n\tfmt.Println(MyName)\n\tfmt.Println(yourName)\n}\n"
  },
  {
    "path": "04_scope/02_block-scope/01_this-does-not-compile/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tx := 42\n\tfmt.Println(x)\n\tfoo()\n}\n\nfunc foo() {\n\t// no access to x\n\t// this does not compile\n\tfmt.Println(x)\n}\n"
  },
  {
    "path": "04_scope/02_block-scope/02_closure/01/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tx := 42\n\tfmt.Println(x)\n\t{\n\t\tfmt.Println(x)\n\t\ty := \"The credit belongs with the one who is in the ring.\"\n\t\tfmt.Println(y)\n\t}\n\t// fmt.Println(y) // outside scope of y\n}\n"
  },
  {
    "path": "04_scope/02_block-scope/02_closure/02/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nvar x = 0\n\nfunc increment() int {\n\tx++\n\treturn x\n}\n\nfunc main() {\n\tfmt.Println(increment())\n\tfmt.Println(increment())\n}\n\n/*\nclosure helps us limit the scope of variables used by multiple functions\nwithout closure, for two or more funcs to have access to the same variable,\nthat variable would need to be package scope\n*/\n"
  },
  {
    "path": "04_scope/02_block-scope/02_closure/03/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tx := 0\n\tincrement := func() int {\n\t\tx++\n\t\treturn x\n\t}\n\tfmt.Println(increment())\n\tfmt.Println(increment())\n}\n\n/*\nclosure helps us limit the scope of variables used by multiple functions\nwithout closure, for two or more funcs to have access to the same variable,\nthat variable would need to be package scope\n\nanonymous function\na function without a name\n\nfunc expression\nassigning a func to a variable\n*/\n"
  },
  {
    "path": "04_scope/02_block-scope/02_closure/04/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc wrapper() func() int {\n\tx := 0\n\treturn func() int {\n\t\tx++\n\t\treturn x\n\t}\n}\n\nfunc main() {\n\tincrement := wrapper()\n\tfmt.Println(increment())\n\tfmt.Println(increment())\n}\n\n/*\nclosure helps us limit the scope of variables used by multiple functions\nwithout closure, for two or more funcs to have access to the same variable,\nthat variable would need to be package scope\n*/\n"
  },
  {
    "path": "04_scope/03_order-matters/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(x)\n\tfmt.Println(y)\n\tx := 42\n}\n\nvar y = 42\n"
  },
  {
    "path": "04_scope/04_variable-shadowing/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc max(x int) int {\n\treturn 42 + x\n}\n\nfunc main() {\n\tmax := max(7)\n\tfmt.Println(max) // max is now the result, not the function\n}\n\n// don't do this; bad coding practice to shadow variables\n"
  },
  {
    "path": "04_scope/05_same-package/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(x)\n}\n\n// IMPORTANT\n// to run this code:\n// go run *.go\n// ---- OR ----\n// go build\n//./05_same-package\n"
  },
  {
    "path": "04_scope/05_same-package/same.go",
    "content": "package main\n\nvar x = 7\n"
  },
  {
    "path": "05_blank-identifier/01_invalid-code/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\ta := \"stored in a\"\n\tb := \"stored in b\"\n\tfmt.Println(\"a - \", a)\n\t// b is not being used - invalid code\n}\n"
  },
  {
    "path": "05_blank-identifier/02_http-get_example/01_with-error-checking/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tres, err := http.Get(\"http://www.geekwiseacademy.com/\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tpage, err := ioutil.ReadAll(res.Body)\n\tres.Body.Close()\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tfmt.Printf(\"%s\", page)\n}\n"
  },
  {
    "path": "05_blank-identifier/02_http-get_example/02_no-error-checking/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tres, _ := http.Get(\"http://www.geekwiseacademy.com/\")\n\tpage, _ := ioutil.ReadAll(res.Body)\n\tres.Body.Close()\n\tfmt.Printf(\"%s\", page)\n}"
  },
  {
    "path": "06_constants/01_constant/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nconst p = \"death & taxes\"\n\nfunc main() {\n\n\tconst q = 42\n\n\tfmt.Println(\"p - \", p)\n\tfmt.Println(\"q - \", q)\n}\n\n// a CONSTANT is a simple unchanging value\n"
  },
  {
    "path": "06_constants/02_multiple-initialization/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nconst (\n\tpi       = 3.14\n\tlanguage = \"Go\"\n)\n\nfunc main() {\n\tfmt.Println(pi)\n\tfmt.Println(language)\n}\n"
  },
  {
    "path": "06_constants/03_iota/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nconst (\n\ta = iota // 0\n\tb = iota // 1\n\tc = iota // 2\n)\n\nfunc main() {\n\tfmt.Println(a)\n\tfmt.Println(b)\n\tfmt.Println(c)\n}\n"
  },
  {
    "path": "06_constants/04_iota/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nconst (\n\ta = iota // 0\n\tb        // 1\n\tc        // 2\n)\n\nfunc main() {\n\tfmt.Println(a)\n\tfmt.Println(b)\n\tfmt.Println(c)\n}\n"
  },
  {
    "path": "06_constants/05_iota/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nconst (\n\ta = iota // 0\n\tb        // 1\n\tc        // 2\n)\n\nconst (\n\td = iota // 0\n\te        // 1\n\tf        // 2\n)\n\nfunc main() {\n\tfmt.Println(a)\n\tfmt.Println(b)\n\tfmt.Println(c)\n\tfmt.Println(d)\n\tfmt.Println(e)\n\tfmt.Println(f)\n}\n"
  },
  {
    "path": "06_constants/06_iota/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nconst (\n\t_ = iota      // 0\n\tb = iota * 10 // 1 * 10\n\tc = iota * 10 // 2 * 10\n)\n\nfunc main() {\n\tfmt.Println(b)\n\tfmt.Println(c)\n}\n"
  },
  {
    "path": "06_constants/07_iota/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nconst (\n\t_  = iota             // 0\n\tKB = 1 << (iota * 10) // 1 << (1 * 10)\n\tMB = 1 << (iota * 10) // 1 << (2 * 10)\n\tGB = 1 << (iota * 10) // 1 << (3 * 10)\n\tTB = 1 << (iota * 10) // 1 << (4 * 10)\n)\n\nfunc main() {\n\tfmt.Println(\"binary\\t\\tdecimal\")\n\tfmt.Printf(\"%b\\t\", KB)\n\tfmt.Printf(\"%d\\n\", KB)\n\tfmt.Printf(\"%b\\t\", MB)\n\tfmt.Printf(\"%d\\n\", MB)\n\tfmt.Printf(\"%b\\t\", GB)\n\tfmt.Printf(\"%d\\n\", GB)\n\tfmt.Printf(\"%b\\t\", TB)\n\tfmt.Printf(\"%d\\n\", TB)\n}\n"
  },
  {
    "path": "07_memory-address/01_showing-address/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\ta := 43\n\n\tfmt.Println(\"a - \", a)\n\tfmt.Println(\"a's memory address - \", &a)\n\tfmt.Printf(\"%d \\n\", &a)\n}\n"
  },
  {
    "path": "07_memory-address/02_using-address/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nconst metersToYards float64 = 1.09361\n\nfunc main() {\n\tvar meters float64\n\tfmt.Print(\"Enter meters swam: \")\n\tfmt.Scan(&meters)\n\tyards := meters * metersToYards\n\tfmt.Println(meters, \" meters is \", yards, \" yards.\")\n}\n"
  },
  {
    "path": "08_pointers/01_referencing/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\n\ta := 43\n\n\tfmt.Println(a)\n\tfmt.Println(&a)\n\n\tvar b = &a\n\n\tfmt.Println(b)\n\n\t// the above code makes b a pointer to the memory address where an int is stored\n\t// b is of type \"int pointer\"\n\t// *int -- the * is part of the type -- b is of type *int\n}\n"
  },
  {
    "path": "08_pointers/02_dereferencing/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\ta := 43\n\n\tfmt.Println(a)  // 43\n\tfmt.Println(&a) // 0x20818a220\n\n\tvar b = &a\n\tfmt.Println(b)  // 0x20818a220\n\tfmt.Println(*b) // 43\n\n\t// b is an int pointer;\n\t// b points to the memory address where an int is stored\n\t// to see the value in that memory address, add a * in front of b\n\t// this is known as dereferencing\n\t// the * is an operator in this case\n}\n"
  },
  {
    "path": "08_pointers/03_using-pointers/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\ta := 43\n\n\tfmt.Println(a)  // 43\n\tfmt.Println(&a) // 0x20818a220\n\n\tvar b = &a\n\tfmt.Println(b)  // 0x20818a220\n\tfmt.Println(*b) // 43\n\n\t*b = 42        // b says, \"The value at this address, change it to 42\"\n\tfmt.Println(a) // 42\n\n\t// this is useful\n\t// we can pass a memory address instead of a bunch of values (we can pass a reference)\n\t// and then we can still change the value of whatever is stored at that memory address\n\t// this makes our programs more performant\n\t// we don't have to pass around large amounts of data\n\t// we only have to pass around addresses\n\n\t// everything is PASS BY VALUE in go, btw\n\t// when we pass a memory address, we are passing a value\n}\n"
  },
  {
    "path": "08_pointers/04_using-pointers/01_no-pointer/01/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc zero(z int) {\n\tz = 0\n}\n\nfunc main() {\n\tx := 5\n\tzero(x)\n\tfmt.Println(x) // x is still 5\n}\n"
  },
  {
    "path": "08_pointers/04_using-pointers/01_no-pointer/02_see-the-addresses/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc zero(z int) {\n\tfmt.Printf(\"%p\\n\", &z) // address in func zero\n\tfmt.Println(&z)        // address in func zero\n\tz = 0\n}\n\nfunc main() {\n\tx := 5\n\tfmt.Printf(\"%p\\n\", &x) // address in main\n\tfmt.Println(&x)        // address in main\n\tzero(x)\n\tfmt.Println(x) // x is still 5\n}\n"
  },
  {
    "path": "08_pointers/04_using-pointers/02_pointer/01/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc zero(z *int) {\n\t*z = 0\n}\n\nfunc main() {\n\tx := 5\n\tzero(&x)\n\tfmt.Println(x) // x is 0\n}\n"
  },
  {
    "path": "08_pointers/04_using-pointers/02_pointer/02_see-the-addresses/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc zero(z *int) {\n\tfmt.Println(z)\n\t*z = 0\n}\n\nfunc main() {\n\tx := 5\n\tfmt.Println(&x)\n\tzero(&x)\n\tfmt.Println(x) // x is 0\n}\n"
  },
  {
    "path": "09_remainder/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tx := 13 % 3\n\tfmt.Println(x)\n\tif x == 1 {\n\t\tfmt.Println(\"Odd\")\n\t} else {\n\t\tfmt.Println(\"Even\")\n\t}\n\n\tfor i := 1; i < 70; i++ {\n\t\tif i%2 == 1 {\n\t\t\tfmt.Println(\"Odd\")\n\t\t} else {\n\t\t\tfmt.Println(\"Even\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "10_for-loop/01_init-condition-post/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfor i := 0; i <= 100; i++ {\n\t\tfmt.Println(i)\n\t}\n}\n"
  },
  {
    "path": "10_for-loop/02_nested/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfor i := 0; i < 5; i++ {\n\t\tfor j := 0; j < 5; j++ {\n\t\t\tfmt.Println(i, \" - \", j)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "10_for-loop/03_for-condition-while-ish/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\ti := 0\n\tfor i < 10 {\n\t\tfmt.Println(i)\n\t\ti++\n\t}\n}\n"
  },
  {
    "path": "10_for-loop/04_for_no-condition/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\ti := 0\n\tfor {\n\t\tfmt.Println(i)\n\t\ti++\n\t}\n}\n"
  },
  {
    "path": "10_for-loop/05_for_break/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\ti := 0\n\tfor {\n\t\tfmt.Println(i)\n\t\tif i >= 10 {\n\t\t\tbreak\n\t\t}\n\t\ti++\n\t}\n}\n"
  },
  {
    "path": "10_for-loop/06_for_continue/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\ti := 0\n\tfor {\n\t\ti++\n\t\tif i%2 == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tfmt.Println(i)\n\t\tif i >= 50 {\n\t\t\tbreak\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "10_for-loop/07_rune-loop_UTF8/01/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfor i := 250; i <= 340; i++ {\n\t\tfmt.Println(i, \" - \", string(i), \" - \", []byte(string(i)))\n\t}\n\tfoo := \"a\"\n\tfmt.Println(foo)\n\tfmt.Printf(\"%T \\n\", foo)\n}\n\n/*\nNOTE:\nSome operating systems (Windows) might not print characters where i < 256\n\nIf you have this issue, you can use this code:\n\nfmt.Println(i, \" - \", string(i), \" - \", []int32(string(i)))\n\nUTF-8 is the text coding scheme used by Go.\n\nUTF-8 works with 1 - 4 bytes.\n\nA byte is 8 bits.\n\n[]byte deals with bytes, that is, only 1 byte (8 bits) at a time.\n\n[]int32 allows us to store the value of 4 bytes, that is, 4 bytes * 8 bits per byte = 32 bits.\n*/\n"
  },
  {
    "path": "10_for-loop/07_rune-loop_UTF8/02/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfor i := 50; i <= 140; i++ {\n\t\tfmt.Printf(\"%v - %v - %v \\n\", i, string(i), []byte(string(i)))\n\t}\n}\n"
  },
  {
    "path": "11_switch-statements/01_switch/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tswitch \"Mhi\" {\n\tcase \"Daniel\":\n\t\tfmt.Println(\"Wassup Daniel\")\n\tcase \"Medhi\":\n\t\tfmt.Println(\"Wassup Medhi\")\n\tcase \"Jenny\":\n\t\tfmt.Println(\"Wassup Jenny\")\n\tdefault:\n\t\tfmt.Println(\"Have you no friends?\")\n\t}\n}\n\n/*\n  no default fallthrough\n  fallthrough is optional\n  -- you can specify fallthrough by explicitly stating it\n  -- break isn't needed like in other languages\n*/\n"
  },
  {
    "path": "11_switch-statements/02_fallthrough/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tswitch \"Marcus\" {\n\tcase \"Tim\":\n\t\tfmt.Println(\"Wassup Tim\")\n\tcase \"Jenny\":\n\t\tfmt.Println(\"Wassup Jenny\")\n\tcase \"Marcus\":\n\t\tfmt.Println(\"Wassup Marcus\")\n\t\tfallthrough\n\tcase \"Medhi\":\n\t\tfmt.Println(\"Wassup Medhi\")\n\t\tfallthrough\n\tcase \"Julian\":\n\t\tfmt.Println(\"Wassup Julian\")\n\tcase \"Sushant\":\n\t\tfmt.Println(\"Wassup Sushant\")\n\t}\n}\n"
  },
  {
    "path": "11_switch-statements/03_multiple-evals/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tswitch \"Jenny\" {\n\tcase \"Tim\", \"Jenny\":\n\t\tfmt.Println(\"Wassup Tim, or, err, Jenny\")\n\tcase \"Marcus\", \"Medhi\":\n\t\tfmt.Println(\"Both of your names start with M\")\n\tcase \"Julian\", \"Sushant\":\n\t\tfmt.Println(\"Wassup Julian / Sushant\")\n\t}\n}\n"
  },
  {
    "path": "11_switch-statements/04_no-expression/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tmyFriendsName := \"Mar\"\n\n\tswitch {\n\tcase len(myFriendsName) == 2:\n\t\tfmt.Println(\"Wassup my friend with name of length 2\")\n\tcase myFriendsName == \"Tim\":\n\t\tfmt.Println(\"Wassup Tim\")\n\tcase myFriendsName == \"Jenny\":\n\t\tfmt.Println(\"Wassup Jenny\")\n\tcase myFriendsName == \"Marcus\", myFriendsName == \"Medhi\":\n\t\tfmt.Println(\"Your name is either Marcus or Medhi\")\n\tcase myFriendsName == \"Julian\":\n\t\tfmt.Println(\"Wassup Julian\")\n\tcase myFriendsName == \"Sushant\":\n\t\tfmt.Println(\"Wassup Sushant\")\n\tdefault:\n\t\tfmt.Println(\"nothing matched; this is the default\")\n\t}\n}\n\n/*\n  expression not needed\n  -- if no expression provided, go checks for the first case that evals to true\n  -- makes the switch operate like if/if else/else\n  cases can be expressions\n*/\n"
  },
  {
    "path": "11_switch-statements/05_on-type/type.go",
    "content": "package main\n\nimport \"fmt\"\n\n//  switch on types\n//  -- normally we switch on value of variable\n//  -- go allows you to switch on type of variable\n\ntype contact struct {\n\tgreeting string\n\tname     string\n}\n\n// SwitchOnType works with interfaces\n// we'll learn more about interfaces later\nfunc SwitchOnType(x interface{}) {\n\tswitch x.(type) { // this is an assert; asserting, \"x is of this type\"\n\tcase int:\n\t\tfmt.Println(\"int\")\n\tcase string:\n\t\tfmt.Println(\"string\")\n\tcase contact:\n\t\tfmt.Println(\"contact\")\n\tdefault:\n\t\tfmt.Println(\"unknown\")\n\n\t}\n}\n\nfunc main() {\n\tSwitchOnType(7)\n\tSwitchOnType(\"McLeod\")\n\tvar t = contact{\"Good to see you,\", \"Tim\"}\n\tSwitchOnType(t)\n\tSwitchOnType(t.greeting)\n\tSwitchOnType(t.name)\n}\n"
  },
  {
    "path": "12_if_else-if_else/01_eval-true/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tif true {\n\t\tfmt.Println(\"This ran\")\n\t}\n\n\tif false {\n\t\tfmt.Println(\"This did not run\")\n\t}\n}\n"
  },
  {
    "path": "12_if_else-if_else/02_not-exclamation/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tif !true {\n\t\tfmt.Println(\"This did not run\")\n\t}\n\n\tif !false {\n\t\tfmt.Println(\"This ran\")\n\t}\n\n}\n"
  },
  {
    "path": "12_if_else-if_else/03_init-statement/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tb := true\n\n\tif food := \"Chocolate\"; b {\n\t\tfmt.Println(food)\n\t}\n\n}\n"
  },
  {
    "path": "12_if_else-if_else/04_init-statement_error_invalid-code/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tb := true\n\n\tif food := \"Chocolate\"; b {\n\t\tfmt.Println(food)\n\t}\n\n\tfmt.Println(food)\n\n}\n"
  },
  {
    "path": "12_if_else-if_else/05_if-else/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tif false {\n\t\tfmt.Println(\"first print statement\")\n\t} else {\n\t\tfmt.Println(\"second print statement\")\n\t}\n\n}\n"
  },
  {
    "path": "12_if_else-if_else/06_if-elseif-else/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tif false {\n\t\tfmt.Println(\"first print statement\")\n\t} else if true {\n\t\tfmt.Println(\"second print statement\")\n\t} else {\n\t\tfmt.Println(\"third print statement\")\n\t}\n\n}\n"
  },
  {
    "path": "12_if_else-if_else/07_if-elseif-elseif-else/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tif false {\n\t\tfmt.Println(\"first print statement\")\n\t} else if false {\n\t\tfmt.Println(\"second print statement\")\n\t} else if true {\n\t\tfmt.Println(\"ahahaha print statement\")\n\t} else {\n\t\tfmt.Println(\"third print statement\")\n\t}\n\n}\n"
  },
  {
    "path": "12_if_else-if_else/08_divisibleByThree/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfor i := 0; i <= 100; i++ {\n\t\tif i%3 == 0 {\n\t\t\tfmt.Println(i)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "13_exercise-solutions/01_hello-world/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(\"Hello World\")\n}\n"
  },
  {
    "path": "13_exercise-solutions/02_hello-NAME/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tname := \"Todd\"\n\tfmt.Println(\"Hello\", name)\n}\n"
  },
  {
    "path": "13_exercise-solutions/03_hello-user-input/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar name string\n\tfmt.Print(\"Please enter your name: \")\n\tfmt.Scan(&name)\n\tfmt.Println(\"Hello\", name)\n}\n"
  },
  {
    "path": "13_exercise-solutions/04_user-enters-numbers/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar numOne int\n\tvar numTwo int\n\tfmt.Print(\"Please enter a large number: \")\n\tfmt.Scan(&numOne)\n\tfmt.Print(\"Please enter a smaller number: \")\n\tfmt.Scan(&numTwo)\n\tfmt.Println(numOne, \"%\", numTwo, \" = \", numOne%numTwo)\n}\n"
  },
  {
    "path": "13_exercise-solutions/05_even-numbers/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfor i := 0; i <= 100; i++ {\n\t\tif i%2 == 0 {\n\t\t\tfmt.Println(i)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "13_exercise-solutions/06_fizzBuzz/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfor i := 0; i <= 100; i++ {\n\t\tif i%15 == 0 {\n\t\t\tfmt.Println(i, \" -- FizzBuzz\")\n\t\t} else if i%3 == 0 {\n\t\t\tfmt.Println(i, \" -- FIZZ\")\n\t\t} else if i%5 == 0 {\n\t\t\tfmt.Println(i, \" -- BUZZ\")\n\t\t} else {\n\t\t\tfmt.Println(i)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "13_exercise-solutions/07_threeFive/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tcounter := 0\n\tfor i := 0; i < 1000; i++ {\n\t\tif i%3 == 0 {\n\t\t\tcounter += i\n\t\t} else if i%5 == 0 {\n\t\t\tcounter += i\n\t\t}\n\t}\n\tfmt.Println(counter)\n}\n\n/*\n\nIf we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9.\nThe sum of these multiples is 23.\n\nFind the sum of all the multiples of 3 or 5 below 1000.\n*/\n"
  },
  {
    "path": "13_exercise-solutions/08_just-fyi/01_benchMark/bm_test.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n)\n\nfunc BenchmarkHello(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tfmt.Sprintf(\"hello\")\n\t}\n}\n\n// run this at command:\n// go test -bench='.*'\n"
  },
  {
    "path": "13_exercise-solutions/08_just-fyi/02_benchMark/bm_test.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n)\n\nfunc BenchmarkHello(b *testing.B) {\n\tcounter := 0\n\tfor i := 0; i < b.N; i++ {\n\t\tif i%3 == 0 {\n\t\t\tcounter += i\n\t\t} else if i%5 == 0 {\n\t\t\tcounter += i\n\t\t}\n\t}\n\tfmt.Println(counter)\n}\n\n// run this at command:\n// go test -bench='.*'\n"
  },
  {
    "path": "13_exercise-solutions/08_just-fyi/03_utf/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(\"Hello\"[1])\n}\n"
  },
  {
    "path": "14_functions/01_main/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(\"Hello world!\")\n}\n\n// main is the entry point to your program\n"
  },
  {
    "path": "14_functions/02_param-arg/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tgreet(\"Jane\")\n\tgreet(\"John\")\n}\n\nfunc greet(name string) {\n\tfmt.Println(name)\n}\n\n// greet is declared with a parameter\n// when calling greet, pass in an argument\n"
  },
  {
    "path": "14_functions/03_two-params/01/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tgreet(\"Jane\", \"Doe\")\n}\n\nfunc greet(fname string, lname string) {\n\tfmt.Println(fname, lname)\n}\n"
  },
  {
    "path": "14_functions/03_two-params/02/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tgreet(\"Jane\", \"Doe\")\n}\n\nfunc greet(fname, lname string) {\n\tfmt.Println(fname, lname)\n}\n"
  },
  {
    "path": "14_functions/04_return/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(greet(\"Jane \", \"Doe\"))\n}\n\nfunc greet(fname, lname string) string {\n\treturn fmt.Sprint(fname, lname)\n}\n"
  },
  {
    "path": "14_functions/05_return-naming/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(greet(\"Jane \", \"Doe\"))\n}\n\nfunc greet(fname string, lname string) (s string) {\n\ts = fmt.Sprint(fname, lname)\n\treturn\n}\n\n/*\nIMPORTANT\nAvoid using named returns.\n\n\nOccasionally named returns are useful. Read this article for more information:\nhttps://www.goinggo.net/2013/10/functions-and-naked-returns-in-go.html\n*/\n"
  },
  {
    "path": "14_functions/06_return-multiple/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(greet(\"Jane \", \"Doe \"))\n}\n\nfunc greet(fname, lname string) (string, string) {\n\treturn fmt.Sprint(fname, lname), fmt.Sprint(lname, fname)\n}\n"
  },
  {
    "path": "14_functions/07_variadic-params/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tn := average(43, 56, 87, 12, 45, 57)\n\tfmt.Println(n)\n}\n\nfunc average(sf ...float64) float64 {\n\tfmt.Println(sf)\n\tfmt.Printf(\"%T \\n\", sf)\n\tvar total float64\n\tfor _, v := range sf {\n\t\ttotal += v\n\t}\n\treturn total / float64(len(sf))\n}\n"
  },
  {
    "path": "14_functions/08_variadic-args/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tdata := []float64{43, 56, 87, 12, 45, 57}\n\tn := average(data...)\n\tfmt.Println(n)\n}\n\nfunc average(sf ...float64) float64 {\n\ttotal := 0.0\n\tfor _, v := range sf {\n\t\ttotal += v\n\t}\n\treturn total / float64(len(sf))\n}\n"
  },
  {
    "path": "14_functions/09_slice-param-arg/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tdata := []float64{43, 56, 87, 12, 45, 57}\n\tn := average(data)\n\tfmt.Println(n)\n}\n\nfunc average(sf []float64) float64 {\n\ttotal := 0.0\n\tfor _, v := range sf {\n\t\ttotal += v\n\t}\n\treturn total / float64(len(sf))\n}\n"
  },
  {
    "path": "14_functions/10_func-expression/01_before-func-expression/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc greeting() {\n\tfmt.Println(\"Hello world!\")\n}\n\nfunc main() {\n\tgreeting()\n}\n"
  },
  {
    "path": "14_functions/10_func-expression/02_func-expression/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tgreeting := func() {\n\t\tfmt.Println(\"Hello world!\")\n\t}\n\n\tgreeting()\n}\n"
  },
  {
    "path": "14_functions/10_func-expression/03_func-expression_shows-type/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tgreeting := func() {\n\t\tfmt.Println(\"Hello world!\")\n\t}\n\n\tgreeting()\n\tfmt.Printf(\"%T\\n\", greeting)\n}\n"
  },
  {
    "path": "14_functions/10_func-expression/04_another-way_func-expression/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc makeGreeter() func() string {\n\treturn func() string {\n\t\treturn \"Hello world!\"\n\t}\n}\n\nfunc main() {\n\tgreet := makeGreeter()\n\tfmt.Println(greet())\n}\n"
  },
  {
    "path": "14_functions/10_func-expression/05_another-way_func-expression_shows-type/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc makeGreeter() func() string {\n\treturn func() string {\n\t\treturn \"Hello world!\"\n\t}\n}\n\nfunc main() {\n\tgreet := makeGreeter()\n\tfmt.Println(greet())\n\tfmt.Printf(\"%T\\n\", greet)\n}\n"
  },
  {
    "path": "14_functions/11_closure/01/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tx := 42\n\tfmt.Println(x)\n\t{\n\t\tfmt.Println(x)\n\t\ty := \"The credit belongs with the one who is in the ring.\"\n\t\tfmt.Println(y)\n\t}\n\t// fmt.Println(y) // outside scope of y\n}\n"
  },
  {
    "path": "14_functions/11_closure/02/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nvar x int\n\nfunc increment() int {\n\tx++\n\treturn x\n}\n\nfunc main() {\n\tfmt.Println(increment())\n\tfmt.Println(increment())\n}\n\n/*\nclosure helps us limit the scope of variables used by multiple functions\nwithout closure, for two or more funcs to have access to the same variable,\nthat variable would need to be package scope\n*/\n"
  },
  {
    "path": "14_functions/11_closure/03/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tx := 0\n\tincrement := func() int {\n\t\tx++\n\t\treturn x\n\t}\n\tfmt.Println(increment())\n\tfmt.Println(increment())\n}\n\n/*\nclosure helps us limit the scope of variables used by multiple functions\nwithout closure, for two or more funcs to have access to the same variable,\nthat variable would need to be package scope\n\nanonymous function\na function without a name\n\nfunc expression\nassigning a func to a variable\n*/\n"
  },
  {
    "path": "14_functions/11_closure/04/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc wrapper() func() int {\n\tvar x int\n\treturn func() int {\n\t\tx++\n\t\treturn x\n\t}\n}\n\nfunc main() {\n\tincrement := wrapper()\n\tfmt.Println(increment())\n\tfmt.Println(increment())\n}\n\n/*\nclosure helps us limit the scope of variables used by multiple functions\nwithout closure, for two or more funcs to have access to the same variable,\nthat variable would need to be package scope\n*/\n"
  },
  {
    "path": "14_functions/11_closure/05/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc wrapper() func() int {\n\tvar x int\n\treturn func() int {\n\t\tx++\n\t\treturn x\n\t}\n}\n\nfunc main() {\n\tincrementA := wrapper()\n\tincrementB := wrapper()\n\tfmt.Println(\"A:\", incrementA())\n\tfmt.Println(\"A:\", incrementA())\n\tfmt.Println(\"B:\", incrementB())\n\tfmt.Println(\"B:\", incrementB())\n\tfmt.Println(\"B:\", incrementB())\n}\n\n/*\nclosure helps us limit the scope of variables used by multiple functions\nwithout closure, for two or more funcs to have access to the same variable,\nthat variable would need to be package scope\n*/\n"
  },
  {
    "path": "14_functions/12_callbacks/01_print-nums/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc visit(numbers []int, callback func(int)) {\n\tfor _, n := range numbers {\n\t\tcallback(n)\n\t}\n}\n\nfunc main() {\n\tvisit([]int{1, 2, 3, 4}, func(n int) {\n\t\tfmt.Println(n)\n\t})\n}\n\n// callback: passing a func as an argument\n"
  },
  {
    "path": "14_functions/12_callbacks/02_filter-nums/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc filter(numbers []int, callback func(int) bool) []int {\n\tvar xs []int\n\tfor _, n := range numbers {\n\t\tif callback(n) {\n\t\t\txs = append(xs, n)\n\t\t}\n\t}\n\treturn xs\n}\n\nfunc main() {\n\txs := filter([]int{1, 2, 3, 4}, func(n int) bool {\n\t\treturn n > 1\n\t})\n\tfmt.Println(xs) // [2 3 4]\n}\n"
  },
  {
    "path": "14_functions/13_recursion/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc factorial(x int) int {\n\tif x == 0 {\n\t\treturn 1\n\t}\n\treturn x * factorial(x-1)\n}\n\nfunc main() {\n\tfmt.Println(factorial(4))\n}\n"
  },
  {
    "path": "14_functions/14_defer/01_no-defer/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc hello() {\n\tfmt.Print(\"hello \")\n}\n\nfunc world() {\n\tfmt.Println(\"world\")\n}\n\nfunc main() {\n\tworld()\n\thello()\n}\n"
  },
  {
    "path": "14_functions/14_defer/02_with-defer/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc hello() {\n\tfmt.Print(\"hello \")\n}\n\nfunc world() {\n\tfmt.Println(\"world\")\n}\n\nfunc main() {\n\tdefer world()\n\thello()\n}\n"
  },
  {
    "path": "14_functions/15_passing-by-value/01_int/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tage := 44\n\tchangeMe(age)\n\tfmt.Println(age) // 44\n}\n\nfunc changeMe(z int) {\n\tfmt.Println(z)\n\tz = 24\n}\n\n// when changeMe is called on line 8\n// the value 44 is being passed as an argument\n"
  },
  {
    "path": "14_functions/15_passing-by-value/02_int-pointer/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tage := 44\n\tfmt.Println(&age) // 0x82023c080\n\n\tchangeMe(&age)\n\n\tfmt.Println(&age) //0x82023c080\n\tfmt.Println(age)  //24\n}\n\nfunc changeMe(z *int) {\n\tfmt.Println(z)  // 0x82023c080\n\tfmt.Println(*z) // 44\n\t*z = 24\n\tfmt.Println(z)  // 0x82023c080\n\tfmt.Println(*z) // 24\n}\n"
  },
  {
    "path": "14_functions/15_passing-by-value/03_string/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tname := \"Todd\"\n\tfmt.Println(name) // Todd\n\n\tchangeMe(name)\n\n\tfmt.Println(name) // Todd\n}\n\nfunc changeMe(z string) {\n\tfmt.Println(z) // Todd\n\tz = \"Rocky\"\n\tfmt.Println(z) // Rocky\n}\n"
  },
  {
    "path": "14_functions/15_passing-by-value/04_string-pointer/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tname := \"Todd\"\n\tfmt.Println(&name) // 0x82023c080\n\n\tchangeMe(&name)\n\n\tfmt.Println(&name) //0x82023c080\n\tfmt.Println(name)  //Rocky\n}\n\nfunc changeMe(z *string) {\n\tfmt.Println(z)  // 0x82023c080\n\tfmt.Println(*z) // Todd\n\t*z = \"Rocky\"\n\tfmt.Println(z)  // 0x82023c080\n\tfmt.Println(*z) // Rocky\n}\n"
  },
  {
    "path": "14_functions/15_passing-by-value/05_REFERENCE-TYPE/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tm := make(map[string]int)\n\tchangeMe(m)\n\tfmt.Println(m[\"Todd\"]) // 44\n}\n\nfunc changeMe(z map[string]int) {\n\tz[\"Todd\"] = 44\n}\n\n/*\nAllocation with make\nBack to allocation. The built-in function make(T, args)\nserves a purpose different from new(T). It creates slices, maps, and channels only,\nand it returns an initialized (not zeroed) value of type T (not *T). The reason for\nthe distinction is that these three types represent, under the covers, references to data structures\nthat must be initialized before use. A slice, for example, is a three-item descriptor containing\na pointer to the data (inside an array), the length, and the capacity, and until those items are initialized,\nthe slice is nil. For slices, maps, and channels, make initializes the internal data structure and prepares\nthe value for use.\n*/\n// https://golang.org/doc/effective_go.html#allocation_make\n"
  },
  {
    "path": "14_functions/15_passing-by-value/06_REFERENCE-TYPE/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tm := make([]string, 1, 25)\n\tfmt.Println(m) // [ ]\n\tchangeMe(m)\n\tfmt.Println(m) // [Todd]\n}\n\nfunc changeMe(z []string) {\n\tz[0] = \"Todd\"\n\tfmt.Println(z) // [Todd]\n}\n"
  },
  {
    "path": "14_functions/15_passing-by-value/07_struct-pointer/main.go",
    "content": "package main\n\nimport \"fmt\"\n\ntype customer struct {\n\tname string\n\tage  int\n}\n\nfunc main() {\n\tc1 := customer{\"Todd\", 44}\n\tfmt.Println(&c1.name) // 0x8201e4120\n\n\tchangeMe(&c1)\n\n\tfmt.Println(c1)       // {Rocky 44}\n\tfmt.Println(&c1.name) // 0x8201e4120\n}\n\nfunc changeMe(z *customer) {\n\tfmt.Println(z)       // &{Todd 44}\n\tfmt.Println(&z.name) // 0x8201e4120\n\tz.name = \"Rocky\"\n\tfmt.Println(z)       // &{Rocky 44}\n\tfmt.Println(&z.name) // 0x8201e4120\n\n}\n"
  },
  {
    "path": "14_functions/16_anon_self-executing/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfunc() {\n\t\tfmt.Println(\"I'm driving!\")\n\t}()\n}\n"
  },
  {
    "path": "15_bool-expressions/01_true-false/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tif true {\n\t\tfmt.Println(\"This ran\")\n\t}\n\n\tif false {\n\t\tfmt.Println(\"This did not run\")\n\t}\n}\n"
  },
  {
    "path": "15_bool-expressions/02_not/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tif !true {\n\t\tfmt.Println(\"This did not run\")\n\t}\n\n\tif !false {\n\t\tfmt.Println(\"This ran\")\n\t}\n\n}\n"
  },
  {
    "path": "15_bool-expressions/03_or/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tif true || false {\n\t\tfmt.Println(\"This ran\")\n\t}\n}\n"
  },
  {
    "path": "15_bool-expressions/04_and/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tif true && false {\n\t\tfmt.Println(\"This did not run\")\n\t}\n\n}\n"
  },
  {
    "path": "16_exercise-solutions/01_half/01/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc half(n int) (int, bool) {\n\treturn n / 2, n%2 == 0\n}\n\nfunc main() {\n\th, even := half(5)\n\tfmt.Println(h, even)\n}\n"
  },
  {
    "path": "16_exercise-solutions/01_half/02/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc half(n int) (float64, bool) {\n\treturn float64(n) / 2, n%2 == 0\n}\n\nfunc main() {\n\th, even := half(5)\n\tfmt.Println(h, even)\n}\n"
  },
  {
    "path": "16_exercise-solutions/02_func-expression/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\thalf := func(n int) (int, bool) {\n\t\treturn n / 2, n%2 == 0\n\t}\n\n\tfmt.Println(half(5))\n}\n"
  },
  {
    "path": "16_exercise-solutions/03_variadic-greatest/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc max(numbers ...int) int {\n\tvar largest int\n\tfor _, v := range numbers {\n\t\tif v > largest {\n\t\t\tlargest = v\n\t\t}\n\t}\n\treturn largest\n}\n\nfunc main() {\n\tgreatest := max(4, 7, 9, 123, 543, 23, 435, 53, 125)\n\tfmt.Println(greatest)\n}\n\n/*\nFYI\nFor your code to also work with only negative numbers such as\n\ngreatest := max(-200 -700)\n\ninclude this as your range statement\nfor i, v := range numbers {\n\tif v > largest || i == 0 {\n\t\tlargest = v\n\t}\n}\n\nWhat does that code do?\n\nThe first time through the range loop\nthe index, i, will be zero\nso largest will be set to the first number\n\nOriginally largest is set to the zero value for an int, which is zero\n\nZero would be greater than any negative number\n\nif you only have negative numbers\nyou need largest to be something less than zero\n\nThanks to Ricardo G for this code improvement!\n*/\n"
  },
  {
    "path": "16_exercise-solutions/04_bool-expression/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println((true && false) || (false && true) || !(false && false))\n}\n"
  },
  {
    "path": "16_exercise-solutions/05_params-and-args/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfoo(1, 2)\n\tfoo(1, 2, 3)\n\taSlice := []int{1, 2, 3, 4}\n\tfoo(aSlice...)\n\tfoo()\n}\n\nfunc foo(numbers ...int) {\n\tfmt.Println(numbers)\n}\n"
  },
  {
    "path": "17_array/01/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar x [58]int\n\tfmt.Println(x)\n\tfmt.Println(len(x))\n\tfmt.Println(x[42])\n\tx[42] = 777\n\tfmt.Println(x[42])\n}\n"
  },
  {
    "path": "17_array/02/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar x [58]string\n\n\tfor i := 65; i <= 122; i++ {\n\t\tx[i-65] = string(i)\n\t}\n\n\tfmt.Println(x)\n\tfmt.Println(x[42])\n}\n"
  },
  {
    "path": "17_array/03/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar x [256]int\n\n\tfmt.Println(len(x))\n\tfmt.Println(x[42])\n\tfor i := 0; i < 256; i++ {\n\t\tx[i] = i\n\t}\n\tfor i, v := range x {\n\t\tfmt.Printf(\"%v - %T - %b\\n\", v, v, v)\n\t\tif i > 50 {\n\t\t\tbreak\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "17_array/04/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar x [256]byte\n\n\tfmt.Println(len(x))\n\tfmt.Println(x[42])\n\tfor i := 0; i < 256; i++ {\n\t\tx[i] = byte(i)\n\t}\n\tfor i, v := range x {\n\t\tfmt.Printf(\"%v - %T - %b\\n\", v, v, v)\n\t\tif i > 50 {\n\t\t\tbreak\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "17_array/05/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar x [256]string\n\n\tfmt.Println(len(x))\n\tfmt.Println(x[0])\n\tfor i := 0; i < 256; i++ {\n\t\tx[i] = string(i)\n\t}\n\tfor _, v := range x {\n\t\tfmt.Printf(\"%v - %T - %v\\n\", v, v, []byte(v))\n\t}\n}\n"
  },
  {
    "path": "18_slice/01_int-slice/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tmySlice := []int{1, 3, 5, 7, 9, 11}\n\tfmt.Printf(\"%T\\n\", mySlice)\n\tfmt.Println(mySlice)\n}\n"
  },
  {
    "path": "18_slice/02_int-slice/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\txs := []int{1, 3, 5, 7, 9, 11}\n\n\tfor i, value := range xs {\n\t\tfmt.Println(i, \" - \", value)\n\t}\n\n}\n"
  },
  {
    "path": "18_slice/03_int-slice/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tmySlice := make([]int, 0, 3)\n\n\tfmt.Println(\"-----------------\")\n\tfmt.Println(mySlice)\n\tfmt.Println(len(mySlice))\n\tfmt.Println(cap(mySlice))\n\tfmt.Println(\"-----------------\")\n\n\tfor i := 0; i < 80; i++ {\n\t\tmySlice = append(mySlice, i)\n\t\tfmt.Println(\"Len:\", len(mySlice), \"Capacity:\", cap(mySlice), \"Value: \", mySlice[i])\n\t}\n}\n"
  },
  {
    "path": "18_slice/04_string-slice/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tgreeting := []string{\n\t\t\"Good morning!\",\n\t\t\"Bonjour!\",\n\t\t\"dias!\",\n\t\t\"Bongiorno!\",\n\t\t\"Ohayo!\",\n\t\t\"Selamat pagi!\",\n\t\t\"Gutten morgen!\",\n\t}\n\n\tfor i, currentEntry := range greeting {\n\t\tfmt.Println(i, currentEntry)\n\t}\n\n\tfor j := 0; j < len(greeting); j++ {\n\t\tfmt.Println(greeting[j])\n\t}\n\n}\n"
  },
  {
    "path": "18_slice/05_slicing-a-slice/01/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tvar results []int\n\tfmt.Println(results)\n\n\tmySlice := []string{\"a\", \"b\", \"c\", \"g\", \"m\", \"z\"}\n\tfmt.Println(mySlice)\n\tfmt.Println(mySlice[2:4])  // slicing a slice\n\tfmt.Println(mySlice[2])    // index access; accessing by index\n\tfmt.Println(\"myString\"[2]) // index access; accessing by index\n}\n"
  },
  {
    "path": "18_slice/05_slicing-a-slice/02/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tgreeting := []string{\n\t\t\"Good morning!\",\n\t\t\"Bonjour!\",\n\t\t\"dias!\",\n\t\t\"Bongiorno!\",\n\t\t\"Ohayo!\",\n\t\t\"Selamat pagi!\",\n\t\t\"Gutten morgen!\",\n\t}\n\n\tfmt.Print(\"[1:2] \")\n\tfmt.Println(greeting[1:2])\n\tfmt.Print(\"[:2] \")\n\tfmt.Println(greeting[:2])\n\tfmt.Print(\"[5:] \")\n\tfmt.Println(greeting[5:])\n\tfmt.Print(\"[:] \")\n\tfmt.Println(greeting[:])\n}\n"
  },
  {
    "path": "18_slice/06_make/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tcustomerNumber := make([]int, 3)\n\t// 3 is length & capacity\n\t// // length - number of elements referred to by the slice\n\t// // capacity - number of elements in the underlying array\n\tcustomerNumber[0] = 7\n\tcustomerNumber[1] = 10\n\tcustomerNumber[2] = 15\n\n\tfmt.Println(customerNumber[0])\n\tfmt.Println(customerNumber[1])\n\tfmt.Println(customerNumber[2])\n\n\tgreeting := make([]string, 3, 5)\n\t// 3 is length - number of elements referred to by the slice\n\t// 5 is capacity - number of elements in the underlying array\n\t// you could also do it like this\n\n\tgreeting[0] = \"Good morning!\"\n\tgreeting[1] = \"Bonjour!\"\n\tgreeting[2] = \"dias!\"\n\n\tfmt.Println(greeting[2])\n}\n"
  },
  {
    "path": "18_slice/07_append-invalid/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tgreeting := make([]string, 3, 5)\n\t// 3 is length - number of elements referred to by the slice\n\t// 5 is capacity - number of elements in the underlying array\n\n\tgreeting[0] = \"Good morning!\"\n\tgreeting[1] = \"Bonjour!\"\n\tgreeting[2] = \"buenos dias!\"\n\tgreeting[3] = \"suprabadham\"\n\n\tfmt.Println(greeting[2])\n}\n"
  },
  {
    "path": "18_slice/08_append/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tgreeting := make([]string, 3, 5)\n\t// 3 is length - number of elements referred to by the slice\n\t// 5 is capacity - number of elements in the underlying array\n\n\tgreeting[0] = \"Good morning!\"\n\tgreeting[1] = \"Bonjour!\"\n\tgreeting[2] = \"buenos dias!\"\n\tgreeting = append(greeting, \"Suprabadham\")\n\n\tfmt.Println(greeting[3])\n}\n"
  },
  {
    "path": "18_slice/09_append-beyond-capacity/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tgreeting := make([]string, 3, 5)\n\t// 3 is length - number of elements referred to by the slice\n\t// 5 is capacity - number of elements in the underlying array\n\n\tgreeting[0] = \"Good morning!\"\n\tgreeting[1] = \"Bonjour!\"\n\tgreeting[2] = \"buenos dias!\"\n\tgreeting = append(greeting, \"Suprabadham\")\n\tgreeting = append(greeting, \"Zǎo'ān\")\n\tgreeting = append(greeting, \"Ohayou gozaimasu\")\n\tgreeting = append(greeting, \"gidday\")\n\n\tfmt.Println(greeting[6])\n\tfmt.Println(len(greeting))\n\tfmt.Println(cap(greeting))\n}\n"
  },
  {
    "path": "18_slice/10_append_slice-to-slice/01_slice-of-ints/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tmySlice := []int{1, 2, 3, 4, 5}\n\tmyOtherSlice := []int{6, 7, 8, 9}\n\n\tmySlice = append(mySlice, myOtherSlice...)\n\n\tfmt.Println(mySlice)\n}\n"
  },
  {
    "path": "18_slice/10_append_slice-to-slice/02_slice-of-strings/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tmySlice := []string{\"Monday\", \"Tuesday\"}\n\tmyOtherSlice := []string{\"Wednesday\", \"Thursday\", \"Friday\"}\n\n\tmySlice = append(mySlice, myOtherSlice...)\n\n\tfmt.Println(mySlice)\n}\n"
  },
  {
    "path": "18_slice/11_delete/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tmySlice := []string{\"Monday\", \"Tuesday\"}\n\tmyOtherSlice := []string{\"Wednesday\", \"Thursday\", \"Friday\"}\n\n\tmySlice = append(mySlice, myOtherSlice...)\n\tfmt.Println(mySlice)\n\n\tmySlice = append(mySlice[:2], mySlice[3:]...)\n\tfmt.Println(mySlice)\n\n}\n"
  },
  {
    "path": "18_slice/12_multi-dimensional/01_shorthand-slice/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tstudent := []string{}\n\tstudents := [][]string{}\n\tfmt.Println(student)\n\tfmt.Println(students)\n\tfmt.Println(student == nil)\n}\n"
  },
  {
    "path": "18_slice/12_multi-dimensional/02_var-slice/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tvar student []string\n\tvar students [][]string\n\tfmt.Println(student)\n\tfmt.Println(students)\n\tfmt.Println(student == nil)\n}\n"
  },
  {
    "path": "18_slice/12_multi-dimensional/03_make-slice/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tstudent := make([]string, 35)\n\tstudents := make([][]string, 35)\n\tfmt.Println(student)\n\tfmt.Println(students)\n\tfmt.Println(student == nil)\n}\n"
  },
  {
    "path": "18_slice/12_multi-dimensional/04_comparing_shorthand_var_make/01_shorthand-slice/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tstudent := []string{}\n\tstudents := [][]string{}\n\tstudent[0] = \"Todd\"\n\t// student = append(student, \"Todd\")\n\tfmt.Println(student)\n\tfmt.Println(students)\n}\n"
  },
  {
    "path": "18_slice/12_multi-dimensional/04_comparing_shorthand_var_make/02_var-slice/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tvar student []string\n\tvar students [][]string\n\tstudent[0] = \"Todd\"\n\t// student = append(student, \"Todd\")\n\tfmt.Println(student)\n\tfmt.Println(students)\n}\n"
  },
  {
    "path": "18_slice/12_multi-dimensional/04_comparing_shorthand_var_make/03_make-slice/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tstudent := make([]string, 35)\n\tstudents := make([][]string, 35)\n\tstudent[0] = \"Todd\"\n\t// student = append(student, \"Todd\")\n\tfmt.Println(student)\n\tfmt.Println(students)\n}\n"
  },
  {
    "path": "18_slice/12_multi-dimensional/05_slice-of-slice-of-string/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tvar records [][]string\n\t// student 1\n\tstudent1 := make([]string, 4)\n\tstudent1[0] = \"Foster\"\n\tstudent1[1] = \"Nathan\"\n\tstudent1[2] = \"100.00\"\n\tstudent1[3] = \"74.00\"\n\t// store the record\n\trecords = append(records, student1)\n\t// student 2\n\tstudent2 := make([]string, 4)\n\tstudent2[0] = \"Gomez\"\n\tstudent2[1] = \"Lisa\"\n\tstudent2[2] = \"92.00\"\n\tstudent2[3] = \"96.00\"\n\t// store the record\n\trecords = append(records, student2)\n\t// print\n\tfmt.Println(records)\n}\n"
  },
  {
    "path": "18_slice/12_multi-dimensional/06_slice-of-slice-of-int/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\n\ttransactions := make([][]int, 0, 3)\n\n\tfor i := 0; i < 3; i++ {\n\t\ttransaction := make([]int, 0, 4)\n\t\tfor j := 0; j < 4; j++ {\n\t\t\ttransaction = append(transaction, j)\n\t\t}\n\t\ttransactions = append(transactions, transaction)\n\t}\n\tfmt.Println(transactions)\n}\n"
  },
  {
    "path": "18_slice/13_int-slice-plus-plus/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tmySlice := make([]int, 1)\n\tfmt.Println(mySlice[0])\n\tmySlice[0] = 7\n\tfmt.Println(mySlice[0])\n\tmySlice[0]++\n\tfmt.Println(mySlice[0])\n}\n"
  },
  {
    "path": "19_map/01_var_nil-map/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tvar myGreeting map[string]string\n\tfmt.Println(myGreeting)\n\tfmt.Println(myGreeting == nil)\n}\n\n// add these lines:\n/*\n\tmyGreeting[\"Tim\"] = \"Good morning.\"\n\tmyGreeting[\"Jenny\"] = \"Bonjour.\"\n*/\n// and you will get this:\n// panic: assignment to entry in nil map\n"
  },
  {
    "path": "19_map/02_var_make/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tvar myGreeting = make(map[string]string)\n\tmyGreeting[\"Tim\"] = \"Good morning.\"\n\tmyGreeting[\"Jenny\"] = \"Bonjour.\"\n\n\tfmt.Println(myGreeting)\n}\n"
  },
  {
    "path": "19_map/03_shorthand_make/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tmyGreeting := make(map[string]string)\n\tmyGreeting[\"Tim\"] = \"Good morning.\"\n\tmyGreeting[\"Jenny\"] = \"Bonjour.\"\n\n\tfmt.Println(myGreeting)\n}\n"
  },
  {
    "path": "19_map/04_shorthand_composite-literal/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tmyGreeting := map[string]string{}\n\tmyGreeting[\"Tim\"] = \"Good morning.\"\n\tmyGreeting[\"Jenny\"] = \"Bonjour.\"\n\n\tfmt.Println(myGreeting)\n}\n"
  },
  {
    "path": "19_map/05_shorthand_composite-literal/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tmyGreeting := map[string]string{\n\t\t\"Tim\":   \"Good morning!\",\n\t\t\"Jenny\": \"Bonjour!\",\n\t}\n\n\tfmt.Println(myGreeting[\"Jenny\"])\n}\n"
  },
  {
    "path": "19_map/06_adding-entry/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tmyGreeting := map[string]string{\n\t\t\"Tim\":   \"Good morning!\",\n\t\t\"Jenny\": \"Bonjour!\",\n\t}\n\n\tmyGreeting[\"Harleen\"] = \"Howdy\"\n\n\tfmt.Println(myGreeting)\n}\n"
  },
  {
    "path": "19_map/07_len/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tmyGreeting := map[string]string{\n\t\t\"Tim\":   \"Good morning!\",\n\t\t\"Jenny\": \"Bonjour!\",\n\t}\n\n\tmyGreeting[\"Harleen\"] = \"Howdy\"\n\n\tfmt.Println(len(myGreeting))\n}\n"
  },
  {
    "path": "19_map/08_updating-entry/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tmyGreeting := map[string]string{\n\t\t\"Tim\":   \"Good morning!\",\n\t\t\"Jenny\": \"Bonjour!\",\n\t}\n\n\tmyGreeting[\"Harleen\"] = \"Howdy\"\n\tfmt.Println(myGreeting)\n\tmyGreeting[\"Harleen\"] = \"Gidday\"\n\tfmt.Println(myGreeting)\n}\n"
  },
  {
    "path": "19_map/09_deleting-entry/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tmyGreeting := map[string]string{\n\t\t\"zero\":  \"Good morning!\",\n\t\t\"one\":   \"Bonjour!\",\n\t\t\"two\":   \"Buenos dias!\",\n\t\t\"three\": \"Bongiorno!\",\n\t}\n\n\tfmt.Println(myGreeting)\n\tdelete(myGreeting, \"two\")\n\tfmt.Println(myGreeting)\n}\n"
  },
  {
    "path": "19_map/10_comma-ok-idiom_val-exists/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tmyGreeting := map[int]string{\n\t\t0: \"Good morning!\",\n\t\t1: \"Bonjour!\",\n\t\t2: \"Buenos dias!\",\n\t\t3: \"Bongiorno!\",\n\t}\n\n\tfmt.Println(myGreeting)\n\n\t// delete(myGreeting, 2)\n\n\tif val, exists := myGreeting[2]; exists {\n\t\tfmt.Println(\"That value exists.\")\n\t\tfmt.Println(\"val: \", val)\n\t\tfmt.Println(\"exists: \", exists)\n\t} else {\n\t\tfmt.Println(\"That value doesn't exist.\")\n\t\tfmt.Println(\"val: \", val)\n\t\tfmt.Println(\"exists: \", exists)\n\t}\n\n\tfmt.Println(myGreeting)\n}\n"
  },
  {
    "path": "19_map/11_deleting-entry_no-error/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tmyGreeting := map[int]string{\n\t\t0: \"Good morning!\",\n\t\t1: \"Bonjour!\",\n\t\t2: \"Buenos dias!\",\n\t\t3: \"Bongiorno!\",\n\t}\n\n\tfmt.Println(myGreeting)\n\tdelete(myGreeting, 7)\n\tfmt.Println(myGreeting)\n}\n"
  },
  {
    "path": "19_map/12_comma-ok-idiom_val-not-exists/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tmyGreeting := map[int]string{\n\t\t0: \"Good morning!\",\n\t\t1: \"Bonjour!\",\n\t\t2: \"Buenos dias!\",\n\t\t3: \"Bongiorno!\",\n\t}\n\n\tfmt.Println(myGreeting)\n\n\tif val, exists := myGreeting[7]; exists {\n\t\tdelete(myGreeting, 7)\n\t\tfmt.Println(\"val: \", val)\n\t\tfmt.Println(\"exists: \", exists)\n\t} else {\n\t\tfmt.Println(\"That value doesn't exist.\")\n\t\tfmt.Println(\"val: \", val)\n\t\tfmt.Println(\"exists: \", exists)\n\t}\n\n\tfmt.Println(myGreeting)\n}\n"
  },
  {
    "path": "19_map/13_loop-range/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tmyGreeting := map[int]string{\n\t\t0: \"Good morning!\",\n\t\t1: \"Bonjour!\",\n\t\t2: \"Buenos dias!\",\n\t\t3: \"Bongiorno!\",\n\t}\n\n\tfor key, val := range myGreeting {\n\t\tfmt.Println(key, \" - \", val)\n\t}\n}\n"
  },
  {
    "path": "19_map/14_hash-table/01_letter-buckets/01_runes-are-numbers/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tletter := 'A'\n\tfmt.Println(letter)\n\tfmt.Printf(\"%T \\n\", letter)\n}\n"
  },
  {
    "path": "19_map/14_hash-table/01_letter-buckets/02_strings-to-rune-conversion/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tletter := rune(\"A\"[0])\n\tfmt.Println(letter)\n}\n"
  },
  {
    "path": "19_map/14_hash-table/01_letter-buckets/03_string-index-access/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tword := \"Hello\"\n\tletter := rune(word[0])\n\tfmt.Println(letter)\n}\n"
  },
  {
    "path": "19_map/14_hash-table/01_letter-buckets/04_remainder-bucket-selection/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfor i := 65; i <= 122; i++ {\n\t\tfmt.Println(i, \" - \", string(i), \" - \", i%12)\n\t}\n}\n"
  },
  {
    "path": "19_map/14_hash-table/01_letter-buckets/05_hash-function/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tn := hashBucket(\"Go\", 12)\n\tfmt.Println(n)\n}\n\nfunc hashBucket(word string, buckets int) int {\n\tletter := int(word[0])\n\tbucket := letter % buckets\n\treturn bucket\n}\n"
  },
  {
    "path": "19_map/14_hash-table/01_letter-buckets/06_get/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tres, err := http.Get(\"http://www.gutenberg.org/files/2701/old/moby10b.txt\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tbs, err := ioutil.ReadAll(res.Body)\n\tres.Body.Close()\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tfmt.Printf(\"%s\", bs)\n}\n"
  },
  {
    "path": "19_map/14_hash-table/01_letter-buckets/07_scanner/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\t// An artificial input source.\n\tconst input = \"It is not the critic who counts; not the man who points out how the strong man stumbles, or where the doer of deeds could have done them better. The credit belongs to the man who is actually in the arena, whose face is marred by dust and sweat and blood; who strives valiantly; who errs, who comes short again and again, because there is no effort without error and shortcoming; but who does actually strive to do the deeds; who knows great enthusiasms, the great devotions; who spends himself in a worthy cause; who at the best knows in the end the triumph of high achievement, and who at the worst, if he fails, at least fails while daring greatly, so that his place shall never be with those cold and timid souls who neither know victory nor defeat. \"\n\tscanner := bufio.NewScanner(strings.NewReader(input))\n\t// Set the split function for the scanning operation.\n\tscanner.Split(bufio.ScanWords)\n\t// Count the words.\n\tfor scanner.Scan() {\n\t\tfmt.Println(scanner.Text())\n\t}\n\tif err := scanner.Err(); err != nil {\n\t\tfmt.Fprintln(os.Stderr, \"reading input:\", err)\n\t}\n}\n"
  },
  {
    "path": "19_map/14_hash-table/01_letter-buckets/08_moby-dicks-words/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc main() {\n\t// get the book moby dick\n\tres, err := http.Get(\"http://www.gutenberg.org/files/2701/old/moby10b.txt\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\t// scan the page\n\t// NewScanner takes a reader and res.Body implements the reader interface (so it is a reader)\n\tscanner := bufio.NewScanner(res.Body)\n\tdefer res.Body.Close()\n\t// Set the split function for the scanning operation.\n\tscanner.Split(bufio.ScanWords)\n\t// Loop over the words\n\tfor scanner.Scan() {\n\t\tfmt.Println(scanner.Text())\n\t}\n}\n"
  },
  {
    "path": "19_map/14_hash-table/01_letter-buckets/09_int-slice-plus-plus/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tbuckets := make([]int, 1)\n\tfmt.Println(buckets[0])\n\tbuckets[0] = 42\n\tfmt.Println(buckets[0])\n\tbuckets[0]++\n\tfmt.Println(buckets[0])\n}\n"
  },
  {
    "path": "19_map/14_hash-table/01_letter-buckets/10_hash-letter-buckets/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc main() {\n\t// get the book moby dick\n\tres, err := http.Get(\"http://www.gutenberg.org/files/2701/old/moby10b.txt\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\t// scan the page\n\tscanner := bufio.NewScanner(res.Body)\n\tdefer res.Body.Close()\n\t// Set the split function for the scanning operation.\n\tscanner.Split(bufio.ScanWords)\n\t// Create slice to hold counts\n\tbuckets := make([]int, 200)\n\t// Loop over the words\n\tfor scanner.Scan() {\n\t\tn := hashBucket(scanner.Text())\n\t\tbuckets[n]++\n\t}\n\tfmt.Println(buckets[65:123])\n\t// fmt.Println(\"***************\")\n\t// for i := 28; i <= 126; i++ {\n\t// fmt.Printf(\"%v - %c - %v \\n\", i, i, buckets[i])\n\t// }\n}\n\nfunc hashBucket(word string) int {\n\treturn int(word[0])\n}\n"
  },
  {
    "path": "19_map/14_hash-table/01_letter-buckets/11_hash-remainder-buckets/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc main() {\n\t// get the book moby dick\n\tres, err := http.Get(\"http://www.gutenberg.org/files/2701/old/moby10b.txt\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\t// scan the page\n\tscanner := bufio.NewScanner(res.Body)\n\tdefer res.Body.Close()\n\t// Set the split function for the scanning operation.\n\tscanner.Split(bufio.ScanWords)\n\t// Create slice to hold counts\n\tbuckets := make([]int, 12)\n\t// Loop over the words\n\tfor scanner.Scan() {\n\t\tn := hashBucket(scanner.Text(), 12)\n\t\tbuckets[n]++\n\t}\n\tfmt.Println(buckets)\n}\n\nfunc hashBucket(word string, buckets int) int {\n\tletter := int(word[0])\n\tbucket := letter % buckets\n\treturn bucket\n}\n"
  },
  {
    "path": "19_map/14_hash-table/02_even-dstribution-hash/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc main() {\n\t// get the book adventures of sherlock holmes\n\tres, err := http.Get(\"http://www.gutenberg.org/cache/epub/1661/pg1661.txt\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\t// scan the page\n\tscanner := bufio.NewScanner(res.Body)\n\tdefer res.Body.Close()\n\t// Set the split function for the scanning operation.\n\tscanner.Split(bufio.ScanWords)\n\t// Create slice to hold counts\n\tbuckets := make([]int, 12)\n\t// Loop over the words\n\tfor scanner.Scan() {\n\t\tn := hashBucket(scanner.Text(), 12)\n\t\tbuckets[n]++\n\t}\n\tfmt.Println(buckets)\n}\n\nfunc hashBucket(word string, buckets int) int {\n\tvar sum int\n\tfor _, v := range word {\n\t\tsum += int(v)\n\t}\n\treturn sum % buckets\n}\n"
  },
  {
    "path": "19_map/14_hash-table/03_words-in-buckets/01_slice-bucket/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc main() {\n\t// get the book adventures of sherlock holmes\n\tres, err := http.Get(\"http://www.gutenberg.org/cache/epub/1661/pg1661.txt\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\t// scan the page\n\tscanner := bufio.NewScanner(res.Body)\n\tdefer res.Body.Close()\n\t// Set the split function for the scanning operation.\n\tscanner.Split(bufio.ScanWords)\n\t// Create slice of slice of string to hold slices of words\n\tbuckets := make([][]string, 12)\n\n\t// code here has been updated from the recording\n\t// see below for explanation\n\n\t// Loop over the words\n\tfor scanner.Scan() {\n\t\tword := scanner.Text()\n\t\tn := hashBucket(word, 12)\n\t\tbuckets[n] = append(buckets[n], word)\n\t}\n\t// Print len of each bucket\n\tfor i := 0; i < 12; i++ {\n\t\tfmt.Println(i, \" - \", len(buckets[i]))\n\t}\n\t// Print the words in one of the buckets\n\t// fmt.Println(buckets[6])\n\tfmt.Println(len(buckets))\n\tfmt.Println(cap(buckets))\n}\n\nfunc hashBucket(word string, buckets int) int {\n\tvar sum int\n\tfor _, v := range word {\n\t\tsum += int(v)\n\t}\n\treturn sum % buckets\n\t// comment out the above, then uncomment the below\n\t// a more uneven distribution\n\t// return len(word) % buckets\n}\n\n/*\nUPDATED CODE\nUp above, the code has been updated from the recording\nI used to have this ...\n\t\tbuckets = append(buckets, []string{})\n... and changed it to this ...\n\t\tbuckets[i] = []string{}\n\nREASON:\n\nThis line of code ...\n\tbuckets := make([][]string, 12)\n... creates a slice with len and cap equal to 12. I can now access each of the twelve positions in the slice by index and assign values to them. If I \"append\" to this slice, like this ....\n\t\tbuckets = append(buckets, []string{})\n... I am adding another twelve positions to my slice; my len increases to 24 and my cap increases to 24. This is unnecessary. I can, instead, just direclty begin accessing the first twelve positions in my slice ... and that's why I changed the code to this ...\n\t\tbuckets[i] = []string{}\n\nEVEN MORE EXPLANATION\n\nYou don't even need this entire chunk of code ...\n\n\tfor i := 0; i < 12; i++ {\n\t\tbuckets[i] = []string{}\n\t}\n\n... as this code ...\n\n\tbuckets := make([][]string, 12)\n\n... creates a slice holding a []string, but it doesn't yet have a len or cap, so later I use append which is how you add an item to a slice in a position that does not yet have an item (beyond its current len).\n\nThank you to Lee Trent for pointing this out!\n*/\n"
  },
  {
    "path": "19_map/14_hash-table/03_words-in-buckets/02_map-bucket/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc main() {\n\t// get the book adventures of sherlock holmes\n\tres, err := http.Get(\"http://www.gutenberg.org/cache/epub/1661/pg1661.txt\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\t// scan the page\n\tscanner := bufio.NewScanner(res.Body)\n\tdefer res.Body.Close()\n\t// Set the split function for the scanning operation.\n\tscanner.Split(bufio.ScanWords)\n\t// Create map with a key of int\n\t// and a value of another map\n\t// with a key of string, which will be the word\n\t// and a value of int, which will be the number of times the word occurs\n\tbuckets := make(map[int]map[string]int)\n\t// Create slices to hold words words\n\tfor i := 0; i < 12; i++ {\n\t\tbuckets[i] = make(map[string]int)\n\t}\n\t// Loop over the words\n\tfor scanner.Scan() {\n\t\tword := scanner.Text()\n\t\tn := hashBucket(word, 12)\n\t\tbuckets[n][word]++\n\t}\n\t// Print words in a bucket\n\tfor k, v := range buckets[6] {\n\t\tfmt.Println(v, \" \\t- \", k)\n\t}\n}\n\nfunc hashBucket(word string, buckets int) int {\n\tvar sum int\n\tfor _, v := range word {\n\t\tsum += int(v)\n\t}\n\treturn sum % buckets\n}\n"
  },
  {
    "path": "19_map/14_hash-table/04_english-alphabet/01/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tres, err := http.Get(\"http://www-01.sil.org/linguistics/wordlists/english/wordlist/wordsEn.txt\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tbs, _ := ioutil.ReadAll(res.Body)\n\tstr := string(bs)\n\tfmt.Println(str)\n\n}\n"
  },
  {
    "path": "19_map/14_hash-table/04_english-alphabet/02/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\tres, err := http.Get(\"http://www-01.sil.org/linguistics/wordlists/english/wordlist/wordsEn.txt\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\twords := make(map[string]string)\n\n\tsc := bufio.NewScanner(res.Body)\n\tsc.Split(bufio.ScanWords)\n\n\tfor sc.Scan() {\n\t\twords[sc.Text()] = \"\"\n\t}\n\tif err := sc.Err(); err != nil {\n\t\tfmt.Fprintln(os.Stderr, \"reading input:\", err)\n\t}\n\n\ti := 0\n\tfor k := range words {\n\t\tfmt.Println(k)\n\t\tif i == 200 {\n\t\t\tbreak\n\t\t}\n\t\ti++\n\t}\n\n}\n"
  },
  {
    "path": "20_struct/00_object-oriented/notes.txt",
    "content": "Go is Object Oriented\n\n(1) Encapsulation\nstate (\"fields\")\nbehavior (\"methods\")\nexported / un-exported\n\n(2) Reusability\ninheritance (\"embedded types\")\n\n(3) Polymorphism\ninterfaces\n\n(4) Overriding\n\"promotion\"\n\n//////////////\nTraditional OOP\n\nClasses\n-- data structure describing a type of object\n-- you can then create \"instances\"/\"objects\" from the class/blue-print\n-- classes hold both:\n==== state / data / fields\n==== behavior / methods\n-- public / private\n\nInheritance\n\n//////////////\nIn Go:\n- you don't create classes, you create a type\n- you don't instantiate, you create a value of a type"
  },
  {
    "path": "20_struct/01_user-defined-types/01_alias-type_not-idiomatic/main.go",
    "content": "package main\n\nimport \"fmt\"\n\ntype foo int\n\nfunc main() {\n\tvar myAge foo\n\tmyAge = 44\n\tfmt.Printf(\"%T %v \\n\", myAge, myAge)\n}\n"
  },
  {
    "path": "20_struct/01_user-defined-types/02_static-typing/main.go",
    "content": "package main\n\nimport \"fmt\"\n\ntype foo int\n\nfunc main() {\n\tvar myAge foo\n\tmyAge = 44\n\tfmt.Printf(\"%T %v \\n\", myAge, myAge)\n\n\tvar yourAge int\n\tyourAge = 29\n\tfmt.Printf(\"%T %v \\n\", yourAge, yourAge)\n\n\t// this doesn't work:\n\t//\t fmt.Println(myAge + yourAge)\n\n\t// this conversion works:\n\t//\t fmt.Println(int(myAge) + yourAge)\n}\n"
  },
  {
    "path": "20_struct/01_user-defined-types/notes.txt",
    "content": " user defined types - we declare a new type, foo\n the underlying type of foo: int\n\n conversion:int(myAge)\n converting type foo to type int\n\n THIS CODE IS ONLY FOR EXAMPLE\n IT IS A BAD PRACTICE TO ALIAS TYPES\n one exception: if you need to attach methods to a type\n see the time package for an example of this\n     godoc.org/time\n     type Duration int64\n Duration has methods attached to it"
  },
  {
    "path": "20_struct/02_struct_fields_values_initialization/main.go",
    "content": "package main\n\nimport \"fmt\"\n\ntype person struct {\n\tfirst string\n\tlast  string\n\tage   int\n}\n\nfunc main() {\n\tp1 := person{\"James\", \"Bond\", 20}\n\tp2 := person{\"Miss\", \"Moneypenny\", 18}\n\tfmt.Println(p1.first, p1.last, p1.age)\n\tfmt.Println(p2.first, p2.last, p2.age)\n}\n"
  },
  {
    "path": "20_struct/02_struct_fields_values_initialization/notes.txt",
    "content": " We used shorthand notation:\n to create a variable named p1 of type person\n to create a variable named p2 of type person\n We initialized those variables with specific values\n We used the short variable declaration operator with a struct literal to initialize\n ----------------------------------------\n here is how we talk about structs:\n -- user defined type\n -- we declare the type\n -- the type has fields\n -- the type can also have \"tags\"\n ----  we haven't seen this yet\n -- the type has an underlying type\n ---- in this case, the underlying type is struct\n -- we declare variables of the type\n -- we initialize those variables\n ---- initialize with a specific value, or\n ---- or, initiliaze to the zero value\n -- a struct is a composite type\n ----------------------------------------\n Bill Kennedy:\n Go allows us the ability to declare our own types.\n Struct types are declared by composing a fixed set of unique fields together.\n Each field in a struct is declared with a known type.\n This could be a built-in type or another user defined type.\n Once we have a type declared, we can create values from the type\n When we declare variables, the value that the variable represents is always initialized.\n The value can be initialized with a specific value or it can be initialized to its zero value\n For numeric types, the zero value would be 0; for strings it would be empty;\n and for booleans it would be false.\n In the case of a struct, the zero value would apply to all the different fields in the struct.\n Anytime a variable is created and initialized to its zero value, it is idiomatic to use the keyword var.\n Reserve the use of the keyword var as a way to indicate that a variable is being set to its zero value.\n If the variable will be initialized to something other than its zero value,\n then use the short variable declaration operator with a struct literal\n"
  },
  {
    "path": "20_struct/03_methods/main.go",
    "content": "package main\n\nimport \"fmt\"\n\ntype person struct {\n\tfirst string\n\tlast  string\n\tage   int\n}\n\nfunc (p person) fullName() string {\n\treturn p.first + p.last\n}\n\nfunc main() {\n\tp1 := person{\"James\", \"Bond\", 20}\n\tp2 := person{\"Miss\", \"Moneypenny\", 18}\n\tfmt.Println(p1.fullName())\n\tfmt.Println(p2.fullName())\n}\n"
  },
  {
    "path": "20_struct/03_methods/notes.txt",
    "content": "(p person) is the \"receiver\"\nit is another parameter\nnot idiomatic to use \"this\" or \"self\"\n\n\n\"Not many people know this, but method notation, i.e. v.Method() is actually syntactic sugar and Go also understands the de-sugared version of it: (T).Method(v). You can see an example here. Naming the receiver like any other parameter reflects that it is, in fact, just another parameter quite well.\nThis also implies that the receiver-argument inside a method may be nil. This is not the case with this in e.g. Java.\"\nSOURCE:\nhttps://www.reddit.com/r/golang/comments/3qoo36/question_why_is_self_or_this_not_considered_a/?utm_source=golangweekly&utm_medium=email\n"
  },
  {
    "path": "20_struct/04_embedded-types/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\ntype person struct {\n\tFirst string\n\tLast  string\n\tAge   int\n}\n\ntype doubleZero struct {\n\tperson\n\tLicenseToKill bool\n}\n\nfunc main() {\n\tp1 := doubleZero{\n\t\tperson: person{\n\t\t\tFirst: \"James\",\n\t\t\tLast:  \"Bond\",\n\t\t\tAge:   20,\n\t\t},\n\t\tLicenseToKill: true,\n\t}\n\n\tp2 := doubleZero{\n\t\tperson: person{\n\t\t\tFirst: \"Miss\",\n\t\t\tLast:  \"MoneyPenny\",\n\t\t\tAge:   19,\n\t\t},\n\t\tLicenseToKill: false,\n\t}\n\n\tfmt.Println(p1.First, p1.Last, p1.Age, p1.LicenseToKill)\n\tfmt.Println(p2.First, p2.Last, p2.Age, p2.LicenseToKill)\n}\n"
  },
  {
    "path": "20_struct/05_promotion/01_overriding-fields/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\ntype person struct {\n\tFirst string\n\tLast  string\n\tAge   int\n}\n\ntype doubleZero struct {\n\tperson\n\tFirst         string\n\tLicenseToKill bool\n}\n\nfunc main() {\n\tp1 := doubleZero{\n\t\tperson: person{\n\t\t\tFirst: \"James\",\n\t\t\tLast:  \"Bond\",\n\t\t\tAge:   20,\n\t\t},\n\t\tFirst:         \"Double Zero Seven\",\n\t\tLicenseToKill: true,\n\t}\n\n\tp2 := doubleZero{\n\t\tperson: person{\n\t\t\tFirst: \"Miss\",\n\t\t\tLast:  \"MoneyPenny\",\n\t\t\tAge:   19,\n\t\t},\n\t\tFirst:         \"If looks could kill\",\n\t\tLicenseToKill: false,\n\t}\n\n\t// fields and methods of the inner-type are promoted to the outer-type\n\tfmt.Println(p1.First, p1.person.First)\n\tfmt.Println(p2.First, p2.person.First)\n}\n"
  },
  {
    "path": "20_struct/05_promotion/02_overriding-methods/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\ntype person struct {\n\tName string\n\tAge  int\n}\n\ntype doubleZero struct {\n\tperson\n\tLicenseToKill bool\n}\n\nfunc (p person) Greeting() {\n\tfmt.Println(\"I'm just a regular person.\")\n}\n\nfunc (dz doubleZero) Greeting() {\n\tfmt.Println(\"Miss Moneypenny, so good to see you.\")\n}\n\nfunc main() {\n\tp1 := person{\n\t\tName: \"Ian Flemming\",\n\t\tAge:  44,\n\t}\n\n\tp2 := doubleZero{\n\t\tperson: person{\n\t\t\tName: \"James Bond\",\n\t\t\tAge:  23,\n\t\t},\n\t\tLicenseToKill: true,\n\t}\n\tp1.Greeting()\n\tp2.Greeting()\n\tp2.person.Greeting()\n}\n"
  },
  {
    "path": "20_struct/06_struct-pointer/main.go",
    "content": "package main\n\nimport \"fmt\"\n\ntype person struct {\n\tname string\n\tage  int\n}\n\nfunc main() {\n\tp1 := &person{\"James\", 20}\n\tfmt.Println(p1)\n\tfmt.Printf(\"%T\\n\", p1)\n\tfmt.Println(p1.name)\n\tfmt.Println(p1.age)\n}\n"
  },
  {
    "path": "20_struct/07_marshal_unmarshal/01_marshal/01_exported/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\ntype person struct {\n\tFirst       string\n\tLast        string\n\tAge         int\n\tnotExported int\n}\n\nfunc main() {\n\tp1 := person{\"James\", \"Bond\", 20, 007}\n\tbs, _ := json.Marshal(p1)\n\tfmt.Println(bs)\n\tfmt.Printf(\"%T \\n\", bs)\n\tfmt.Println(string(bs))\n}\n"
  },
  {
    "path": "20_struct/07_marshal_unmarshal/01_marshal/02_unexported/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\ntype person struct {\n\tfirst string\n\tlast  string\n\tage   int\n}\n\nfunc main() {\n\tp1 := person{\"James\", \"Bond\", 20}\n\tfmt.Println(p1)\n\tbs, _ := json.Marshal(p1)\n\tfmt.Println(string(bs))\n}\n"
  },
  {
    "path": "20_struct/07_marshal_unmarshal/01_marshal/03_tags/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\ntype person struct {\n\tFirst string\n\tLast  string `json:\"-\"`\n\tAge   int    `json:\"wisdom score\"`\n}\n\nfunc main() {\n\tp1 := person{\"James\", \"Bond\", 20}\n\tbs, _ := json.Marshal(p1)\n\tfmt.Println(string(bs))\n}\n"
  },
  {
    "path": "20_struct/07_marshal_unmarshal/02_unmarshal/01/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\ntype person struct {\n\tFirst string\n\tLast  string\n\tAge   int\n}\n\nfunc main() {\n\tvar p1 person\n\tfmt.Println(p1.First)\n\tfmt.Println(p1.Last)\n\tfmt.Println(p1.Age)\n\n\tbs := []byte(`{\"First\":\"James\", \"Last\":\"Bond\", \"Age\":20}`)\n\tjson.Unmarshal(bs, &p1)\n\n\tfmt.Println(\"--------------\")\n\tfmt.Println(p1.First)\n\tfmt.Println(p1.Last)\n\tfmt.Println(p1.Age)\n\tfmt.Printf(\"%T \\n\", p1)\n}\n"
  },
  {
    "path": "20_struct/07_marshal_unmarshal/02_unmarshal/02_tags/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\ntype person struct {\n\tFirst string\n\tLast  string\n\tAge   int `json:\"wisdom score\"`\n}\n\nfunc main() {\n\tvar p1 person\n\tfmt.Println(p1.First)\n\tfmt.Println(p1.Last)\n\tfmt.Println(p1.Age)\n\n\tbs := []byte(`{\"First\":\"James\", \"Last\":\"Bond\", \"wisdom score\":20}`)\n\tjson.Unmarshal(bs, &p1)\n\n\tfmt.Println(\"--------------\")\n\tfmt.Println(p1.First)\n\tfmt.Println(p1.Last)\n\tfmt.Println(p1.Age)\n\tfmt.Printf(\"%T \\n\", p1)\n}\n"
  },
  {
    "path": "20_struct/08_encode_decode/01_encode/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"os\"\n)\n\ntype person struct {\n\tFirst       string\n\tLast        string\n\tAge         int\n\tnotExported int\n}\n\nfunc main() {\n\tp1 := person{\"James\", \"Bond\", 20, 007}\n\tjson.NewEncoder(os.Stdout).Encode(p1)\n}\n"
  },
  {
    "path": "20_struct/08_encode_decode/02_decode/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n)\n\ntype person struct {\n\tFirst       string\n\tLast        string\n\tAge         int\n\tnotExported int\n}\n\nfunc main() {\n\tvar p1 person\n\trdr := strings.NewReader(`{\"First\":\"James\", \"Last\":\"Bond\", \"Age\":20}`)\n\tjson.NewDecoder(rdr).Decode(&p1)\n\n\tfmt.Println(p1.First)\n\tfmt.Println(p1.Last)\n\tfmt.Println(p1.Age)\n}\n"
  },
  {
    "path": "21_interfaces/00_notes.txt",
    "content": "\"Polymorphism is the ability to write code that can take on different behavior through the\n implementation of types. Once a type implements an interface, an entire world of\n functionality can be opened up to values of that type.\"\n - Bill Kennedy\n\n\"Interfaces are types that just declare behavior. This behavior is never implemented by the\n interface type directly, but instead by user-defined types via methods. When a\n user-defined type implements the set of methods declared by an interface type, values of\n the user-defined type can be assigned to values of the interface type. This assignment\n stores the value of the user-defined type into the interface value.\n\n If a method call is made against an interface value, the equivalent method for the\n stored user-defined value is executed. Since any user-defined type can implement any\n interface, method calls against an interface value are polymorphic in nature. The\n user-defined type in this relationship is often called a concrete type, since interface values\n have no concrete behavior without the implementation of the stored user-defined value.\"\n  - Bill Kennedy\n\nReceivers       Values\n-----------------------------------------------\n(t T)           T and *T\n(t *T)          *T\n\nValues          Receivers\n-----------------------------------------------\nT               (t T)\n*T              (t T) and (t *T)\n\n\nSOURCE:\nGo In Action\nWilliam Kennedy\n/////////////////////////////////////////////////////////////////////////\n\nInterface types express generalizations or abstractions about the behaviors of other types.\nBy generalizing, interfaces let us write functions that are more flexible and adaptable\nbecause they are not tied to the details of one particular implementation.\n\nMany object-oriented lagnuages have some notion of interfaces, but what makes Go's interfaces\nso distinctive is that they are SATISIFIED IMPLICITLY. In other words, there's no need to declare\nall the interfaces that a given CONCRETE TYPE satisifies; simply possessing the necessary methods\nis enough. This design lets you create new interfaces that are satisifed by existing CONCRETE TYPES\nwithout changing the existing types, which is particularly useful for types defined in packages that\nyou don't control.\n\nAll the types we've looked at so far have been CONCRETE TYPES. A CONCRETE TYPE specifies the exact\nrepresentation of its values and exposes the intrinsic operations of that representation, such as\narithmetic for numbers, or indexing, append, and range for slices. A CONCRETE TYPE may also provide\nadditional behaviors through its methods. When you have a value of a CONCRETE TYPE, you know exactly\nwhat is IS and what you can DO with it.\n\nThere is another kind of type in Go called an INTERFACE TYPE. An interface is an ABSTRACT TYPE. It doesn't\nexpose the representation or internal structure of its values, or the set of basic operations they support;\nit reveals only some of their methods. When you have a value of an interface type, you know nothing about\nwhat it IS; you know only what it can DO, or more precisely, what BEHAVIORS ARE PROVIDED BY ITS METHODS.\n\n-------------------\n\ntype ReadWriter interface {\n    Reader\n    Writer\n}\n\nThis is called EMBEDDING an interface.\n\n\n-------------------\n\nA type SATISFIES an interface if it possesses all the methods the interface requires.\n\n-------------------\n\nConceptually, a value of an interface type, or INTERFACE VALUE, has two components,\n    a CONCRETE TYPE and a\n    VALUE OF THAT TYPE.\nThese are called the interface's\n    DYNAMIC TYPE and\n    DYNAMIC VALUE.\n\nFor a statically typed language like Go, types are a compile-time concept, so a type is not a value.\nIn our conceptual model, a set of values called TYPE DESCRIPTORS provide information about each type,\nsuch as its name and methods. In an interface value, the type component is represented by the appropriate\ntype descriptor.\n\n\nvar w io.Writer\nw = os.Stdout\nw = new(bytes.Buffer)\nw = nil\n\n\nvar w io.Writer\nw\ntype: nil\nvalue: nil\n\nw = os.Stdout\nw\ntype: *os.File\nvalue: the address where a value of type os.File is stored\n\nw = new(bytes.Buffer)\nw\ntype: *bytes.Buffer\nvalue: the address where a value of type bytes.Buffer is stored\n\nw = nil\nw\ntype: nil\nvalue: nil\n\n-------------------\nThe Go Programming Language\nDonovan and Kernighan\n\nCaplitalization and identation mine."
  },
  {
    "path": "21_interfaces/01_interface/01_no-interface/main.go",
    "content": "package main\n\nimport \"fmt\"\n\ntype square struct {\n\tside float64\n}\n\nfunc (z square) area() float64 {\n\treturn z.side * z.side\n}\n\nfunc main() {\n\ts := square{10}\n\tfmt.Println(\"Area: \", s.area())\n}\n"
  },
  {
    "path": "21_interfaces/01_interface/02_interface/main.go",
    "content": "package main\n\nimport \"fmt\"\n\ntype square struct {\n\tside float64\n}\n\nfunc (z square) area() float64 {\n\treturn z.side * z.side\n}\n\ntype shape interface {\n\tarea() float64\n}\n\nfunc info(z shape) {\n\tfmt.Println(z)\n\tfmt.Println(z.area())\n}\n\nfunc main() {\n\ts := square{10}\n\tfmt.Printf(\"%T\\n\",s)\n\tinfo(s)\n}\n"
  },
  {
    "path": "21_interfaces/01_interface/03_interface/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"math\"\n)\n\ntype square struct {\n\tside float64\n}\n\n// another shape\ntype circle struct {\n\tradius float64\n}\n\ntype shape interface {\n\tarea() float64\n}\n\nfunc (s square) area() float64 {\n\treturn s.side * s.side\n}\n\n// which implements the shape interface\nfunc (c circle) area() float64 {\n\treturn math.Pi * c.radius * c.radius\n}\n\nfunc info(z shape) {\n\tfmt.Println(z)\n\tfmt.Println(z.area())\n}\n\nfunc main() {\n\ts := square{10}\n\tc := circle{5}\n\tinfo(s)\n\tinfo(c)\n}\n"
  },
  {
    "path": "21_interfaces/01_interface/04_interface/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"math\"\n)\n\ntype circle struct {\n\tradius float64\n}\n\ntype square struct {\n\tside float64\n}\n\ntype shape interface {\n\tarea() float64\n}\n\nfunc (c circle) area() float64 {\n\treturn math.Pi * c.radius * c.radius\n}\n\nfunc (s square) area() float64 {\n\treturn s.side * s.side\n}\n\nfunc info(z shape) {\n\tfmt.Println(z)\n\tfmt.Println(z.area())\n}\n\n// a new method which takes the INTERFACE TYPE shape\nfunc totalArea(shapes ...shape) float64 {\n\tvar area float64\n\tfor _, s := range shapes {\n\t\tarea += s.area()\n\t}\n\treturn area\n}\n\nfunc main() {\n\ts := square{10}\n\tc := circle{5}\n\tinfo(s)\n\tinfo(c)\n\tfmt.Println(\"Total Area: \", totalArea(c, s))\n}\n"
  },
  {
    "path": "21_interfaces/01_interface/05_io-copy/01_no-error-checking/main.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tmsg := \"Do not dwell in the past, do not dream of the future, concentrate the mind on the present.\"\n\trdr := strings.NewReader(msg)\n\tio.Copy(os.Stdout, rdr)\n\n\trdr2 := bytes.NewBuffer([]byte(msg))\n\tio.Copy(os.Stdout, rdr2)\n\n\tres, _ := http.Get(\"http://www.mcleods.com\")\n\tio.Copy(os.Stdout, res.Body)\n\tres.Body.Close()\n}\n"
  },
  {
    "path": "21_interfaces/01_interface/05_io-copy/02_error-checking/main.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tmsg := \"Do not dwell in the past, do not dream of the future, concentrate the mind on the present.\"\n\trdr := strings.NewReader(msg)\n\t_, err := io.Copy(os.Stdout, rdr)\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\n\trdr2 := bytes.NewBuffer([]byte(msg))\n\t_, err = io.Copy(os.Stdout, rdr2)\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\n\tres, err := http.Get(\"http://www.mcleods.com\")\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\n\tio.Copy(os.Stdout, res.Body)\n\tif err := res.Body.Close(); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n}\n"
  },
  {
    "path": "21_interfaces/02_package-sort/00_notes.txt",
    "content": "Use https://godoc.org/sort to sort the following:\n\n(1)\ntype people []string\nstudyGroup := people{\"Zeno\", \"John\", \"Al\", \"Jenny\"}\n\n(2)\ns := []string{\"Zeno\", \"John\", \"Al\", \"Jenny\"}\n\n(3)\nn := []int{7, 4, 8, 2, 9, 19, 12, 32, 3}\n\nAlso sort the above in reverse order"
  },
  {
    "path": "21_interfaces/02_package-sort/01_sort-names/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n)\n\ntype people []string\n\nfunc (p people) Len() int           { return len(p) }\nfunc (p people) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }\nfunc (p people) Less(i, j int) bool { return p[i] < p[j] }\n\nfunc main() {\n\tstudyGroup := people{\"Zeno\", \"John\", \"Al\", \"Jenny\"}\n\n\tfmt.Println(studyGroup)\n\tsort.Sort(studyGroup)\n\tfmt.Println(studyGroup)\n\n}\n\n// https://golang.org/pkg/sort/#Sort\n// https://golang.org/pkg/sort/#Interface\n"
  },
  {
    "path": "21_interfaces/02_package-sort/02_sort-names_type-StringSlice/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n)\n\nfunc main() {\n\ts := []string{\"Zeno\", \"John\", \"Al\", \"Jenny\"}\n\tfmt.Println(s)\n\t//\tsort.StringSlice(s).Sort()\n\tsort.Sort(sort.StringSlice(s))\n\tfmt.Println(s)\n\n}\n\n// https://golang.org/pkg/sort/#Sort\n"
  },
  {
    "path": "21_interfaces/02_package-sort/03_sort-Strings/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n)\n\nfunc main() {\n\ts := []string{\"Zeno\", \"John\", \"Al\", \"Jenny\"}\n\tsort.Strings(s)\n\tfmt.Println(s)\n}\n"
  },
  {
    "path": "21_interfaces/02_package-sort/04_sort-names_type-StringSlice_reverse/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n)\n\nfunc main() {\n\ts := []string{\"Zeno\", \"John\", \"Al\", \"Jenny\"}\n\n\tfmt.Println(s)\n\tsort.Sort(sort.Reverse(sort.StringSlice(s)))\n\tfmt.Println(s)\n\n\t// for experimentation to understand what's going on:\n\t// uncomment and experiment with the code below:\n\n\t//\tsort.Sort(sort.StringSlice(s))\n\t//\tfmt.Println(s)\n\t//\n\t//\tfmt.Printf(\"just s: %T\\n\", s)\n\t//\ts = sort.StringSlice(s)\n\t//\tfmt.Printf(\"just s: %T\\n\", s)\n\t//\tt := sort.StringSlice(s)\n\t//\tfmt.Printf(\"just t: %T\\n\", t)\n\t//\n\t//\tfmt.Printf(\"s converted to StringSlice: %T\\n\", sort.StringSlice(s))\n\t////\tfmt.Printf(\"s sorted: %T\\n\", sort.Sort(sort.StringSlice(s)))\n\t//\tfmt.Printf(\"s reversed: %T\\n\", sort.Reverse(sort.StringSlice(s)))\n\t//\ti := sort.Reverse(sort.StringSlice(s))\n\t//\tfmt.Println(i)\n\t//\tfmt.Printf(\"%T\\n\", i)\n\t//\tsort.Sort(i)\n\t//\tfmt.Println(s)\n}\n\n// https://golang.org/pkg/sort/#Sort\n"
  },
  {
    "path": "21_interfaces/02_package-sort/05_sort-int_type-IntSlice/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n)\n\nfunc main() {\n\tn := []int{7, 4, 8, 2, 9, 19, 12, 32, 3}\n\n\tfmt.Println(n)\n\tsort.Sort(sort.IntSlice(n))\n\tfmt.Println(n)\n\n}\n"
  },
  {
    "path": "21_interfaces/02_package-sort/06_sort-int_type-IntSlice_reverse/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n)\n\nfunc main() {\n\tn := []int{7, 4, 8, 2, 9, 19, 12, 32, 3}\n\n\tfmt.Println(n)\n\tsort.Sort(sort.Reverse(sort.IntSlice(n)))\n\tfmt.Println(n)\n\n}\n"
  },
  {
    "path": "21_interfaces/02_package-sort/07_sort-Ints/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n)\n\nfunc main() {\n\tn := []int{5, 2, 6, 3, 1, 4}\n\tsort.Ints(n)\n\tfmt.Println(n)\n}\n"
  },
  {
    "path": "21_interfaces/02_package-sort/08_standard-library-example/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n)\n\ntype person struct {\n\tName string\n\tAge  int\n}\n\nfunc (p person) String() string {\n\treturn fmt.Sprintf(\"YAYAYA %s: %d\", p.Name, p.Age)\n}\n\n// ByAge implements sort.Interface for []person based on\n// the Age field.\ntype ByAge []person\n\nfunc (a ByAge) Len() int           { return len(a) }\nfunc (a ByAge) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }\nfunc (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }\n\n//func (a ByAge) Less(i, j int) bool { return a[i].Name < a[j].Name }\n\nfunc main() {\n\tpeople := []person{\n\t\t{\"Bob\", 31},\n\t\t{\"John\", 42},\n\t\t{\"Michael\", 17},\n\t\t{\"Jenny\", 26},\n\t}\n\n\tfmt.Println(people[0])\n\tfmt.Println(people)\n\tsort.Sort(ByAge(people))\n\tfmt.Println(people)\n\n}\n\n// https://golang.org/pkg/sort/#Sort\n// https://golang.org/pkg/sort/#Interface\n\n// String() string\n// https://golang.org/doc/effective_go.html#printing\n"
  },
  {
    "path": "21_interfaces/03_empty-interface/01_no-interface/main.go",
    "content": "package main\n\nimport \"fmt\"\n\ntype vehicle struct {\n\tSeats    int\n\tMaxSpeed int\n\tColor    string\n}\n\ntype car struct {\n\tvehicle\n\tWheels int\n\tDoors  int\n}\n\ntype plane struct {\n\tvehicle\n\tJet bool\n}\n\ntype boat struct {\n\tvehicle\n\tLength int\n}\n\nfunc main() {\n\tprius := car{}\n\ttacoma := car{}\n\tbmw528 := car{}\n\tcars := []car{prius, tacoma, bmw528}\n\n\tboeing747 := plane{}\n\tboeing757 := plane{}\n\tboeing767 := plane{}\n\tplanes := []plane{boeing747, boeing757, boeing767}\n\n\tsanger := boat{}\n\tnautique := boat{}\n\tmalibu := boat{}\n\tboats := []boat{sanger, nautique, malibu}\n\n\tfor key, value := range cars {\n\t\tfmt.Println(key, \" - \", value)\n\t}\n\n\tfor key, value := range planes {\n\t\tfmt.Println(key, \" - \", value)\n\t}\n\n\tfor key, value := range boats {\n\t\tfmt.Println(key, \" - \", value)\n\t}\n}\n"
  },
  {
    "path": "21_interfaces/03_empty-interface/02_empty-interface/main.go",
    "content": "package main\n\nimport \"fmt\"\n\ntype vehicles interface{}\n\ntype vehicle struct {\n\tSeats    int\n\tMaxSpeed int\n\tColor    string\n}\n\ntype car struct {\n\tvehicle\n\tWheels int\n\tDoors  int\n}\n\ntype plane struct {\n\tvehicle\n\tJet bool\n}\n\ntype boat struct {\n\tvehicle\n\tLength int\n}\n\nfunc main() {\n\tprius := car{}\n\ttacoma := car{}\n\tbmw528 := car{}\n\tboeing747 := plane{}\n\tboeing757 := plane{}\n\tboeing767 := plane{}\n\tsanger := boat{}\n\tnautique := boat{}\n\tmalibu := boat{}\n\trides := []vehicles{prius, tacoma, bmw528, boeing747, boeing757, boeing767, sanger, nautique, malibu}\n\n\tfor key, value := range rides {\n\t\tfmt.Println(key, \" - \", value)\n\t}\n}\n"
  },
  {
    "path": "21_interfaces/03_empty-interface/03_param-accepts-any-type/main.go",
    "content": "package main\n\nimport \"fmt\"\n\ntype animal struct {\n\tsound string\n}\n\ntype dog struct {\n\tanimal\n\tfriendly bool\n}\n\ntype cat struct {\n\tanimal\n\tannoying bool\n}\n\nfunc specs(a interface{}) {\n\tfmt.Println(a)\n}\n\nfunc main() {\n\tfido := dog{animal{\"woof\"}, true}\n\tfifi := cat{animal{\"meow\"}, true}\n\tspecs(fido)\n\tspecs(fifi)\n}\n"
  },
  {
    "path": "21_interfaces/03_empty-interface/04_slice-of-any-type/main.go",
    "content": "package main\n\nimport \"fmt\"\n\ntype animal struct {\n\tsound string\n}\n\ntype dog struct {\n\tanimal\n\tfriendly bool\n}\n\ntype cat struct {\n\tanimal\n\tannoying bool\n}\n\nfunc main() {\n\tfido := dog{animal{\"woof\"}, true}\n\tfifi := cat{animal{\"meow\"}, true}\n\tshadow := dog{animal{\"woof\"}, true}\n\tcritters := []interface{}{fido, fifi, shadow}\n\tfmt.Println(critters)\n}\n"
  },
  {
    "path": "21_interfaces/04_method-sets/01_value-receiver_value-type/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"math\"\n)\n\ntype circle struct {\n\tradius float64\n}\n\ntype shape interface {\n\tarea() float64\n}\n\nfunc (c circle) area() float64 {\n\treturn math.Pi * c.radius * c.radius\n}\n\nfunc info(s shape) {\n\tfmt.Println(\"area\", s.area())\n}\n\nfunc main() {\n\tc := circle{5}\n\tinfo(c)\n}\n"
  },
  {
    "path": "21_interfaces/04_method-sets/02_value-receiver_pointer-type/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"math\"\n)\n\ntype circle struct {\n\tradius float64\n}\n\ntype shape interface {\n\tarea() float64\n}\n\nfunc (c circle) area() float64 {\n\treturn math.Pi * c.radius * c.radius\n}\n\nfunc info(s shape) {\n\tfmt.Println(\"area\", s.area())\n}\n\nfunc main() {\n\tc := circle{5}\n\tinfo(&c)\n}\n"
  },
  {
    "path": "21_interfaces/04_method-sets/03_pointer-receiver_pointer-type/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"math\"\n)\n\ntype circle struct {\n\tradius float64\n}\n\ntype shape interface {\n\tarea() float64\n}\n\nfunc (c *circle) area() float64 {\n\treturn math.Pi * c.radius * c.radius\n}\n\nfunc info(s shape) {\n\tfmt.Println(\"area\", s.area())\n}\n\nfunc main() {\n\tc := circle{5}\n\tinfo(&c)\n}\n"
  },
  {
    "path": "21_interfaces/04_method-sets/04_pointer-receiver_value-type/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"math\"\n)\n\ntype circle struct {\n\tradius float64\n}\n\ntype shape interface {\n\tarea() float64\n}\n\nfunc (c *circle) area() float64 {\n\treturn math.Pi * c.radius * c.radius\n}\n\nfunc info(s shape) {\n\tfmt.Println(\"area\", s.area())\n}\n\nfunc main() {\n\tc := circle{5}\n\tinfo(c)\n}\n"
  },
  {
    "path": "21_interfaces/05_conversion-vs-assertion/01_conversion/01_int-to-float/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar x = 12\n\tvar y = 12.1230123\n\tfmt.Println(y + float64(x))\n\t// conversion: int to float64\n}\n"
  },
  {
    "path": "21_interfaces/05_conversion-vs-assertion/01_conversion/02_float-to-int/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar x = 12\n\tvar y = 12.1230123\n\tfmt.Println(int(y) + x)\n\t// conversion: float64 to int\n}\n"
  },
  {
    "path": "21_interfaces/05_conversion-vs-assertion/01_conversion/03_rune-to-string/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar x rune = 'a' // rune is an alias for int32; normally omitted in this statement\n\tvar y int32 = 'b'\n\tfmt.Println(x)\n\tfmt.Println(y)\n\tfmt.Println(string(x))\n\tfmt.Println(string(y))\n\t// conversion: rune to string\n}\n"
  },
  {
    "path": "21_interfaces/05_conversion-vs-assertion/01_conversion/04_rune-to-slice-of-bytes-to-string/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(string([]byte{'h', 'e', 'l', 'l', 'o'}))\n\t// conversion: []bytes to string\n\t// we'll learn about []bytes soon\n}\n"
  },
  {
    "path": "21_interfaces/05_conversion-vs-assertion/01_conversion/05_string-to-slice-of-bytes/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println([]byte(\"hello\"))\n\t// conversion: string to []bytes\n\t// we'll learn about []bytes soon\n}\n"
  },
  {
    "path": "21_interfaces/05_conversion-vs-assertion/01_conversion/06_strconv/01_Atoi/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n)\n\nfunc main() {\n\tvar x = \"12\"\n\tvar y = 6\n\tz, _ := strconv.Atoi(x)\n\tfmt.Println(y + z)\n}\n"
  },
  {
    "path": "21_interfaces/05_conversion-vs-assertion/01_conversion/06_strconv/02_Itoa/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n)\n\nfunc main() {\n\tx := 12\n\ty := \"I have this many: \" + strconv.Itoa(x)\n\tfmt.Println(y)\n\t//\tfmt.Println(\"I have this many: \", strconv.Itoa(x), x)\n}\n"
  },
  {
    "path": "21_interfaces/05_conversion-vs-assertion/01_conversion/06_strconv/03_ParseInt/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n)\n\nfunc main() {\n\n\t//\tParseBool, ParseFloat, ParseInt, and ParseUint convert strings to values:\n\tb, _ := strconv.ParseBool(\"true\")\n\tf, _ := strconv.ParseFloat(\"3.1415\", 64)\n\ti, _ := strconv.ParseInt(\"-42\", 10, 64)\n\tu, _ := strconv.ParseUint(\"42\", 10, 64)\n\n\tfmt.Println(b, f, i, u)\n\n\t//\tFormatBool, FormatFloat, FormatInt, and FormatUint convert values to strings:\n\tw := strconv.FormatBool(true)\n\tx := strconv.FormatFloat(3.1415, 'E', -1, 64)\n\ty := strconv.FormatInt(-42, 16)\n\tz := strconv.FormatUint(42, 16)\n\n\tfmt.Println(w, x, y, z)\n}\n"
  },
  {
    "path": "21_interfaces/05_conversion-vs-assertion/02_assertion/01_non-interface-error_invalid-code/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tname := \"Sydney\"\n\tstr, ok := name.(string)\n\tif ok {\n\t\tfmt.Printf(\"%q\\n\", str)\n\t} else {\n\t\tfmt.Printf(\"value is not a string\\n\")\n\t}\n}\n"
  },
  {
    "path": "21_interfaces/05_conversion-vs-assertion/02_assertion/02_interface-string/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar name interface{} = \"Sydney\"\n\tstr, ok := name.(string)\n\tif ok {\n\t\tfmt.Printf(\"%T\\n\", str)\n\t} else {\n\t\tfmt.Printf(\"value is not a string\\n\")\n\t}\n}\n"
  },
  {
    "path": "21_interfaces/05_conversion-vs-assertion/02_assertion/03_interface-string_not-ok/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar name interface{} = 7\n\tstr, ok := name.(string)\n\tif ok {\n\t\tfmt.Printf(\"%T\\n\", str)\n\t} else {\n\t\tfmt.Printf(\"value is not a string\\n\")\n\t}\n}\n"
  },
  {
    "path": "21_interfaces/05_conversion-vs-assertion/02_assertion/04_interface-int_print-type/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar val interface{} = 7\n\tfmt.Printf(\"%T\\n\", val)\n}\n"
  },
  {
    "path": "21_interfaces/05_conversion-vs-assertion/02_assertion/05_interface-int_mistmatched-types-error/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar val interface{} = 7\n\tfmt.Println(val + 6)\n}\n"
  },
  {
    "path": "21_interfaces/05_conversion-vs-assertion/02_assertion/06_interface-int-sum/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar val interface{} = 7\n\tfmt.Println(val.(int) + 6)\n}\n"
  },
  {
    "path": "21_interfaces/05_conversion-vs-assertion/02_assertion/07_casting-reminder/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\trem := 7.24\n\tfmt.Printf(\"%T\\n\", rem)\n\tfmt.Printf(\"%T\\n\", int(rem))\n}\n"
  },
  {
    "path": "21_interfaces/05_conversion-vs-assertion/02_assertion/08_interface-cast-error_need-type-assertion/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\trem := 7.24\n\tfmt.Printf(\"%T\\n\", rem)\n\tfmt.Printf(\"%T\\n\", int(rem))\n\n\tvar val interface{} = 7\n\tfmt.Printf(\"%T\\n\", val)\n\tfmt.Printf(\"%T\\n\", int(val))\n\t//\tfmt.Printf(\"%T\\n\", val.(int))\n}\n"
  },
  {
    "path": "22_go-routines/01_no-go/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfoo()\n\tbar()\n}\n\nfunc foo() {\n\tfor i := 0; i < 45; i++ {\n\t\tfmt.Println(\"Foo:\", i)\n\t}\n}\n\nfunc bar() {\n\tfor i := 0; i < 45; i++ {\n\t\tfmt.Println(\"Bar:\", i)\n\t}\n}\n"
  },
  {
    "path": "22_go-routines/02_go_concurrency/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tgo foo()\n\tgo bar()\n}\n\nfunc foo() {\n\tfor i := 0; i < 45; i++ {\n\t\tfmt.Println(\"Foo:\", i)\n\t}\n}\n\nfunc bar() {\n\tfor i := 0; i < 45; i++ {\n\t\tfmt.Println(\"Bar:\", i)\n\t}\n}\n"
  },
  {
    "path": "22_go-routines/03_wait-group/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\nvar wg sync.WaitGroup\n\nfunc main() {\n\twg.Add(2)\n\tgo foo()\n\tgo bar()\n\twg.Wait()\n}\n\nfunc foo() {\n\tfor i := 0; i < 45; i++ {\n\t\tfmt.Println(\"Foo:\", i)\n\t}\n\twg.Done()\n}\n\nfunc bar() {\n\tfor i := 0; i < 45; i++ {\n\t\tfmt.Println(\"Bar:\", i)\n\t}\n\twg.Done()\n}\n"
  },
  {
    "path": "22_go-routines/04_time-sleep/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n)\n\nvar wg sync.WaitGroup\n\nfunc main() {\n\twg.Add(2)\n\tgo foo()\n\tgo bar()\n\twg.Wait()\n}\n\nfunc foo() {\n\tfor i := 0; i < 45; i++ {\n\t\tfmt.Println(\"Foo:\", i)\n\t\ttime.Sleep(3 * time.Millisecond)\n\t}\n\twg.Done()\n}\n\nfunc bar() {\n\tfor i := 0; i < 45; i++ {\n\t\tfmt.Println(\"Bar:\", i)\n\t\ttime.Sleep(20 * time.Millisecond)\n\t}\n\twg.Done()\n}\n"
  },
  {
    "path": "22_go-routines/05_gomaxprocs_parallelism/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"runtime\"\n\t\"sync\"\n\t\"time\"\n)\n\nvar wg sync.WaitGroup\n\nfunc init() {\n\truntime.GOMAXPROCS(runtime.NumCPU())\n}\n\nfunc main() {\n\twg.Add(2)\n\tgo foo()\n\tgo bar()\n\twg.Wait()\n}\n\nfunc foo() {\n\tfor i := 0; i < 45; i++ {\n\t\tfmt.Println(\"Foo:\", i)\n\t\ttime.Sleep(3 * time.Millisecond)\n\t}\n\twg.Done()\n}\n\nfunc bar() {\n\tfor i := 0; i < 45; i++ {\n\t\tfmt.Println(\"Bar:\", i)\n\t\ttime.Sleep(20 * time.Millisecond)\n\t}\n\twg.Done()\n}\n"
  },
  {
    "path": "22_go-routines/06_race-condition/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"sync\"\n\t\"time\"\n)\n\nvar wg sync.WaitGroup\nvar counter int\n\nfunc main() {\n\twg.Add(2)\n\tgo incrementor(\"Foo:\")\n\tgo incrementor(\"Bar:\")\n\twg.Wait()\n\tfmt.Println(\"Final Counter:\", counter)\n}\n\nfunc incrementor(s string) {\n\trand.Seed(time.Now().UnixNano())\n\tfor i := 0; i < 20; i++ {\n\t\tx := counter\n\t\tx++\n\t\ttime.Sleep(time.Duration(rand.Intn(3)) * time.Millisecond)\n\t\tcounter = x\n\t\tfmt.Println(s, i, \"Counter:\", counter)\n\t}\n\twg.Done()\n}\n\n// go run -race main.go\n// vs\n// go run main.go\n"
  },
  {
    "path": "22_go-routines/07_mutex/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"sync\"\n\t\"time\"\n)\n\nvar wg sync.WaitGroup\nvar counter int\nvar mutex sync.Mutex\n\nfunc main() {\n\twg.Add(2)\n\tgo incrementor(\"Foo:\")\n\tgo incrementor(\"Bar:\")\n\twg.Wait()\n\tfmt.Println(\"Final Counter:\", counter)\n}\n\nfunc incrementor(s string) {\n\tfor i := 0; i < 20; i++ {\n\t\ttime.Sleep(time.Duration(rand.Intn(20)) * time.Millisecond)\n\t\tmutex.Lock()\n\t\tcounter++\n\t\tfmt.Println(s, i, \"Counter:\", counter)\n\t\tmutex.Unlock()\n\t}\n\twg.Done()\n}\n\n// go run -race main.go\n// vs\n// go run main.go\n"
  },
  {
    "path": "22_go-routines/08_atomicity/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\nvar wg sync.WaitGroup\nvar counter int64\n\nfunc main() {\n\twg.Add(2)\n\tgo incrementor(\"Foo:\")\n\tgo incrementor(\"Bar:\")\n\twg.Wait()\n\tfmt.Println(\"Final Counter:\", counter)\n}\n\nfunc incrementor(s string) {\n\tfor i := 0; i < 20; i++ {\n\t\ttime.Sleep(time.Duration(rand.Intn(3)) * time.Millisecond)\n\t\tatomic.AddInt64(&counter, 1)\n\t\tfmt.Println(s, i, \"Counter:\", atomic.LoadInt64(&counter)) // access without race\n\t}\n\twg.Done()\n}\n\n// go run -race main.go\n// vs\n// go run main.go\n"
  },
  {
    "path": "22_go-routines/09_channels/00_unbuffered-channels-block/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\nfunc main() {\n\tc := make(chan int)\n\n\tgo func() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tc <- i\n\t\t}\n\t}()\n\n\tgo func() {\n\t\tfor {\n\t\t\tfmt.Println(<-c)\n\t\t}\n\t}()\n\n\ttime.Sleep(time.Second)\n}\n"
  },
  {
    "path": "22_go-routines/09_channels/01_range/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tc := make(chan int)\n\n\tgo func() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tc <- i\n\t\t}\n\t\tclose(c)\n\t}()\n\n\tfor n := range c {\n\t\tfmt.Println(n)\n\t}\n}\n"
  },
  {
    "path": "22_go-routines/09_channels/02_n-to-1/01_race-condition/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\nfunc main() {\n\n\tc := make(chan int)\n\n\tvar wg sync.WaitGroup\n\n\tgo func() {\n\t\twg.Add(1)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tc <- i\n\t\t}\n\t\twg.Done()\n\t}()\n\n\tgo func() {\n\t\twg.Add(1)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tc <- i\n\t\t}\n\t\twg.Done()\n\t}()\n\n\tgo func() {\n\t\twg.Wait()\n\t\tclose(c)\n\t}()\n\n\tfor n := range c {\n\t\tfmt.Println(n)\n\t}\n}\n"
  },
  {
    "path": "22_go-routines/09_channels/02_n-to-1/02_wait-group/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\nfunc main() {\n\n\tc := make(chan int)\n\n\tvar wg sync.WaitGroup\n\twg.Add(2)\n\n\tgo func() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tc <- i\n\t\t}\n\t\twg.Done()\n\t}()\n\n\tgo func() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tc <- i\n\t\t}\n\t\twg.Done()\n\t}()\n\n\tgo func() {\n\t\twg.Wait()\n\t\tclose(c)\n\t}()\n\n\tfor n := range c {\n\t\tfmt.Println(n)\n\t}\n}\n"
  },
  {
    "path": "22_go-routines/09_channels/02_n-to-1/03_semaphore/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\n\tc := make(chan int)\n\tdone := make(chan bool)\n\n\tgo func() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tc <- i\n\t\t}\n\t\tdone <- true\n\t}()\n\n\tgo func() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tc <- i\n\t\t}\n\t\tdone <- true\n\t}()\n\n\tgo func() {\n\t\t<-done\n\t\t<-done\n\t\tclose(c)\n\t}()\n\n\tfor n := range c {\n\t\tfmt.Println(n)\n\t}\n}\n"
  },
  {
    "path": "22_go-routines/09_channels/02_n-to-1/04_semaphore_wrong-way/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\n\tc := make(chan int)\n\tdone := make(chan bool)\n\n\tgo func() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tc <- i\n\t\t}\n\t\tdone <- true\n\t}()\n\n\tgo func() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tc <- i\n\t\t}\n\t\tdone <- true\n\t}()\n\n\t// we block here until done <- true\n\t<-done\n\t<-done\n\tclose(c)\n\n\t// to unblock above\n\t// we need to take values off of chan c here\n\t// but we never get here, because we're blocked above\n\tfor n := range c {\n\t\tfmt.Println(n)\n\t}\n}\n"
  },
  {
    "path": "22_go-routines/09_channels/02_n-to-1/05_n-times_to_1/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\n\tn := 10\n\tc := make(chan int)\n\tdone := make(chan bool)\n\n\tfor i := 0; i < n; i++ {\n\t\tgo func() {\n\t\t\tfor i := 0; i < 10; i++ {\n\t\t\t\tc <- i\n\t\t\t}\n\t\t\tdone <- true\n\t\t}()\n\t}\n\n\tgo func() {\n\t\tfor i := 0; i < n; i++ {\n\t\t\t<-done\n\t\t}\n\t\tclose(c)\n\t}()\n\n\tfor n := range c {\n\t\tfmt.Println(n)\n\t}\n}\n"
  },
  {
    "path": "22_go-routines/09_channels/03_1-to-n/01_1_to_2-times/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\n\tc := make(chan int)\n\tdone := make(chan bool)\n\n\tgo func() {\n\t\tfor i := 0; i < 100000; i++ {\n\t\t\tc <- i\n\t\t}\n\t\tclose(c)\n\t}()\n\n\tgo func() {\n\t\tfor n := range c {\n\t\t\tfmt.Println(n)\n\t\t}\n\t\tdone <- true\n\t}()\n\n\tgo func() {\n\t\tfor n := range c {\n\t\t\tfmt.Println(n)\n\t\t}\n\t\tdone <- true\n\t}()\n\n\t<-done\n\t<-done\n\n}\n"
  },
  {
    "path": "22_go-routines/09_channels/03_1-to-n/02_1_to_n-times/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\n\tn := 10\n\tc := make(chan int)\n\tdone := make(chan bool)\n\n\tgo func() {\n\t\tfor i := 0; i < 100000; i++ {\n\t\t\tc <- i\n\t\t}\n\t\tclose(c)\n\t}()\n\n\tfor i := 0; i < n; i++ {\n\t\tgo func() {\n\t\t\tfor n := range c {\n\t\t\t\tfmt.Println(n)\n\t\t\t}\n\t\t\tdone <- true\n\t\t}()\n\t}\n\n\tfor i := 0; i < n; i++ {\n\t\t<-done\n\t}\n}\n"
  },
  {
    "path": "22_go-routines/09_channels/04_pass-return-channels/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tc := incrementor()\n\tcSum := puller(c)\n\tfor n := range cSum {\n\t\tfmt.Println(n)\n\t}\n}\n\nfunc incrementor() chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tout <- i\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc puller(c chan int) chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tvar sum int\n\t\tfor n := range c {\n\t\t\tsum += n\n\t\t}\n\t\tout <- sum\n\t\tclose(out)\n\t}()\n\treturn out\n}\n"
  },
  {
    "path": "22_go-routines/09_channels/05_channel-direction/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tc := incrementor()\n\tcSum := puller(c)\n\tfor n := range cSum {\n\t\tfmt.Println(n)\n\t}\n}\n\nfunc incrementor() <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tout <- i\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc puller(c <-chan int) <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tvar sum int\n\t\tfor n := range c {\n\t\t\tsum += n\n\t\t}\n\t\tout <- sum\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\n/*\nThe optional <- operator specifies the channel direction, send or receive.\nIf no direction is given, the channel is bidirectional.\nhttps://golang.org/ref/spec#Channel_types\n*/\n"
  },
  {
    "path": "22_go-routines/09_channels/06_refactor/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tc := incrementor()\n\tfor n := range puller(c) {\n\t\tfmt.Println(n)\n\t}\n}\n\nfunc incrementor() <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tout <- i\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc puller(c <-chan int) <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tvar sum int\n\t\tfor n := range c {\n\t\t\tsum += n\n\t\t}\n\t\tout <- sum\n\t\tclose(out)\n\t}()\n\treturn out\n}\n"
  },
  {
    "path": "22_go-routines/09_channels/07_incrementor/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tc1 := incrementor(\"Foo:\")\n\tc2 := incrementor(\"Bar:\")\n\tc3 := puller(c1)\n\tc4 := puller(c2)\n\tfmt.Println(\"Final Counter:\", <-c3+<-c4)\n}\n\nfunc incrementor(s string) chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor i := 0; i < 20; i++ {\n\t\t\tout <- 1\n\t\t\tfmt.Println(s, i)\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc puller(c chan int) chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tvar sum int\n\t\tfor n := range c {\n\t\t\tsum += n\n\t\t}\n\t\tout <- sum\n\t\tclose(out)\n\t}()\n\treturn out\n}\n"
  },
  {
    "path": "22_go-routines/09_channels/08_closures/01_no-closure-binding/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tdone := make(chan bool)\n\n\tvalues := []string{\"a\", \"b\", \"c\"}\n\tfor _, v := range values {\n\t\tgo func() {\n\t\t\tfmt.Println(v)\n\t\t\tdone <- true\n\t\t}()\n\t}\n\n\t// wait for all goroutines to complete before exiting\n\tfor _ = range values {\n\t\t<-done\n\t}\n}\n\n/*\nSome confusion may arise when using closures with concurrency.\n\nOne might mistakenly expect to see a, b, c as the output.\nWhat you'll probably see instead is c, c, c. This is because\neach iteration of the loop uses the same instance of the variable v,\nso each closure shares that single variable. When the closure runs,\nit prints the value of v at the time fmt.Println is executed,\nbut v may have been modified since the goroutine was launched.\nTo help detect this and other problems before they happen,\nrun go vet.\n\nSOURCE:\nhttps://golang.org/doc/faq#closures_and_goroutines\n*/\n"
  },
  {
    "path": "22_go-routines/09_channels/08_closures/02_closure-binding/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tdone := make(chan bool)\n\n\tvalues := []string{\"a\", \"b\", \"c\"}\n\tfor _, v := range values {\n\t\tgo func(u string) {\n\t\t\tfmt.Println(u)\n\t\t\tdone <- true\n\t\t}(v)\n\t}\n\n\t// wait for all goroutines to complete before exiting\n\tfor _ = range values {\n\t\t<-done\n\t}\n}\n\n/*\nTo bind the current value of v to each closure as it is launched,\none must modify the inner loop to create a new variable each iteration.\nOne way is to pass the variable as an argument to the closure.\n\nIn this example, the value of v is passed as an argument to the anonymous function.\nThat value is then accessible inside the function as the variable u.\n\nSOURCE:\nhttps://golang.org/doc/faq#closures_and_goroutines\n*/\n"
  },
  {
    "path": "22_go-routines/09_channels/08_closures/03_closure-binding/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tdone := make(chan bool)\n\n\tvalues := []string{\"a\", \"b\", \"c\"}\n\tfor _, v := range values {\n\t\tv := v // create a new 'v'.\n\t\tgo func() {\n\t\t\tfmt.Println(v)\n\t\t\tdone <- true\n\t\t}()\n\t}\n\n\t// wait for all goroutines to complete before exiting\n\tfor _ = range values {\n\t\t<-done\n\t}\n}\n\n/*\nEven easier is just to create a new variable,\nusing a declaration style that may seem odd but works fine in Go.\n\nSOURCE:\nhttps://golang.org/doc/faq#closures_and_goroutines\n*/\n"
  },
  {
    "path": "22_go-routines/10_deadlock-challenges/01_deadlock-challenge/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tc := make(chan int)\n\tc <- 1\n\tfmt.Println(<-c)\n}\n\n// This results in a deadlock.\n// Can you determine why?\n// And what would you do to fix it?\n"
  },
  {
    "path": "22_go-routines/10_deadlock-challenges/02_deadlock-solution/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tc := make(chan int)\n\tgo func() {\n\t\tc <- 1\n\t}()\n\tfmt.Println(<-c)\n}\n"
  },
  {
    "path": "22_go-routines/10_deadlock-challenges/03_deadlock-challenge/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tc := make(chan int)\n\n\tgo func() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tc <- i\n\t\t}\n\t}()\n\n\tfmt.Println(<-c)\n}\n\n// Why does this only print zero?\n// And what can you do to get it to print all 0 - 9 numbers?\n"
  },
  {
    "path": "22_go-routines/10_deadlock-challenges/04_deadlock-challenge/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tc := make(chan int)\n\n\tgo func() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tc <- i\n\t\t}\n\t}()\n\n\tfor {\n\t\tfmt.Println(<-c)\n\t}\n}\n\n// This prints the number, but we have received this error:\n// fatal error: all goroutines are asleep - deadlock!\n// Where is the deadlock?\n// Why are all goroutines asleep?\n// How can we fix this?\n"
  },
  {
    "path": "22_go-routines/10_deadlock-challenges/05_deadlock-solution/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tc := make(chan int)\n\n\tgo func() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tc <- i\n\t\t}\n\t\tclose(c)\n\t}()\n\n\tfor n := range c {\n\t\tfmt.Println(n)\n\t}\n}\n\n// remember to close your channel\n// if you do not close your channel, you will receive this error\n// fatal error: all goroutines are asleep - deadlock!\n\n// ************** IMPORTANT **************\n// YOU NEED GO VERSION 1.5.2 OR GREATER\n// otherwise you will receive this error\n// fatal error: all goroutines are asleep - deadlock!\n"
  },
  {
    "path": "22_go-routines/11_factorial-challenge/01_challenge-description/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tf := factorial(4)\n\tfmt.Println(\"Total:\", f)\n}\n\nfunc factorial(n int) int {\n\ttotal := 1\n\tfor i := n; i > 0; i-- {\n\t\ttotal *= i\n\t}\n\treturn total\n}\n\n/*\nCHALLENGE #1:\n-- Use goroutines and channels to calculate factorial\n\nCHALLENGE #2:\n-- Why might you want to use goroutines and channels to calculate factorial?\n---- Formulate your own answer, then post that answer to this discussion area: https://goo.gl/flGsyX\n---- Read a few of the other answers at the discussion area to see the reasons of others\n*/\n"
  },
  {
    "path": "22_go-routines/11_factorial-challenge/02_challenge-solution/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tc := factorial(4)\n\tfor n := range c {\n\t\tfmt.Println(n)\n\t}\n}\n\nfunc factorial(n int) chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\ttotal := 1\n\t\tfor i := n; i > 0; i-- {\n\t\t\ttotal *= i\n\t\t}\n\t\tout <- total\n\t\tclose(out)\n\t}()\n\treturn out\n}\n"
  },
  {
    "path": "22_go-routines/12_channels_pipeline/01_sq-output/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\t// Set up the pipeline.\n\tc := gen(2, 3)\n\tout := sq(c)\n\n\t// Consume the output.\n\tfmt.Println(<-out) // 4\n\tfmt.Println(<-out) // 9\n}\n\nfunc gen(nums ...int) chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor _, n := range nums {\n\t\t\tout <- n\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc sq(in chan int) chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor n := range in {\n\t\t\tout <- n * n\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n"
  },
  {
    "path": "22_go-routines/12_channels_pipeline/02_sq-output/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\t// Set up the pipeline and consume the output.\n\tfor n := range sq(sq(gen(2, 3))) {\n\t\tfmt.Println(n) // 16 then 81\n\t}\n}\n\nfunc gen(nums ...int) chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor _, n := range nums {\n\t\t\tout <- n\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc sq(in chan int) chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor n := range in {\n\t\t\tout <- n * n\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n"
  },
  {
    "path": "22_go-routines/12_channels_pipeline/03_challenge-description/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tc := factorial(4)\n\tfor n := range c {\n\t\tfmt.Println(n)\n\t}\n}\n\nfunc factorial(n int) chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\ttotal := 1\n\t\tfor i := n; i > 0; i-- {\n\t\t\ttotal *= i\n\t\t}\n\t\tout <- total\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\n/*\nCHALLENGE #1:\n-- Change the code above to execute 100 factorial computations concurrently and in parallel.\n-- Use the \"pipeline\" pattern to accomplish this\n\nPOST TO DISCUSSION:\n-- What realizations did you have about working with concurrent code when building your solution?\n-- eg, what insights did you have which helped you understand working with concurrency?\n-- Post your answer, and read other answers, here: https://goo.gl/uJa99G\n*/\n"
  },
  {
    "path": "22_go-routines/12_channels_pipeline/04_challenge-solution/01_original-solution/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\n\tin := gen()\n\n\tf := factorial(in)\n\n\tfor n := range f {\n\t\tfmt.Println(n)\n\t}\n}\n\nfunc gen() <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tfor j := 3; j < 13; j++ {\n\t\t\t\tout <- j\n\t\t\t}\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc factorial(in <-chan int) <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor n := range in {\n\t\t\tout <- fact(n)\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc fact(n int) int {\n\ttotal := 1\n\tfor i := n; i > 0; i-- {\n\t\ttotal *= i\n\t}\n\treturn total\n}\n"
  },
  {
    "path": "22_go-routines/12_channels_pipeline/04_challenge-solution/02_another-solution/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"sync\"\n)\n\nconst numFactorials = 100\nconst rdLimit = 20\n\nfunc main() {\n\tvar w sync.WaitGroup\n\tw.Add(numFactorials)\n\tfactorial(&w)\n\tw.Wait()\n\n}\n\nfunc factorial(wmain *sync.WaitGroup) {\n\tvar w sync.WaitGroup\n\trand.Seed(42)\n\n\tw.Add(numFactorials + 1)\n\n\tfor j := 1; j <= numFactorials; j++ {\n\n\t\tgo func() {\n\t\t\tf := rand.Intn(rdLimit)\n\t\t\tw.Wait()\n\t\t\ttotal := 1\n\t\t\tfor i := f; i > 0; i-- {\n\n\t\t\t\ttotal *= i\n\t\t\t}\n\t\t\tfmt.Println(f, total)\n\t\t\t(*wmain).Done()\n\t\t\t//out <- total\n\n\t\t}()\n\t\tw.Done()\n\t}\n\tfmt.Println(\"All done with initialization\")\n\tw.Done()\n}"
  },
  {
    "path": "22_go-routines/12_channels_pipeline/04_challenge-solution/README.md",
    "content": "A student sent me the below note so I included the student's excellent solution to this project:\n\nTodd, I reviewed your solution to 22_go-routines/04_challenge-solution in your Golang Programming class.\n\nI believe your solution might not run 100 factorial computations concurrently and in parallel as the following statement will calculate the factorials sequentially, since it is receiving them - one by one -  from the pipeline:\nout <- fact(n)\n\nI used the sync package to create a solution that I believe will accomplish your goal. Let me know if I am missing something:\n\nhttps://github.com/arsanjea/udemyTraining/blob/master/Exercises/exercise38.go\n\n/////\n\n# Definitions\n\n## concurrency\na design pattern\ngo uses goroutines to create concurrent design patterns\n\n## parallelism\nrunning code from a program on more than one cpu\nparallelism implies you have used concurrent design patterns\n\n## sequentially\none thing happening after another, in sequence\n\n# here are my thoughts\n\nThe original solution uses concurrent design patterns. It uses two different goroutines. The [control flow](https://en.wikipedia.org/wiki/Control_flow) of the program is no longer a straight top-to-bottom sequence. Different goroutines have been launched.\n\nThe program may or may not run in parallel. If the program is run on a machine with two or more cpus, the program has the potential to run in parallel. Each of our three goroutines (the two goroutines we launched, and main) could be running on different cpu cores.\n\nJean-Marc Arsan is correct: the program IS still running sequentially. Even though calculations are occuring in different goroutines, and potentially on different CPU cores, the sequence in which they occur is still sequential. \n\ngoroutines allow synchronization of code.\n\nIn this original example, the code is synchronized.\n\nThank you, Jean-Marc, for your comment on this code!\n\nI appreciate these discussions and hope the notes and your new code sample are helpful to everyone!\n\n"
  },
  {
    "path": "22_go-routines/13_channels_fan-out_fan-in/01_boring/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"time\"\n)\n\nfunc main() {\n\tc := fanIn(boring(\"Joe\"), boring(\"Ann\"))\n\tfor i := 0; i < 10; i++ {\n\t\tfmt.Println(<-c)\n\t}\n\tfmt.Println(\"You're both boring; I'm leaving.\")\n}\n\nfunc boring(msg string) <-chan string {\n\tc := make(chan string)\n\tgo func() {\n\t\tfor i := 0; ; i++ {\n\t\t\tc <- fmt.Sprintf(\"%s %d\", msg, i)\n\t\t\ttime.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)\n\t\t}\n\t}()\n\treturn c\n}\n\n// FAN IN\nfunc fanIn(input1, input2 <-chan string) <-chan string {\n\tc := make(chan string)\n\tgo func() {\n\t\tfor {\n\t\t\tc <- <-input1\n\t\t}\n\t}()\n\tgo func() {\n\t\tfor {\n\t\t\tc <- <-input2\n\t\t}\n\t}()\n\treturn c\n}\n\n/*\ncode source:\nRob Pike\nhttps://talks.golang.org/2012/concurrency.slide#25\n*/\n\n/*\nFAN OUT\nMultiple functions reading from the same channel until that channel is closed\n\nFAN IN\nA function can read from multiple inputs and proceed until all are closed by\nmultiplexing the input channels onto a single channel that's closed when\nall the inputs are closed.\n\nPATTERN\nthere's a pattern to our pipeline functions:\n-- stages close their outbound channels when all the send operations are done.\n-- stages keep receiving values from inbound channels until those channels are closed.\n\nsource:\nhttps://blog.golang.org/pipelines\n*/\n"
  },
  {
    "path": "22_go-routines/13_channels_fan-out_fan-in/02_sq-output/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\nfunc main() {\n\tin := gen(2, 3)\n\n\t// FAN OUT\n\t// Distribute the sq work across two goroutines that both read from in.\n\tc1 := sq(in)\n\tc2 := sq(in)\n\n\t// FAN IN\n\t// Consume the merged output from multiple channels.\n\tfor n := range merge(c1, c2) {\n\t\tfmt.Println(n) // 4 then 9, or 9 then 4\n\t}\n}\n\nfunc gen(nums ...int) chan int {\n\tfmt.Printf(\"TYPE OF NUMS %T\\n\", nums) // just FYI\n\n\tout := make(chan int)\n\tgo func() {\n\t\tfor _, n := range nums {\n\t\t\tout <- n\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc sq(in chan int) chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor n := range in {\n\t\t\tout <- n * n\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc merge(cs ...chan int) chan int {\n\tfmt.Printf(\"TYPE OF CS: %T\\n\", cs) // just FYI\n\n\tout := make(chan int)\n\tvar wg sync.WaitGroup\n\twg.Add(len(cs))\n\n\tfor _, c := range cs {\n\t\tgo func(ch chan int) {\n\t\t\tfor n := range ch {\n\t\t\t\tout <- n\n\t\t\t}\n\t\t\twg.Done()\n\t\t}(c)\n\t}\n\n\tgo func() {\n\t\twg.Wait()\n\t\tclose(out)\n\t}()\n\n\treturn out\n}\n\n/*\nFAN OUT\nMultiple functions reading from the same channel until that channel is closed\n\nFAN IN\nA function can read from multiple inputs and proceed until all are closed by\nmultiplexing the input channels onto a single channel that's closed when\nall the inputs are closed.\n\nPATTERN\nthere's a pattern to our pipeline functions:\n-- stages close their outbound channels when all the send operations are done.\n-- stages keep receiving values from inbound channels until those channels are closed.\n\nsource:\nhttps://blog.golang.org/pipelines\n*/\n\n/*\nCHALLENGE #1\nWhen know HOW to do fan out / fan in, but do we know WHY?\nWhy would we want to do fan out / fan in?\n*/\n"
  },
  {
    "path": "22_go-routines/13_channels_fan-out_fan-in/03_sq-output_variation/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\nfunc main() {\n\tin := gen(2, 3)\n\n\t// Distribute the sq work across two goroutines that both read from in.\n\tc1 := sq(in)\n\tc2 := sq(in)\n\n\t// Consume the merged output from c1 and c2.\n\tfor n := range merge(c1, c2) {\n\t\tfmt.Println(n) // 4 then 9, or 9 then 4\n\t}\n}\n\nfunc gen(nums ...int) <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor _, n := range nums {\n\t\t\tout <- n\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc sq(in <-chan int) <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor n := range in {\n\t\t\tout <- n * n\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc merge(cs ...<-chan int) <-chan int {\n\tvar wg sync.WaitGroup\n\tout := make(chan int)\n\n\t// Start an output goroutine for each input channel in cs.\n\t// output copies values from c to out until c is closed, then calls wg.Done.\n\toutput := func(c <-chan int) {\n\t\tfor n := range c {\n\t\t\tout <- n\n\t\t}\n\t\twg.Done()\n\t}\n\n\twg.Add(len(cs))\n\tfor _, c := range cs {\n\t\tgo output(c)\n\t}\n\n\t// Start a goroutine to close out once all the output goroutines are\n\t// done.  This must start after the wg.Add call.\n\tgo func() {\n\t\twg.Wait()\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\n/*\nFAN OUT\nMultiple functions reading from the same channel until that channel is closed\n\nFAN IN\nA function can read from multiple inputs and proceed until all are closed by\nmultiplexing the input channels onto a single channel that's closed when\nall the inputs are closed.\n\nPATTERN\nthere's a pattern to our pipeline functions:\n-- stages close their outbound channels when all the send operations are done.\n-- stages keep receiving values from inbound channels until those channels are closed.\n\nsource:\nhttps://blog.golang.org/pipelines\n*/\n"
  },
  {
    "path": "22_go-routines/13_channels_fan-out_fan-in/04_challenge-description/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\nvar workerID int\nvar publisherID int\n\nfunc main() {\n\tinput := make(chan string)\n\tgo workerProcess(input)\n\tgo workerProcess(input)\n\tgo workerProcess(input)\n\tgo publisher(input)\n\tgo publisher(input)\n\tgo publisher(input)\n\tgo publisher(input)\n\ttime.Sleep(1 * time.Millisecond)\n}\n\n// publisher pushes data into a channel\nfunc publisher(out chan string) {\n\tpublisherID++\n\tthisID := publisherID\n\tdataID := 0\n\tfor {\n\t\tdataID++\n\t\tfmt.Printf(\"publisher %d is pushing data\\n\", thisID)\n\t\tdata := fmt.Sprintf(\"Data from publisher %d. Data %d\", thisID, dataID)\n\t\tout <- data\n\t}\n}\n\nfunc workerProcess(in <-chan string) {\n\tworkerID++\n\tthisID := workerID\n\tfor {\n\t\tfmt.Printf(\"%d: waiting for input...\\n\", thisID)\n\t\tinput := <-in\n\t\tfmt.Printf(\"%d: input is: %s\\n\", thisID, input)\n\t}\n}\n\n/*\nCHALLENGE #1\nIs this fan out?\n\nCHALLENGE #2\nIs this fan in?\n*/\n"
  },
  {
    "path": "22_go-routines/13_channels_fan-out_fan-in/05_challenge-solution/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\t\"sync/atomic\"\n)\n\nvar workerID int64\nvar publisherID int64\n\nfunc main() {\n\tinput := make(chan string)\n\tgo workerProcess(input)\n\tgo workerProcess(input)\n\tgo workerProcess(input)\n\tgo publisher(input)\n\tgo publisher(input)\n\tgo publisher(input)\n\tgo publisher(input)\n\ttime.Sleep(1 * time.Millisecond)\n}\n\n// publisher pushes data into a channel\nfunc publisher(out chan string) {\n\tatomic.AddInt64(&publisherID, 1)\n\t// atomic was added after recording to fix a race condition\n\t// discover race conditions with the -race flag\n\t// for example: go run -race main.go\n\t// learn about the atomic package: https://godoc.org/sync/atomic#AddInt64\n\tthisID := atomic.LoadInt64(&publisherID)\n\tdataID := 0\n\tfor {\n\t\tdataID++\n\t\tfmt.Printf(\"publisher %d is pushing data\\n\", thisID)\n\t\tdata := fmt.Sprintf(\"Data from publisher %d. Data %d\", thisID, dataID)\n\t\tout <- data\n\t}\n}\n\nfunc workerProcess(in <-chan string) {\n\tatomic.AddInt64(&workerID, 1)\n\t// atomic was added after recording to fix a race condition\n\t// discover race conditions with the -race flag\n\t// for example: go run -race main.go\n\t// learn about the atomic package: https://godoc.org/sync/atomic#AddInt64\n\tthisID := atomic.LoadInt64(&workerID)\n\tfor {\n\t\tfmt.Printf(\"%d: waiting for input...\\n\", thisID)\n\t\tinput := <-in\n\t\tfmt.Printf(\"%d: input is: %s\\n\", thisID, input)\n\t}\n}\n\n/*\nCHALLENGE #1\nIs this fan out?\nMy Answer:\nYes.\n-- YES\nAre we \"fanning out\" work? Yes. We've launched several goroutines that are simultaneously publishing a message onto our channel. The golang blog says, \"Fan out means you have multiple functions reading from the same channel until that channel is closed.\" Here we do have multiple functions reading from the same channel. So, okay, we're fanning out.\n\n\nCHALLENGE #2\nIs this fan in?\nNo.\nWhat is being \"fanned in\" here? We have launched several goroutines of the same function: workerProcess. What do those goroutines do? They are all reading from an unbuffered channel. If there was a tremendous amount of processing that each \"workerProcess\" func executed, then all three of the \"workerProcess\" funcs could be processing in parallel: pulling values off the channel and processing them. There is no \"fanning in\" though here. Remember what the golang blog describes fan in: \"A function can read from multiple inputs and proceed until all are closed by multiplexing the input channels onto a single channel that's closed when all the inputs are closed.\" We don't have many channels here converging into one channel.\n\n*/\n"
  },
  {
    "path": "22_go-routines/13_channels_fan-out_fan-in/06_challenge-description/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\n\tin := gen()\n\n\tf := factorial(in)\n\n\tfor n := range f {\n\t\tfmt.Println(n)\n\t}\n}\n\nfunc gen() <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tfor j := 3; j < 13; j++ {\n\t\t\t\tout <- j\n\t\t\t}\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc factorial(in <-chan int) <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor n := range in {\n\t\t\tout <- fact(n)\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc fact(n int) int {\n\ttotal := 1\n\tfor i := n; i > 0; i-- {\n\t\ttotal *= i\n\t}\n\treturn total\n}\n\n/*\nCHALLENGE #1:\n-- Change the code above to execute 1,000 factorial computations concurrently and in parallel.\n-- Use the \"fan out / fan in\" pattern\n\nCHALLENGE #2:\nWATCH MY SOLUTION BEFORE DOING THIS CHALLENGE #2\n-- While running the factorial computations, try to find how much of your resources are being used.\n-- Post the percentage of your resources being used to this discussion: https://goo.gl/BxKnOL\n*/\n"
  },
  {
    "path": "22_go-routines/13_channels_fan-out_fan-in/07_challenge-solution/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\nfunc main() {\n\n\tin := gen()\n\n\t// FAN OUT\n\t// Multiple functions reading from the same channel until that channel is closed\n\t// Distribute work across multiple functions (ten goroutines) that all read from in.\n\tc0 := factorial(in)\n\tc1 := factorial(in)\n\tc2 := factorial(in)\n\tc3 := factorial(in)\n\tc4 := factorial(in)\n\tc5 := factorial(in)\n\tc6 := factorial(in)\n\tc7 := factorial(in)\n\tc8 := factorial(in)\n\tc9 := factorial(in)\n\n\t// FAN IN\n\t// multiplex multiple channels onto a single channel\n\t// merge the channels from c0 through c9 onto a single channel\n\tvar y int\n\tfor n := range merge(c0, c1, c2, c3, c4, c5, c6, c7, c8, c9) {\n\t\ty++\n\t\tfmt.Println(y, \"\\t\", n)\n\t}\n\n}\n\nfunc gen() <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tfor j := 3; j < 13; j++ {\n\t\t\t\tout <- j\n\t\t\t}\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc factorial(in <-chan int) <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor n := range in {\n\t\t\tout <- fact(n)\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc fact(n int) int {\n\ttotal := 1\n\tfor i := n; i > 0; i-- {\n\t\ttotal *= i\n\t}\n\treturn total\n}\n\nfunc merge(cs ...<-chan int) <-chan int {\n\tvar wg sync.WaitGroup\n\tout := make(chan int)\n\n\toutput := func(c <-chan int) {\n\t\tfor n := range c {\n\t\t\tout <- n\n\t\t}\n\t\twg.Done()\n\t}\n\n\twg.Add(len(cs))\n\tfor _, c := range cs {\n\t\tgo output(c)\n\t}\n\n\t// Start a goroutine to close out once all the output goroutines are\n\t// done.  This must start after the wg.Add call.\n\tgo func() {\n\t\twg.Wait()\n\t\tclose(out)\n\t}()\n\treturn out\n}\n"
  },
  {
    "path": "22_go-routines/13_channels_fan-out_fan-in/08_challenge-description/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\nfunc main() {\n\n\tin := gen()\n\n\t// FAN OUT\n\t// Multiple functions reading from the same channel until that channel is closed\n\t// Distribute work across multiple functions (ten goroutines) that all read from in.\n\txc := fanOut(in, 10)\n\n\t// FAN IN\n\t// multiplex multiple channels onto a single channel\n\t// merge the channels from c0 through c9 onto a single channel\n\tfor n := range merge(xc...) {\n\t\tfmt.Println(n)\n\t}\n\n}\n\nfunc gen() <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tfor j := 3; j < 13; j++ {\n\t\t\t\tout <- j\n\t\t\t}\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc fanOut(in <-chan int, n int) []<-chan int {\n\txc := make([]<-chan int, n)\n\tfor i := 0; i < n; i++ {\n\t\txc = append(xc, factorial(in))\n\t}\n\treturn xc\n}\n\nfunc factorial(in <-chan int) <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor n := range in {\n\t\t\tout <- fact(n)\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc fact(n int) int {\n\ttotal := 1\n\tfor i := n; i > 0; i-- {\n\t\ttotal *= i\n\t}\n\treturn total\n}\n\nfunc merge(cs ...<-chan int) <-chan int {\n\tvar wg sync.WaitGroup\n\tout := make(chan int)\n\n\toutput := func(c <-chan int) {\n\t\tfor n := range c {\n\t\t\tout <- n\n\t\t}\n\t\twg.Done()\n\t}\n\n\twg.Add(len(cs))\n\tfor _, c := range cs {\n\t\tgo output(c)\n\t}\n\n\t// Start a goroutine to close out once all the output goroutines are\n\t// done.  This must start after the wg.Add call.\n\tgo func() {\n\t\twg.Wait()\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\n/*\nCHALLENGE #1:\n-- This code throws an error: fatal error: all goroutines are asleep - deadlock!\n-- fix this code!\n*/\n"
  },
  {
    "path": "22_go-routines/13_channels_fan-out_fan-in/09_challenge-solution/01_troubleshooting-step/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\nfunc main() {\n\n\tin := gen()\n\n\t// FAN OUT\n\t// Multiple functions reading from the same channel until that channel is closed\n\t// Distribute work across multiple functions (ten goroutines) that all read from in.\n\txc := fanOut(in, 10)\n\n\t// FAN IN\n\t// multiplex multiple channels onto a single channel\n\t// merge the channels from c0 through c9 onto a single channel\n\n\t// TROUBLESHOOTING\n\tfmt.Printf(\"%T \\n\", xc)\n\tfmt.Println(\"*******************\", len(xc))\n\tfor _, v := range xc {\n\t\tfmt.Println(\"********\", <-v)\n\t}\n\n\tfor n := range merge(xc...) {\n\t\tfmt.Println(n)\n\t}\n\n}\n\nfunc gen() <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tfor j := 3; j < 13; j++ {\n\t\t\t\tout <- j\n\t\t\t}\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc fanOut(in <-chan int, n int) []<-chan int {\n\tvar xc []<-chan int // this needed to be zero\n\tfor i := 0; i < n; i++ {\n\t\txc = append(xc, factorial(in))\n\t}\n\treturn xc\n}\n\nfunc factorial(in <-chan int) <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor n := range in {\n\t\t\tout <- fact(n)\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc fact(n int) int {\n\ttotal := 1\n\tfor i := n; i > 0; i-- {\n\t\ttotal *= i\n\t}\n\treturn total\n}\n\nfunc merge(cs ...<-chan int) <-chan int {\n\tvar wg sync.WaitGroup\n\tout := make(chan int)\n\n\toutput := func(c <-chan int) {\n\t\tfor n := range c {\n\t\t\tout <- n\n\t\t}\n\t\twg.Done()\n\t}\n\n\twg.Add(len(cs))\n\tfor _, c := range cs {\n\t\tgo output(c)\n\t}\n\n\t// Start a goroutine to close out once all the output goroutines are\n\t// done.  This must start after the wg.Add call.\n\tgo func() {\n\t\twg.Wait()\n\t\tclose(out)\n\t}()\n\treturn out\n}\n"
  },
  {
    "path": "22_go-routines/13_channels_fan-out_fan-in/09_challenge-solution/02_solution/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\nfunc main() {\n\n\tin := gen()\n\n\t// FAN OUT\n\t// Multiple functions reading from the same channel until that channel is closed\n\t// Distribute work across multiple functions (ten goroutines) that all read from in.\n\txc := fanOut(in, 10)\n\n\t// FAN IN\n\t// multiplex multiple channels onto a single channel\n\t// merge the channels from c0 through c9 onto a single channel\n\tfor n := range merge(xc...) {\n\t\tfmt.Println(n)\n\t}\n\n}\n\nfunc gen() <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tfor j := 3; j < 13; j++ {\n\t\t\t\tout <- j\n\t\t\t}\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc fanOut(in <-chan int, n int) []<-chan int {\n\tvar xc []<-chan int // this needed to be zero\n\tfor i := 0; i < n; i++ {\n\t\txc = append(xc, factorial(in))\n\t}\n\treturn xc\n}\n\nfunc factorial(in <-chan int) <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor n := range in {\n\t\t\tout <- fact(n)\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc fact(n int) int {\n\ttotal := 1\n\tfor i := n; i > 0; i-- {\n\t\ttotal *= i\n\t}\n\treturn total\n}\n\nfunc merge(cs ...<-chan int) <-chan int {\n\tvar wg sync.WaitGroup\n\tout := make(chan int)\n\n\toutput := func(c <-chan int) {\n\t\tfor n := range c {\n\t\t\tout <- n\n\t\t}\n\t\twg.Done()\n\t}\n\n\twg.Add(len(cs))\n\tfor _, c := range cs {\n\t\tgo output(c)\n\t}\n\n\t// Start a goroutine to close out once all the output goroutines are\n\t// done.  This must start after the wg.Add call.\n\tgo func() {\n\t\twg.Wait()\n\t\tclose(out)\n\t}()\n\treturn out\n}\n"
  },
  {
    "path": "22_go-routines/13_channels_fan-out_fan-in/10_van-sickle_fan-out_fan-in/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\n\tin := gen()\n\tout := make(chan int)\n\n\t// FAN OUT\n\t// Multiple functions reading from the same channel until that channel is closed\n\t// Distribute work across multiple functions (ten goroutines) that all read from in.\n\tfanOut(in, 10, out)\n\n\t// FAN IN\n\t// multiplex multiple channels onto a single channel\n\t// merge the channels from c0 through c9 onto a single channel\n\tgo func() {\n\t\tfor v := range out {\n\t\t\tfmt.Println(v)\n\t\t}\n\t}()\n\n\tvar a string\n\tfmt.Scanln(&a)\n}\n\nfunc gen() <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tfor j := 3; j < 13; j++ {\n\t\t\t\tout <- j\n\t\t\t}\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc fanOut(in <-chan int, n int, out chan<- int) {\n\tfor i := 0; i < n; i++ {\n\t\tfactorial(in, out)\n\t}\n}\n\nfunc factorial(in <-chan int, out chan<- int) {\n\tgo func() {\n\t\tfor n := range in {\n\n\t\t\tout <- fact(n)\n\t\t}\n\t}()\n}\n\nfunc fact(n int) int {\n\ttotal := 1\n\tfor i := n; i > 0; i-- {\n\t\ttotal *= i\n\t}\n\treturn total\n}\n\n/*\nThis code was provided by my friend, Mike Van Sickle\nHe is an awesome programmer, an awesome Go programmer, and an awesome teacher\nCheck out his courses on pluralsight to learn more about Go!\n*/\n"
  },
  {
    "path": "22_go-routines/14_incrementor-challenge/01_description/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"sync/atomic\"\n)\n\nvar count int64\nvar wg sync.WaitGroup\n\nfunc main() {\n\twg.Add(2)\n\tgo incrementor(\"1\")\n\tgo incrementor(\"2\")\n\twg.Wait()\n\tfmt.Println(\"Final Counter:\", count)\n}\n\nfunc incrementor(s string) {\n\tfor i := 0; i < 20; i++ {\n\t\tatomic.AddInt64(&count, 1)\n\t\tfmt.Println(\"Process: \"+s+\" printing:\", i)\n\t}\n\twg.Done()\n}\n\n/*\nCHALLENGE #1\n-- Take the code from above and change it to use channels instead of wait groups and atomicity\n*/\n"
  },
  {
    "path": "22_go-routines/14_incrementor-challenge/02_solution/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n)\n\nfunc main() {\n\n\tc := incrementor(2)\n\n\tvar count int\n\tfor n := range c {\n\t\tcount++\n\t\tfmt.Println(n)\n\t}\n\n\tfmt.Println(\"Final Count:\", count)\n}\n\nfunc incrementor(n int) chan string {\n\tc := make(chan string)\n\tdone := make(chan bool)\n\n\tfor i := 0; i < n; i++ {\n\t\tgo func(i int) {\n\t\t\tfor k := 0; k < 20; k++ {\n\t\t\t\tc <- fmt.Sprint(\"Process: \"+strconv.Itoa(i)+\" printing:\", k)\n\t\t\t}\n\t\t\tdone <- true\n\t\t}(i)\n\t}\n\n\tgo func() {\n\t\tfor i := 0; i < n; i++ {\n\t\t\t<-done\n\t\t}\n\t\tclose(c)\n\t}()\n\n\treturn c\n}\n"
  },
  {
    "path": "22_go-routines/15_for-fun/01/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tm := map[int]int{}\n\tm[4] = 7\n\tm[3] = 87\n\tm[72] = 19\n\n\tch := make(chan int)\n\n\t// for closing ch\n\tch2 := make(chan int)\n\tgo func() {\n\t\tvar i int\n\t\tfor n := range ch2 {\n\t\t\ti += n\n\t\t\tif i == len(m) {\n\t\t\t\tclose(ch)\n\t\t\t}\n\t\t}\n\t}()\n\n\tgo func() {\n\t\tfor _, v := range m {\n\t\t\tch <- v\n\t\t\tch2 <- 1\n\t\t}\n\t}()\n\n\tfor v := range ch {\n\t\tfmt.Println(v)\n\t}\n\n\t// good housekeeping\n\tclose(ch2)\n}"
  },
  {
    "path": "22_go-routines/15_for-fun/README.md",
    "content": "# New Code\n\nThese files were added into this repo after the training was recorded.\n\nThere are no lectures associated with these files. However, please peruse them and enjoy them!"
  },
  {
    "path": "23_error-handling/01_golint/01_before/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tx := 1\n\tstr := evalInt(x)\n\tfmt.Println(str)\n}\n\nfunc evalInt(n int) string {\n\tif n > 10 {\n\t\treturn fmt.Sprint(\"x is greater than 10\")\n\t} else {\n\t\treturn fmt.Sprint(\"x is less than 10\")\n\t}\n}\n"
  },
  {
    "path": "23_error-handling/01_golint/02_after/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tx := 1\n\tstr := evalInt(x)\n\tfmt.Println(str)\n}\n\nfunc evalInt(n int) string {\n\n\tif n > 10 {\n\t\treturn fmt.Sprint(\"x is greater than 10\")\n\t}\n\n\treturn fmt.Sprint(\"x is less than 10\")\n}\n"
  },
  {
    "path": "23_error-handling/02_err-not-nil/01_fmt-println/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n)\n\nfunc main() {\n\t_, err := os.Open(\"no-file.txt\")\n\tif err != nil {\n\t\tfmt.Println(\"err happened\", err)\n\t\t//\t\tlog.Println(\"err happened\", err)\n\t\t//\t\tlog.Fatalln(err)\n\t\t//\t\tpanic(err)\n\t}\n}\n\n// Println formats using the default formats for its operands and writes to standard output.\n"
  },
  {
    "path": "23_error-handling/02_err-not-nil/02_log-println/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\t_, err := os.Open(\"no-file.txt\")\n\tif err != nil {\n\t\t//\t\tfmt.Println(\"err happened\", err)\n\t\tlog.Println(\"err happened\", err)\n\t\t//\t\tlog.Fatalln(err)\n\t\t//\t\tpanic(err)\n\t}\n}\n\n/*\nPackage log implements a simple logging package ... writes to standard error and prints the date and time of each logged message ... the Fatal functions call os.Exit(1) after writing the log message ... the Panic functions call panic after writing the log message.\n*/\n\n// log.Println calls Output to print to the standard logger. Arguments are handled in the manner of fmt.Println.\n"
  },
  {
    "path": "23_error-handling/02_err-not-nil/03_log-set-output/log.txt",
    "content": "2016/02/17 04:35:28 err happened open no-file.txt: no such file or directory\n"
  },
  {
    "path": "23_error-handling/02_err-not-nil/03_log-set-output/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc init() {\n\tnf, err := os.Create(\"log.txt\")\n\tif err != nil {\n\t\tfmt.Println(err)\n\t}\n\tlog.SetOutput(nf)\n}\n\nfunc main() {\n\t_, err := os.Open(\"no-file.txt\")\n\tif err != nil {\n\t\t//\t\tfmt.Println(\"err happened\", err)\n\t\tlog.Println(\"err happened\", err)\n\t\t//\t\tlog.Fatalln(err)\n\t\t//\t\tpanic(err)\n\t}\n}\n\n/*\nPackage log implements a simple logging package ... writes to standard error and prints the date and time of each logged message ... the Fatal functions call os.Exit(1) after writing the log message ... the Panic functions call panic after writing the log message.\n*/\n\n// Println calls Output to print to the standard logger. Arguments are handled in the manner of fmt.Println.\n"
  },
  {
    "path": "23_error-handling/02_err-not-nil/04_log-fatalln/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\t_, err := os.Open(\"no-file.txt\")\n\tif err != nil {\n\t\t//\t\tfmt.Println(\"err happened\", err)\n\t\t//\t\tlog.Println(\"err happened\", err)\n\t\tlog.Fatalln(err)\n\t\t//\t\tpanic(err)\n\t}\n}\n\n/*\nPackage log implements a simple logging package ... writes to standard error and prints the date and time of each logged message ... the Fatal functions call os.Exit(1) after writing the log message ... the Panic functions call panic after writing the log message.\n*/\n\n// Fatalln is equivalent to Println() followed by a call to os.Exit(1).\n"
  },
  {
    "path": "23_error-handling/02_err-not-nil/05_panic/main.go",
    "content": "package main\n\nimport (\n\t\"os\"\n)\n\nfunc main() {\n\t_, err := os.Open(\"no-file.txt\")\n\tif err != nil {\n\t\t//\t\tfmt.Println(\"err happened\", err)\n\t\t//\t\tlog.Println(\"err happened\", err)\n\t\t//\t\tlog.Fatalln(err)\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "23_error-handling/03_custom-errors/01_errors-new/main.go",
    "content": "package main\n\nimport (\n\t\"errors\"\n\t\"log\"\n)\n\nfunc main() {\n\t_, err := Sqrt(-10)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n\nfunc Sqrt(f float64) (float64, error) {\n\tif f < 0 {\n\t\treturn 0, errors.New(\"norgate math: square root of negative number\")\n\t}\n\t// implementation\n\treturn 42, nil\n}\n"
  },
  {
    "path": "23_error-handling/03_custom-errors/02_errors-new_var/main.go",
    "content": "package main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n)\n\nvar ErrNorgateMath = errors.New(\"norgate math: square root of negative number\")\n\nfunc main() {\n\tfmt.Printf(\"%T\\n\", ErrNorgateMath)\n\t_, err := Sqrt(-10)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n\nfunc Sqrt(f float64) (float64, error) {\n\tif f < 0 {\n\t\treturn 0, ErrNorgateMath\n\t}\n\t// implementation\n\treturn 42, nil\n}\n\n// see use of errors.New in standard library:\n// http://golang.org/src/pkg/bufio/bufio.go\n// http://golang.org/src/pkg/io/io.go\n"
  },
  {
    "path": "23_error-handling/03_custom-errors/03_fmt-errorf/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n)\n\nfunc main() {\n\t_, err := Sqrt(-10.23)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n\nfunc Sqrt(f float64) (float64, error) {\n\tif f < 0 {\n\t\treturn 0, fmt.Errorf(\"norgate math again: square root of negative number: %v\", f)\n\t}\n\t// implementation\n\treturn 42, nil\n}\n"
  },
  {
    "path": "23_error-handling/03_custom-errors/04_fmt-errorf_var/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n)\n\nfunc main() {\n\t_, err := Sqrt(-10.23)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n\nfunc Sqrt(f float64) (float64, error) {\n\tif f < 0 {\n\t\tErrNorgateMath := fmt.Errorf(\"norgate math again: square root of negative number: %v\", f)\n\t\treturn 0, ErrNorgateMath\n\t}\n\t// implementation\n\treturn 42, nil\n}\n"
  },
  {
    "path": "23_error-handling/03_custom-errors/05_custom-type/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n)\n\ntype NorgateMathError struct {\n\tlat, long string\n\terr       error\n}\n\nfunc (n *NorgateMathError) Error() string {\n\treturn fmt.Sprintf(\"a norgate math error occured: %v %v %v\", n.lat, n.long, n.err)\n}\n\nfunc main() {\n\t_, err := Sqrt(-10.23)\n\tif err != nil {\n\t\tlog.Println(err)\n\t}\n}\n\nfunc Sqrt(f float64) (float64, error) {\n\tif f < 0 {\n\t\tnme := fmt.Errorf(\"norgate math redux: square root of negative number: %v\", f)\n\t\treturn 0, &NorgateMathError{\"50.2289 N\", \"99.4656 W\", nme}\n\t}\n\t// implementation\n\treturn 42, nil\n}\n\n// see use of structs with error type in standard library:\n// http://www.goinggo.net/2014/11/error-handling-in-go-part-ii.html\n//\n// http://golang.org/pkg/net/#OpError\n// http://golang.org/src/pkg/net/dial.go\n// http://golang.org/src/pkg/net/net.go\n//\n// http://golang.org/src/pkg/encoding/json/decode.go\n"
  },
  {
    "path": "24_testing/math.go",
    "content": "package math\n\nfunc Adder(xs ...int) int {\n\tres := 0\n\tfor _, v := range xs {\n\t\tres += v\n\t}\n\treturn res\n}\n"
  },
  {
    "path": "24_testing/math_test.go",
    "content": "package math\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"testing/quick\"\n)\n\nfunc TestAdder(t *testing.T) {\n\tresult := Adder(4, 7)\n\tif result != 11 {\n\t\tt.Fatal(\"4 + 7 did not equal 11\")\n\t}\n}\n\nfunc BenchmarkAdder(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tAdder(4, 7)\n\t}\n}\n\nfunc ExampleAdder() {\n\tfmt.Println(Adder(4, 7))\n\t// Output:\n\t// 11\n}\n\nfunc ExampleAdder_multiple() {\n\tfmt.Println(Adder(3, 6, 7, 4, 61))\n\t// Output:\n\t// 81\n}\n\nfunc TestAdderBlackbox(t *testing.T) {\n\terr := quick.Check(a, nil)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n\nfunc a(x, y int) bool {\n\treturn Adder(x, y) == x+y\n}\n"
  },
  {
    "path": "25_code-walk/main.go",
    "content": "// Copyright 2011 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n)\n\nconst (\n\twin            = 100 // The winning score in a game of Pig\n\tgamesPerSeries = 10  // The number of games per series to simulate\n)\n\ntype score struct {\n\tplayer, opponent, thisTurn int\n}\n\ntype action func(current score) (result score, turnIsOver bool)\n\nfunc roll(s score) (score, bool) {\n\toutcome := rand.Intn(6) + 1 // A random int in [1, 6]\n\tif outcome == 1 {\n\t\treturn score{s.opponent, s.player, 0}, true\n\t}\n\treturn score{s.player, s.opponent, outcome + s.thisTurn}, false\n}\n\nfunc stay(s score) (score, bool) {\n\treturn score{s.opponent, s.player + s.thisTurn, 0}, true\n}\n\ntype strategy func(score) action\n\nfunc stayAtK(k int) strategy {\n\treturn func(s score) action {\n\t\tif s.thisTurn >= k {\n\t\t\treturn stay\n\t\t}\n\t\treturn roll\n\t}\n}\n\nfunc play(strategy0, strategy1 strategy) int {\n\tstrategies := []strategy{strategy0, strategy1}\n\tvar s score\n\tvar turnIsOver bool\n\tcurrentPlayer := rand.Intn(2) // Randomly decide who plays first\n\tfor s.player+s.thisTurn < win {\n\t\taction := strategies[currentPlayer](s)\n\t\ts, turnIsOver = action(s)\n\t\tif turnIsOver {\n\t\t\tcurrentPlayer = (currentPlayer + 1) % 2\n\t\t}\n\t}\n\treturn currentPlayer\n}\n\nfunc roundRobin(strategies []strategy) ([]int, int) {\n\twins := make([]int, len(strategies))\n\tfor i := 0; i < len(strategies); i++ {\n\t\tfor j := i + 1; j < len(strategies); j++ {\n\t\t\tfor k := 0; k < gamesPerSeries; k++ {\n\t\t\t\twinner := play(strategies[i], strategies[j])\n\t\t\t\tif winner == 0 {\n\t\t\t\t\twins[i]++\n\t\t\t\t} else {\n\t\t\t\t\twins[j]++\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tgamesPerStrategy := gamesPerSeries * (len(strategies) - 1) // no self play\n\treturn wins, gamesPerStrategy\n}\n\nfunc ratioString(vals ...int) string {\n\ttotal := 0\n\tfor _, val := range vals {\n\t\ttotal += val\n\t}\n\ts := \"\"\n\tfor _, val := range vals {\n\t\tif s != \"\" {\n\t\t\ts += \", \"\n\t\t}\n\t\tpct := 100 * float64(val) / float64(total)\n\t\ts += fmt.Sprintf(\"%d/%d (%0.1f%%)\", val, total, pct)\n\t}\n\treturn s\n}\n\nfunc main() {\n\tstrategies := make([]strategy, win)\n\tfor k := range strategies {\n\t\tstrategies[k] = stayAtK(k + 1)\n\t}\n\twins, games := roundRobin(strategies)\n\n\tfor k := range strategies {\n\t\tfmt.Printf(\"Wins, losses staying at k =% 4d: %s\\n\",\n\t\t\tk+1, ratioString(wins[k], games-wins[k]))\n\t}\n}\n"
  },
  {
    "path": "25_code-walk/with-comments/main.go",
    "content": "// Copyright 2011 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n)\n\nconst (\n\twin            = 100 // The winning score in a game of Pig\n\tgamesPerSeries = 10  // The number of games per series to simulate\n)\n\n// A score includes scores accumulated in previous turns for each player,\n// as well as the points scored by the current player in this turn.\ntype score struct {\n\tplayer, opponent, thisTurn int\n}\n\n// An action transitions stochastically to a resulting score.\ntype action func(current score) (result score, turnIsOver bool)\n\n// roll returns the (result, turnIsOver) outcome of simulating a die roll.\n// If the roll value is 1, then thisTurn score is abandoned, and the players'\n// roles swap.  Otherwise, the roll value is added to thisTurn.\nfunc roll(s score) (score, bool) {\n\toutcome := rand.Intn(6) + 1 // A random int in [1, 6]\n\tif outcome == 1 {\n\t\treturn score{s.opponent, s.player, 0}, true\n\t}\n\treturn score{s.player, s.opponent, outcome + s.thisTurn}, false\n}\n\n// stay returns the (result, turnIsOver) outcome of staying.\n// thisTurn score is added to the player's score, and the players' roles swap.\nfunc stay(s score) (score, bool) {\n\treturn score{s.opponent, s.player + s.thisTurn, 0}, true\n}\n\n// A strategy chooses an action for any given score.\ntype strategy func(score) action\n\n// stayAtK returns a strategy that rolls until thisTurn is at least k, then stays.\nfunc stayAtK(k int) strategy {\n\treturn func(s score) action {\n\t\tif s.thisTurn >= k {\n\t\t\treturn stay\n\t\t}\n\t\treturn roll\n\t}\n}\n\n// play simulates a Pig game and returns the winner (0 or 1).\nfunc play(strategy0, strategy1 strategy) int {\n\tstrategies := []strategy{strategy0, strategy1}\n\tvar s score\n\tvar turnIsOver bool\n\tcurrentPlayer := rand.Intn(2) // Randomly decide who plays first\n\tfor s.player+s.thisTurn < win {\n\t\taction := strategies[currentPlayer](s)\n\t\ts, turnIsOver = action(s)\n\t\tif turnIsOver {\n\t\t\tcurrentPlayer = (currentPlayer + 1) % 2\n\t\t}\n\t}\n\treturn currentPlayer\n}\n\n// roundRobin simulates a series of games between every pair of strategies.\nfunc roundRobin(strategies []strategy) ([]int, int) {\n\twins := make([]int, len(strategies))\n\tfor i := 0; i < len(strategies); i++ {\n\t\tfor j := i + 1; j < len(strategies); j++ {\n\t\t\tfor k := 0; k < gamesPerSeries; k++ {\n\t\t\t\twinner := play(strategies[i], strategies[j])\n\t\t\t\tif winner == 0 {\n\t\t\t\t\twins[i]++\n\t\t\t\t} else {\n\t\t\t\t\twins[j]++\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tgamesPerStrategy := gamesPerSeries * (len(strategies) - 1) // no self play\n\treturn wins, gamesPerStrategy\n}\n\n// ratioString takes a list of integer values and returns a string that lists\n// each value and its percentage of the sum of all values.\n// e.g., ratios(1, 2, 3) = \"1/6 (16.7%), 2/6 (33.3%), 3/6 (50.0%)\"\nfunc ratioString(vals ...int) string {\n\ttotal := 0\n\tfor _, val := range vals {\n\t\ttotal += val\n\t}\n\ts := \"\"\n\tfor _, val := range vals {\n\t\tif s != \"\" {\n\t\t\ts += \", \"\n\t\t}\n\t\tpct := 100 * float64(val) / float64(total)\n\t\ts += fmt.Sprintf(\"%d/%d (%0.1f%%)\", val, total, pct)\n\t}\n\treturn s\n}\n\nfunc main() {\n\tstrategies := make([]strategy, win)\n\tfor k := range strategies {\n\t\tstrategies[k] = stayAtK(k + 1)\n\t}\n\twins, games := roundRobin(strategies)\n\n\tfor k := range strategies {\n\t\tfmt.Printf(\"Wins, losses staying at k =% 4d: %s\\n\",\n\t\t\tk+1, ratioString(wins[k], games-wins[k]))\n\t}\n}\n"
  },
  {
    "path": "26_QUESTIONS-FROM-STUDENTS/01-package-scope/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(x)\n}\n"
  },
  {
    "path": "26_QUESTIONS-FROM-STUDENTS/01-package-scope/variables.go",
    "content": "package main\n\nvar x = 7\n"
  },
  {
    "path": "26_QUESTIONS-FROM-STUDENTS/02-goroutines-printing/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tc := make(chan int)\n\n\tgo func() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tfmt.Println(\"In goroutine:\", i)\n\t\t\tc <- i\n\t\t}\n\t\tclose(c)\n\t}()\n\n\tfor n := range c {\n\t\tfmt.Println(\"In main: \", n)\n\t}\n}\n"
  },
  {
    "path": "26_QUESTIONS-FROM-STUDENTS/03-range-chan/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\nfunc main() {\n\n\tin := gen()\n\n\t// FAN OUT\n\t// Multiple functions reading from the same channel until that channel is closed\n\t// Distribute work across multiple functions (ten goroutines) that all read from in.\n\tc0 := factorial(in)\n\tc1 := factorial(in)\n\tc2 := factorial(in)\n\tc3 := factorial(in)\n\tc4 := factorial(in)\n\tc5 := factorial(in)\n\tc6 := factorial(in)\n\tc7 := factorial(in)\n\tc8 := factorial(in)\n\tc9 := factorial(in)\n\n\t// FAN IN\n\t// multiplex multiple channels onto a single channel\n\t// merge the channels from c0 through c9 onto a single channel\n\tvar y int\n\tfor n := range merge(c0, c1, c2, c3, c4, c5, c6, c7, c8, c9) {\n\t\ty++\n\t\tfmt.Println(y, \"\\t\", n)\n\t}\n\n}\n\nfunc gen() <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tfor j := 3; j < 13; j++ {\n\t\t\t\tout <- j\n\t\t\t}\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc factorial(in <-chan int) <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor n := range in {\n\t\t\tout <- fact(n)\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc fact(n int) int {\n\ttotal := 1\n\tfor i := n; i > 0; i-- {\n\t\ttotal *= i\n\t}\n\treturn total\n}\n\nfunc merge(cs ...<-chan int) <-chan int {\n\tvar wg sync.WaitGroup\n\tout := make(chan int)\n\n\toutput := func(c <-chan int) {\n\t\tfor n := range c {\n\t\t\tout <- n\n\t\t}\n\t\twg.Done()\n\t}\n\n\twg.Add(len(cs))\n\tfor _, c := range cs {\n\t\tgo output(c)\n\t}\n\n\t// Start a goroutine to close out once all the output goroutines are\n\t// done.  This must start after the wg.Add call.\n\tgo func() {\n\t\twg.Wait()\n\t\tclose(out)\n\t}()\n\treturn out\n}\n"
  },
  {
    "path": "26_QUESTIONS-FROM-STUDENTS/04_goroutines_closing-chan/01_broken-code/main.go",
    "content": "package main\n\nimport \"fmt\"\n\n// THIS CODE DOES NOT RUN\n// see next folder for fixed code with notes\n\nvar done chan bool\n\nfunc main() {\n\tdone = make(chan bool)\n\tc := fanIn(incrementor(\"1\"), incrementor(\"2\"))\n\tfor n := range c {\n\t\tfmt.Println(n)\n\t}\n}\n\nfunc incrementor(s string) <-chan string {\n\tc := make(chan string)\n\tgo func() {\n\t\tfor i := 0; i < 20; i++ {\n\t\t\tc <- fmt.Sprintf(\"Process: \"+s+\" printing:\", i)\n\t\t}\n\t\tdone <- true\n\t}()\n\treturn c\n}\n\n// FAN IN\nfunc fanIn(input1, input2 <-chan string) <-chan string {\n\tc := make(chan string)\n\tgo func() {\n\t\tfor {\n\t\t\tc <- <-input1\n\t\t}\n\t}()\n\tgo func() {\n\t\tfor {\n\t\t\tc <- <-input2\n\t\t}\n\t}()\n\tgo func() {\n\t\t<-done\n\t\t<-done\n\t\tclose(c)\n\t}()\n\treturn c\n}\n"
  },
  {
    "path": "26_QUESTIONS-FROM-STUDENTS/04_goroutines_closing-chan/02_fixed-code/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\t// read NOTE ONE below\n\tc1 := incrementor(\"1\")\n\tc2 := incrementor(\"2\")\n\t// NOTE TWO\n\t// the flow of code continues here in main\n\t// incrementor is called\n\t// launches goroutines\n\t// returns channels which will eventually be closed\n\t// by the code that is running in the goroutines\n\t// launched by incrementor\n\t// program flow in main continues on down vertically here\n\n\t// NOTE THREE\n\t// you're passing into \"fanIn\" two channels\n\t// fanIn HAS TO pull values off of those channels\n\t// otherwise: DEADLOCK\n\t// fanIn will need to launch goroutines to pull those values\n\tc := fanIn(c1, c2)\n\n\t// NOTE SEVEN\n\t// we are held up here\n\t// pulling values off of c\n\t// until c is closed\n\t// and all values have been pulled from c\n\t// at which point ...\n\tfor n := range c {\n\t\tfmt.Println(n)\n\t}\n\n\t// NOTE EIGHT\n\t// our program is done\n\t// flow of code exits out of main\n\t// program ends\n}\n\nfunc incrementor(s string) <-chan string {\n\tc := make(chan string)\n\tgo func() {\n\t\tfor i := 0; i < 20; i++ {\n\t\t\t// NOTE NINE\n\t\t\t// use Sprint here, or Sprintln, not Sprintf\n\t\t\t// this code is formatted for Sprintln\n\t\t\t// Sprintf would need this\n\t\t\t// c <- fmt.Sprintf(\"Process: %v, printing %v\", s, i)\n\t\t\tc <- fmt.Sprint(\"Process: \"+s+\" printing:\", i)\n\t\t}\n\t\t// NOTE ONE\n\t\t// incrementor\n\t\t// every time it's called\n\t\t// create a channel, put values on the channel\n\t\t// ******** important ********\n\t\t// have some other goroutine somewhere\n\t\t// pulling values off the channel\n\t\t// ***************************\n\t\t// close the channel\n\t\t// return that closed channel\n\t\t// these \"incrementor\" goroutines are off and running\n\t\tclose(c)\n\t}()\n\treturn c\n}\n\n// FAN IN\nfunc fanIn(input1, input2 <-chan string) <-chan string {\n\tc := make(chan string)\n\tdone := make(chan bool)\n\n\t// NOTE FOUR\n\t// these goroutines will pull values off the \"incrementor\" channels\n\t// I'm defining the func to have a channel as a parameter and\n\t// I'm passing the channels in as an argument\n\t// as this is good practice to avoid different channels\n\t// accessing the same data and creating a race condition\n\t// not needed here, but good practice\n\t// and good to know about\n\n\tgo func(x <-chan string) {\n\t\tfor n := range x {\n\t\t\tc <- n\n\t\t}\n\t\tdone <- true\n\t}(input1)\n\n\tgo func(x <-chan string) {\n\t\tfor n := range x {\n\t\t\tc <- n\n\t\t}\n\t\tdone <- true\n\t}(input2)\n\n\t// NOTE FIVE\n\t// this will signal when we're done writing values to c\n\tgo func() {\n\t\t<-done\n\t\t<-done\n\t\tclose(c)\n\t}()\n\n\t// NOTE SIX\n\t// all of the above code\n\t// just flows straight through\n\t// goroutines are launched\n\t// and even though they're not done processing\n\t// program flow comes to here and this func returns\n\t// the channel c\n\treturn c\n}\n"
  },
  {
    "path": "26_QUESTIONS-FROM-STUDENTS/05_concurrency-channels/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tn := 10\n\tc := make(chan int)\n\tdone := make(chan bool)\n\n\tgo func() {\n\t\tfor i := 0; i < 1000; i++ {\n\t\t\tc <- i\n\t\t}\n\t\tclose(c)\n\t}()\n\n\tfor i := 0; i < n; i++ {\n\t\tgo func(x int) {\n\t\t\tfor q := range c {\n\t\t\t\tfmt.Println(\"i\", x, \"q\", q)\n\t\t\t}\n\t\t\tdone <- true\n\t\t}(i)\n\t}\n\n\tfor i := 0; i < n; i++ {\n\t\t<-done\n\t}\n}\n"
  },
  {
    "path": "26_QUESTIONS-FROM-STUDENTS/06_performance-ramifications/01_called/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\nfunc main() {\n\tstart := time.Now()\n\tin := gen()\n\n\tf := factorial(in)\n\n\tfor n := range f {\n\t\tfmt.Println(n)\n\t}\n\n\tfmt.Println(time.Since(start))\n}\n\nfunc gen() <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tfor j := 3; j < 13; j++ {\n\t\t\t\tout <- j\n\t\t\t}\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc factorial(in <-chan int) <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor n := range in {\n\t\t\tout <- fact(n)\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc fact(n int) int {\n\ttotal := 1\n\tfor i := n; i > 0; i-- {\n\t\ttotal *= i\n\t}\n\treturn total\n}\n"
  },
  {
    "path": "26_QUESTIONS-FROM-STUDENTS/06_performance-ramifications/02_not-called/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\nfunc main() {\n\tstart := time.Now()\n\tin := gen()\n\n\tf := factorial(in)\n\n\tfor n := range f {\n\t\tfmt.Println(n)\n\t}\n\n\tfmt.Println(time.Since(start))\n}\n\nfunc gen() <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tfor j := 3; j < 13; j++ {\n\t\t\t\tout <- j\n\t\t\t}\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n\nfunc factorial(in <-chan int) <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tfor n := range in {\n\t\t\ttotal := 1\n\t\t\tfor i := n; i > 0; i-- {\n\t\t\t\ttotal *= i\n\t\t\t}\n\t\t\tout <- total\n\t\t}\n\t\tclose(out)\n\t}()\n\treturn out\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/00_types/01_division/01_int-int/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(32 / 16)\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/00_types/01_division/02_int-float/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(32 / 3.74)\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/00_types/01_division/03_var_int-float/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tanswer := 32 / 3.74\n\tfmt.Println(answer)\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/00_types/01_division/04_var_int-float_invalid-code/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar answer int\n\tanswer = 32 / 3.74\n\tfmt.Println(answer)\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/00_types/02_strings/01_escape-sequences/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(\"Hello\\tWorld\\nHow are you?\")\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/00_types/02_strings/02_sequence-of-bytes/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tintro := \"Four score and seven years ago....\"\n\tfmt.Println(intro)\n\tfmt.Println([]byte(intro)) // sequence of bytes\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/00_types/02_strings/03_immutable/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tintro := \"Four score and seven years ago....\"\n\tfmt.Println(intro)\n\tfmt.Println(&intro)\n\tintro = \"Hahahaha!\"\n\tfmt.Println(intro)\n\tfmt.Println(&intro)\n\t//  the below is invalid\n\t//\tintro[0] = 70\n\t//\tfmt.Println(intro)\n\t//\tfmt.Println(&intro)\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/00_types/02_strings/04_len/01_len-english/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(len(\"hello\"))\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/00_types/02_strings/04_len/02_len-chinese/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(len(\"世界\"))\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/00_types/02_strings/04_len/03_binary/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tintro := \"Four 世\"\n\tfmt.Printf(\"%T\\n\", intro)\n\tfmt.Println(intro)\n\tbs := []byte(intro)\n\tfmt.Println(bs)\n\tfmt.Printf(\"%T\\n\", bs)\n\tfmt.Println(\"*********\")\n\tfmt.Printf(\"%d\\n\", bs)\n\n\tfor _, v := range bs {\n\t\tfmt.Printf(\"%d\\t\\t %#x\\t %b\\n\", v, v, v)\n\t}\n\tfmt.Println(\"*********\")\n\ty := 9999999999999999\n\n\tfmt.Printf(\"%d\\t\\t %#x\\t %b\\n\", y, y, y)\n\tfmt.Println(&y)\n\tfmt.Sprint(y)\n\tfmt.Println(\"*********\")\n\n\tz := 'h'\n\tfmt.Printf(\"%T\\n\", z)\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/00_types/02_strings/05_index-access/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tgreeting := \"Hello\"\n\tfmt.Println(greeting)\n\tfmt.Println(greeting[0])\n\tfmt.Println(greeting[4])\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/00_types/02_strings/06_slicing/01/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tgreeting := \"Hello\"\n\tfmt.Println(greeting)\n\tfmt.Println(greeting[0])\n\tfmt.Println(greeting[4])\n\tfmt.Println(\"-------------\")\n\tfmt.Println(\"What the ... \")\n\tfmt.Println(greeting[:4])\n\tfmt.Println(\"... did that just do?\")\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/00_types/02_strings/06_slicing/02/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tgreeting := \"Hello\"\n\tfmt.Println(greeting)\n\tfmt.Println(greeting[:4])\n\tfmt.Println(greeting[0:4])\n\tfmt.Println(greeting[1:4])\n\tfmt.Println(greeting[1:])\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/00_types/02_strings/06_slicing/03_invalid_negative-index/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tgreeting := \"Hello\"\n\tfmt.Println(greeting)\n\tfmt.Println(greeting[:4])\n\tfmt.Println(greeting[0:4])\n\tfmt.Println(greeting[1:4])\n\tfmt.Println(greeting[1:])\n\tfmt.Println(greeting[:-2]) // invalid\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/00_types/02_strings/07_concatenation/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfname := \"James\"\n\tlname := \"Bond\"\n\tfmt.Println(fname + \" \" + lname)\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/00_types/03_strconv/01_itoa/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n)\n\nfunc main() {\n\tvar x int = 5\n\tstr := \"Hello world \" + strconv.Itoa(x) // int to ascii\n\tfmt.Println(str)\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/00_types/03_strconv/02_fmt-sprint/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar x int = 5\n\tstr := \"Hello world \" + fmt.Sprint(x)\n\tfmt.Println(str)\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/00_types/03_strconv/03_atoi/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n)\n\nfunc main() {\n\ti, _ := strconv.Atoi(\"32\")\n\tfmt.Println(i + 10)\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/00_types/06_math-pkg/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"math\"\n)\n\nfunc main() {\n\tup := 34.705945\n\tdown := 34.405945\n\tfmt.Println(math.Floor(up + 0.5))\n\tfmt.Println(math.Floor(down + 0.5))\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/00_types/07_typeOf/01_better-code/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n)\n\nfunc main() {\n\ta := \"this is stored in the variable a\"\n\tb := 42\n\tc, d, e, f := 44.7, true, false, 'm' // single quotes\n\tg := \"g\"                             // double quotes\n\th := `h`                             // back ticks\n\n\tfmt.Println(\"a - \", reflect.TypeOf(a), \" - \", a)\n\tfmt.Println(\"b - \", reflect.TypeOf(b), \" - \", b)\n\tfmt.Println(\"c - \", reflect.TypeOf(c), \" - \", c)\n\tfmt.Println(\"d - \", reflect.TypeOf(d), \" - \", d)\n\tfmt.Println(\"e - \", reflect.TypeOf(e), \" - \", e)\n\tfmt.Println(\"f - \", reflect.TypeOf(f), \" - \", f)\n\tfmt.Println(\"g - \", reflect.TypeOf(g), \" - \", g)\n\tfmt.Println(\"h - \", reflect.TypeOf(h), \" - \", h)\n\tfmt.Printf(\"h -  %T\\n\", h)\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/00_types/07_typeOf/02_worse-code/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n)\n\nvar a string = \"this is stored in the variable a\" // package scope\nvar b, c string = \"stored in b\", \"stored in c\"    // package scope\nvar d string                                      // package scope\n\nfunc main() {\n\n\td = \"stored in d\" // declaration above; assignment here; package scope\n\tvar e int = 42    // function scope - subsequent variables have same package scope:\n\tf := 43\n\tg := \"stored in g\"\n\th, i := \"stored in h\", \"stored in i\"\n\tj, k, l, m := 44.7, true, false, 'm' // single quotes\n\tn := \"n\"                             // double quotes\n\to := `o`                             // back ticks\n\n\tfmt.Println(\"a - \", reflect.TypeOf(a), \" - \", a)\n\tfmt.Println(\"b - \", reflect.TypeOf(b), \" - \", b)\n\tfmt.Println(\"c - \", reflect.TypeOf(c), \" - \", c)\n\tfmt.Println(\"d - \", reflect.TypeOf(d), \" - \", d)\n\tfmt.Println(\"e - \", reflect.TypeOf(e), \" - \", e)\n\tfmt.Println(\"f - \", reflect.TypeOf(f), \" - \", f)\n\tfmt.Println(\"g - \", reflect.TypeOf(g), \" - \", g)\n\tfmt.Println(\"h - \", reflect.TypeOf(h), \" - \", h)\n\tfmt.Println(\"i - \", reflect.TypeOf(i), \" - \", i)\n\tfmt.Println(\"j - \", reflect.TypeOf(j), \" - \", j)\n\tfmt.Println(\"k - \", reflect.TypeOf(k), \" - \", k)\n\tfmt.Println(\"l - \", reflect.TypeOf(l), \" - \", l)\n\tfmt.Println(\"m - \", reflect.TypeOf(m), \" - \", m)\n\tfmt.Println(\"n - \", reflect.TypeOf(n), \" - \", n)\n\tfmt.Println(\"o - \", reflect.TypeOf(o), \" - \", o)\n\tfmt.Printf(\"o -  %T\\n\", o)\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/01_struct/main.go",
    "content": "package main\n\nimport \"fmt\"\n\ntype person struct {\n\tname string\n\tage  int\n}\n\nfunc main() {\n\tp1 := person{\"James\", 20}\n\tfmt.Println(p1)\n\tfmt.Println(p1.name)\n\tfmt.Println(p1.age)\n\tfmt.Printf(\"%T\\n\", p1)\n}\n\n// we've already seen the above code\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/02_string/main.go",
    "content": "package main\n\nimport \"fmt\"\n\ntype mySentence string\n\nfunc main() {\n\tvar message mySentence = \"Hello World!\"\n\tfmt.Println(message)\n\tfmt.Printf(\"%T\\n\", message)\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/03_string-conversion/main.go",
    "content": "package main\n\nimport \"fmt\"\n\ntype mySentence string\n\nfunc main() {\n\tvar message mySentence = \"Hello World!\"\n\tfmt.Println(message)\n\tfmt.Printf(\"%T\\n\", message)\n\tfmt.Printf(\"%T\\n\", string(message))\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/04_string_assertion_invalid-code/main.go",
    "content": "package main\n\nimport \"fmt\"\n\ntype mySentence string\n\nfunc main() {\n\tvar message mySentence = \"Hello World!\"\n\tfmt.Println(message)\n\tfmt.Printf(\"%T\\n\", message)\n\tfmt.Printf(\"%T\\n\", message.(string))\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/05_var-for-zero-val-initalization/main.go",
    "content": "package main\n\nimport \"fmt\"\n\ntype person struct {\n\tname string\n\tage  int\n}\n\nfunc main() {\n\tvar p1 person\n\tfmt.Println(p1)\n\tfmt.Println(p1.name)\n\tfmt.Println(p1.age)\n\tfmt.Printf(\"%T\\n\", p1)\n}\n\n// always use var to create and\n// initialize a variable to its zero value\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/06_shorthand-notation_nonzero-initalization/main.go",
    "content": "package main\n\nimport \"fmt\"\n\ntype person struct {\n\tname string\n\tage  int\n}\n\nfunc main() {\n\tp1 := person{\n\t\tname: \"James\",\n\t\tage:  20,\n\t}\n\tfmt.Println(p1)\n\tfmt.Println(p1.name)\n\tfmt.Println(p1.age)\n\tfmt.Printf(\"%T\\n\", p1)\n}\n\n// always use shorthand notation to\n// create and initialize a variable to values\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/xx05_slice-strings/main.go",
    "content": "package main\n\nimport \"fmt\"\n\ntype mySentences []string\n\nfunc main() {\n\tvar messages mySentences = []string{\"Hello World!\", \"More coffee\"}\n\tfmt.Println(messages)\n\tfmt.Printf(\"%T\\n\", messages)\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/xx06_slice-strings_conversion/main.go",
    "content": "package main\n\nimport \"fmt\"\n\ntype mySentences []string\n\nfunc main() {\n\tvar messages mySentences = []string{\"Hello World!\", \"More coffee\"}\n\tfmt.Println(messages)\n\tfmt.Printf(\"%T\\n\", messages)\n\tfmt.Printf(\"%T\\n\", []string(messages))\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/xx07_int/main.go",
    "content": "package main\n\nimport \"fmt\"\n\ntype myType int\n\nfunc main() {\n\tvar x myType = 32\n\tfmt.Println(x)\n\tfmt.Printf(\"%T\\n\", x)\n\tfmt.Printf(\"%T\\n\", int(x))\n}\n"
  },
  {
    "path": "27_code-in-process/26_playing-with-type/xx08_slice-ints/main.go",
    "content": "package main\n\nimport \"fmt\"\n\ntype myType []int\n\nfunc main() {\n\tvar x myType = []int{32, 44, 57}\n\tfmt.Println(x)\n\tfmt.Printf(\"%T\\n\", x)\n\tfmt.Printf(\"%T\\n\", []int(x))\n}\n"
  },
  {
    "path": "27_code-in-process/27_package-os/00_args/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n)\n\nfunc main() {\n\tentry := os.Args[1]\n\tfmt.Println(entry)\n}\n\n/*\nstep 1:\ngo install\n\nstep 2 - from terminal:\nprogramName arguments\n\n*/\n"
  },
  {
    "path": "27_code-in-process/27_package-os/01_Read/01/dst.txt",
    "content": "ABCDE"
  },
  {
    "path": "27_code-in-process/27_package-os/01_Read/01/main.go",
    "content": "package main\n\nimport (\n\t\"os\"\n)\n\nfunc main() {\n\tsrc, err := os.Open(\"src.txt\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer src.Close()\n\n\tdst, err := os.Create(\"dst.txt\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer dst.Close()\n\n\tbs := make([]byte, 5)\n\tsrc.Read(bs)\n\tdst.Write(bs)\n}\n\n// this is a limit reader\n// we limit what is read\n// see io.ReadFull for func similiar to (*File)Read\n"
  },
  {
    "path": "27_code-in-process/27_package-os/01_Read/01/src.txt",
    "content": "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  },
  {
    "path": "27_code-in-process/27_package-os/02_Write/01/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\n\tdst, err := os.Create(os.Args[1])\n\tif err != nil {\n\t\tlog.Fatalf(\"error creating destination file:%v \", err)\n\t}\n\tdefer dst.Close()\n\n\tdst.Write([]byte(\"Hello World\"))\n}\n\n/*\n\nos.Create\nfunc Create(name string) (*File, error)\n\nos\nfunc (f *File) Write(b []byte) (n int, err error)\n\nos\nfunc (f *File) Read(b []byte) (n int, err error)\n\n*/\n\n/*\n\nstep 1 - at command line enter:\ngo install\n\nstep 2 - at command line enter:\nprogramName initial.txt second.txt\n\n*/\n"
  },
  {
    "path": "27_code-in-process/27_package-os/02_Write/02/hello.txt",
    "content": "Put some phrase here."
  },
  {
    "path": "27_code-in-process/27_package-os/02_Write/02/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\n\tdst, err := os.Create(\"hello.txt\")\n\tif err != nil {\n\t\tlog.Fatalln(\"error creating destination file: \", err.Error())\n\t}\n\tdefer dst.Close()\n\n\tbs := []byte(\"Put some phrase here.\")\n\n\t_, err = dst.Write(bs)\n\tif err != nil {\n\t\tlog.Fatalln(\"error writing to file: \", err.Error())\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/27_package-os/02_Write/03_absolute-path/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\n\tdst, err := os.Create(\"/tmp/hello.txt\")\n\tif err != nil {\n\t\tlog.Fatalln(\"error creating destination file: \", err.Error())\n\t}\n\tdefer dst.Close()\n\n\tbs := []byte(\"Put some phrase here.\")\n\n\t_, err = dst.Write(bs)\n\tif err != nil {\n\t\tlog.Fatalln(\"error writing to file: \", err.Error())\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/27_package-os/03_mkdir/01/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\n\terr := os.Mkdir(\"/somefolderthatdoesntexist\", 0x777)\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke on mkdir: \", err.Error())\n\t}\n\n\tf, err := os.Create(\"/somefolderthatdoesntexist/hello.txt\")\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke\", err.Error())\n\t}\n\tdefer f.Close()\n\n\tstr := \"Put some phrase here.\"\n\tbs := []byte(str)\n\n\t_, err = f.Write(bs)\n\tif err != nil {\n\t\tlog.Fatalln(\"error writing to file: \", err.Error())\n\t}\n}\n\n/*\n\nstep 1 - at command line enter:\ngo install\n\nstep 2 - at command line enter:\nsudo 05_mkdir_write-file_absolute-path\n\n--- or ---\n\nstep 1 - at command line enter:\nsudo go run main.go\n\n---------\n\nuse at command line to see folder:\nls /somefolderthatdoesntexist\n\nuse at command line to remove folder:\nrm -rf /somefolderthatdoesntexist\n\n*/\n"
  },
  {
    "path": "27_code-in-process/27_package-os/03_mkdir/02/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\n\t// using os.ModePerm instead of 0x777\n\terr := os.Mkdir(\"/somefolderthatdoesntexist\", os.ModePerm)\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke on mkdir: \", err.Error())\n\t}\n\n\tf, err := os.Create(\"/somefolderthatdoesntexist/hello.txt\")\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke\", err.Error())\n\t}\n\tdefer f.Close()\n\n\tstr := \"Put some phrase here.\"\n\tbs := []byte(str)\n\n\t_, err = f.Write(bs)\n\tif err != nil {\n\t\tlog.Fatalln(\"error writing to file: \", err.Error())\n\t}\n}\n\n/*\n\nstep 1 - at command line enter:\ngo install\n\nstep 2 - at command line enter:\nsudo 05_mkdir_write-file_absolute-path\n\n--- or ---\n\nstep 1 - at command line enter:\nsudo go run main.go\n\n---------\n\nuse at command line to see folder:\nls /somefolderthatdoesntexist\n\nuse at command line to remove folder:\nrm -rf /somefolderthatdoesntexist\n\n*/\n"
  },
  {
    "path": "27_code-in-process/27_package-os/04_FileMode/01/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n)\n\nfunc main() {\n\tfmt.Println(os.ModeDir)\n\tfmt.Printf(\"%p\\n\", os.ModeDir)\n\tfmt.Printf(\"%d\\n\", os.ModeDir)\n\tfmt.Println(os.ModeAppend)\n\tfmt.Println(os.ModeExclusive)\n\tfmt.Println(os.ModeTemporary)\n\tfmt.Println(os.ModeSymlink)\n\tfmt.Println(os.ModeDevice)\n\tfmt.Println(os.ModeNamedPipe)\n\tfmt.Println(os.ModeSocket)\n\tfmt.Println(os.ModeSetuid)\n\tfmt.Println(os.ModeSetgid)\n\tfmt.Println(os.ModeCharDevice)\n\tfmt.Println(os.ModeSticky)\n\tfmt.Println(os.ModeType)\n\tfmt.Println(os.ModePerm)\n}\n"
  },
  {
    "path": "27_code-in-process/27_package-os/04_FileMode/02/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nconst (\n\tModeDir = 1 << (32 - 1 - iota)\n\tModeAppend\n\tModeExclusive\n\tModeTemporary\n\tModeSymlink\n\tModeDevice\n\tModeNamedPipe\n\tModeSocket\n\tModeSetuid\n\tModeSetgid\n\tModeCharDevice\n\tModeSticky\n)\n\nfunc main() {\n\tfmt.Println(\"ModeDir         - \", ModeDir)\n\tfmt.Println(\"ModeAppend      - \", ModeAppend)\n\tfmt.Println(\"ModeExclusive   - \", ModeExclusive)\n\tfmt.Println(\"ModeTemporary   - \", ModeTemporary)\n\tfmt.Println(\"ModeSymlink     - \", ModeSymlink)\n\tfmt.Println(\"ModeDevice      - \", ModeDevice)\n\tfmt.Println(\"ModeNamedPipe   - \", ModeNamedPipe)\n\tfmt.Println(\"ModeSocket      - \", ModeSocket)\n\tfmt.Println(\"ModeSetuid      - \", ModeSetuid)\n\tfmt.Println(\"ModeSetgid      - \", ModeSetgid)\n\tfmt.Println(\"ModeCharDevice  - \", ModeCharDevice)\n\tfmt.Println(\"ModeSticky      - \", ModeSticky)\n\n\t//decimal (base 10)\n\tfmt.Printf(\"ModeDir         - %d\\n\", ModeDir)\n\tfmt.Printf(\"ModeAppend      - %d\\n\", ModeAppend)\n\tfmt.Printf(\"ModeExclusive   - %d\\n\", ModeExclusive)\n\tfmt.Printf(\"ModeTemporary   - %d\\n\", ModeTemporary)\n\tfmt.Printf(\"ModeSymlink     - %d\\n\", ModeSymlink)\n\tfmt.Printf(\"ModeDevice      - %d\\n\", ModeDevice)\n\tfmt.Printf(\"ModeNamedPipe   - %d\\n\", ModeNamedPipe)\n\tfmt.Printf(\"ModeSocket      - %d\\n\", ModeSocket)\n\tfmt.Printf(\"ModeSetuid      - %d\\n\", ModeSetuid)\n\tfmt.Printf(\"ModeSetgid      - %d\\n\", ModeSetgid)\n\tfmt.Printf(\"ModeCharDevice  - %d\\n\", ModeCharDevice)\n\tfmt.Printf(\"ModeSticky      - %d\\n\", ModeSticky)\n\n\t//binary (base 2)\n\tfmt.Printf(\"ModeDir         - %b\\n\", ModeDir)\n\tfmt.Printf(\"ModeAppend      - %b\\n\", ModeAppend)\n\tfmt.Printf(\"ModeExclusive   - %b\\n\", ModeExclusive)\n\tfmt.Printf(\"ModeTemporary   - %b\\n\", ModeTemporary)\n\tfmt.Printf(\"ModeSymlink     - %b\\n\", ModeSymlink)\n\tfmt.Printf(\"ModeDevice      - %b\\n\", ModeDevice)\n\tfmt.Printf(\"ModeNamedPipe   - %b\\n\", ModeNamedPipe)\n\tfmt.Printf(\"ModeSocket      - %b\\n\", ModeSocket)\n\tfmt.Printf(\"ModeSetuid      - %b\\n\", ModeSetuid)\n\tfmt.Printf(\"ModeSetgid      - %b\\n\", ModeSetgid)\n\tfmt.Printf(\"ModeCharDevice  - %b\\n\", ModeCharDevice)\n\tfmt.Printf(\"ModeSticky      - %b\\n\", ModeSticky)\n\n\t//hexadecimal (base 16)\n\tfmt.Printf(\"ModeDir         - %x\\n\", ModeDir)\n\tfmt.Printf(\"ModeAppend      - %x\\n\", ModeAppend)\n\tfmt.Printf(\"ModeExclusive   - %x\\n\", ModeExclusive)\n\tfmt.Printf(\"ModeTemporary   - %x\\n\", ModeTemporary)\n\tfmt.Printf(\"ModeSymlink     - %x\\n\", ModeSymlink)\n\tfmt.Printf(\"ModeDevice      - %x\\n\", ModeDevice)\n\tfmt.Printf(\"ModeNamedPipe   - %x\\n\", ModeNamedPipe)\n\tfmt.Printf(\"ModeSocket      - %x\\n\", ModeSocket)\n\tfmt.Printf(\"ModeSetuid      - %x\\n\", ModeSetuid)\n\tfmt.Printf(\"ModeSetgid      - %x\\n\", ModeSetgid)\n\tfmt.Printf(\"ModeCharDevice  - %x\\n\", ModeCharDevice)\n\tfmt.Printf(\"ModeSticky      - %x\\n\", ModeSticky)\n}\n"
  },
  {
    "path": "27_code-in-process/27_package-os/05_file-open/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\tf, err := os.Open(os.Args[1])\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke\", err.Error())\n\t}\n\tdefer f.Close()\n\n\tbs, err := ioutil.ReadAll(f)\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke again\")\n\t}\n\n\tstr := string(bs)\n\tfmt.Println(str)\n}\n\n/*\n\nstep 1 - at command line enter:\ngo install\n\nstep 2 - at command line enter:\n06_cat main.go\n\n*/\n"
  },
  {
    "path": "27_code-in-process/27_package-os/06_file-create/main.go",
    "content": "package main\n\nimport (\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\tf, err := os.Open(os.Args[1])\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke opening: \", err.Error())\n\t}\n\tdefer f.Close()\n\n\tnf, err := os.Create(\"newFile.txt\")\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke creating: \", err.Error())\n\t}\n\n\tbs, err := ioutil.ReadAll(f)\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke reading: \", err.Error())\n\t}\n\n\t_, err = nf.Write(bs)\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke writing: \", err.Error())\n\t}\n}\n\n/*\n\nstep 1 - at command line enter:\ngo install\n\nstep 2 - at command line enter:\n07_copy main.go\n\n*/\n"
  },
  {
    "path": "27_code-in-process/27_package-os/07_Stdout_Stdin/01/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\n\tf, err := os.Open(os.Args[1:])\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke: \", err.Error())\n\t}\n\tdefer f.Close()\n\n\tio.Copy(os.Stdout, f)\n}\n"
  },
  {
    "path": "27_code-in-process/27_package-os/07_Stdout_Stdin/02/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\trdr := strings.NewReader(\"test\")\n\tio.Copy(os.Stdout, rdr)\n}\n"
  },
  {
    "path": "27_code-in-process/28_package-strings/01_strings/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nfunc main() {\n\tfmt.Println(\n\t\t// true\n\t\tstrings.Contains(\"test\", \"es\"),\n\n\t\t// 2\n\t\tstrings.Count(\"test\", \"t\"),\n\n\t\t// true\n\t\tstrings.HasPrefix(\"test\", \"te\"),\n\n\t\t// true\n\t\tstrings.HasSuffix(\"test\", \"st\"),\n\n\t\t// 1\n\t\tstrings.Index(\"test\", \"e\"),\n\n\t\t// \"a-b\"\n\t\tstrings.Join([]string{\"a\", \"b\"}, \"-\"),\n\n\t\t// == \"aaaaa\"\n\t\tstrings.Repeat(\"a\", 5),\n\n\t\t// \"bbaa\"\n\t\tstrings.Replace(\"aaaa\", \"a\", \"b\", 2),\n\n\t\t// []string{\"a\",\"b\",\"c\",\"d\",\"e\"}\n\t\tstrings.Split(\"a-b-c-d-e\", \"-\"),\n\n\t\t// \"test\"\n\t\tstrings.ToLower(\"TEST\"),\n\n\t\t// \"TEST\"\n\t\tstrings.ToUpper(\"test\"),\n\n\t\t// \"test\"\n\t\tstrings.TrimSpace(\"  test      \"),\n\t)\n\n\tarr := []byte(\"test\")\n\tfmt.Println(arr)\n\n\tstr := string([]byte{'t', 'e', 's', 't'})\n\tfmt.Println(str)\n}\n"
  },
  {
    "path": "27_code-in-process/28_package-strings/02_NewReader/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\n\tdst, err := os.Create(os.Args[1])\n\tif err != nil {\n\t\tlog.Fatalf(\"error creating destination file:%v \", err)\n\t}\n\tdefer dst.Close()\n\n\trdr := strings.NewReader(\"hello world\")\n\n\tio.Copy(dst, rdr)\n}\n\n/*\n\nio.Copy\nfunc Copy(dst Writer, src Reader) (written int64, err error)\n\nstrings.NewReader\nfunc NewReader(s string) *Reader\n\nstrings\nfunc (r *Reader) Read(b []byte) (n int, err error)\n\n*/\n\n/*\n\nstep 1 - at command line enter:\ngo install\n\nstep 2 - at command line enter:\nprogramName initial.txt second.txt\n\n*/\n"
  },
  {
    "path": "27_code-in-process/29_package-bufio/01_NewReader/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc cp(srcName, dstName string) error {\n\n\tsrc, err := os.Open(srcName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error opening source file: %v\", err)\n\t}\n\tdefer src.Close()\n\n\tdst, err := os.Create(dstName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating destination file:%v \", err)\n\t}\n\tdefer dst.Close()\n\n\tbr := bufio.NewReader(src)\n\n\t_, err = io.Copy(dst, br)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error writing to destination file: %v \", err)\n\t}\n\n\treturn nil\n}\n\nfunc main() {\n\n\tif len(os.Args) < 3 {\n\t\tlog.Fatalln(\"Usage: 07_bufio_io-copy <SRC> <DST>\")\n\t}\n\n\tsrcName := os.Args[1]\n\tdstName := os.Args[2]\n\n\terr := cp(srcName, dstName)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n}\n\n/*\n\nstep 1 - at command line enter:\ngo install\n\nstep 2 - at command line enter:\nprogramName initial.txt second.txt\n\n*/\n"
  },
  {
    "path": "27_code-in-process/29_package-bufio/02_NewScanner/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\tsrc, err := os.Open(\"initial.txt\")\n\tif err != nil {\n\t\tlog.Printf(\"error opening source file: %v\", err)\n\t}\n\tdefer src.Close()\n\n\tscanner := bufio.NewScanner(src)\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\t\tfmt.Println(\">>>\", line)\n\t}\n}\n\n/*\nscanners allow us to interact with files line-by-line\n*/\n"
  },
  {
    "path": "27_code-in-process/29_package-bufio/03_scan-lines/01/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tsrc, err := os.Open(\"initial.txt\")\n\tif err != nil {\n\t\tlog.Printf(\"error opening source file: %v\", err)\n\t}\n\tdefer src.Close()\n\n\tscanner := bufio.NewScanner(src)\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\t\tif len(line) > 0 {\n\t\t\tfmt.Println(\">>>\", strings.ToUpper(line[0:1])+line[1:], \"\\n\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/29_package-bufio/03_scan-lines/02/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"os\"\n)\n\nfunc main() {\n\tscanner := bufio.NewScanner(os.Stdin)\n\tfor scanner.Scan() {\n\t\tfmt.Println(scanner.Text()) // Println will add back the final '\\n'\n\t}\n\tif err := scanner.Err(); err != nil {\n\t\tfmt.Fprintln(os.Stderr, \"reading standard input:\", err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/29_package-bufio/04_scan-words/01/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tsrc, err := os.Open(\"initial.txt\")\n\tif err != nil {\n\t\tlog.Printf(\"error opening source file: %v\", err)\n\t}\n\tdefer src.Close()\n\n\tscanner := bufio.NewScanner(src)\n\tscanner.Split(bufio.ScanWords)\n\tfor scanner.Scan() {\n\t\tword := scanner.Text()\n\t\tif len(word) > 0 {\n\t\t\tfmt.Print(strings.ToUpper(word[0:1])+word[1:], \" \")\n\t\t}\n\t}\n\tfmt.Println()\n}\n"
  },
  {
    "path": "27_code-in-process/29_package-bufio/04_scan-words/02/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\t// An artificial input source.\n\tconst input = \"Now is the winter of our discontent,\\nMade glorious summer by this sun of York.\\n\"\n\tscanner := bufio.NewScanner(strings.NewReader(input))\n\t// Set the split function for the scanning operation.\n\tscanner.Split(bufio.ScanWords)\n\t// Count the words.\n\tcount := 0\n\tfor scanner.Scan() {\n\t\tcount++\n\t}\n\tif err := scanner.Err(); err != nil {\n\t\tfmt.Fprintln(os.Stderr, \"reading input:\", err)\n\t}\n\tfmt.Printf(\"%d\\n\", count)\n}\n"
  },
  {
    "path": "27_code-in-process/29_package-bufio/04_scan-words/03/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\t// An artificial input source.\n\tconst input = \"Now is the winter of our discontent,\\nMade glorious summer by this sun of York.\\n\"\n\tscanner := bufio.NewScanner(strings.NewReader(input))\n\t// Set the split function for the scanning operation.\n\tscanner.Split(bufio.ScanWords)\n\t// Count the words.\n\tfor scanner.Scan() {\n\t\tfmt.Println(scanner.Text())\n\t}\n\tif err := scanner.Err(); err != nil {\n\t\tfmt.Fprintln(os.Stderr, \"reading input:\", err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/30_package-io/01_copy/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\trdr := strings.NewReader(\"test\")\n\tio.Copy(os.Stdout, rdr)\n}\n"
  },
  {
    "path": "27_code-in-process/30_package-io/02_copy/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc cp(srcName, dstName string) error {\n\n\tsrc, err := os.Open(srcName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error opening source file: %v\", err)\n\t}\n\tdefer src.Close()\n\n\tdst, err := os.Create(dstName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating destination file:%v \", err)\n\t}\n\tdefer dst.Close()\n\n\t_, err = io.Copy(dst, src)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error writing to destination file: %v \", err)\n\t}\n\n\treturn nil\n}\n\nfunc main() {\n\n\tif len(os.Args) < 3 {\n\t\tlog.Fatalln(\"Usage: 04_io-copy <SRC> <DST>\")\n\t}\n\n\tsrcName := os.Args[1]\n\tdstName := os.Args[2]\n\n\terr := cp(srcName, dstName)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n}\n\n/*\n\nstep 1 - at command line enter:\ngo install\n\nstep 2 - at command line enter:\n04_io-copy initial.txt second.txt\n\n*/\n"
  },
  {
    "path": "27_code-in-process/30_package-io/03_copy/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\n\tdst, err := os.Create(os.Args[1])\n\tif err != nil {\n\t\tlog.Fatalf(\"error creating destination file:%v \", err)\n\t}\n\tdefer dst.Close()\n\n\trdr := strings.NewReader(\"hello world\")\n\n\tio.Copy(dst, rdr)\n}\n\n/*\n\nio.Copy\nfunc Copy(dst Writer, src Reader) (written int64, err error)\n\nstrings.NewReader\nfunc NewReader(s string) *Reader\n\nstrings\nfunc (r *Reader) Read(b []byte) (n int, err error)\n\n*/\n\n/*\n\nstep 1 - at command line enter:\ngo install\n\nstep 2 - at command line enter:\nprogramName initial.txt second.txt\n\n*/\n"
  },
  {
    "path": "27_code-in-process/30_package-io/04_TeeReader/01/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"os\"\n)\n\nfunc main() {\n\tsrc, err := os.Open(\"src.txt\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer src.Close()\n\n\tdst1, err := os.Create(\"dst1.txt\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer dst1.Close()\n\n\tdst2, err := os.Create(\"dst2.txt\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer dst2.Close()\n\n\trdr := io.TeeReader(src, dst1)\n\trdr = io.TeeReader(rdr, os.Stdout)\n\n\tio.Copy(dst2, rdr)\n\n}\n\n/*\n\nfunc TeeReader(r Reader, w Writer) Reader\n\nTeeReader returns a Reader that writes to w what it reads from r. All reads from r performed through it are matched with corresponding writes to w. There is no internal buffering - the write must complete before the read completes. Any error encountered while writing is reported as a read error.\n\n\n*/\n"
  },
  {
    "path": "27_code-in-process/30_package-io/04_TeeReader/01/src.txt",
    "content": "TEST"
  },
  {
    "path": "27_code-in-process/30_package-io/04_TeeReader/02/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"os\"\n)\n\nfunc main() {\n\tsrc, err := os.Open(\"src.txt\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer src.Close()\n\n\tdst1, err := os.Create(\"dst1.txt\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer dst1.Close()\n\n\tdst2, err := os.Create(\"dst2.txt\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer dst2.Close()\n\n\tdst3, err := os.Create(\"dst3.txt\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer dst3.Close()\n\n\trdr := io.TeeReader(src, dst1)\n\trdr = io.TeeReader(rdr, os.Stdout)\n\trdr = io.TeeReader(rdr, dst2)\n\n\tio.Copy(dst3, rdr)\n\n}\n\n/*\n\nfunc TeeReader(r Reader, w Writer) Reader\n\nTeeReader returns a Reader that writes to w what it reads from r. All reads from r performed through it are matched with corresponding writes to w. There is no internal buffering - the write must complete before the read completes. Any error encountered while writing is reported as a read error.\n\n\n*/\n"
  },
  {
    "path": "27_code-in-process/30_package-io/04_TeeReader/02/src.txt",
    "content": "TEST"
  },
  {
    "path": "27_code-in-process/30_package-io/05_ReadFull/dst.txt",
    "content": "ABCDE"
  },
  {
    "path": "27_code-in-process/30_package-io/05_ReadFull/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"os\"\n)\n\nfunc main() {\n\tsrc, err := os.Open(\"src.txt\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer src.Close()\n\n\tdst, err := os.Create(\"dst.txt\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer dst.Close()\n\n\tbs := make([]byte, 5)\n\tio.ReadFull(src, bs)\n\tdst.Write(bs)\n\n}\n\n// this is a limit reader\n// we limit what is read\n// see (*File)Read (os package) for func similiar to io.ReadFull\n"
  },
  {
    "path": "27_code-in-process/30_package-io/05_ReadFull/src.txt",
    "content": "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  },
  {
    "path": "27_code-in-process/30_package-io/06_LimitReader/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"os\"\n)\n\nfunc main() {\n\tsrc, err := os.Open(\"src.txt\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer src.Close()\n\n\tdst, err := os.Create(\"dst.txt\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer dst.Close()\n\n\trdr := io.LimitReader(src, 5)\n\tio.Copy(dst, rdr)\n\n}\n"
  },
  {
    "path": "27_code-in-process/30_package-io/06_LimitReader/src.txt",
    "content": "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  },
  {
    "path": "27_code-in-process/30_package-io/07_WriteString/01_one-way/hello.txt",
    "content": "Put some phrase here."
  },
  {
    "path": "27_code-in-process/30_package-io/07_WriteString/01_one-way/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\n\tf, err := os.Create(\"hello.txt\")\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke\", err.Error())\n\t}\n\tdefer f.Close()\n\n\tstr := \"Put some phrase here.\"\n\tbs := []byte(str)\n\n\t_, err = f.Write(bs)\n\tif err != nil {\n\t\tlog.Fatalln(\"error writing to file: \", err.Error())\n\t}\n}\n\n/*\n\nfunc WriteString(w Writer, s string) (n int, err error)\n\nWriteString writes the contents of the string s to w,\nwhich accepts a slice of bytes. If w implements a WriteString method, it is invoked directly.\n\n*/\n"
  },
  {
    "path": "27_code-in-process/30_package-io/07_WriteString/02_another-way/hello.txt",
    "content": "Put some phrase here."
  },
  {
    "path": "27_code-in-process/30_package-io/07_WriteString/02_another-way/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\n\tf, err := os.Create(\"hello.txt\")\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke\", err.Error())\n\t}\n\tdefer f.Close()\n\n\tstr := \"Put some phrase here.\"\n\t//\tbs := []byte(str)\n\n\t_, err = io.WriteString(f, str)\n\t//\t_, err = f.Write(bs)\n\tif err != nil {\n\t\tlog.Fatalln(\"error writing to file: \", err.Error())\n\t}\n}\n\n/*\n\nfunc WriteString(w Writer, s string) (n int, err error)\n\nWriteString writes the contents of the string s to w,\nwhich accepts a slice of bytes. If w implements a WriteString method, it is invoked directly.\n\n*/\n"
  },
  {
    "path": "27_code-in-process/31_package-ioutil/00_ReadAll/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"strings\"\n)\n\nfunc main() {\n\tmyPhrase := \"mmm, licorice\"\n\trdr := strings.NewReader(myPhrase)\n\n\tbs, err := ioutil.ReadAll(rdr)\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke again\")\n\t}\n\n\tstr := string(bs)\n\tfmt.Println(str)\n}\n\n/*\n\nstep 1 - at command line enter:\ngo install\n\nstep 2 - at command line enter:\n06_cat main.go\n\n*/\n"
  },
  {
    "path": "27_code-in-process/31_package-ioutil/01_ReadAll/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\tf, err := os.Open(os.Args[1])\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke\", err.Error())\n\t}\n\tdefer f.Close()\n\n\tbs, err := ioutil.ReadAll(f)\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke again\")\n\t}\n\n\tstr := string(bs)\n\tfmt.Println(str)\n}\n\n/*\n\nstep 1 - at command line enter:\ngo install\n\nstep 2 - at command line enter:\n06_cat main.go\n\n*/\n"
  },
  {
    "path": "27_code-in-process/31_package-ioutil/02_WriteFile/main.go",
    "content": "package main\n\nimport (\n\t\"io/ioutil\"\n)\n\nfunc main() {\n\n\terr := ioutil.WriteFile(\"hello.txt\", []byte(\"Hello world\"), 0777)\n\tif err != nil {\n\t\tpanic(\"something went wrong\")\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/31_package-ioutil/03_ReadAll_WriteFile/hey.txt",
    "content": "Hello Everybody"
  },
  {
    "path": "27_code-in-process/31_package-ioutil/03_ReadAll_WriteFile/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\tmyStr := \"Hello Everybody\"\n\n\terr := ioutil.WriteFile(\"hey.txt\", []byte(myStr), 0777)\n\tif err != nil {\n\t\tlog.Fatalln(\"something went wrong!\", err.Error())\n\t}\n\n\tf, err := os.Open(\"hey.txt\")\n\tif err != nil {\n\t\tlog.Fatalln(\"couldn't read file!\", err.Error())\n\t}\n\tdefer f.Close()\n\n\tbs, err := ioutil.ReadAll(f)\n\tif err != nil {\n\t\tlog.Fatalln(\"Readall crashed!\", err.Error())\n\t}\n\n\tfmt.Println(string(bs))\n\n}\n"
  },
  {
    "path": "27_code-in-process/32_package-encoding-csv/01_NewReader/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\t// #1 open a file\n\tf, err := os.Open(\"../state_table.csv\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer f.Close()\n\n\t// #2 parse a csv file\n\tcsvReader := csv.NewReader(f)\n\tfor {\n\t\trecord, err := csvReader.Read()\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\t\tfmt.Println(record)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/32_package-encoding-csv/02_column-headings/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\t// #1 open a file\n\tf, err := os.Open(\"../state_table.csv\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer f.Close()\n\n\t// #2 parse a csv file\n\tcsvReader := csv.NewReader(f)\n\tfor rowCount := 0; ; rowCount++ {\n\t\trecord, err := csvReader.Read()\n\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\n\t\tcolumns := make(map[string]int)\n\t\tif rowCount == 0 {\n\t\t\tfor idx, column := range record {\n\t\t\t\tcolumns[column] = idx\n\t\t\t}\n\t\t}\n\n\t\tfmt.Println(columns)\n\t\tbreak\n\t}\n\t// #3 do stuff for each row\n\t// #4 print out a table of information\n}\n"
  },
  {
    "path": "27_code-in-process/32_package-encoding-csv/03_panics/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n)\n\ntype state struct {\n\tid               int\n\tname             string\n\tabbreviation     string\n\tcensusRegionName string\n}\n\nfunc parseState(columns map[string]int, record []string) (*state, error) {\n\tpanic(\"not implemented\")\n}\n\nfunc main() {\n\t// #1 open a file\n\tf, err := os.Open(\"../state_table.csv\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer f.Close()\n\n\t// #2 parse a csv file\n\tcsvReader := csv.NewReader(f)\n\tcolumns := make(map[string]int)\n\n\tfor rowCount := 0; ; rowCount++ {\n\t\trecord, err := csvReader.Read()\n\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\n\t\tif rowCount == 0 {\n\t\t\tfor idx, column := range record {\n\t\t\t\tcolumns[column] = idx\n\t\t\t}\n\t\t} else {\n\t\t\tstate, err := parseState(columns, record)\n\t\t\tif err != nil {\n\t\t\t\tlog.Fatalln(err)\n\t\t\t}\n\t\t\tlog.Println(state)\n\t\t}\n\t}\n\t// #3 do stuff for each row\n\t// #4 print out a table of information\n}\n"
  },
  {
    "path": "27_code-in-process/32_package-encoding-csv/04_parse-state/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"strconv\"\n)\n\ntype state struct {\n\tid               int\n\tname             string\n\tabbreviation     string\n\tcensusRegionName string\n}\n\nfunc parseState(columns map[string]int, record []string) (*state, error) {\n\tid, err := strconv.Atoi(record[columns[\"id\"]])\n\tname := record[columns[\"name\"]]\n\tabbreviation := record[columns[\"abbreviation\"]]\n\tcensusRegionName := record[columns[\"census_region_name\"]]\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &state{\n\t\tid:               id,\n\t\tname:             name,\n\t\tabbreviation:     abbreviation,\n\t\tcensusRegionName: censusRegionName,\n\t}, nil\n}\n\nfunc main() {\n\t// #1 open a file\n\tf, err := os.Open(\"../state_table.csv\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer f.Close()\n\n\t// #2 parse a csv file\n\tcsvReader := csv.NewReader(f)\n\tcolumns := make(map[string]int)\n\n\tfor rowCount := 0; ; rowCount++ {\n\t\trecord, err := csvReader.Read()\n\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\n\t\tif rowCount == 0 {\n\t\t\tfor idx, column := range record {\n\t\t\t\tcolumns[column] = idx\n\t\t\t}\n\t\t} else {\n\t\t\t// #3 do stuff for each row\n\t\t\tstate, err := parseState(columns, record)\n\t\t\tif err != nil {\n\t\t\t\tlog.Fatalln(err)\n\t\t\t}\n\t\t\t// #4 print out each row\n\t\t\tlog.Println(state)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/32_package-encoding-csv/05_state-lookup/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"strconv\"\n)\n\ntype state struct {\n\tid               int\n\tname             string\n\tabbreviation     string\n\tcensusRegionName string\n}\n\nfunc parseState(columns map[string]int, record []string) (*state, error) {\n\tid, err := strconv.Atoi(record[columns[\"id\"]])\n\tname := record[columns[\"name\"]]\n\tabbreviation := record[columns[\"abbreviation\"]]\n\tcensusRegionName := record[columns[\"census_region_name\"]]\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &state{\n\t\tid:               id,\n\t\tname:             name,\n\t\tabbreviation:     abbreviation,\n\t\tcensusRegionName: censusRegionName,\n\t}, nil\n}\n\nfunc main() {\n\t// #1 open a file\n\tf, err := os.Open(\"../state_table.csv\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer f.Close()\n\n\t// #2 parse a csv file\n\tcsvReader := csv.NewReader(f)\n\tcolumns := make(map[string]int)\n\n\tstateLookup := map[string]*state{}\n\n\tfor rowCount := 0; ; rowCount++ {\n\t\trecord, err := csvReader.Read()\n\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\n\t\tif rowCount == 0 {\n\t\t\tfor idx, column := range record {\n\t\t\t\tcolumns[column] = idx\n\t\t\t}\n\t\t} else {\n\t\t\t// #3 do stuff for each row\n\t\t\tstate, err := parseState(columns, record)\n\t\t\tif err != nil {\n\t\t\t\tlog.Fatalln(err)\n\t\t\t}\n\t\t\t// #4 add each row to stateLookup map\n\t\t\tstateLookup[state.abbreviation] = state\n\t\t}\n\t}\n\n\t// #5 lookup the state\n\tif len(os.Args) < 2 {\n\t\tlog.Fatalln(\"expected state abbreviation\")\n\t}\n\tabbreviation := os.Args[1]\n\tstate, ok := stateLookup[abbreviation]\n\tif !ok {\n\t\tlog.Fatalln(\"invalid state abbreviation\")\n\t}\n\tfmt.Println(state)\n}\n\n/*\nat terminal:\ngo install\n\nat terminal:\nprogramName <state abbreviation>\n\nfor example:\nstep05_state-lookup CA\n\nwill show this:\n&{5 California CA West}\n\n*/\n"
  },
  {
    "path": "27_code-in-process/32_package-encoding-csv/06_write-to-html/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"strconv\"\n)\n\ntype state struct {\n\tid               int\n\tname             string\n\tabbreviation     string\n\tcensusRegionName string\n}\n\nfunc parseState(columns map[string]int, record []string) (*state, error) {\n\tid, err := strconv.Atoi(record[columns[\"id\"]])\n\tname := record[columns[\"name\"]]\n\tabbreviation := record[columns[\"abbreviation\"]]\n\tcensusRegionName := record[columns[\"census_region_name\"]]\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &state{\n\t\tid:               id,\n\t\tname:             name,\n\t\tabbreviation:     abbreviation,\n\t\tcensusRegionName: censusRegionName,\n\t}, nil\n}\n\nfunc main() {\n\t// #1 open a file\n\tf, err := os.Open(\"../state_table.csv\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer f.Close()\n\n\t// #2 parse a csv file\n\tcsvReader := csv.NewReader(f)\n\tcolumns := make(map[string]int)\n\n\tstateLookup := map[string]*state{}\n\n\tfor rowCount := 0; ; rowCount++ {\n\t\trecord, err := csvReader.Read()\n\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\n\t\tif rowCount == 0 {\n\t\t\tfor idx, column := range record {\n\t\t\t\tcolumns[column] = idx\n\t\t\t}\n\t\t} else {\n\t\t\t// #3 do stuff for each row\n\t\t\tstate, err := parseState(columns, record)\n\t\t\tif err != nil {\n\t\t\t\tlog.Fatalln(err)\n\t\t\t}\n\t\t\t// #4 add each row to stateLookup map\n\t\t\tstateLookup[state.abbreviation] = state\n\t\t}\n\t}\n\n\t// #5 lookup the state\n\tif len(os.Args) < 2 {\n\t\tlog.Fatalln(\"expected state abbreviation\")\n\t}\n\tabbreviation := os.Args[1]\n\tstate, ok := stateLookup[abbreviation]\n\tif !ok {\n\t\tlog.Fatalln(\"invalid state abbreviation\")\n\t}\n\tfmt.Println(`\n<html>\n    <head></head>\n    <body>\n      <table>\n        <tr>\n          <th>Abbreviation</th>\n          <th>Name</th>\n        </tr>`)\n\n\tfmt.Println(`\n        <tr>\n          <td>` + state.abbreviation + `</td>\n          <td>` + state.name + `</td>\n        </tr>\n    `)\n\n\tfmt.Println(`\n      </table>\n    </body>\n</html>\n    `)\n}\n\n/*\nat terminal:\ngo install\n\nat terminal:\nprogramName <state abbreviation> > index.html\n\n*/\n"
  },
  {
    "path": "27_code-in-process/32_package-encoding-csv/07_NewReader/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n)\n\ntype record struct {\n\tDate string\n\tOpen float64\n}\n\nfunc makeRecord(row []string) record {\n\topen, _ := strconv.ParseFloat(row[1], 64)\n\treturn record{\n\t\tDate: row[0],\n\t\tOpen: open,\n\t}\n}\n\nfunc main() {\n\tf, err := os.Open(\"table.csv\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer f.Close()\n\n\trdr := csv.NewReader(f)\n\trows, err := rdr.ReadAll()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfor _, row := range rows {\n\t\trecord := makeRecord(row)\n\t\tfmt.Println(record)\n\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/32_package-encoding-csv/07_NewReader/table.csv",
    "content": "Date,Open,High,Low,Close,Volume,Adj Close\n2015-07-09,523.119995,523.77002,520.349976,520.679993,1839400,520.679993\n2015-07-08,521.049988,522.734009,516.109985,516.830017,1264600,516.830017\n2015-07-07,523.130005,526.179993,515.179993,525.02002,1595700,525.02002\n2015-07-06,519.50,525.25,519.00,522.859985,1276500,522.859985\n2015-07-02,521.080017,524.650024,521.080017,523.400024,1234000,523.400024\n2015-07-01,524.72998,525.690002,518.22998,521.840027,1961000,521.840027\n2015-06-30,526.02002,526.25,520.50,520.51001,2217200,520.51001\n2015-06-29,525.01001,528.609985,520.539978,521.52002,1930900,521.52002\n2015-06-26,537.26001,537.76001,531.349976,531.690002,2011500,531.690002\n2015-06-25,538.869995,540.900024,535.22998,535.22998,1331500,535.22998\n2015-06-24,540.00,540.00,535.659973,537.840027,1283400,537.840027\n2015-06-23,539.640015,541.499023,535.25,540.47998,1196000,540.47998\n2015-06-22,539.590027,543.73999,537.530029,538.190002,1242500,538.190002\n2015-06-19,537.210022,538.25,533.01001,536.690002,1885700,536.690002\n2015-06-18,531.00,538.150024,530.789978,536.72998,1828100,536.72998\n2015-06-17,529.369995,530.97998,525.099976,529.26001,1268600,529.26001\n2015-06-16,528.400024,529.640015,525.559998,528.150024,1069300,528.150024\n2015-06-15,528.00,528.299988,524.00,527.200012,1630700,527.200012\n2015-06-12,531.599976,533.119995,530.159973,532.330017,952400,532.330017\n2015-06-11,538.424988,538.97998,533.02002,534.609985,1205000,534.609985\n2015-06-10,529.359985,538.359985,529.349976,536.690002,1811400,536.690002\n2015-06-09,527.559998,529.200012,523.01001,526.690002,1441600,526.690002\n2015-06-08,533.309998,534.119995,526.23999,526.830017,1520600,526.830017\n2015-06-05,536.349976,537.200012,532.52002,533.330017,1375000,533.330017\n2015-06-04,537.76001,540.590027,534.320007,536.700012,1335600,536.700012\n2015-06-03,539.909973,543.50,537.109985,540.309998,1714500,540.309998\n2015-06-02,532.929993,543.00,531.330017,539.179993,1934700,539.179993\n2015-06-01,536.789978,536.789978,529.76001,533.98999,1899600,533.98999\n2015-05-29,537.369995,538.630005,531.450012,532.109985,2584900,532.109985\n2015-05-28,538.01001,540.609985,536.25,539.780029,1027900,539.780029\n2015-05-27,532.799988,540.549988,531.710022,539.789978,1520400,539.789978\n2015-05-26,538.119995,539.00,529.880005,532.320007,2403400,532.320007\n2015-05-22,540.150024,544.190002,539.51001,540.109985,1173300,540.109985\n2015-05-21,537.950012,543.840027,535.97998,542.51001,1461400,542.51001\n2015-05-20,538.48999,542.919983,532.971985,539.27002,1429100,539.27002\n2015-05-19,533.97998,540.659973,533.039978,537.359985,1963300,537.359985\n2015-05-18,532.01001,534.820007,528.849976,532.299988,1998600,532.299988\n2015-05-15,539.179993,539.273987,530.380005,533.849976,1962700,533.849976\n2015-05-14,533.77002,539.00,532.409973,538.400024,1399100,538.400024\n2015-05-13,530.559998,534.322021,528.655029,529.619995,1252300,529.619995\n2015-05-12,531.599976,533.208984,525.26001,529.039978,1625400,529.039978\n2015-05-11,538.369995,541.97998,535.400024,535.700012,905300,535.700012\n2015-05-08,536.650024,541.150024,525.00,538.219971,1527600,538.219971\n2015-05-07,523.98999,533.460022,521.75,530.700012,1546300,530.700012\n2015-05-06,531.23999,532.380005,521.085022,524.219971,1567000,524.219971\n2015-05-05,538.210022,539.73999,530.390991,530.799988,1383100,530.799988\n2015-05-04,538.530029,544.070007,535.059998,540.780029,1308000,540.780029\n2015-05-01,538.429993,539.539978,532.099976,537.900024,1768200,537.900024\n2015-04-30,547.869995,548.590027,535.049988,537.340027,2082200,537.340027\n2015-04-29,550.469971,553.679993,546.905029,549.080017,1698800,549.080017\n2015-04-28,554.640015,556.02002,550.366028,553.679993,1491000,553.679993\n2015-04-27,563.390015,565.950012,553.200012,555.369995,2398000,555.369995\n2015-04-24,566.102522,571.14259,557.252507,565.062561,4932500,565.062561\n2015-04-23,541.002435,550.96249,540.23244,547.002472,4184900,547.002472\n2015-04-22,534.402426,541.082489,531.752397,539.367458,1593600,539.367458\n2015-04-21,537.512456,539.392429,533.677415,533.972413,1844800,533.972413\n2015-04-20,525.602352,536.092424,524.50235,535.382408,1679300,535.382408\n2015-04-17,528.662379,529.842435,521.012371,524.052386,2144100,524.052386\n2015-04-16,529.902414,535.592457,529.612373,533.802391,1299900,533.802391\n2015-04-15,528.702406,534.732432,523.22235,532.532429,2318800,532.532429\n2015-04-14,536.252409,537.572435,528.094354,530.392405,2604100,530.392405\n2015-04-13,538.412385,544.062463,537.312445,539.172404,1645300,539.172404\n2015-04-10,542.292411,542.292411,537.312445,540.012477,1409500,540.012477\n2015-04-09,541.032486,541.95249,535.49239,540.782472,1557900,540.782472\n2015-04-08,538.382457,543.852415,538.382457,541.612446,1178500,541.612446\n2015-04-07,538.08244,542.692434,536.002395,537.022465,1302900,537.022465\n2015-04-06,532.222375,538.412385,529.572407,536.767432,1324400,536.767432\n2015-04-02,540.852427,540.852427,533.849395,535.532478,1716400,535.532478\n2015-04-01,548.602441,551.142488,539.502472,542.562439,1963100,542.562439\n2015-03-31,550.00246,554.712521,546.722468,548.002468,1588000,548.002468\n2015-03-30,551.622503,553.472487,548.17249,552.032502,1287500,552.032502\n2015-03-27,553.002509,555.282565,548.132463,548.342512,1897500,548.342512\n2015-03-26,557.59255,558.90254,550.652497,555.172522,1572600,555.172522\n2015-03-25,570.50259,572.262605,558.742494,558.787478,2152300,558.787478\n2015-03-24,562.562541,574.592603,561.212586,570.192597,2583300,570.192597\n2015-03-23,560.432554,562.362529,555.832536,558.81251,1643800,558.81251\n2015-03-20,561.652574,561.722529,559.052548,560.362537,2616900,560.362537\n2015-03-19,559.392531,560.802526,556.147548,557.992512,1197300,557.992512\n2015-03-18,552.50248,559.782578,547.002472,559.502513,2134500,559.502513\n2015-03-17,551.712533,553.802493,548.002468,550.842532,1805500,550.842532\n2015-03-16,550.952514,556.852484,546.002476,554.512509,1641000,554.512509\n2015-03-13,553.502537,558.402572,544.222448,547.322503,1703600,547.322503\n2015-03-12,553.512513,556.37253,550.462523,555.512505,1389600,555.512505\n2015-03-11,555.142533,558.142521,550.682486,551.182515,1820800,551.182515\n2015-03-10,564.252539,564.852512,554.732473,555.012538,1792300,555.012538\n2015-03-09,566.862541,570.272589,563.537504,568.852557,1062100,568.852557\n2015-03-06,574.882583,576.682625,566.762597,567.687558,1659100,567.687558\n2015-03-05,575.022616,577.912621,573.412548,575.332609,1389600,575.332609\n2015-03-04,571.872558,577.112576,568.012607,573.372583,1876800,573.372583\n2015-03-03,570.452587,575.392649,566.522559,573.64261,1704800,573.64261\n2015-03-02,560.532559,572.152623,558.752531,571.342601,2129600,571.342601\n2015-02-27,554.242482,564.712602,552.902503,558.402572,2410200,558.402572\n2015-02-26,543.212476,556.142529,541.502464,555.482516,2311500,555.482516\n2015-02-25,535.90245,546.22244,535.447406,543.872489,1826000,543.872489\n2015-02-24,530.002419,536.792403,528.252381,536.092424,1005100,536.092424\n2015-02-23,536.052398,536.441465,529.412361,531.912381,1457900,531.912381\n2015-02-20,543.132484,543.75247,535.802444,538.952441,1444400,538.952441\n2015-02-19,538.042413,543.11247,538.012424,542.872432,989100,542.872432\n2015-02-18,541.402458,545.492471,537.512456,539.702422,1453100,539.702422\n2015-02-17,546.832511,550.00246,541.092465,542.842504,1616800,542.842504\n2015-02-13,543.352447,549.912491,543.132484,549.012501,1900300,549.012501\n2015-02-12,537.252405,544.822482,534.675391,542.932472,1620200,542.932472\n2015-02-11,535.302416,538.452473,533.380397,535.972405,1377800,535.972405\n2015-02-10,529.302379,537.702431,526.922378,536.942412,1749900,536.942412\n2015-02-09,528.002366,532.002411,526.022388,527.832406,1267800,527.832406\n2015-02-06,527.642431,537.202463,526.412373,531.002415,1749400,531.002415\n2015-02-05,523.792334,528.502395,522.092359,527.582391,1849800,527.582391\n2015-02-04,529.2424,532.67442,521.272361,522.762349,1663700,522.762349\n2015-02-03,528.002366,533.40243,523.262377,529.2424,2038700,529.2424\n2015-02-02,531.732383,533.002407,518.552316,528.482381,2849800,528.482381\n2015-01-30,515.862322,539.872444,515.522339,534.522445,5606400,534.522445\n2015-01-29,511.002313,511.092313,501.202274,510.662331,4186400,510.662331\n2015-01-28,522.782423,522.992349,510.002318,510.002318,1683800,510.002318\n2015-01-27,529.972369,530.702398,518.192381,518.63237,1904000,518.63237\n2015-01-26,538.532466,539.002444,529.672413,535.212448,1543700,535.212448\n2015-01-23,535.592457,542.172453,533.002407,539.952437,2281700,539.952437\n2015-01-22,521.482349,536.332463,519.702382,534.39245,2676900,534.39245\n2015-01-21,507.252283,519.282407,506.202315,518.042312,2268700,518.042312\n2015-01-20,511.002313,512.502307,506.018277,506.902294,2227900,506.902294\n2015-01-16,500.012273,508.1923,500.002267,508.082288,2298300,508.082288\n2015-01-15,505.572291,505.682273,497.762267,501.792271,2715800,501.792271\n2015-01-14,494.652237,503.232286,493.002234,500.872267,2235700,500.872267\n2015-01-13,498.842256,502.982302,492.392254,496.182251,2370500,496.182251\n2015-01-12,494.942247,495.978261,487.562205,492.552209,2322400,492.552209\n2015-01-09,504.7623,504.922285,494.792239,496.172274,2069400,496.172274\n2015-01-08,497.992238,503.4823,491.002212,502.682255,3353600,502.682255\n2015-01-07,507.002299,507.246285,499.652247,501.102268,2065100,501.102268\n2015-01-06,515.002358,516.177334,501.052266,501.962262,2899900,501.962262\n2015-01-05,523.262377,524.332389,513.062315,513.872306,2059800,513.872306\n2015-01-02,529.012399,531.272443,524.102327,524.812404,1447600,524.812404\n2014-12-31,531.252429,532.602384,525.802363,526.402397,1368200,526.402397\n2014-12-30,528.092396,531.152424,527.132366,530.422394,876300,530.422394\n2014-12-29,532.192446,535.482414,530.013375,530.332426,2278500,530.332426\n2014-12-26,528.772422,534.252417,527.312364,534.032454,1036000,534.032454\n2014-12-24,530.512424,531.761394,527.022384,528.772422,705900,528.772422\n2014-12-23,527.00237,534.56241,526.292354,530.592416,2197600,530.592416\n2014-12-22,516.082347,526.462376,516.082347,524.872383,2723800,524.872383\n2014-12-19,511.512318,517.722342,506.91331,516.352313,3690200,516.352313\n2014-12-18,512.952333,513.872306,504.70229,511.102319,2926700,511.102319\n2014-12-17,497.002248,507.002299,496.812244,504.892295,2883200,504.892295\n2014-12-16,511.562321,513.052308,489.00222,495.392273,3964300,495.392273\n2014-12-15,522.742335,523.102331,513.272333,513.80229,2813400,513.80229\n2014-12-12,523.512391,528.502395,518.662298,518.662298,1994600,518.662298\n2014-12-11,527.802355,533.922411,527.102376,528.34241,1610800,528.34241\n2014-12-10,533.082399,536.332463,525.562386,526.062353,1712300,526.062353\n2014-12-09,522.142362,534.192438,520.502366,533.37244,1871300,533.37244\n2014-12-08,527.132366,531.002415,523.792334,526.982357,2329400,526.982357\n2014-12-05,531.002415,532.892425,524.282386,525.262369,2565600,525.262369\n2014-12-04,531.1624,537.342434,528.592424,537.312445,1392100,537.312445\n2014-12-03,531.442404,535.998416,529.262414,531.322384,1278000,531.322384\n2014-12-02,533.512412,535.502427,529.802408,533.752389,1525800,533.752389\n2014-12-01,538.902438,541.412434,531.862379,533.802391,2115400,533.802391\n2014-11-28,540.622426,542.002431,536.602429,541.832471,1148300,541.832471\n2014-11-26,540.882478,541.552406,537.044437,540.372412,1523000,540.372412\n2014-11-25,539.002444,543.98241,538.60444,541.082489,1789100,541.082489\n2014-11-24,537.652489,542.702471,535.622446,539.272471,1706000,539.272471\n2014-11-21,541.612446,542.142464,536.562402,537.502419,2223700,537.502419\n2014-11-20,531.252429,535.112381,531.082408,534.832438,1562000,534.832438\n2014-11-19,535.002399,538.242425,530.082412,536.992415,1391600,536.992415\n2014-11-18,537.502419,541.942452,534.172425,535.032449,1962700,535.032449\n2014-11-17,543.582448,543.792436,534.063361,536.512461,1725800,536.512461\n2014-11-14,546.682442,546.682442,542.152501,544.402507,1289200,544.402507\n2014-11-13,549.802448,549.802448,543.482442,545.38249,1339400,545.38249\n2014-11-12,550.392507,550.462523,545.172441,547.312465,1129400,547.312465\n2014-11-11,548.492459,551.942473,546.302493,550.29244,965500,550.29244\n2014-11-10,541.462498,549.592522,541.022449,547.492463,1134600,547.492463\n2014-11-07,546.212525,546.212525,538.672437,541.012473,1633800,541.012473\n2014-11-06,545.502448,546.887472,540.972385,542.042458,1333300,542.042458\n2014-11-05,556.802481,556.802481,544.052426,545.922423,2032300,545.922423\n2014-11-04,553.002509,555.502529,549.302481,554.112486,1244200,554.112486\n2014-11-03,555.502529,557.902544,553.23251,555.222464,1382300,555.222464\n2014-10-31,559.352504,559.572529,554.752486,559.082538,2035100,559.082538\n2014-10-30,548.952522,552.802497,543.512493,550.312514,1455500,550.312514\n2014-10-29,550.00246,554.19254,546.982459,549.332532,1770500,549.332532\n2014-10-28,543.002488,548.98245,541.622422,548.902519,1271000,548.902519\n2014-10-27,537.032441,544.412422,537.032441,540.772496,1185300,540.772496\n2014-10-24,544.36248,544.882461,535.792407,539.782476,1973100,539.782476\n2014-10-23,539.322474,547.222436,535.852386,543.98241,2348800,543.98241\n2014-10-22,529.892437,539.802428,528.802351,532.712427,2919300,532.712427\n2014-10-21,525.192353,526.792383,519.112324,526.542369,2336300,526.542369\n2014-10-20,509.452317,521.762353,508.102301,520.84241,2607500,520.84241\n2014-10-17,527.252385,530.982402,508.532313,511.172335,5539400,511.172335\n2014-10-16,519.002342,529.432374,515.002358,524.512387,3708600,524.512387\n2014-10-15,531.012391,532.802396,518.302363,530.032409,3719400,530.032409\n2014-10-14,538.902438,547.192507,533.172368,537.942408,2222600,537.942408\n2014-10-13,544.992443,549.502492,533.102413,533.212456,2581700,533.212456\n2014-10-10,557.722484,565.132577,544.052426,544.492476,3081900,544.492476\n2014-10-09,571.182555,571.492549,559.062524,560.882579,2524800,560.882579\n2014-10-08,565.572566,573.882587,557.492484,572.502582,1990900,572.502582\n2014-10-07,574.402629,575.27263,563.742534,563.742534,1911300,563.742534\n2014-10-06,578.802574,581.002639,574.442595,577.352614,1214600,577.352614\n2014-10-03,573.052613,577.227576,572.502582,575.282606,1141700,575.282606\n2014-10-02,567.312567,571.912585,563.322559,570.082615,1178400,570.082615\n2014-10-01,576.012635,577.582615,567.01255,568.272597,1445500,568.272597\n2014-09-30,576.932578,579.852634,572.852541,577.36259,1621700,577.36259\n2014-09-29,571.7526,578.192625,571.172579,576.362594,1282400,576.362594\n2014-09-26,576.062638,579.2526,574.662558,577.1026,1443700,577.1026\n2014-09-25,587.552646,587.982658,574.182604,575.062581,1926000,575.062581\n2014-09-24,581.462641,589.632691,580.522624,587.992634,1728100,587.992634\n2014-09-23,586.852606,586.852606,581.002639,581.132634,1471400,581.132634\n2014-09-22,593.82271,593.951665,583.462694,587.372648,1689500,587.372648\n2014-09-19,591.502688,596.482654,589.502696,596.082692,3736600,596.082692\n2014-09-18,587.002675,589.542661,585.002622,589.272695,1444600,589.272695\n2014-09-17,580.012619,587.522656,578.777665,584.772683,1692800,584.772683\n2014-09-16,572.762572,581.502606,572.662566,579.95264,1480400,579.95264\n2014-09-15,572.94257,574.952599,568.212618,573.102555,1597600,573.102555\n2014-09-12,581.002639,581.642639,574.462608,575.622589,1601700,575.622589\n2014-09-11,580.362639,581.812599,576.262588,581.352598,1221000,581.352598\n2014-09-10,581.502606,583.502659,576.942615,583.102636,977400,583.102636\n2014-09-09,588.902723,589.002667,580.002643,581.012615,1287200,581.012615\n2014-09-08,586.602653,591.772715,586.302635,589.722659,1431000,589.722659\n2014-09-05,583.982613,586.55265,581.952632,586.082672,1632400,586.082672\n2014-09-04,580.002643,586.00268,579.222611,581.982621,1458200,581.982621\n2014-09-03,580.002643,582.992655,575.002602,577.942611,1215100,577.942611\n2014-09-02,571.852545,577.832629,571.192593,577.332662,1578400,577.332662\n2014-08-29,571.332625,572.04258,567.07155,571.60253,1083800,571.60253\n2014-08-28,569.562573,573.252563,567.102518,569.202577,1292900,569.202577\n2014-08-27,577.272622,578.492581,570.105627,571.002557,1703400,571.002557\n2014-08-26,581.262629,581.802623,576.582619,577.862619,1639700,577.862619\n2014-08-25,584.722619,585.002622,579.002647,580.202654,1361400,580.202654\n2014-08-22,583.592689,585.238682,580.642643,582.562642,789100,582.562642\n2014-08-21,583.822628,584.502655,581.142671,583.372664,914800,583.372664\n2014-08-20,585.88266,586.702658,582.572618,584.492618,1036700,584.492618\n2014-08-19,585.002622,587.342658,584.002627,586.862643,978700,586.862643\n2014-08-18,576.11258,584.512631,576.002598,582.162619,1284100,582.162619\n2014-08-15,577.862619,579.382595,570.522603,573.482564,1519200,573.482564\n2014-08-14,576.182596,577.902645,570.882599,574.652643,985500,574.652643\n2014-08-13,567.312567,575.002602,565.752564,574.782639,1441800,574.782639\n2014-08-12,564.522567,565.902572,560.882579,562.732562,1542000,562.732562\n2014-08-11,569.992585,570.492553,566.002578,567.882551,1214700,567.882551\n2014-08-08,563.562536,570.252576,560.3525,568.772626,1494800,568.772626\n2014-08-07,568.00257,569.89258,561.102482,563.362525,1110900,563.362525\n2014-08-06,561.782569,570.702601,560.002541,566.376589,1334400,566.376589\n2014-08-05,570.052564,571.982601,562.612543,565.072598,1551200,565.072598\n2014-08-04,569.042531,575.352561,564.102531,573.152619,1427300,573.152619\n2014-08-01,570.402584,575.962633,562.85252,566.072594,1955300,566.072594\n2014-07-31,580.602616,583.652668,570.002561,571.60253,2102800,571.60253\n2014-07-30,586.55265,589.502696,584.002627,587.42265,1016500,587.42265\n2014-07-29,588.752653,589.702707,583.517654,585.612633,1349900,585.612633\n2014-07-28,588.072688,592.502683,584.755668,590.602636,986800,590.602636\n2014-07-25,590.402686,591.862684,587.032665,589.022681,932500,589.022681\n2014-07-24,596.452725,599.502716,591.772715,593.352671,1035100,593.352671\n2014-07-23,593.232652,597.852683,592.502683,595.982686,1233200,595.982686\n2014-07-22,590.722655,599.652725,590.602636,594.742652,1699200,594.742652\n2014-07-21,591.752702,594.402731,585.235622,589.472645,2062100,589.472645\n2014-07-18,593.002712,596.802684,582.002635,595.082696,4014200,595.082696\n2014-07-17,579.532665,580.992601,568.61258,573.732579,3016600,573.732579\n2014-07-16,588.002671,588.402694,582.202646,582.662587,1397100,582.662587\n2014-07-15,585.742628,585.807626,576.562606,584.782659,1623000,584.782659\n2014-07-14,582.602608,585.212671,578.032641,584.872627,1854100,584.872627\n2014-07-11,571.912585,580.85263,571.422594,579.182645,1621700,579.182645\n2014-07-10,565.912548,576.592656,565.012558,571.102563,1356700,571.102563\n2014-07-09,571.582578,576.72259,569.378536,576.082652,1116800,576.082652\n2014-07-08,577.662607,579.530645,566.137592,571.092587,1909500,571.092587\n2014-07-07,583.76265,586.432631,579.592644,582.252649,1064600,582.252649\n2014-07-03,583.352589,585.01266,580.922585,584.732656,714200,584.732656\n2014-07-02,583.352589,585.442672,580.392628,582.33766,1056400,582.33766\n2014-07-01,578.32262,584.402649,576.652635,582.672624,1448000,582.672624\n2014-06-30,578.662603,579.572631,574.752588,575.282606,1313800,575.282606\n2014-06-27,577.182592,579.872648,573.802595,577.242632,2236900,577.242632\n2014-06-26,581.002639,582.45266,571.852545,576.002598,1742000,576.002598\n2014-06-25,565.262572,579.962616,565.222546,578.652627,1969400,578.652627\n2014-06-24,565.192556,572.648612,561.012574,564.622572,2207100,564.622572\n2014-06-23,555.152509,565.002582,554.252519,564.952579,1536800,564.952579\n2014-06-20,556.852484,557.582513,550.394526,556.362492,4508300,556.362492\n2014-06-19,554.242482,555.0025,548.512473,554.902556,2456800,554.902556\n2014-06-18,544.862448,553.562516,544.002484,553.372481,1741800,553.372481\n2014-06-17,544.202496,545.32245,539.33245,543.012465,1444600,543.012465\n2014-06-16,549.262515,549.62245,541.522477,544.282488,1702600,544.282488\n2014-06-13,552.262503,552.302469,545.562488,551.762536,1220500,551.762536\n2014-06-12,557.302509,557.992512,548.462531,551.352476,1458500,551.352476\n2014-06-11,558.002549,559.882522,555.022514,558.842561,1100100,558.842561\n2014-06-10,560.512546,563.602502,557.902544,560.552511,1351700,560.552511\n2014-06-09,557.152562,562.902584,556.042523,562.122552,1467500,562.122552\n2014-06-06,558.062528,558.062528,548.932448,556.332564,1736800,556.332564\n2014-06-05,546.402499,554.952498,544.452449,553.90256,1689100,553.90256\n2014-06-04,541.502464,548.612478,538.752429,544.662436,1816500,544.662436\n2014-06-03,550.99248,552.342557,542.552463,544.942501,1866600,544.942501\n2014-06-02,560.702581,560.902593,545.732448,553.932488,1435000,553.932488\n2014-05-30,560.802526,561.352496,555.912467,559.892559,1771100,559.892559\n2014-05-29,563.352549,564.002525,558.712565,560.082534,1354100,560.082534\n2014-05-28,564.57257,567.842585,561.002537,561.682502,1652000,561.682502\n2014-05-27,556.002496,566.002578,554.352463,565.952575,2104200,565.952575\n2014-05-23,547.262462,553.642508,543.702467,552.702492,1932200,552.702492\n2014-05-22,541.132431,547.602445,540.782472,545.062459,1615800,545.062459\n2014-05-21,532.902462,539.185441,531.912381,538.942465,1196300,538.942465\n2014-05-20,529.742368,536.232396,526.302392,529.772418,1784800,529.772418\n2014-05-19,519.702382,529.782456,517.58537,528.862391,1277800,528.862391\n2014-05-16,521.39238,521.802379,515.442347,520.632362,1485300,520.632362\n2014-05-15,525.702357,525.872379,517.422325,519.982324,1704400,519.982324\n2014-05-14,533.002407,533.002407,525.292358,526.652412,1191800,526.652412\n2014-05-13,530.892433,536.072411,529.512428,533.092437,1653400,533.092437\n2014-05-12,523.512391,530.192393,519.012379,529.922366,1912500,529.922366\n2014-05-09,510.75233,519.902393,504.202292,518.732314,2439500,518.732314\n2014-05-08,508.462297,517.23229,506.452298,511.002313,2021300,511.002313\n2014-05-07,515.792305,516.68232,503.302272,509.962291,3224300,509.962291\n2014-05-06,525.232379,526.812396,515.062337,515.14233,1689000,515.14233\n2014-05-05,524.822381,528.902418,521.322364,527.812392,1024100,527.812392\n2014-05-02,533.762426,534.002403,525.612389,527.932411,1688500,527.932411\n2014-05-01,527.112352,532.932391,523.882364,531.352374,1905500,531.352374\n2014-04-30,527.602343,528.002366,522.522372,526.662388,1751200,526.662388\n2014-04-29,516.902344,529.462425,516.322324,527.70241,2699100,527.70241\n2014-04-28,517.182348,518.602319,502.802274,517.152359,3335500,517.152359\n2014-04-25,522.512395,524.702361,515.422333,516.182352,2100400,516.182352\n2014-04-24,530.072374,531.652452,522.122349,525.162363,1883200,525.162363\n2014-04-23,533.792415,533.872408,526.252389,526.942391,2052300,526.942391\n2014-04-22,528.642427,537.232391,527.512375,534.812425,2365400,534.812425\n2014-04-21,536.1024,536.702435,525.602352,528.622414,2566700,528.622414\n2014-04-17,548.81249,549.502492,531.152424,536.1024,6809500,536.1024\n2014-04-16,543.002488,557.002492,540.00244,556.54249,4893300,556.54249\n2014-04-15,536.822454,538.452473,518.462348,536.442444,3855100,536.442444\n2014-04-14,538.252462,544.102429,529.56237,532.522453,2575100,532.522453\n2014-04-11,532.552381,540.00244,526.532392,530.602392,3924800,530.602392\n2014-04-10,565.002582,565.002582,539.902495,540.952433,4036900,540.952433\n2014-04-09,559.622532,565.372554,552.952506,564.142557,3330800,564.142557\n2014-04-08,542.602466,555.0025,541.612446,554.902556,3151200,554.902556\n2014-04-07,540.742445,548.482483,527.15244,538.152456,4401700,538.152456\n2014-04-04,574.652643,577.77265,543.002488,543.14246,6369300,543.14246\n2014-04-03,569.852553,587.282679,564.132581,569.742571,5099200,569.742571\n2014-04-02,599.992707,604.832763,562.192568,567.002574,147100,567.002574\n2014-04-01,558.712565,568.452595,558.712565,567.162558,7900,567.162558\n2014-03-31,566.892592,567.002574,556.932537,556.972503,10800,556.972503\n2014-03-28,561.202549,566.43259,558.672477,559.992504,41200,559.992504\n2014-03-27,568.00257,568.00257,552.922516,558.462551,13100,558.462551\n"
  },
  {
    "path": "27_code-in-process/32_package-encoding-csv/state_table.csv",
    "content": "id,name,abbreviation,country,type,sort,status,occupied,notes,fips_state,assoc_press,standard_federal_region,census_region,census_region_name,census_division,census_division_name,circuit_court\n\"1\",\"Alabama\",\"AL\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"1\",\"Ala.\",\"IV\",\"3\",\"South\",\"6\",\"East South Central\",\"11\"\n\"2\",\"Alaska\",\"AK\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"2\",\"Alaska\",\"X\",\"4\",\"West\",\"9\",\"Pacific\",\"9\"\n\"3\",\"Arizona\",\"AZ\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"4\",\"Ariz.\",\"IX\",\"4\",\"West\",\"8\",\"Mountain\",\"9\"\n\"4\",\"Arkansas\",\"AR\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"5\",\"Ark.\",\"VI\",\"3\",\"South\",\"7\",\"West South Central\",\"8\"\n\"5\",\"California\",\"CA\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"6\",\"Calif.\",\"IX\",\"4\",\"West\",\"9\",\"Pacific\",\"9\"\n\"6\",\"Colorado\",\"CO\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"8\",\"Colo.\",\"VIII\",\"4\",\"West\",\"8\",\"Mountain\",\"10\"\n\"7\",\"Connecticut\",\"CT\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"9\",\"Conn.\",\"I\",\"1\",\"Northeast\",\"1\",\"New England\",\"2\"\n\"8\",\"Delaware\",\"DE\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"10\",\"Del.\",\"III\",\"3\",\"South\",\"5\",\"South Atlantic\",\"3\"\n\"9\",\"Florida\",\"FL\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"12\",\"Fla.\",\"IV\",\"3\",\"South\",\"5\",\"South Atlantic\",\"11\"\n\"10\",\"Georgia\",\"GA\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"13\",\"Ga.\",\"IV\",\"3\",\"South\",\"5\",\"South Atlantic\",\"11\"\n\"11\",\"Hawaii\",\"HI\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"15\",\"Hawaii\",\"IX\",\"4\",\"West\",\"9\",\"Pacific\",\"9\"\n\"12\",\"Idaho\",\"ID\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"16\",\"Idaho\",\"X\",\"4\",\"West\",\"8\",\"Mountain\",\"9\"\n\"13\",\"Illinois\",\"IL\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"17\",\"Ill.\",\"V\",\"2\",\"Midwest\",\"3\",\"East North Central\",\"7\"\n\"14\",\"Indiana\",\"IN\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"18\",\"Ind.\",\"V\",\"2\",\"Midwest\",\"3\",\"East North Central\",\"7\"\n\"15\",\"Iowa\",\"IA\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"19\",\"Iowa\",\"VII\",\"2\",\"Midwest\",\"4\",\"West North Central\",\"8\"\n\"16\",\"Kansas\",\"KS\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"20\",\"Kan.\",\"VII\",\"2\",\"Midwest\",\"4\",\"West North Central\",\"10\"\n\"17\",\"Kentucky\",\"KY\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"21\",\"Ky.\",\"IV\",\"3\",\"South\",\"6\",\"East South Central\",\"6\"\n\"18\",\"Louisiana\",\"LA\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"22\",\"La.\",\"VI\",\"3\",\"South\",\"7\",\"West South Central\",\"5\"\n\"19\",\"Maine\",\"ME\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"23\",\"Maine\",\"I\",\"1\",\"Northeast\",\"1\",\"New England\",\"1\"\n\"20\",\"Maryland\",\"MD\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"24\",\"Md.\",\"III\",\"3\",\"South\",\"5\",\"South Atlantic\",\"4\"\n\"21\",\"Massachusetts\",\"MA\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"25\",\"Mass.\",\"I\",\"1\",\"Northeast\",\"1\",\"New England\",\"1\"\n\"22\",\"Michigan\",\"MI\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"26\",\"Mich.\",\"V\",\"2\",\"Midwest\",\"3\",\"East North Central\",\"6\"\n\"23\",\"Minnesota\",\"MN\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"27\",\"Minn.\",\"V\",\"2\",\"Midwest\",\"4\",\"West North Central\",\"8\"\n\"24\",\"Mississippi\",\"MS\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"28\",\"Miss.\",\"IV\",\"3\",\"South\",\"6\",\"East South Central\",\"5\"\n\"25\",\"Missouri\",\"MO\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"29\",\"Mo.\",\"VII\",\"2\",\"Midwest\",\"4\",\"West North Central\",\"8\"\n\"26\",\"Montana\",\"MT\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"30\",\"Mont.\",\"VIII\",\"4\",\"West\",\"8\",\"Mountain\",\"9\"\n\"27\",\"Nebraska\",\"NE\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"31\",\"Nebr.\",\"VII\",\"2\",\"Midwest\",\"4\",\"West North Central\",\"8\"\n\"28\",\"Nevada\",\"NV\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"32\",\"Nev.\",\"IX\",\"4\",\"West\",\"8\",\"Mountain\",\"9\"\n\"29\",\"New Hampshire\",\"NH\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"33\",\"N.H.\",\"I\",\"1\",\"Northeast\",\"1\",\"New England\",\"1\"\n\"30\",\"New Jersey\",\"NJ\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"34\",\"N.J.\",\"II\",\"1\",\"Northeast\",\"2\",\"Mid-Atlantic\",\"3\"\n\"31\",\"New Mexico\",\"NM\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"35\",\"N.M.\",\"VI\",\"4\",\"West\",\"8\",\"Mountain\",\"10\"\n\"32\",\"New York\",\"NY\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"36\",\"N.Y.\",\"II\",\"1\",\"Northeast\",\"2\",\"Mid-Atlantic\",\"2\"\n\"33\",\"North Carolina\",\"NC\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"37\",\"N.C.\",\"IV\",\"3\",\"South\",\"5\",\"South Atlantic\",\"4\"\n\"34\",\"North Dakota\",\"ND\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"38\",\"N.D.\",\"VIII\",\"2\",\"Midwest\",\"4\",\"West North Central\",\"8\"\n\"35\",\"Ohio\",\"OH\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"39\",\"Ohio\",\"V\",\"2\",\"Midwest\",\"3\",\"East North Central\",\"6\"\n\"36\",\"Oklahoma\",\"OK\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"40\",\"Okla.\",\"VI\",\"3\",\"South\",\"7\",\"West South Central\",\"10\"\n\"37\",\"Oregon\",\"OR\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"41\",\"Ore.\",\"X\",\"4\",\"West\",\"9\",\"Pacific\",\"9\"\n\"38\",\"Pennsylvania\",\"PA\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"42\",\"Pa.\",\"III\",\"1\",\"Northeast\",\"2\",\"Mid-Atlantic\",\"3\"\n\"39\",\"Rhode Island\",\"RI\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"44\",\"R.I.\",\"I\",\"1\",\"Northeast\",\"1\",\"New England\",\"1\"\n\"40\",\"South Carolina\",\"SC\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"45\",\"S.C.\",\"IV\",\"3\",\"South\",\"5\",\"South Atlantic\",\"4\"\n\"41\",\"South Dakota\",\"SD\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"46\",\"S.D.\",\"VIII\",\"2\",\"Midwest\",\"4\",\"West North Central\",\"8\"\n\"42\",\"Tennessee\",\"TN\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"47\",\"Tenn.\",\"IV\",\"3\",\"South\",\"6\",\"East South Central\",\"6\"\n\"43\",\"Texas\",\"TX\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"48\",\"Texas\",\"VI\",\"3\",\"South\",\"7\",\"West South Central\",\"5\"\n\"44\",\"Utah\",\"UT\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"49\",\"Utah\",\"VIII\",\"4\",\"West\",\"8\",\"Mountain\",\"10\"\n\"45\",\"Vermont\",\"VT\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"50\",\"Vt.\",\"I\",\"1\",\"Northeast\",\"1\",\"New England\",\"2\"\n\"46\",\"Virginia\",\"VA\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"51\",\"Va.\",\"III\",\"3\",\"South\",\"5\",\"South Atlantic\",\"4\"\n\"47\",\"Washington\",\"WA\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"53\",\"Wash.\",\"X\",\"4\",\"West\",\"9\",\"Pacific\",\"9\"\n\"48\",\"West Virginia\",\"WV\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"54\",\"W.Va.\",\"III\",\"3\",\"South\",\"5\",\"South Atlantic\",\"4\"\n\"49\",\"Wisconsin\",\"WI\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"55\",\"Wis.\",\"V\",\"2\",\"Midwest\",\"3\",\"East North Central\",\"7\"\n\"50\",\"Wyoming\",\"WY\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"56\",\"Wyo.\",\"VIII\",\"4\",\"West\",\"8\",\"Mountain\",\"10\"\n\"51\",\"Washington DC\",\"DC\",\"USA\",\"capitol\",\"10\",\"current\",\"occupied\",\"\",\"11\",\"\",\"III\",\"3\",\"South\",\"5\",\"South Atlantic\",\"D.C.\"\n"
  },
  {
    "path": "27_code-in-process/33_package-path-filepath/01_Walk/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\nfunc main() {\n\tfilepath.Walk(\".\", func(path string, info os.FileInfo, err error) error {\n\t\tfmt.Println(info)\n\t\treturn nil\n\t})\n}\n\n/*\nwalk is recursive\nreaddir is not\n*/\n"
  },
  {
    "path": "27_code-in-process/33_package-path-filepath/02_Walk/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\nfunc main() {\n\tfilepath.Walk(\".\", func(path string, info os.FileInfo, err error) error {\n\t\tfmt.Println(path, info.Name(), info.Size(), info.Mode(), info.IsDir())\n\t\treturn nil\n\t})\n}\n\n/*\nwalk is recursive\nreaddir is not\n*/\n"
  },
  {
    "path": "27_code-in-process/33_package-path-filepath/03_Walk/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\nfunc main() {\n\tfilepath.Walk(\".\", func(path string, info os.FileInfo, err error) error {\n\n\t\tif info.IsDir() {\n\t\t\treturn nil\n\t\t}\n\n\t\tfmt.Println(info)\n\t\treturn nil\n\t})\n}\n\n/*\nwalk is recursive\nreaddir is not\n*/\n"
  },
  {
    "path": "27_code-in-process/33_package-path-filepath/04_Walk/main.go",
    "content": "package main\n\nimport (\n\t\"crypto/md5\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\nfunc md5file(fileName string) []byte {\n\tf, err := os.Open(fileName)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer f.Close()\n\n\th := md5.New()\n\tio.Copy(h, f)\n\treturn h.Sum(nil)\n}\n\nfunc main() {\n\tfilepath.Walk(\"../\", func(path string, info os.FileInfo, err error) error {\n\t\tif info.IsDir() {\n\t\t\treturn nil\n\t\t}\n\n\t\tbs := md5file(path)\n\t\tfmt.Printf(\"%s %x\\n\", path, bs)\n\t\treturn nil\n\t})\n}\n\n/*\nwalk is recursive\nreaddir is not\n*/\n"
  },
  {
    "path": "27_code-in-process/34_package-time/01_now/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\nfunc main() {\n\tfmt.Println(time.Now())\n}\n"
  },
  {
    "path": "27_code-in-process/34_package-time/02_time-parse/01/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\nfunc main() {\n\ttimeAsString := \"2012-01-22\"\n\tfmt.Println(time.Parse(\"2006-01-01_this-does-not-compile\", timeAsString))\n}\n"
  },
  {
    "path": "27_code-in-process/34_package-time/02_time-parse/02/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\nfunc main() {\n\ttimeAsString := \"01/22/2012\"\n\tfmt.Println(time.Parse(\"01/01_this-does-not-compile/2006\", timeAsString))\n}\n"
  },
  {
    "path": "27_code-in-process/34_package-time/03_format/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\nfunc main() {\n\ttimeAsString := \"01/22/2012\"\n\ttimeAsTime, _ := time.Parse(\"01/01_this-does-not-compile/2006\", timeAsString)\n\tfmt.Println(timeAsTime)\n\n\tfmt.Println(timeAsTime.Format(\"01/01_this-does-not-compile/2006\"))\n\tfmt.Println(timeAsTime.Format(time.Kitchen))\n\tfmt.Println(timeAsTime.Format(time.UnixDate))\n}\n"
  },
  {
    "path": "27_code-in-process/34_package-time/04_date-diff/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"time\"\n)\n\nfunc main() {\n\tfrom, to := os.Args[1], os.Args[2]\n\n\tfromTime, _ := time.Parse(\"2006-01-01_this-does-not-compile\", from)\n\ttoTime, _ := time.Parse(\"2006-01-01_this-does-not-compile\", to)\n\n\tdur := toTime.Sub(fromTime)\n\tfmt.Println(\"elapsed days:\", int(dur/(time.Hour*24)))\n\n}\n"
  },
  {
    "path": "27_code-in-process/35_hash/00_notes/notes.txt",
    "content": "md5 not secure\n\nsha-1 not secure\n\nsha-256 still fine\n\nfnv not cryptographic, but super fast!\n\nfor passwords / confidential data:\nbcrypt\nscrypt\n"
  },
  {
    "path": "27_code-in-process/35_hash/01_FNV/01/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"hash/fnv\"\n\t\"io\"\n\t\"os\"\n)\n\nfunc main() {\n\tf, err := os.Open(os.Args[1])\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer f.Close()\n\n\th := fnv.New64()\n\tio.Copy(h, f)\n\tfmt.Println(h.Sum64())\n}\n"
  },
  {
    "path": "27_code-in-process/35_hash/01_FNV/02/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"hash/fnv\"\n\t\"io\"\n\t\"os\"\n)\n\nfunc main() {\n\tf, err := os.Open(os.Args[1])\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer f.Close()\n\n\th := fnv.New64()\n\tio.Copy(h, f)\n\tfmt.Println(\"The sum is:\", h.Sum64())\n}\n"
  },
  {
    "path": "27_code-in-process/35_hash/02_MD5/01/main.go",
    "content": "package main\n\nimport (\n\t\"crypto/md5\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n)\n\nfunc main() {\n\tf, err := os.Open(os.Args[1])\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer f.Close()\n\n\th := md5.New()\n\tio.Copy(h, f)\n\tfmt.Printf(\"%x\\n\", h.Sum(nil))\n}\n"
  },
  {
    "path": "27_code-in-process/35_hash/02_MD5/02/main.go",
    "content": "package main\n\nimport (\n\t\"crypto/md5\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\n\t// one way\n\t// reads bytes on the fly\n\tf, err := os.Open(\"../resources/table.csv\")\n\tif err != nil {\n\t\tlog.Fatalln(\"couldn't open file\", err.Error())\n\t}\n\tdefer f.Close()\n\n\th := md5.New()\n\tio.Copy(h, f)\n\tfmt.Printf(\"The hash (sum) is: %x\\n\", h.Sum(nil))\n\n\t// or this way\n\t// but reads all the bytes at once, then does it\n\tf.Seek(0, 0)\n\tbs, err := ioutil.ReadAll(f)\n\tif err != nil {\n\t\tlog.Fatalln(\"readall didn't read well\", err.Error())\n\t}\n\tfmt.Printf(\"The hash (sum) is: %x\\n\", md5.Sum(bs))\n}\n"
  },
  {
    "path": "27_code-in-process/36_package-filepath/01_walk/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\nfunc walk() {\n\tvar counter int\n\tfilepath.Walk(\".\", func(path string, info os.FileInfo, err error) error {\n\t\tif info.IsDir() {\n\t\t\treturn nil\n\t\t}\n\t\tcounter++\n\t\tfmt.Println(path)\n\t\treturn nil\n\t})\n\tfmt.Println(counter)\n}\n\nfunc main() {\n\twalk()\n}\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/01_gravatar/main.go",
    "content": "package main\n\nimport (\n\t\"crypto/md5\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc getGravatarHash(email string) string {\n\temail = strings.TrimSpace(email)\n\temail = strings.ToLower(email)\n\th := md5.New()\n\tio.WriteString(h, email)\n\tfinalBytes := h.Sum(nil)\n\tfinalString := hex.EncodeToString(finalBytes)\n\treturn finalString\n}\n\nfunc main() {\n\tvar email string = os.Args[1]\n\tvar gravatarHash = getGravatarHash(email)\n\tfmt.Println(`<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n</head>\n<body>\n<img src=\"http://www.gravatar.com/avatar/` + gravatarHash + `\" alt=\"user picture\">\n</body>\n</html>`)\n\n}\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/01_gravatar/page.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n</head>\n<body>\n<img src=\"http://www.gravatar.com/avatar/86f0872e49042085c67d2ee277b86494\" alt=\"user picture\">\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/02_word-count/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nfunc wordCount(str string) map[string]int {\n\t//\tpanic(\"not implemented\")\n\tvar words []string = strings.Fields(str)\n\tm := make(map[string]int)\n\tfor _, v := range words {\n\t\tm[v]++\n\t}\n\treturn m\n}\n\nfunc main() {\n\tstr := `Robert Cohn was once middleweight boxing champion of Princeton. Do not think that I am very much impressed by that as a boxing title, but it meant a lot to Cohn. He cared nothing for boxing, in fact he disliked it, but he learned it painfully and thoroughly to counteract the feeling of inferiority and shyness he had felt on being treated as a Jew at Princeton. There was a certain inner comfort in knowing he could knock down anybody who was snooty to him, although, being very shy and a thoroughly nice boy, he never fought except in the gym. He was Spider Kelly's star pupil. Spider Kelly taught all his young gentlemen to box like featherweights, no matter whether they weighed one hundred and five or two hundred and five pounds. But it seemed to fit Cohn. He was really very fast. He was so good that Spider promptly overmatched him and got his nose permanently flattened. This increased Cohn's distaste for boxing, but it gave him a certain satisfaction of some strange sort, and it certainly improved his nose. In his last year at Princeton he read too much and took to wearing spectacles. I never met any one of his class who remembered him. They did not even remember that he was middleweight boxing champion. I mistrust all frank and simple people, especially when their stories hold together, and I always had a suspicion that perhaps Robert Cohn had never been middleweight boxing champion, and that perhaps a horse had stepped on his face, or that maybe his mother had been frightened or seen something, or that he had, maybe, bumped into something as a young child, but I finally had somebody verify the story from Spider Kelly. Spider Kelly not only remembered Cohn. He had often wondered what had become of him. Robert Cohn was a member, through his father, of one of the richest Jewish families in New York, and through his mother of one of the oldest. At the military school where he prepped for Princeton, and played a very good end on the football team, no one had made him race-conscious. No one had ever made him feel he was a Jew, and hence any different from anybody else, until he went to Princeton. He was a nice boy, a friendly boy, and very shy, and it made him bitter. He took it out in boxing, and he came out of Princeton with painful self-consciousness and the flattened nose, and was married by the first girl who was nice to him. He was married five years, had three children, lost most of the fifty thousand dollars his father left him, the balance of the estate having gone to his mother, hardened into a rather unattractive mould under domestic unhappiness with a rich wife; and just when he had made up his mind to leave his wife she left him and went off with a miniature-painter. As he had been thinking for months about leaving his wife and had not done it because it would be too cruel to deprive her of himself, her departure was a very healthful shock. The divorce was arranged and Robert Cohn went out to the Coast. In California he fell among literary people and, as he still had a little of the fifty thousand left, in a short time he was backing a review of the Arts. The review commenced publication in Carmel, California, and finished in Provincetown, Massachusetts. By that time Cohn, who had been regarded purely as an angel, and whose name had appeared on the editorial page merely as a member of the advisory board, had become the sole editor. It was his money and he discovered he liked the authority of editing. He was sorry when the magazine became too expensive and he had to give it up. By that time, though, he had other things to worry about. He had been taken in hand by a lady who hoped to rise with the magazine. She was very forceful, and Cohn never had a chance of not being taken in hand. Also he was sure that he loved her. When this lady saw that the magazine was not going to rise, she became a little disgusted with Cohn and decided that she might as well get what there was to get while there was still something available, so http://www.en8848.com.cn she urged that they go to Europe, where Cohn could write. They came to Europe, where the lady had been educated, and stayed three years. During these three years, the first spent in travel, the last two in Paris, Robert Cohn had two friends, Braddocks and myself. Braddocks was his literary friend. I was his tennis friend. The lady who had him, her name was Frances, found toward the end of the second year that her looks were going, and her attitude toward Robert changed from one of careless possession and exploitation to the absolute determination that he should marry her. During this time Robert's mother had settled an allowance on him, about three hundred dollars a month. During two years and a half I do not believe that Robert Cohn looked at another woman. He was fairly happy, except that, like many people living in Europe, he would rather have been in America, and he had discovered writing. He wrote a novel, and it was not really such a bad novel as the critics later called it, although it was a very poor novel. He read many books, played bridge, played tennis, and boxed at a local gymnasium. I first became aware of his lady's attitude toward him one night after the three of us had dined together. We had dined at l'Avenue's and afterward went to the Café de Versailles for coffee. We had several _fines_ after the coffee, and I said I must be going. Cohn had been talking about the two of us going off somewhere on a weekend trip. He wanted to get out of town and get in a good walk. I suggested we fly to Strasbourg and walk up to Saint Odile, or somewhere or other in Alsace. \"I know a girl in Strasbourg who can show us the town,\" I said. Somebody kicked me under the table. I thought it was accidental and went on: \"She's been there two years and knows everything there is to know about the town. She's a swell girl.\" I was kicked again under the table and, looking, saw Frances, Robert's lady, her chin lifting and her face hardening. \"Hell,\" I said, \"why go to Strasbourg? We could go up to Bruges, or to the Ardennes.\" Cohn looked relieved. I was not kicked again. I said good-night and went out. Cohn said he wanted to buy a paper and would walk to the corner with me. \"For God's sake,\" he said, \"why did you say that about that girl in Strasbourg for? Didn't you see Frances?\" \"No, why should I? If I know an American girl that lives in Strasbourg what the hell is it to Frances?\" \"It doesn't make any difference. Any girl. I couldn't go, that would be all.\" \"Don't be silly.\" \"You don't know Frances. Any girl at all. Didn't you see the way she looked?\" \"Oh, well,\" I said, \"let's go to Senlis.\" \"Don't get sore.\" \"I'm not sore. Senlis is a good place and we can stay at the Grand Cerf and take a hike in the woods and come home.\" \"Good, that will be fine.\" \"Well, I'll see you to-morrow at the courts,\" I said. \"Good-night, Jake,\" he said, and started back to the café. \"You forgot to get your paper,\" I said. \"That's so.\" He walked with me up to the kiosque at the corner. \"You are not sore, are you, Jake?\" He turned with the paper in his hand. \"No, why should I be?\" \"See you at tennis,\" he said. I watched him walk back to the café holding his paper. I rather liked him and evidently she led him quite a life.`\n\tfmt.Println(wordCount(str))\n}\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/03_centered_average/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n)\n\nfunc main() {\n\tx := []int{\n\t\t48, 96, 86, 68,\n\t\t57, 82, 63, 70,\n\t\t37, 34, 83, 27,\n\t\t19, 97, 9, 17,\n\t}\n\n\tfmt.Println(x)\n\n\tsort.Ints(x)\n\n\tfmt.Println(x)\n\n\tx = x[1:]\n\tfmt.Println(x)\n\n\tx = x[:(len(x) - 1)]\n\tfmt.Println(x)\n\n\ttotal := 0\n\n\tfor _, value := range x {\n\t\ttotal += value\n\t}\n\n\tfmt.Println(total)\n\tfmt.Println(total / len(x))\n}\n\n/*\nImplement a centeredAverage function\nthat computes the average of a list of numbers,\nbut removes the largest and smallest values.\n\ncenteredAverage([]float64{1, 2, 3, 4, 100}) → 3\n*/\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/04_swap-two_pointers/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc swap(x, y *int) {\n\t*x, *y = *y, *x\n}\n\nfunc main() {\n\tx := 1\n\ty := 2\n\tswap(&x, &y)\n\tfmt.Println(\"x\", x)\n\tfmt.Println(\"y\", y)\n}\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/05_clumps/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc countClumps(xs []int) int {\n\tclumps := 0\n\tinClumps := false\n\tfor i := 1; i < len(xs); i++ {\n\t\tcurr, prev := xs[i], xs[i-1]\n\t\tif !inClumps && curr == prev {\n\t\t\tinClumps = true\n\t\t\tclumps++\n\t\t}\n\t\tif inClumps && curr != prev {\n\t\t\tinClumps = false\n\t\t}\n\t}\n\treturn clumps\n}\n\nfunc main() {\n\tclumps := countClumps([]int{1, 1, 1, 1, 1})\n\tfmt.Println(clumps)\n}\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/06_cat/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\tf, err := os.Open(os.Args[1])\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke\", err.Error())\n\t}\n\tdefer f.Close()\n\n\tbs, err := ioutil.ReadAll(f)\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke again\")\n\t}\n\n\tstr := string(bs)\n\tfmt.Println(str)\n}\n\n/*\n\nstep 1 - at command line enter:\ngo install\n\nstep 2 - at command line enter:\n06_cat main.go\n\n*/\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/07_copy/main.go",
    "content": "package main\n\nimport (\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\tf, err := os.Open(os.Args[1])\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke opening: \", err.Error())\n\t}\n\tdefer f.Close()\n\n\tnf, err := os.Create(\"newFile.txt\")\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke creating: \", err.Error())\n\t}\n\n\tbs, err := ioutil.ReadAll(f)\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke reading: \", err.Error())\n\t}\n\n\t_, err = nf.Write(bs)\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke writing: \", err.Error())\n\t}\n}\n\n/*\n\nstep 1 - at command line enter:\ngo install\n\nstep 2 - at command line enter:\n07_copy main.go\n\n*/\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/07_copy/newFile.txt",
    "content": "package main\n\nimport (\n\t\"os\"\n\t\"log\"\n\t\"io/ioutil\"\n)\n\nfunc main() {\n\tf, err := os.Open(os.Args[1])\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke opening: \", err.Error())\n\t}\n\tdefer f.Close()\n\n\tnf, err := os.Create(\"newFile.txt\")\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke creating: \", err.Error())\n\t}\n\n\tbs, err := ioutil.ReadAll(f)\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke reading: \", err.Error())\n\t}\n\n\t_, err = nf.Write(bs)\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke writing: \", err.Error())\n\t}\n}\n\n/*\n\nstep 1 - at command line enter:\ngo install\n\nstep 2 - at command line enter:\n07_copy main.go\n\n*/"
  },
  {
    "path": "27_code-in-process/37_review-exercises/08_cp/01/initial.txt",
    "content": "this is the starting text in the file"
  },
  {
    "path": "27_code-in-process/37_review-exercises/08_cp/01/main.go",
    "content": "package main\n\nimport (\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\tsrcName := os.Args[1]\n\tdstName := os.Args[2]\n\n\tsrc, err := os.Open(srcName)\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke opening: \", err.Error())\n\t}\n\tdefer src.Close()\n\n\tdst, err := os.Create(dstName)\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke creating: \", err.Error())\n\t}\n\tdefer dst.Close()\n\n\tbs, err := ioutil.ReadAll(src)\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke reading: \", err.Error())\n\t}\n\n\t_, err = dst.Write(bs)\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke writing: \", err.Error())\n\t}\n}\n\n/*\n\nstep 1 - at command line enter:\ngo install\n\nstep 2 - at command line enter:\n01 initial.txt second.txt\n\n*/\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/08_cp/02/initial.txt",
    "content": "this is the starting text in the file"
  },
  {
    "path": "27_code-in-process/37_review-exercises/08_cp/02/main.go",
    "content": "package main\n\nimport (\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\n\tif len(os.Args) < 3 {\n\t\tlog.Fatalln(\"Usage: 01_this-does-not-compile <SRC> <DST>\")\n\t}\n\n\tsrcName := os.Args[1]\n\tdstName := os.Args[2]\n\n\tsrc, err := os.Open(srcName)\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke opening: \", err.Error())\n\t}\n\tdefer src.Close()\n\n\tdst, err := os.Create(dstName)\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke creating: \", err.Error())\n\t}\n\tdefer dst.Close()\n\n\tbs, err := ioutil.ReadAll(src)\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke reading: \", err.Error())\n\t}\n\n\t_, err = dst.Write(bs)\n\tif err != nil {\n\t\tlog.Fatalln(\"my program broke writing: \", err.Error())\n\t}\n}\n\n/*\n\nstep 1 - at command line enter:\ngo install\n\nstep 2 - at command line enter:\n01_this-does-not-compile initial.txt second.txt\n\n*/\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/08_cp/03/initial.txt",
    "content": "this is the starting text in the file"
  },
  {
    "path": "27_code-in-process/37_review-exercises/08_cp/03/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc cp(srcName, dstName string) error {\n\n\tsrc, err := os.Open(srcName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"my program broke opening: %v\", err)\n\t}\n\tdefer src.Close()\n\n\tdst, err := os.Create(dstName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"my program broke creating:%v \", err)\n\t}\n\tdefer dst.Close()\n\n\tbs, err := ioutil.ReadAll(src)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"my program broke reading: %v\", err)\n\t}\n\n\t_, err = dst.Write(bs)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"my program broke writing: %v\", err)\n\t}\n\n\treturn nil\n}\n\nfunc main() {\n\n\tif len(os.Args) < 3 {\n\t\tlog.Fatalln(\"Usage: 03 <SRC> <DST>\")\n\t}\n\n\tsrcName := os.Args[1]\n\tdstName := os.Args[2]\n\n\terr := cp(srcName, dstName)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n}\n\n// THE PROBLEM WITH THIS PROGRAM:\n// it reads the entire file into memory\n// not good if you're copying a multi-gigabyte file\n\n/*\n\nstep 1 - at command line enter:\ngo install\n\nstep 2 - at command line enter:\n03 initial.txt second.txt\n\n*/\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/08_cp/04_io-copy/initial.txt",
    "content": "this is the starting text in the file"
  },
  {
    "path": "27_code-in-process/37_review-exercises/08_cp/04_io-copy/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc cp(srcName, dstName string) error {\n\n\tsrc, err := os.Open(srcName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error opening source file: %v\", err)\n\t}\n\tdefer src.Close()\n\n\tdst, err := os.Create(dstName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating destination file:%v \", err)\n\t}\n\tdefer dst.Close()\n\n\t_, err = io.Copy(dst, src)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error writing to destination file: %v \", err)\n\t}\n\n\treturn nil\n}\n\nfunc main() {\n\n\tif len(os.Args) < 3 {\n\t\tlog.Fatalln(\"Usage: 04_io-copy <SRC> <DST>\")\n\t}\n\n\tsrcName := os.Args[1]\n\tdstName := os.Args[2]\n\n\terr := cp(srcName, dstName)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n}\n\n/*\n\nstep 1 - at command line enter:\ngo install\n\nstep 2 - at command line enter:\n04_io-copy initial.txt second.txt\n\n*/\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/08_cp/05_os-write_slice-bytes/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\n\tdst, err := os.Create(os.Args[1])\n\tif err != nil {\n\t\tlog.Fatalf(\"error creating destination file:%v \", err)\n\t}\n\tdefer dst.Close()\n\n\tdst.Write([]byte(\"Hello World\"))\n}\n\n/*\n\nos.Create\nfunc Create(name string) (*File, error)\n\nos\nfunc (f *File) Write(b []byte) (n int, err error)\n\nos\nfunc (f *File) Read(b []byte) (n int, err error)\n\n*/\n\n/*\n\nstep 1 - at command line enter:\ngo install\n\nstep 2 - at command line enter:\nprogramName initial.txt second.txt\n\n*/\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/08_cp/06_io-copy_string-NewReader/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\n\tdst, err := os.Create(os.Args[1])\n\tif err != nil {\n\t\tlog.Fatalf(\"error creating destination file:%v \", err)\n\t}\n\tdefer dst.Close()\n\n\trdr := strings.NewReader(\"hello world\")\n\n\tio.Copy(dst, rdr)\n}\n\n/*\n\nio.Copy\nfunc Copy(dst Writer, src Reader) (written int64, err error)\n\nstrings.NewReader\nfunc NewReader(s string) *Reader\n\nstrings\nfunc (r *Reader) Read(b []byte) (n int, err error)\n\n*/\n\n/*\n\nstep 1 - at command line enter:\ngo install\n\nstep 2 - at command line enter:\nprogramName initial.txt second.txt\n\n*/\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/08_cp/07_io-copy_bufio-NewReader/initial.txt",
    "content": "this is the starting text in the file"
  },
  {
    "path": "27_code-in-process/37_review-exercises/08_cp/07_io-copy_bufio-NewReader/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc cp(srcName, dstName string) error {\n\n\tsrc, err := os.Open(srcName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error opening source file: %v\", err)\n\t}\n\tdefer src.Close()\n\n\tdst, err := os.Create(dstName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating destination file:%v \", err)\n\t}\n\tdefer dst.Close()\n\n\tbr := bufio.NewReader(src)\n\n\t_, err = io.Copy(dst, br)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error writing to destination file: %v \", err)\n\t}\n\n\treturn nil\n}\n\nfunc main() {\n\n\tif len(os.Args) < 3 {\n\t\tlog.Fatalln(\"Usage: 07_bufio_io-copy <SRC> <DST>\")\n\t}\n\n\tsrcName := os.Args[1]\n\tdstName := os.Args[2]\n\n\terr := cp(srcName, dstName)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n}\n\n/*\n\nstep 1 - at command line enter:\ngo install\n\nstep 2 - at command line enter:\nprogramName initial.txt second.txt\n\n*/\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/08_cp/08_bufio_scanner/initial.txt",
    "content": "line #1\nline #2\nline #3\nDo we really want to travel in hermetically sealed popemobiles through the rural provinces of France, Mexico and the Far East, eating only in Hard Rock Cafes and McDonalds? Or do we want to eat without fear, tearing into the local stew, the humble taqueria's mystery meat, the sincerely offered gift of a lightly grilled fish head? I know what I want. I want it all. I want to try everything once.\nI don't have to agree with you to like you or respect you.\nTravel changes you. As you move through this life and this world you change things slightly, you leave marks behind, however small. And in return, life - and travel - leaves marks on you. Most of the time, those marks - on your body or on your heart - are beautiful. Often, though, they hurt.\nVegetarians, and their Hezbollah-like splinter faction, the vegans ... are the enemy of everything good and decent in the human spirit.\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/08_cp/08_bufio_scanner/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\tsrc, err := os.Open(\"initial.txt\")\n\tif err != nil {\n\t\tlog.Printf(\"error opening source file: %v\", err)\n\t}\n\tdefer src.Close()\n\n\tscanner := bufio.NewScanner(src)\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\t\tfmt.Println(\">>>\", line)\n\t}\n}\n\n/*\nscanners allow us to interact with files line-by-line\n*/\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/09_sentence-case/initial.txt",
    "content": "line #1\nline #2\nline #3\nDo we really want to travel in hermetically sealed popemobiles through the rural provinces of France, Mexico and the Far East, eating only in Hard Rock Cafes and McDonalds? Or do we want to eat without fear, tearing into the local stew, the humble taqueria's mystery meat, the sincerely offered gift of a lightly grilled fish head? I know what I want. I want it all. I want to try everything once.\nI don't have to agree with you to like you or respect you.\nTravel changes you. As you move through this life and this world you change things slightly, you leave marks behind, however small. And in return, life - and travel - leaves marks on you. Most of the time, those marks - on your body or on your heart - are beautiful. Often, though, they hurt.\nVegetarians, and their Hezbollah-like splinter faction, the vegans ... are the enemy of everything good and decent in the human spirit.\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/09_sentence-case/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tsrc, err := os.Open(\"initial.txt\")\n\tif err != nil {\n\t\tlog.Printf(\"error opening source file: %v\", err)\n\t}\n\tdefer src.Close()\n\n\tscanner := bufio.NewScanner(src)\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\t\tif len(line) > 0 {\n\t\t\tfmt.Println(\">>>\", strings.ToUpper(line[0:1])+line[1:], \"\\n\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/10_every-word/initial.txt",
    "content": "line #1\nline #2\nline #3\nDo we really want to travel in hermetically sealed popemobiles through the rural provinces of France, Mexico and the Far East, eating only in Hard Rock Cafes and McDonalds? Or do we want to eat without fear, tearing into the local stew, the humble taqueria's mystery meat, the sincerely offered gift of a lightly grilled fish head? I know what I want. I want it all. I want to try everything once.\nI don't have to agree with you to like you or respect you.\nTravel changes you. As you move through this life and this world you change things slightly, you leave marks behind, however small. And in return, life - and travel - leaves marks on you. Most of the time, those marks - on your body or on your heart - are beautiful. Often, though, they hurt.\nVegetarians, and their Hezbollah-like splinter faction, the vegans ... are the enemy of everything good and decent in the human spirit.\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/10_every-word/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tsrc, err := os.Open(\"initial.txt\")\n\tif err != nil {\n\t\tlog.Printf(\"error opening source file: %v\", err)\n\t}\n\tdefer src.Close()\n\n\tscanner := bufio.NewScanner(src)\n\tscanner.Split(bufio.ScanWords)\n\tfor scanner.Scan() {\n\t\tword := scanner.Text()\n\t\tif len(word) > 0 {\n\t\t\tfmt.Print(strings.ToUpper(word[0:1])+word[1:], \" \")\n\t\t}\n\t}\n\tfmt.Println()\n}\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/11_every-other-word/initial.txt",
    "content": "line #1\nline #2\nline #3\nDo we really want to travel in hermetically sealed popemobiles through the rural provinces of France, Mexico and the Far East, eating only in Hard Rock Cafes and McDonalds? Or do we want to eat without fear, tearing into the local stew, the humble taqueria's mystery meat, the sincerely offered gift of a lightly grilled fish head? I know what I want. I want it all. I want to try everything once.\nI don't have to agree with you to like you or respect you.\nTravel changes you. As you move through this life and this world you change things slightly, you leave marks behind, however small. And in return, life - and travel - leaves marks on you. Most of the time, those marks - on your body or on your heart - are beautiful. Often, though, they hurt.\nVegetarians, and their Hezbollah-like splinter faction, the vegans ... are the enemy of everything good and decent in the human spirit.\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/11_every-other-word/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tsrc, err := os.Open(\"initial.txt\")\n\tif err != nil {\n\t\tlog.Printf(\"error opening source file: %v\", err)\n\t}\n\tdefer src.Close()\n\n\ti := 0\n\tscanner := bufio.NewScanner(src)\n\tscanner.Split(bufio.ScanWords)\n\tfor scanner.Scan() {\n\t\tword := scanner.Text()\n\t\tif len(word) > 0 && i%2 == 0 {\n\t\t\tfmt.Print(strings.ToUpper(word), \" \")\n\t\t} else {\n\t\t\tfmt.Print(word, \" \")\n\t\t}\n\t\ti++\n\t}\n\tfmt.Println()\n}\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/12_count-words/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc wordCount(rdr io.Reader) map[string]int {\n\tcounts := map[string]int{}\n\tscanner := bufio.NewScanner(rdr)\n\tscanner.Split(bufio.ScanWords)\n\tfor scanner.Scan() {\n\t\tword := scanner.Text()\n\t\tword = strings.ToLower(word)\n\t\tword = strings.Replace(word, \",\", \"\", 1)\n\t\tword = strings.Replace(word, \".\", \"\", 1)\n\t\tcounts[word]++\n\t}\n\treturn counts\n}\n\nfunc main() {\n\tsrcFile, err := os.Open(\"moby10b.txt\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer srcFile.Close()\n\n\tcounts := wordCount(srcFile)\n\tfmt.Println(counts[\"whale\"])\n\n}\n\n/*\nget moby dick from terminal:\ncurl -O http://www.gutenberg.org/files/2701/old/moby10b.txt\n*/\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/13_longest-word/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc longestWord(rdr io.Reader) string {\n\tlongWord := \"\"\n\tscanner := bufio.NewScanner(rdr)\n\tscanner.Split(bufio.ScanWords)\n\tfor scanner.Scan() {\n\t\tword := scanner.Text()\n\t\tif len(word) > len(longWord) {\n\t\t\tlongWord = word\n\t\t}\n\t}\n\treturn longWord\n}\n\nfunc main() {\n\tsrcFile, err := os.Open(\"moby10b.txt\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer srcFile.Close()\n\n\tfmt.Println(longestWord(srcFile))\n\n}\n\n/*\nget moby dick from terminal:\ncurl -O http://www.gutenberg.org/files/2701/old/moby10b.txt\n*/\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/14_cat-files/01/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\tfor _, v := range os.Args[1:] {\n\t\tf, err := os.Open(v)\n\t\tif err != nil {\n\t\t\tlog.Fatalln(\"my program broke: \", err.Error())\n\t\t}\n\t\tdefer f.Close()\n\n\t\tio.Copy(os.Stdout, f)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/14_cat-files/02/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\trdrs := make([]io.Reader, len(os.Args)-1)\n\tfor i, v := range os.Args[1:] {\n\t\tf, err := os.Open(v)\n\t\tif err != nil {\n\t\t\tlog.Fatalln(\"my program broke: \", err.Error())\n\t\t}\n\t\tdefer f.Close()\n\t\trdrs[i] = f\n\t}\n\n\trdr := io.MultiReader(rdrs...)\n\n\tio.Copy(os.Stdout, rdr)\n}\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/15_csv_state-info/state_table.csv",
    "content": "id,name,abbreviation,country,type,sort,status,occupied,notes,fips_state,assoc_press,standard_federal_region,census_region,census_region_name,census_division,census_division_name,circuit_court\n\"1\",\"Alabama\",\"AL\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"1\",\"Ala.\",\"IV\",\"3\",\"South\",\"6\",\"East South Central\",\"11\"\n\"2\",\"Alaska\",\"AK\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"2\",\"Alaska\",\"X\",\"4\",\"West\",\"9\",\"Pacific\",\"9\"\n\"3\",\"Arizona\",\"AZ\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"4\",\"Ariz.\",\"IX\",\"4\",\"West\",\"8\",\"Mountain\",\"9\"\n\"4\",\"Arkansas\",\"AR\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"5\",\"Ark.\",\"VI\",\"3\",\"South\",\"7\",\"West South Central\",\"8\"\n\"5\",\"California\",\"CA\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"6\",\"Calif.\",\"IX\",\"4\",\"West\",\"9\",\"Pacific\",\"9\"\n\"6\",\"Colorado\",\"CO\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"8\",\"Colo.\",\"VIII\",\"4\",\"West\",\"8\",\"Mountain\",\"10\"\n\"7\",\"Connecticut\",\"CT\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"9\",\"Conn.\",\"I\",\"1\",\"Northeast\",\"1\",\"New England\",\"2\"\n\"8\",\"Delaware\",\"DE\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"10\",\"Del.\",\"III\",\"3\",\"South\",\"5\",\"South Atlantic\",\"3\"\n\"9\",\"Florida\",\"FL\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"12\",\"Fla.\",\"IV\",\"3\",\"South\",\"5\",\"South Atlantic\",\"11\"\n\"10\",\"Georgia\",\"GA\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"13\",\"Ga.\",\"IV\",\"3\",\"South\",\"5\",\"South Atlantic\",\"11\"\n\"11\",\"Hawaii\",\"HI\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"15\",\"Hawaii\",\"IX\",\"4\",\"West\",\"9\",\"Pacific\",\"9\"\n\"12\",\"Idaho\",\"ID\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"16\",\"Idaho\",\"X\",\"4\",\"West\",\"8\",\"Mountain\",\"9\"\n\"13\",\"Illinois\",\"IL\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"17\",\"Ill.\",\"V\",\"2\",\"Midwest\",\"3\",\"East North Central\",\"7\"\n\"14\",\"Indiana\",\"IN\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"18\",\"Ind.\",\"V\",\"2\",\"Midwest\",\"3\",\"East North Central\",\"7\"\n\"15\",\"Iowa\",\"IA\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"19\",\"Iowa\",\"VII\",\"2\",\"Midwest\",\"4\",\"West North Central\",\"8\"\n\"16\",\"Kansas\",\"KS\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"20\",\"Kan.\",\"VII\",\"2\",\"Midwest\",\"4\",\"West North Central\",\"10\"\n\"17\",\"Kentucky\",\"KY\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"21\",\"Ky.\",\"IV\",\"3\",\"South\",\"6\",\"East South Central\",\"6\"\n\"18\",\"Louisiana\",\"LA\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"22\",\"La.\",\"VI\",\"3\",\"South\",\"7\",\"West South Central\",\"5\"\n\"19\",\"Maine\",\"ME\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"23\",\"Maine\",\"I\",\"1\",\"Northeast\",\"1\",\"New England\",\"1\"\n\"20\",\"Maryland\",\"MD\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"24\",\"Md.\",\"III\",\"3\",\"South\",\"5\",\"South Atlantic\",\"4\"\n\"21\",\"Massachusetts\",\"MA\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"25\",\"Mass.\",\"I\",\"1\",\"Northeast\",\"1\",\"New England\",\"1\"\n\"22\",\"Michigan\",\"MI\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"26\",\"Mich.\",\"V\",\"2\",\"Midwest\",\"3\",\"East North Central\",\"6\"\n\"23\",\"Minnesota\",\"MN\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"27\",\"Minn.\",\"V\",\"2\",\"Midwest\",\"4\",\"West North Central\",\"8\"\n\"24\",\"Mississippi\",\"MS\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"28\",\"Miss.\",\"IV\",\"3\",\"South\",\"6\",\"East South Central\",\"5\"\n\"25\",\"Missouri\",\"MO\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"29\",\"Mo.\",\"VII\",\"2\",\"Midwest\",\"4\",\"West North Central\",\"8\"\n\"26\",\"Montana\",\"MT\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"30\",\"Mont.\",\"VIII\",\"4\",\"West\",\"8\",\"Mountain\",\"9\"\n\"27\",\"Nebraska\",\"NE\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"31\",\"Nebr.\",\"VII\",\"2\",\"Midwest\",\"4\",\"West North Central\",\"8\"\n\"28\",\"Nevada\",\"NV\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"32\",\"Nev.\",\"IX\",\"4\",\"West\",\"8\",\"Mountain\",\"9\"\n\"29\",\"New Hampshire\",\"NH\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"33\",\"N.H.\",\"I\",\"1\",\"Northeast\",\"1\",\"New England\",\"1\"\n\"30\",\"New Jersey\",\"NJ\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"34\",\"N.J.\",\"II\",\"1\",\"Northeast\",\"2\",\"Mid-Atlantic\",\"3\"\n\"31\",\"New Mexico\",\"NM\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"35\",\"N.M.\",\"VI\",\"4\",\"West\",\"8\",\"Mountain\",\"10\"\n\"32\",\"New York\",\"NY\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"36\",\"N.Y.\",\"II\",\"1\",\"Northeast\",\"2\",\"Mid-Atlantic\",\"2\"\n\"33\",\"North Carolina\",\"NC\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"37\",\"N.C.\",\"IV\",\"3\",\"South\",\"5\",\"South Atlantic\",\"4\"\n\"34\",\"North Dakota\",\"ND\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"38\",\"N.D.\",\"VIII\",\"2\",\"Midwest\",\"4\",\"West North Central\",\"8\"\n\"35\",\"Ohio\",\"OH\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"39\",\"Ohio\",\"V\",\"2\",\"Midwest\",\"3\",\"East North Central\",\"6\"\n\"36\",\"Oklahoma\",\"OK\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"40\",\"Okla.\",\"VI\",\"3\",\"South\",\"7\",\"West South Central\",\"10\"\n\"37\",\"Oregon\",\"OR\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"41\",\"Ore.\",\"X\",\"4\",\"West\",\"9\",\"Pacific\",\"9\"\n\"38\",\"Pennsylvania\",\"PA\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"42\",\"Pa.\",\"III\",\"1\",\"Northeast\",\"2\",\"Mid-Atlantic\",\"3\"\n\"39\",\"Rhode Island\",\"RI\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"44\",\"R.I.\",\"I\",\"1\",\"Northeast\",\"1\",\"New England\",\"1\"\n\"40\",\"South Carolina\",\"SC\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"45\",\"S.C.\",\"IV\",\"3\",\"South\",\"5\",\"South Atlantic\",\"4\"\n\"41\",\"South Dakota\",\"SD\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"46\",\"S.D.\",\"VIII\",\"2\",\"Midwest\",\"4\",\"West North Central\",\"8\"\n\"42\",\"Tennessee\",\"TN\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"47\",\"Tenn.\",\"IV\",\"3\",\"South\",\"6\",\"East South Central\",\"6\"\n\"43\",\"Texas\",\"TX\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"48\",\"Texas\",\"VI\",\"3\",\"South\",\"7\",\"West South Central\",\"5\"\n\"44\",\"Utah\",\"UT\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"49\",\"Utah\",\"VIII\",\"4\",\"West\",\"8\",\"Mountain\",\"10\"\n\"45\",\"Vermont\",\"VT\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"50\",\"Vt.\",\"I\",\"1\",\"Northeast\",\"1\",\"New England\",\"2\"\n\"46\",\"Virginia\",\"VA\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"51\",\"Va.\",\"III\",\"3\",\"South\",\"5\",\"South Atlantic\",\"4\"\n\"47\",\"Washington\",\"WA\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"53\",\"Wash.\",\"X\",\"4\",\"West\",\"9\",\"Pacific\",\"9\"\n\"48\",\"West Virginia\",\"WV\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"54\",\"W.Va.\",\"III\",\"3\",\"South\",\"5\",\"South Atlantic\",\"4\"\n\"49\",\"Wisconsin\",\"WI\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"55\",\"Wis.\",\"V\",\"2\",\"Midwest\",\"3\",\"East North Central\",\"7\"\n\"50\",\"Wyoming\",\"WY\",\"USA\",\"state\",\"10\",\"current\",\"occupied\",\"\",\"56\",\"Wyo.\",\"VIII\",\"4\",\"West\",\"8\",\"Mountain\",\"10\"\n\"51\",\"Washington DC\",\"DC\",\"USA\",\"capitol\",\"10\",\"current\",\"occupied\",\"\",\"11\",\"\",\"III\",\"3\",\"South\",\"5\",\"South Atlantic\",\"D.C.\"\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/15_csv_state-info/step01_read-and-output/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\t// #1 open a file\n\tf, err := os.Open(\"../state_table.csv\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer f.Close()\n\n\t// #2 parse a csv file\n\tcsvReader := csv.NewReader(f)\n\tfor {\n\t\trecord, err := csvReader.Read()\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\t\tfmt.Println(record)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/15_csv_state-info/step02_column-headings/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\t// #1 open a file\n\tf, err := os.Open(\"../state_table.csv\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer f.Close()\n\n\t// #2 parse a csv file\n\tcsvReader := csv.NewReader(f)\n\tfor rowCount := 0; ; rowCount++ {\n\t\trecord, err := csvReader.Read()\n\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\n\t\tcolumns := make(map[string]int)\n\t\tif rowCount == 0 {\n\t\t\tfor idx, column := range record {\n\t\t\t\tcolumns[column] = idx\n\t\t\t}\n\t\t}\n\n\t\tfmt.Println(columns)\n\t\tbreak\n\t}\n\t// #3 do stuff for each row\n\t// #4 print out a table of information\n}\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/15_csv_state-info/step03_panics/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n)\n\ntype state struct {\n\tid               int\n\tname             string\n\tabbreviation     string\n\tcensusRegionName string\n}\n\nfunc parseState(columns map[string]int, record []string) (*state, error) {\n\tpanic(\"not implemented\")\n}\n\nfunc main() {\n\t// #1 open a file\n\tf, err := os.Open(\"../state_table.csv\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer f.Close()\n\n\t// #2 parse a csv file\n\tcsvReader := csv.NewReader(f)\n\tcolumns := make(map[string]int)\n\n\tfor rowCount := 0; ; rowCount++ {\n\t\trecord, err := csvReader.Read()\n\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\n\t\tif rowCount == 0 {\n\t\t\tfor idx, column := range record {\n\t\t\t\tcolumns[column] = idx\n\t\t\t}\n\t\t} else {\n\t\t\tstate, err := parseState(columns, record)\n\t\t\tif err != nil {\n\t\t\t\tlog.Fatalln(err)\n\t\t\t}\n\t\t\tlog.Println(state)\n\t\t}\n\t}\n\t// #3 do stuff for each row\n\t// #4 print out a table of information\n}\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/15_csv_state-info/step04_parse-state/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"strconv\"\n)\n\ntype state struct {\n\tid               int\n\tname             string\n\tabbreviation     string\n\tcensusRegionName string\n}\n\nfunc parseState(columns map[string]int, record []string) (*state, error) {\n\tid, err := strconv.Atoi(record[columns[\"id\"]])\n\tname := record[columns[\"name\"]]\n\tabbreviation := record[columns[\"abbreviation\"]]\n\tcensusRegionName := record[columns[\"census_region_name\"]]\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &state{\n\t\tid:               id,\n\t\tname:             name,\n\t\tabbreviation:     abbreviation,\n\t\tcensusRegionName: censusRegionName,\n\t}, nil\n}\n\nfunc main() {\n\t// #1 open a file\n\tf, err := os.Open(\"../state_table.csv\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer f.Close()\n\n\t// #2 parse a csv file\n\tcsvReader := csv.NewReader(f)\n\tcolumns := make(map[string]int)\n\n\tfor rowCount := 0; ; rowCount++ {\n\t\trecord, err := csvReader.Read()\n\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\n\t\tif rowCount == 0 {\n\t\t\tfor idx, column := range record {\n\t\t\t\tcolumns[column] = idx\n\t\t\t}\n\t\t} else {\n\t\t\t// #3 do stuff for each row\n\t\t\tstate, err := parseState(columns, record)\n\t\t\tif err != nil {\n\t\t\t\tlog.Fatalln(err)\n\t\t\t}\n\t\t\t// #4 print out each row\n\t\t\tlog.Println(state)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/15_csv_state-info/step05_state-lookup/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"strconv\"\n)\n\ntype state struct {\n\tid               int\n\tname             string\n\tabbreviation     string\n\tcensusRegionName string\n}\n\nfunc parseState(columns map[string]int, record []string) (*state, error) {\n\tid, err := strconv.Atoi(record[columns[\"id\"]])\n\tname := record[columns[\"name\"]]\n\tabbreviation := record[columns[\"abbreviation\"]]\n\tcensusRegionName := record[columns[\"census_region_name\"]]\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &state{\n\t\tid:               id,\n\t\tname:             name,\n\t\tabbreviation:     abbreviation,\n\t\tcensusRegionName: censusRegionName,\n\t}, nil\n}\n\nfunc main() {\n\t// #1 open a file\n\tf, err := os.Open(\"../state_table.csv\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer f.Close()\n\n\t// #2 parse a csv file\n\tcsvReader := csv.NewReader(f)\n\tcolumns := make(map[string]int)\n\n\tstateLookup := map[string]*state{}\n\n\tfor rowCount := 0; ; rowCount++ {\n\t\trecord, err := csvReader.Read()\n\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\n\t\tif rowCount == 0 {\n\t\t\tfor idx, column := range record {\n\t\t\t\tcolumns[column] = idx\n\t\t\t}\n\t\t} else {\n\t\t\t// #3 do stuff for each row\n\t\t\tstate, err := parseState(columns, record)\n\t\t\tif err != nil {\n\t\t\t\tlog.Fatalln(err)\n\t\t\t}\n\t\t\t// #4 add each row to stateLookup map\n\t\t\tstateLookup[state.abbreviation] = state\n\t\t}\n\t}\n\n\t// #5 lookup the state\n\tif len(os.Args) < 2 {\n\t\tlog.Fatalln(\"expected state abbreviation\")\n\t}\n\tabbreviation := os.Args[1]\n\tstate, ok := stateLookup[abbreviation]\n\tif !ok {\n\t\tlog.Fatalln(\"invalid state abbreviation\")\n\t}\n\tfmt.Println(state)\n}\n\n/*\nat terminal:\ngo install\n\nat terminal:\nprogramName <state abbreviation>\n\nfor example:\nstep05_state-lookup CA\n\nwill show this:\n&{5 California CA West}\n\n*/\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/15_csv_state-info/step06_write-to-html/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"strconv\"\n)\n\ntype state struct {\n\tid               int\n\tname             string\n\tabbreviation     string\n\tcensusRegionName string\n}\n\nfunc parseState(columns map[string]int, record []string) (*state, error) {\n\tid, err := strconv.Atoi(record[columns[\"id\"]])\n\tname := record[columns[\"name\"]]\n\tabbreviation := record[columns[\"abbreviation\"]]\n\tcensusRegionName := record[columns[\"census_region_name\"]]\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &state{\n\t\tid:               id,\n\t\tname:             name,\n\t\tabbreviation:     abbreviation,\n\t\tcensusRegionName: censusRegionName,\n\t}, nil\n}\n\nfunc main() {\n\t// #1 open a file\n\tf, err := os.Open(\"../state_table.csv\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer f.Close()\n\n\t// #2 parse a csv file\n\tcsvReader := csv.NewReader(f)\n\tcolumns := make(map[string]int)\n\n\tstateLookup := map[string]*state{}\n\n\tfor rowCount := 0; ; rowCount++ {\n\t\trecord, err := csvReader.Read()\n\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\n\t\tif rowCount == 0 {\n\t\t\tfor idx, column := range record {\n\t\t\t\tcolumns[column] = idx\n\t\t\t}\n\t\t} else {\n\t\t\t// #3 do stuff for each row\n\t\t\tstate, err := parseState(columns, record)\n\t\t\tif err != nil {\n\t\t\t\tlog.Fatalln(err)\n\t\t\t}\n\t\t\t// #4 add each row to stateLookup map\n\t\t\tstateLookup[state.abbreviation] = state\n\t\t}\n\t}\n\n\t// #5 lookup the state\n\tif len(os.Args) < 2 {\n\t\tlog.Fatalln(\"expected state abbreviation\")\n\t}\n\tabbreviation := os.Args[1]\n\tstate, ok := stateLookup[abbreviation]\n\tif !ok {\n\t\tlog.Fatalln(\"invalid state abbreviation\")\n\t}\n\tfmt.Println(`\n<html>\n    <head></head>\n    <body>\n      <table>\n        <tr>\n          <th>Abbreviation</th>\n          <th>Name</th>\n        </tr>`)\n\n\tfmt.Println(`\n        <tr>\n          <td>` + state.abbreviation + `</td>\n          <td>` + state.name + `</td>\n        </tr>\n    `)\n\n\tfmt.Println(`\n      </table>\n    </body>\n</html>\n    `)\n}\n\n/*\nat terminal:\ngo install\n\nat terminal:\nprogramName <state abbreviation> > index.html\n\n*/\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/16_csv_stock-prices/step01_stdout/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n)\n\ntype record struct {\n\tDate string\n\tOpen float64\n}\n\nfunc makeRecord(row []string) record {\n\topen, _ := strconv.ParseFloat(row[1], 64)\n\treturn record{\n\t\tDate: row[0],\n\t\tOpen: open,\n\t}\n}\n\nfunc main() {\n\tf, err := os.Open(\"../table.csv\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer f.Close()\n\n\trdr := csv.NewReader(f)\n\trows, err := rdr.ReadAll()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfor i, row := range rows {\n\t\tif i == 0 {\n\t\t\tcontinue\n\t\t}\n\t\trecord := makeRecord(row)\n\t\tfmt.Println(record)\n\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/16_csv_stock-prices/step02_html/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n)\n\ntype record struct {\n\tDate string\n\tOpen float64\n}\n\nfunc makeRecord(row []string) record {\n\topen, _ := strconv.ParseFloat(row[1], 64)\n\treturn record{\n\t\tDate: row[0],\n\t\tOpen: open,\n\t}\n}\n\nfunc main() {\n\tf, err := os.Open(\"../table.csv\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer f.Close()\n\n\trdr := csv.NewReader(f)\n\trows, err := rdr.ReadAll()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfmt.Println(`<!DOCTYPE html>\n<head></head>\n<body>\n  <table>\n    <thead>\n      <tr>\n        <th>Date</th>\n        <th>Open</th>\n      </tr>\n    </thead>\n    <tbody>\n    `)\n\n\tfor i, row := range rows {\n\t\tif i == 0 {\n\t\t\tcontinue\n\t\t}\n\t\trecord := makeRecord(row)\n\t\tfmt.Println(`\n      <tr>\n        <td>` + record.Date + `</td>\n        <td>` + fmt.Sprintf(\"%.2f\", record.Open) + `</td>\n      </tr>\n      `)\n\n\t}\n\n\tfmt.Println(`\n    </tbody>\n  </table>\n</body>\n    `)\n}\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/16_csv_stock-prices/step03_charting/charting_graphing.txt",
    "content": "http://www.highcharts.com/"
  },
  {
    "path": "27_code-in-process/37_review-exercises/16_csv_stock-prices/step03_charting/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n)\n\ntype record struct {\n\tDate string\n\tOpen float64\n}\n\nfunc makeRecord(row []string) record {\n\topen, _ := strconv.ParseFloat(row[1], 64)\n\treturn record{\n\t\tDate: row[0],\n\t\tOpen: open,\n\t}\n}\n\nfunc main() {\n\tf, err := os.Open(\"table.csv\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer f.Close()\n\n\trdr := csv.NewReader(f)\n\trows, err := rdr.ReadAll()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfmt.Println(`<!DOCTYPE html>\n<head>\n<script src=\"http://code.jquery.com/jquery-1.11.3.min.js\"></script>\n<script src=\"http://code.highcharts.com/highcharts.js\"></script>\n<script src=\"http://code.highcharts.com/modules/exporting.js\"></script>\n</head>\n<body>\n<div id=\"container\" style=\"min-width: 310px; height: 400px; margin: 0 auto\"></div>\n\n\n\n  <table>\n    <thead>\n      <tr>\n        <th>Date</th>\n        <th>Open</th>\n      </tr>\n    </thead>\n    <tbody>\n    `)\n\n\topenValues := []string{}\n\n\tfor i, row := range rows {\n\t\tif i == 0 {\n\t\t\tcontinue\n\t\t}\n\t\trecord := makeRecord(row)\n\t\tfmt.Println(`\n      <tr>\n        <td>` + record.Date + `</td>\n        <td>` + fmt.Sprintf(\"%.2f\", record.Open) + `</td>\n      </tr>\n      `)\n\n\t\topenValues = append(openValues, fmt.Sprintf(\"%.2f\", record.Open))\n\n\t}\n\n\tfmt.Println(`\n    </tbody>\n  </table>\n\n  <script>\n  $(function () {\n      $('#container').highcharts({\n          title: {\n              text: 'Monthly Average Temperature',\n              x: -20 //center\n          },\n          subtitle: {\n              text: 'Source: WorldClimate.com',\n              x: -20\n          },\n          xAxis: {\n              categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',\n                  'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']\n          },\n          yAxis: {\n              title: {\n                  text: 'Temperature (°C)'\n              },\n              plotLines: [{\n                  value: 0,\n                  width: 1,\n                  color: '#808080'\n              }]\n          },\n          tooltip: {\n              valueSuffix: '°C'\n          },\n          legend: {\n              layout: 'vertical',\n              align: 'right',\n              verticalAlign: 'middle',\n              borderWidth: 0\n          },\n          series: [{\n              name: 'Tokyo',\n              data: [\n\n` + strings.Join(openValues, \",\") + `\n\n              ]\n          }]\n      });\n  });\n  </script>\n</body>\n    `)\n}\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/16_csv_stock-prices/table.csv",
    "content": "Date,Open,High,Low,Close,Volume,Adj Close\n2015-07-09,523.119995,523.77002,520.349976,520.679993,1839400,520.679993\n2015-07-08,521.049988,522.734009,516.109985,516.830017,1264600,516.830017\n2015-07-07,523.130005,526.179993,515.179993,525.02002,1595700,525.02002\n2015-07-06,519.50,525.25,519.00,522.859985,1276500,522.859985\n2015-07-02,521.080017,524.650024,521.080017,523.400024,1234000,523.400024\n2015-07-01,524.72998,525.690002,518.22998,521.840027,1961000,521.840027\n2015-06-30,526.02002,526.25,520.50,520.51001,2217200,520.51001\n2015-06-29,525.01001,528.609985,520.539978,521.52002,1930900,521.52002\n2015-06-26,537.26001,537.76001,531.349976,531.690002,2011500,531.690002\n2015-06-25,538.869995,540.900024,535.22998,535.22998,1331500,535.22998\n2015-06-24,540.00,540.00,535.659973,537.840027,1283400,537.840027\n2015-06-23,539.640015,541.499023,535.25,540.47998,1196000,540.47998\n2015-06-22,539.590027,543.73999,537.530029,538.190002,1242500,538.190002\n2015-06-19,537.210022,538.25,533.01001,536.690002,1885700,536.690002\n2015-06-18,531.00,538.150024,530.789978,536.72998,1828100,536.72998\n2015-06-17,529.369995,530.97998,525.099976,529.26001,1268600,529.26001\n2015-06-16,528.400024,529.640015,525.559998,528.150024,1069300,528.150024\n2015-06-15,528.00,528.299988,524.00,527.200012,1630700,527.200012\n2015-06-12,531.599976,533.119995,530.159973,532.330017,952400,532.330017\n2015-06-11,538.424988,538.97998,533.02002,534.609985,1205000,534.609985\n2015-06-10,529.359985,538.359985,529.349976,536.690002,1811400,536.690002\n2015-06-09,527.559998,529.200012,523.01001,526.690002,1441600,526.690002\n2015-06-08,533.309998,534.119995,526.23999,526.830017,1520600,526.830017\n2015-06-05,536.349976,537.200012,532.52002,533.330017,1375000,533.330017\n2015-06-04,537.76001,540.590027,534.320007,536.700012,1335600,536.700012\n2015-06-03,539.909973,543.50,537.109985,540.309998,1714500,540.309998\n2015-06-02,532.929993,543.00,531.330017,539.179993,1934700,539.179993\n2015-06-01,536.789978,536.789978,529.76001,533.98999,1899600,533.98999\n2015-05-29,537.369995,538.630005,531.450012,532.109985,2584900,532.109985\n2015-05-28,538.01001,540.609985,536.25,539.780029,1027900,539.780029\n2015-05-27,532.799988,540.549988,531.710022,539.789978,1520400,539.789978\n2015-05-26,538.119995,539.00,529.880005,532.320007,2403400,532.320007\n2015-05-22,540.150024,544.190002,539.51001,540.109985,1173300,540.109985\n2015-05-21,537.950012,543.840027,535.97998,542.51001,1461400,542.51001\n2015-05-20,538.48999,542.919983,532.971985,539.27002,1429100,539.27002\n2015-05-19,533.97998,540.659973,533.039978,537.359985,1963300,537.359985\n2015-05-18,532.01001,534.820007,528.849976,532.299988,1998600,532.299988\n2015-05-15,539.179993,539.273987,530.380005,533.849976,1962700,533.849976\n2015-05-14,533.77002,539.00,532.409973,538.400024,1399100,538.400024\n2015-05-13,530.559998,534.322021,528.655029,529.619995,1252300,529.619995\n2015-05-12,531.599976,533.208984,525.26001,529.039978,1625400,529.039978\n2015-05-11,538.369995,541.97998,535.400024,535.700012,905300,535.700012\n2015-05-08,536.650024,541.150024,525.00,538.219971,1527600,538.219971\n2015-05-07,523.98999,533.460022,521.75,530.700012,1546300,530.700012\n2015-05-06,531.23999,532.380005,521.085022,524.219971,1567000,524.219971\n2015-05-05,538.210022,539.73999,530.390991,530.799988,1383100,530.799988\n2015-05-04,538.530029,544.070007,535.059998,540.780029,1308000,540.780029\n2015-05-01,538.429993,539.539978,532.099976,537.900024,1768200,537.900024\n2015-04-30,547.869995,548.590027,535.049988,537.340027,2082200,537.340027\n2015-04-29,550.469971,553.679993,546.905029,549.080017,1698800,549.080017\n2015-04-28,554.640015,556.02002,550.366028,553.679993,1491000,553.679993\n2015-04-27,563.390015,565.950012,553.200012,555.369995,2398000,555.369995\n2015-04-24,566.102522,571.14259,557.252507,565.062561,4932500,565.062561\n2015-04-23,541.002435,550.96249,540.23244,547.002472,4184900,547.002472\n2015-04-22,534.402426,541.082489,531.752397,539.367458,1593600,539.367458\n2015-04-21,537.512456,539.392429,533.677415,533.972413,1844800,533.972413\n2015-04-20,525.602352,536.092424,524.50235,535.382408,1679300,535.382408\n2015-04-17,528.662379,529.842435,521.012371,524.052386,2144100,524.052386\n2015-04-16,529.902414,535.592457,529.612373,533.802391,1299900,533.802391\n2015-04-15,528.702406,534.732432,523.22235,532.532429,2318800,532.532429\n2015-04-14,536.252409,537.572435,528.094354,530.392405,2604100,530.392405\n2015-04-13,538.412385,544.062463,537.312445,539.172404,1645300,539.172404\n2015-04-10,542.292411,542.292411,537.312445,540.012477,1409500,540.012477\n2015-04-09,541.032486,541.95249,535.49239,540.782472,1557900,540.782472\n2015-04-08,538.382457,543.852415,538.382457,541.612446,1178500,541.612446\n2015-04-07,538.08244,542.692434,536.002395,537.022465,1302900,537.022465\n2015-04-06,532.222375,538.412385,529.572407,536.767432,1324400,536.767432\n2015-04-02,540.852427,540.852427,533.849395,535.532478,1716400,535.532478\n2015-04-01,548.602441,551.142488,539.502472,542.562439,1963100,542.562439\n2015-03-31,550.00246,554.712521,546.722468,548.002468,1588000,548.002468\n2015-03-30,551.622503,553.472487,548.17249,552.032502,1287500,552.032502\n2015-03-27,553.002509,555.282565,548.132463,548.342512,1897500,548.342512\n2015-03-26,557.59255,558.90254,550.652497,555.172522,1572600,555.172522\n2015-03-25,570.50259,572.262605,558.742494,558.787478,2152300,558.787478\n2015-03-24,562.562541,574.592603,561.212586,570.192597,2583300,570.192597\n2015-03-23,560.432554,562.362529,555.832536,558.81251,1643800,558.81251\n2015-03-20,561.652574,561.722529,559.052548,560.362537,2616900,560.362537\n2015-03-19,559.392531,560.802526,556.147548,557.992512,1197300,557.992512\n2015-03-18,552.50248,559.782578,547.002472,559.502513,2134500,559.502513\n2015-03-17,551.712533,553.802493,548.002468,550.842532,1805500,550.842532\n2015-03-16,550.952514,556.852484,546.002476,554.512509,1641000,554.512509\n2015-03-13,553.502537,558.402572,544.222448,547.322503,1703600,547.322503\n2015-03-12,553.512513,556.37253,550.462523,555.512505,1389600,555.512505\n2015-03-11,555.142533,558.142521,550.682486,551.182515,1820800,551.182515\n2015-03-10,564.252539,564.852512,554.732473,555.012538,1792300,555.012538\n2015-03-09,566.862541,570.272589,563.537504,568.852557,1062100,568.852557\n2015-03-06,574.882583,576.682625,566.762597,567.687558,1659100,567.687558\n2015-03-05,575.022616,577.912621,573.412548,575.332609,1389600,575.332609\n2015-03-04,571.872558,577.112576,568.012607,573.372583,1876800,573.372583\n2015-03-03,570.452587,575.392649,566.522559,573.64261,1704800,573.64261\n2015-03-02,560.532559,572.152623,558.752531,571.342601,2129600,571.342601\n2015-02-27,554.242482,564.712602,552.902503,558.402572,2410200,558.402572\n2015-02-26,543.212476,556.142529,541.502464,555.482516,2311500,555.482516\n2015-02-25,535.90245,546.22244,535.447406,543.872489,1826000,543.872489\n2015-02-24,530.002419,536.792403,528.252381,536.092424,1005100,536.092424\n2015-02-23,536.052398,536.441465,529.412361,531.912381,1457900,531.912381\n2015-02-20,543.132484,543.75247,535.802444,538.952441,1444400,538.952441\n2015-02-19,538.042413,543.11247,538.012424,542.872432,989100,542.872432\n2015-02-18,541.402458,545.492471,537.512456,539.702422,1453100,539.702422\n2015-02-17,546.832511,550.00246,541.092465,542.842504,1616800,542.842504\n2015-02-13,543.352447,549.912491,543.132484,549.012501,1900300,549.012501\n2015-02-12,537.252405,544.822482,534.675391,542.932472,1620200,542.932472\n2015-02-11,535.302416,538.452473,533.380397,535.972405,1377800,535.972405\n2015-02-10,529.302379,537.702431,526.922378,536.942412,1749900,536.942412\n2015-02-09,528.002366,532.002411,526.022388,527.832406,1267800,527.832406\n2015-02-06,527.642431,537.202463,526.412373,531.002415,1749400,531.002415\n2015-02-05,523.792334,528.502395,522.092359,527.582391,1849800,527.582391\n2015-02-04,529.2424,532.67442,521.272361,522.762349,1663700,522.762349\n2015-02-03,528.002366,533.40243,523.262377,529.2424,2038700,529.2424\n2015-02-02,531.732383,533.002407,518.552316,528.482381,2849800,528.482381\n2015-01-30,515.862322,539.872444,515.522339,534.522445,5606400,534.522445\n2015-01-29,511.002313,511.092313,501.202274,510.662331,4186400,510.662331\n2015-01-28,522.782423,522.992349,510.002318,510.002318,1683800,510.002318\n2015-01-27,529.972369,530.702398,518.192381,518.63237,1904000,518.63237\n2015-01-26,538.532466,539.002444,529.672413,535.212448,1543700,535.212448\n2015-01-23,535.592457,542.172453,533.002407,539.952437,2281700,539.952437\n2015-01-22,521.482349,536.332463,519.702382,534.39245,2676900,534.39245\n2015-01-21,507.252283,519.282407,506.202315,518.042312,2268700,518.042312\n2015-01-20,511.002313,512.502307,506.018277,506.902294,2227900,506.902294\n2015-01-16,500.012273,508.1923,500.002267,508.082288,2298300,508.082288\n2015-01-15,505.572291,505.682273,497.762267,501.792271,2715800,501.792271\n2015-01-14,494.652237,503.232286,493.002234,500.872267,2235700,500.872267\n2015-01-13,498.842256,502.982302,492.392254,496.182251,2370500,496.182251\n2015-01-12,494.942247,495.978261,487.562205,492.552209,2322400,492.552209\n2015-01-09,504.7623,504.922285,494.792239,496.172274,2069400,496.172274\n2015-01-08,497.992238,503.4823,491.002212,502.682255,3353600,502.682255\n2015-01-07,507.002299,507.246285,499.652247,501.102268,2065100,501.102268\n2015-01-06,515.002358,516.177334,501.052266,501.962262,2899900,501.962262\n2015-01-05,523.262377,524.332389,513.062315,513.872306,2059800,513.872306\n2015-01-02,529.012399,531.272443,524.102327,524.812404,1447600,524.812404\n2014-12-31,531.252429,532.602384,525.802363,526.402397,1368200,526.402397\n2014-12-30,528.092396,531.152424,527.132366,530.422394,876300,530.422394\n2014-12-29,532.192446,535.482414,530.013375,530.332426,2278500,530.332426\n2014-12-26,528.772422,534.252417,527.312364,534.032454,1036000,534.032454\n2014-12-24,530.512424,531.761394,527.022384,528.772422,705900,528.772422\n2014-12-23,527.00237,534.56241,526.292354,530.592416,2197600,530.592416\n2014-12-22,516.082347,526.462376,516.082347,524.872383,2723800,524.872383\n2014-12-19,511.512318,517.722342,506.91331,516.352313,3690200,516.352313\n2014-12-18,512.952333,513.872306,504.70229,511.102319,2926700,511.102319\n2014-12-17,497.002248,507.002299,496.812244,504.892295,2883200,504.892295\n2014-12-16,511.562321,513.052308,489.00222,495.392273,3964300,495.392273\n2014-12-15,522.742335,523.102331,513.272333,513.80229,2813400,513.80229\n2014-12-12,523.512391,528.502395,518.662298,518.662298,1994600,518.662298\n2014-12-11,527.802355,533.922411,527.102376,528.34241,1610800,528.34241\n2014-12-10,533.082399,536.332463,525.562386,526.062353,1712300,526.062353\n2014-12-09,522.142362,534.192438,520.502366,533.37244,1871300,533.37244\n2014-12-08,527.132366,531.002415,523.792334,526.982357,2329400,526.982357\n2014-12-05,531.002415,532.892425,524.282386,525.262369,2565600,525.262369\n2014-12-04,531.1624,537.342434,528.592424,537.312445,1392100,537.312445\n2014-12-03,531.442404,535.998416,529.262414,531.322384,1278000,531.322384\n2014-12-02,533.512412,535.502427,529.802408,533.752389,1525800,533.752389\n2014-12-01,538.902438,541.412434,531.862379,533.802391,2115400,533.802391\n2014-11-28,540.622426,542.002431,536.602429,541.832471,1148300,541.832471\n2014-11-26,540.882478,541.552406,537.044437,540.372412,1523000,540.372412\n2014-11-25,539.002444,543.98241,538.60444,541.082489,1789100,541.082489\n2014-11-24,537.652489,542.702471,535.622446,539.272471,1706000,539.272471\n2014-11-21,541.612446,542.142464,536.562402,537.502419,2223700,537.502419\n2014-11-20,531.252429,535.112381,531.082408,534.832438,1562000,534.832438\n2014-11-19,535.002399,538.242425,530.082412,536.992415,1391600,536.992415\n2014-11-18,537.502419,541.942452,534.172425,535.032449,1962700,535.032449\n2014-11-17,543.582448,543.792436,534.063361,536.512461,1725800,536.512461\n2014-11-14,546.682442,546.682442,542.152501,544.402507,1289200,544.402507\n2014-11-13,549.802448,549.802448,543.482442,545.38249,1339400,545.38249\n2014-11-12,550.392507,550.462523,545.172441,547.312465,1129400,547.312465\n2014-11-11,548.492459,551.942473,546.302493,550.29244,965500,550.29244\n2014-11-10,541.462498,549.592522,541.022449,547.492463,1134600,547.492463\n2014-11-07,546.212525,546.212525,538.672437,541.012473,1633800,541.012473\n2014-11-06,545.502448,546.887472,540.972385,542.042458,1333300,542.042458\n2014-11-05,556.802481,556.802481,544.052426,545.922423,2032300,545.922423\n2014-11-04,553.002509,555.502529,549.302481,554.112486,1244200,554.112486\n2014-11-03,555.502529,557.902544,553.23251,555.222464,1382300,555.222464\n2014-10-31,559.352504,559.572529,554.752486,559.082538,2035100,559.082538\n2014-10-30,548.952522,552.802497,543.512493,550.312514,1455500,550.312514\n2014-10-29,550.00246,554.19254,546.982459,549.332532,1770500,549.332532\n2014-10-28,543.002488,548.98245,541.622422,548.902519,1271000,548.902519\n2014-10-27,537.032441,544.412422,537.032441,540.772496,1185300,540.772496\n2014-10-24,544.36248,544.882461,535.792407,539.782476,1973100,539.782476\n2014-10-23,539.322474,547.222436,535.852386,543.98241,2348800,543.98241\n2014-10-22,529.892437,539.802428,528.802351,532.712427,2919300,532.712427\n2014-10-21,525.192353,526.792383,519.112324,526.542369,2336300,526.542369\n2014-10-20,509.452317,521.762353,508.102301,520.84241,2607500,520.84241\n2014-10-17,527.252385,530.982402,508.532313,511.172335,5539400,511.172335\n2014-10-16,519.002342,529.432374,515.002358,524.512387,3708600,524.512387\n2014-10-15,531.012391,532.802396,518.302363,530.032409,3719400,530.032409\n2014-10-14,538.902438,547.192507,533.172368,537.942408,2222600,537.942408\n2014-10-13,544.992443,549.502492,533.102413,533.212456,2581700,533.212456\n2014-10-10,557.722484,565.132577,544.052426,544.492476,3081900,544.492476\n2014-10-09,571.182555,571.492549,559.062524,560.882579,2524800,560.882579\n2014-10-08,565.572566,573.882587,557.492484,572.502582,1990900,572.502582\n2014-10-07,574.402629,575.27263,563.742534,563.742534,1911300,563.742534\n2014-10-06,578.802574,581.002639,574.442595,577.352614,1214600,577.352614\n2014-10-03,573.052613,577.227576,572.502582,575.282606,1141700,575.282606\n2014-10-02,567.312567,571.912585,563.322559,570.082615,1178400,570.082615\n2014-10-01,576.012635,577.582615,567.01255,568.272597,1445500,568.272597\n2014-09-30,576.932578,579.852634,572.852541,577.36259,1621700,577.36259\n2014-09-29,571.7526,578.192625,571.172579,576.362594,1282400,576.362594\n2014-09-26,576.062638,579.2526,574.662558,577.1026,1443700,577.1026\n2014-09-25,587.552646,587.982658,574.182604,575.062581,1926000,575.062581\n2014-09-24,581.462641,589.632691,580.522624,587.992634,1728100,587.992634\n2014-09-23,586.852606,586.852606,581.002639,581.132634,1471400,581.132634\n2014-09-22,593.82271,593.951665,583.462694,587.372648,1689500,587.372648\n2014-09-19,591.502688,596.482654,589.502696,596.082692,3736600,596.082692\n2014-09-18,587.002675,589.542661,585.002622,589.272695,1444600,589.272695\n2014-09-17,580.012619,587.522656,578.777665,584.772683,1692800,584.772683\n2014-09-16,572.762572,581.502606,572.662566,579.95264,1480400,579.95264\n2014-09-15,572.94257,574.952599,568.212618,573.102555,1597600,573.102555\n2014-09-12,581.002639,581.642639,574.462608,575.622589,1601700,575.622589\n2014-09-11,580.362639,581.812599,576.262588,581.352598,1221000,581.352598\n2014-09-10,581.502606,583.502659,576.942615,583.102636,977400,583.102636\n2014-09-09,588.902723,589.002667,580.002643,581.012615,1287200,581.012615\n2014-09-08,586.602653,591.772715,586.302635,589.722659,1431000,589.722659\n2014-09-05,583.982613,586.55265,581.952632,586.082672,1632400,586.082672\n2014-09-04,580.002643,586.00268,579.222611,581.982621,1458200,581.982621\n2014-09-03,580.002643,582.992655,575.002602,577.942611,1215100,577.942611\n2014-09-02,571.852545,577.832629,571.192593,577.332662,1578400,577.332662\n2014-08-29,571.332625,572.04258,567.07155,571.60253,1083800,571.60253\n2014-08-28,569.562573,573.252563,567.102518,569.202577,1292900,569.202577\n2014-08-27,577.272622,578.492581,570.105627,571.002557,1703400,571.002557\n2014-08-26,581.262629,581.802623,576.582619,577.862619,1639700,577.862619\n2014-08-25,584.722619,585.002622,579.002647,580.202654,1361400,580.202654\n2014-08-22,583.592689,585.238682,580.642643,582.562642,789100,582.562642\n2014-08-21,583.822628,584.502655,581.142671,583.372664,914800,583.372664\n2014-08-20,585.88266,586.702658,582.572618,584.492618,1036700,584.492618\n2014-08-19,585.002622,587.342658,584.002627,586.862643,978700,586.862643\n2014-08-18,576.11258,584.512631,576.002598,582.162619,1284100,582.162619\n2014-08-15,577.862619,579.382595,570.522603,573.482564,1519200,573.482564\n2014-08-14,576.182596,577.902645,570.882599,574.652643,985500,574.652643\n2014-08-13,567.312567,575.002602,565.752564,574.782639,1441800,574.782639\n2014-08-12,564.522567,565.902572,560.882579,562.732562,1542000,562.732562\n2014-08-11,569.992585,570.492553,566.002578,567.882551,1214700,567.882551\n2014-08-08,563.562536,570.252576,560.3525,568.772626,1494800,568.772626\n2014-08-07,568.00257,569.89258,561.102482,563.362525,1110900,563.362525\n2014-08-06,561.782569,570.702601,560.002541,566.376589,1334400,566.376589\n2014-08-05,570.052564,571.982601,562.612543,565.072598,1551200,565.072598\n2014-08-04,569.042531,575.352561,564.102531,573.152619,1427300,573.152619\n2014-08-01,570.402584,575.962633,562.85252,566.072594,1955300,566.072594\n2014-07-31,580.602616,583.652668,570.002561,571.60253,2102800,571.60253\n2014-07-30,586.55265,589.502696,584.002627,587.42265,1016500,587.42265\n2014-07-29,588.752653,589.702707,583.517654,585.612633,1349900,585.612633\n2014-07-28,588.072688,592.502683,584.755668,590.602636,986800,590.602636\n2014-07-25,590.402686,591.862684,587.032665,589.022681,932500,589.022681\n2014-07-24,596.452725,599.502716,591.772715,593.352671,1035100,593.352671\n2014-07-23,593.232652,597.852683,592.502683,595.982686,1233200,595.982686\n2014-07-22,590.722655,599.652725,590.602636,594.742652,1699200,594.742652\n2014-07-21,591.752702,594.402731,585.235622,589.472645,2062100,589.472645\n2014-07-18,593.002712,596.802684,582.002635,595.082696,4014200,595.082696\n2014-07-17,579.532665,580.992601,568.61258,573.732579,3016600,573.732579\n2014-07-16,588.002671,588.402694,582.202646,582.662587,1397100,582.662587\n2014-07-15,585.742628,585.807626,576.562606,584.782659,1623000,584.782659\n2014-07-14,582.602608,585.212671,578.032641,584.872627,1854100,584.872627\n2014-07-11,571.912585,580.85263,571.422594,579.182645,1621700,579.182645\n2014-07-10,565.912548,576.592656,565.012558,571.102563,1356700,571.102563\n2014-07-09,571.582578,576.72259,569.378536,576.082652,1116800,576.082652\n2014-07-08,577.662607,579.530645,566.137592,571.092587,1909500,571.092587\n2014-07-07,583.76265,586.432631,579.592644,582.252649,1064600,582.252649\n2014-07-03,583.352589,585.01266,580.922585,584.732656,714200,584.732656\n2014-07-02,583.352589,585.442672,580.392628,582.33766,1056400,582.33766\n2014-07-01,578.32262,584.402649,576.652635,582.672624,1448000,582.672624\n2014-06-30,578.662603,579.572631,574.752588,575.282606,1313800,575.282606\n2014-06-27,577.182592,579.872648,573.802595,577.242632,2236900,577.242632\n2014-06-26,581.002639,582.45266,571.852545,576.002598,1742000,576.002598\n2014-06-25,565.262572,579.962616,565.222546,578.652627,1969400,578.652627\n2014-06-24,565.192556,572.648612,561.012574,564.622572,2207100,564.622572\n2014-06-23,555.152509,565.002582,554.252519,564.952579,1536800,564.952579\n2014-06-20,556.852484,557.582513,550.394526,556.362492,4508300,556.362492\n2014-06-19,554.242482,555.0025,548.512473,554.902556,2456800,554.902556\n2014-06-18,544.862448,553.562516,544.002484,553.372481,1741800,553.372481\n2014-06-17,544.202496,545.32245,539.33245,543.012465,1444600,543.012465\n2014-06-16,549.262515,549.62245,541.522477,544.282488,1702600,544.282488\n2014-06-13,552.262503,552.302469,545.562488,551.762536,1220500,551.762536\n2014-06-12,557.302509,557.992512,548.462531,551.352476,1458500,551.352476\n2014-06-11,558.002549,559.882522,555.022514,558.842561,1100100,558.842561\n2014-06-10,560.512546,563.602502,557.902544,560.552511,1351700,560.552511\n2014-06-09,557.152562,562.902584,556.042523,562.122552,1467500,562.122552\n2014-06-06,558.062528,558.062528,548.932448,556.332564,1736800,556.332564\n2014-06-05,546.402499,554.952498,544.452449,553.90256,1689100,553.90256\n2014-06-04,541.502464,548.612478,538.752429,544.662436,1816500,544.662436\n2014-06-03,550.99248,552.342557,542.552463,544.942501,1866600,544.942501\n2014-06-02,560.702581,560.902593,545.732448,553.932488,1435000,553.932488\n2014-05-30,560.802526,561.352496,555.912467,559.892559,1771100,559.892559\n2014-05-29,563.352549,564.002525,558.712565,560.082534,1354100,560.082534\n2014-05-28,564.57257,567.842585,561.002537,561.682502,1652000,561.682502\n2014-05-27,556.002496,566.002578,554.352463,565.952575,2104200,565.952575\n2014-05-23,547.262462,553.642508,543.702467,552.702492,1932200,552.702492\n2014-05-22,541.132431,547.602445,540.782472,545.062459,1615800,545.062459\n2014-05-21,532.902462,539.185441,531.912381,538.942465,1196300,538.942465\n2014-05-20,529.742368,536.232396,526.302392,529.772418,1784800,529.772418\n2014-05-19,519.702382,529.782456,517.58537,528.862391,1277800,528.862391\n2014-05-16,521.39238,521.802379,515.442347,520.632362,1485300,520.632362\n2014-05-15,525.702357,525.872379,517.422325,519.982324,1704400,519.982324\n2014-05-14,533.002407,533.002407,525.292358,526.652412,1191800,526.652412\n2014-05-13,530.892433,536.072411,529.512428,533.092437,1653400,533.092437\n2014-05-12,523.512391,530.192393,519.012379,529.922366,1912500,529.922366\n2014-05-09,510.75233,519.902393,504.202292,518.732314,2439500,518.732314\n2014-05-08,508.462297,517.23229,506.452298,511.002313,2021300,511.002313\n2014-05-07,515.792305,516.68232,503.302272,509.962291,3224300,509.962291\n2014-05-06,525.232379,526.812396,515.062337,515.14233,1689000,515.14233\n2014-05-05,524.822381,528.902418,521.322364,527.812392,1024100,527.812392\n2014-05-02,533.762426,534.002403,525.612389,527.932411,1688500,527.932411\n2014-05-01,527.112352,532.932391,523.882364,531.352374,1905500,531.352374\n2014-04-30,527.602343,528.002366,522.522372,526.662388,1751200,526.662388\n2014-04-29,516.902344,529.462425,516.322324,527.70241,2699100,527.70241\n2014-04-28,517.182348,518.602319,502.802274,517.152359,3335500,517.152359\n2014-04-25,522.512395,524.702361,515.422333,516.182352,2100400,516.182352\n2014-04-24,530.072374,531.652452,522.122349,525.162363,1883200,525.162363\n2014-04-23,533.792415,533.872408,526.252389,526.942391,2052300,526.942391\n2014-04-22,528.642427,537.232391,527.512375,534.812425,2365400,534.812425\n2014-04-21,536.1024,536.702435,525.602352,528.622414,2566700,528.622414\n2014-04-17,548.81249,549.502492,531.152424,536.1024,6809500,536.1024\n2014-04-16,543.002488,557.002492,540.00244,556.54249,4893300,556.54249\n2014-04-15,536.822454,538.452473,518.462348,536.442444,3855100,536.442444\n2014-04-14,538.252462,544.102429,529.56237,532.522453,2575100,532.522453\n2014-04-11,532.552381,540.00244,526.532392,530.602392,3924800,530.602392\n2014-04-10,565.002582,565.002582,539.902495,540.952433,4036900,540.952433\n2014-04-09,559.622532,565.372554,552.952506,564.142557,3330800,564.142557\n2014-04-08,542.602466,555.0025,541.612446,554.902556,3151200,554.902556\n2014-04-07,540.742445,548.482483,527.15244,538.152456,4401700,538.152456\n2014-04-04,574.652643,577.77265,543.002488,543.14246,6369300,543.14246\n2014-04-03,569.852553,587.282679,564.132581,569.742571,5099200,569.742571\n2014-04-02,599.992707,604.832763,562.192568,567.002574,147100,567.002574\n2014-04-01,558.712565,568.452595,558.712565,567.162558,7900,567.162558\n2014-03-31,566.892592,567.002574,556.932537,556.972503,10800,556.972503\n2014-03-28,561.202549,566.43259,558.672477,559.992504,41200,559.992504\n2014-03-27,568.00257,568.00257,552.922516,558.462551,13100,558.462551\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/17_MD5-checksum/main.go",
    "content": "package main\n\nimport (\n\t\"crypto/md5\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n)\n\nfunc main() {\n\tf, err := os.Open(os.Args[1])\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer f.Close()\n\n\th := md5.New()\n\tio.Copy(h, f)\n\tfmt.Printf(\"%x\\n\", h.Sum(nil))\n}\n"
  },
  {
    "path": "27_code-in-process/37_review-exercises/18_Walk-dir/main.go",
    "content": "package main\n\nimport (\n\t\"crypto/md5\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\nfunc md5file(fileName string) []byte {\n\tf, err := os.Open(fileName)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer f.Close()\n\n\th := md5.New()\n\tio.Copy(h, f)\n\treturn h.Sum(nil)\n}\n\nfunc main() {\n\tfilepath.Walk(\".\", func(path string, info os.FileInfo, err error) error {\n\t\tif info.IsDir() {\n\t\t\treturn nil\n\t\t}\n\n\t\tbs := md5file(path)\n\t\tfmt.Printf(\"%s %x\\n\", path, bs)\n\t\treturn nil\n\t})\n}\n\n/*\nwalk is recursive\nreaddir is not\n*/\n"
  },
  {
    "path": "27_code-in-process/38_JSON/01/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\nfunc main() {\n\tjsonData := `\n\t{\n\t\"name\": \"Todd McLeod\"\n\t}\n\t`\n\n\tvar obj map[string]string\n\n\terr := json.Unmarshal([]byte(jsonData), &obj)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(obj)\n\tfmt.Println(obj[\"name\"])\n\tfmt.Printf(\"%T\\n\", obj[\"name\"])\n}\n"
  },
  {
    "path": "27_code-in-process/38_JSON/02/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\nfunc main() {\n\tjsonData := `\n\t{\n\t\"name\": \"Todd McLeod\",\n\t\"age\": 44\n\t}\n\t`\n\n\tvar obj map[string]interface{}\n\n\terr := json.Unmarshal([]byte(jsonData), &obj)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(obj)\n\tfmt.Println(obj[\"name\"])\n\tfmt.Println(obj[\"age\"])\n\tfmt.Printf(\"%T\\n\", obj[\"name\"])\n\tfmt.Printf(\"%T\\n\", obj[\"age\"])\n}\n"
  },
  {
    "path": "27_code-in-process/38_JSON/03/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\nfunc main() {\n\tjsonData := `\n\t{\n\t\"name\": \"Todd McLeod\",\n\t\"age\": 44\n\t}\n\t`\n\n\ttype Anything interface{}\n\n\tvar obj map[string]Anything\n\n\terr := json.Unmarshal([]byte(jsonData), &obj)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(obj)\n}\n"
  },
  {
    "path": "27_code-in-process/38_JSON/04/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\nfunc main() {\n\tjsonData := `\n\t[100, 200, 300.5, 400.1234]\n\t`\n\n\tvar obj []float64\n\n\terr := json.Unmarshal([]byte(jsonData), &obj)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(obj)\n\tfmt.Printf(\"%T\\n\", obj)\n\tfmt.Println(obj[1])\n\tfmt.Printf(\"%T\\n\", obj[1])\n}\n"
  },
  {
    "path": "27_code-in-process/38_JSON/05/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\nfunc main() {\n\tjsonData := `\n\t100\n\t`\n\n\tvar obj interface{}\n\n\terr := json.Unmarshal([]byte(jsonData), &obj)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(obj)\n\n\tfmt.Printf(\"%T\", obj)\n}\n"
  },
  {
    "path": "27_code-in-process/38_JSON/06/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\nfunc main() {\n\tjsonData := `\n\t100\n\t`\n\n\tvar obj interface{}\n\n\terr := json.Unmarshal([]byte(jsonData), &obj)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(obj)\n\n\tfmt.Printf(\"%T\\n\", obj)\n\n\tx := 100 + obj.(float64)\n\n\t// conversion\n\t// if you have a concrete type, use conversion\n\t// eg, string(obj)\n\t// eg, float64(obj)\n\n\t// casting\n\t// if you have an interface, use the cast\n\t// obj.(float64)\n\n\tfmt.Println(x)\n}\n"
  },
  {
    "path": "27_code-in-process/38_JSON/07/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\nfunc main() {\n\tjsonData := `\n\t100\n\t`\n\n\tvar obj interface{}\n\n\terr := json.Unmarshal([]byte(jsonData), &obj)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(obj)\n\n\tfmt.Printf(\"%T\\n\", obj)\n\n\tv, ok := obj.(float64)\n\tif !ok {\n\t\tv = 0\n\t}\n\tx := 100 + v\n\n\tfmt.Println(x)\n}\n"
  },
  {
    "path": "27_code-in-process/38_JSON/08/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\nfunc main() {\n\tjsonData := `\n\t100\n\t`\n\n\tvar obj interface{}\n\n\terr := json.Unmarshal([]byte(jsonData), &obj)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(obj)\n\n\tfmt.Printf(\"%T\\n\", obj)\n\n\tv, ok := obj.(float64)\n\tif !ok {\n\t\tv = 0\n\t}\n\tx := 100 + v\n\n\tfmt.Println(x)\n\n\tbs, err := json.Marshal(x)\n\tfmt.Println(string(bs), err)\n}\n"
  },
  {
    "path": "27_code-in-process/38_JSON/09/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\nfunc main() {\n\tjsonData := `\n\t100\n\t`\n\n\tvar obj interface{}\n\n\terr := json.Unmarshal([]byte(jsonData), &obj)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(obj)\n\n\tfmt.Printf(\"%T\\n\", obj)\n\n\tv, ok := obj.(float64)\n\tif !ok {\n\t\tv = 0\n\t}\n\tx := 100 + v\n\n\tfmt.Println(x)\n\n\tbs, err := json.Marshal([]int{1, 2, 3, 4})\n\tfmt.Println(string(bs), err)\n}\n"
  },
  {
    "path": "27_code-in-process/38_JSON/10/main.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\nfunc main() {\n\tjsonData := `\n\t100\n\t`\n\n\tvar obj interface{}\n\n\terr := json.Unmarshal([]byte(jsonData), &obj)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tvar buf bytes.Buffer\n\t_ = json.NewEncoder(&buf).Encode([]int{1, 2, 3, 4})\n\tfmt.Println(buf)\n}\n"
  },
  {
    "path": "27_code-in-process/38_JSON/11/main.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n)\n\ntype Anything interface{}\n\nfunc main() {\n\tjsonData := `\n\t\"100\"\n\t`\n\n\tvar obj interface{}\n\tvar f io.Reader\n\tjson.NewDecoder(f).Decode(&obj)\n\n\terr := json.Unmarshal([]byte(jsonData), &obj)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tvar buf bytes.Buffer\n\terr = json.NewEncoder(&buf).Encode([]int{1, 2, 3, 4})\n\n\t//bs, err := json.Marshal()\n\tfmt.Println(buf.String())\n\n}\n\n// this code doesn't run\n// just captured in lecture\n"
  },
  {
    "path": "27_code-in-process/38_JSON/12/data.json",
    "content": "{\n  \"returns\": [1,2,3,4]\n}"
  },
  {
    "path": "27_code-in-process/38_JSON/12/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n)\n\ntype Anything interface{}\n\nfunc main() {\n\tf, err := os.Open(\"data.json\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer f.Close()\n\n\tvar obj map[string]interface{}\n\terr = json.NewDecoder(f).Decode(&obj)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(obj)\n}\n"
  },
  {
    "path": "27_code-in-process/38_JSON/13/data.json",
    "content": "{\n  \"returns\": [1,2,3,4]\n}"
  },
  {
    "path": "27_code-in-process/38_JSON/13/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n)\n\ntype StockData struct {\n\tReturns []float64 `json:\"returns\"`\n}\n\nfunc main() {\n\tf, err := os.Open(\"data.json\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer f.Close()\n\n\tvar obj StockData\n\terr = json.NewDecoder(f).Decode(&obj)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(obj)\n}\n"
  },
  {
    "path": "27_code-in-process/38_JSON/14/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t//\t\"fmt\"\n\t\"encoding/json\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\n\t//open file\n\tsrc, err := os.Open(\"../../../resources/table.csv\")\n\tif err != nil {\n\t\tlog.Fatalln(\"couldn't open file\", err.Error())\n\t}\n\tdefer src.Close()\n\n\t// reader for csv file\n\trdr := csv.NewReader(src)\n\n\t// read csv file\n\tdata, err := rdr.ReadAll()\n\tif err != nil {\n\t\tlog.Fatalln(\"couldn't readall\", err.Error())\n\t}\n\n\t// convert to JSON\n\tb, err := json.Marshal(data)\n\tif err != nil {\n\t\tlog.Fatalln(\"couldn't marshall\", err.Error())\n\t}\n\n\t// show\n\tos.Stdout.Write(b)\n\t//\tfmt.Println(b)\n\n}\n"
  },
  {
    "path": "27_code-in-process/38_JSON/15/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t\"encoding/json\"\n\t\"log\"\n\t\"os\"\n\t\"strconv\"\n)\n\ntype StockData struct {\n\tDate     string\n\tOpen     float64\n\tHigh     float64\n\tLow      float64\n\tClose    float64\n\tVolume   float64\n\tAdjClose float64\n}\n\nfunc toFloat(str string) float64 {\n\tv, _ := strconv.ParseFloat(str, 64)\n\treturn v\n}\n\nfunc main() {\n\tsrc, err := os.Open(\"../../../resources/table.csv\")\n\tif err != nil {\n\t\tlog.Fatalln(\"couldn't open file\", err.Error())\n\t}\n\tdefer src.Close()\n\n\tdst, err := os.Create(\"output.txt\")\n\tif err != nil {\n\t\tlog.Fatalln(\"couldn't open file\", err.Error())\n\t}\n\tdefer dst.Close()\n\n\trdr := csv.NewReader(src)\n\n\tdata, err := rdr.ReadAll()\n\tif err != nil {\n\t\tlog.Fatalln(\"couldn't readall\", err.Error())\n\t}\n\n\tlistOfStockData := []StockData{}\n\t// put data into struct\n\tfor _, row := range data {\n\t\tsd := StockData{\n\t\t\tDate:     row[0],\n\t\t\tOpen:     toFloat(row[1]),\n\t\t\tHigh:     toFloat(row[2]),\n\t\t\tLow:      toFloat(row[3]),\n\t\t\tClose:    toFloat(row[4]),\n\t\t\tVolume:   toFloat(row[5]),\n\t\t\tAdjClose: toFloat(row[6]),\n\t\t}\n\t\tlistOfStockData = append(listOfStockData, sd)\n\t}\n\n\t//convert to JSON\n\terr = json.NewEncoder(dst).Encode(listOfStockData)\n\tif err != nil {\n\t\tlog.Fatalln(\"couldn't encode\", err.Error())\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/38_JSON/15/output.txt",
    "content": "[{\"Date\":\"Date\",\"Open\":0,\"High\":0,\"Low\":0,\"Close\":0,\"Volume\":0,\"AdjClose\":0},{\"Date\":\"2015-07-09\",\"Open\":523.119995,\"High\":523.77002,\"Low\":520.349976,\"Close\":520.679993,\"Volume\":1.8394e+06,\"AdjClose\":520.679993},{\"Date\":\"2015-07-08\",\"Open\":521.049988,\"High\":522.734009,\"Low\":516.109985,\"Close\":516.830017,\"Volume\":1.2646e+06,\"AdjClose\":516.830017},{\"Date\":\"2015-07-07\",\"Open\":523.130005,\"High\":526.179993,\"Low\":515.179993,\"Close\":525.02002,\"Volume\":1.5957e+06,\"AdjClose\":525.02002},{\"Date\":\"2015-07-06\",\"Open\":519.5,\"High\":525.25,\"Low\":519,\"Close\":522.859985,\"Volume\":1.2765e+06,\"AdjClose\":522.859985},{\"Date\":\"2015-07-02\",\"Open\":521.080017,\"High\":524.650024,\"Low\":521.080017,\"Close\":523.400024,\"Volume\":1.234e+06,\"AdjClose\":523.400024},{\"Date\":\"2015-07-01\",\"Open\":524.72998,\"High\":525.690002,\"Low\":518.22998,\"Close\":521.840027,\"Volume\":1.961e+06,\"AdjClose\":521.840027},{\"Date\":\"2015-06-30\",\"Open\":526.02002,\"High\":526.25,\"Low\":520.5,\"Close\":520.51001,\"Volume\":2.2172e+06,\"AdjClose\":520.51001},{\"Date\":\"2015-06-29\",\"Open\":525.01001,\"High\":528.609985,\"Low\":520.539978,\"Close\":521.52002,\"Volume\":1.9309e+06,\"AdjClose\":521.52002},{\"Date\":\"2015-06-26\",\"Open\":537.26001,\"High\":537.76001,\"Low\":531.349976,\"Close\":531.690002,\"Volume\":2.0115e+06,\"AdjClose\":531.690002},{\"Date\":\"2015-06-25\",\"Open\":538.869995,\"High\":540.900024,\"Low\":535.22998,\"Close\":535.22998,\"Volume\":1.3315e+06,\"AdjClose\":535.22998},{\"Date\":\"2015-06-24\",\"Open\":540,\"High\":540,\"Low\":535.659973,\"Close\":537.840027,\"Volume\":1.2834e+06,\"AdjClose\":537.840027},{\"Date\":\"2015-06-23\",\"Open\":539.640015,\"High\":541.499023,\"Low\":535.25,\"Close\":540.47998,\"Volume\":1.196e+06,\"AdjClose\":540.47998},{\"Date\":\"2015-06-22\",\"Open\":539.590027,\"High\":543.73999,\"Low\":537.530029,\"Close\":538.190002,\"Volume\":1.2425e+06,\"AdjClose\":538.190002},{\"Date\":\"2015-06-19\",\"Open\":537.210022,\"High\":538.25,\"Low\":533.01001,\"Close\":536.690002,\"Volume\":1.8857e+06,\"AdjClose\":536.690002},{\"Date\":\"2015-06-18\",\"Open\":531,\"High\":538.150024,\"Low\":530.789978,\"Close\":536.72998,\"Volume\":1.8281e+06,\"AdjClose\":536.72998},{\"Date\":\"2015-06-17\",\"Open\":529.369995,\"High\":530.97998,\"Low\":525.099976,\"Close\":529.26001,\"Volume\":1.2686e+06,\"AdjClose\":529.26001},{\"Date\":\"2015-06-16\",\"Open\":528.400024,\"High\":529.640015,\"Low\":525.559998,\"Close\":528.150024,\"Volume\":1.0693e+06,\"AdjClose\":528.150024},{\"Date\":\"2015-06-15\",\"Open\":528,\"High\":528.299988,\"Low\":524,\"Close\":527.200012,\"Volume\":1.6307e+06,\"AdjClose\":527.200012},{\"Date\":\"2015-06-12\",\"Open\":531.599976,\"High\":533.119995,\"Low\":530.159973,\"Close\":532.330017,\"Volume\":952400,\"AdjClose\":532.330017},{\"Date\":\"2015-06-11\",\"Open\":538.424988,\"High\":538.97998,\"Low\":533.02002,\"Close\":534.609985,\"Volume\":1.205e+06,\"AdjClose\":534.609985},{\"Date\":\"2015-06-10\",\"Open\":529.359985,\"High\":538.359985,\"Low\":529.349976,\"Close\":536.690002,\"Volume\":1.8114e+06,\"AdjClose\":536.690002},{\"Date\":\"2015-06-09\",\"Open\":527.559998,\"High\":529.200012,\"Low\":523.01001,\"Close\":526.690002,\"Volume\":1.4416e+06,\"AdjClose\":526.690002},{\"Date\":\"2015-06-08\",\"Open\":533.309998,\"High\":534.119995,\"Low\":526.23999,\"Close\":526.830017,\"Volume\":1.5206e+06,\"AdjClose\":526.830017},{\"Date\":\"2015-06-05\",\"Open\":536.349976,\"High\":537.200012,\"Low\":532.52002,\"Close\":533.330017,\"Volume\":1.375e+06,\"AdjClose\":533.330017},{\"Date\":\"2015-06-04\",\"Open\":537.76001,\"High\":540.590027,\"Low\":534.320007,\"Close\":536.700012,\"Volume\":1.3356e+06,\"AdjClose\":536.700012},{\"Date\":\"2015-06-03\",\"Open\":539.909973,\"High\":543.5,\"Low\":537.109985,\"Close\":540.309998,\"Volume\":1.7145e+06,\"AdjClose\":540.309998},{\"Date\":\"2015-06-02\",\"Open\":532.929993,\"High\":543,\"Low\":531.330017,\"Close\":539.179993,\"Volume\":1.9347e+06,\"AdjClose\":539.179993},{\"Date\":\"2015-06-01\",\"Open\":536.789978,\"High\":536.789978,\"Low\":529.76001,\"Close\":533.98999,\"Volume\":1.8996e+06,\"AdjClose\":533.98999},{\"Date\":\"2015-05-29\",\"Open\":537.369995,\"High\":538.630005,\"Low\":531.450012,\"Close\":532.109985,\"Volume\":2.5849e+06,\"AdjClose\":532.109985},{\"Date\":\"2015-05-28\",\"Open\":538.01001,\"High\":540.609985,\"Low\":536.25,\"Close\":539.780029,\"Volume\":1.0279e+06,\"AdjClose\":539.780029},{\"Date\":\"2015-05-27\",\"Open\":532.799988,\"High\":540.549988,\"Low\":531.710022,\"Close\":539.789978,\"Volume\":1.5204e+06,\"AdjClose\":539.789978},{\"Date\":\"2015-05-26\",\"Open\":538.119995,\"High\":539,\"Low\":529.880005,\"Close\":532.320007,\"Volume\":2.4034e+06,\"AdjClose\":532.320007},{\"Date\":\"2015-05-22\",\"Open\":540.150024,\"High\":544.190002,\"Low\":539.51001,\"Close\":540.109985,\"Volume\":1.1733e+06,\"AdjClose\":540.109985},{\"Date\":\"2015-05-21\",\"Open\":537.950012,\"High\":543.840027,\"Low\":535.97998,\"Close\":542.51001,\"Volume\":1.4614e+06,\"AdjClose\":542.51001},{\"Date\":\"2015-05-20\",\"Open\":538.48999,\"High\":542.919983,\"Low\":532.971985,\"Close\":539.27002,\"Volume\":1.4291e+06,\"AdjClose\":539.27002},{\"Date\":\"2015-05-19\",\"Open\":533.97998,\"High\":540.659973,\"Low\":533.039978,\"Close\":537.359985,\"Volume\":1.9633e+06,\"AdjClose\":537.359985},{\"Date\":\"2015-05-18\",\"Open\":532.01001,\"High\":534.820007,\"Low\":528.849976,\"Close\":532.299988,\"Volume\":1.9986e+06,\"AdjClose\":532.299988},{\"Date\":\"2015-05-15\",\"Open\":539.179993,\"High\":539.273987,\"Low\":530.380005,\"Close\":533.849976,\"Volume\":1.9627e+06,\"AdjClose\":533.849976},{\"Date\":\"2015-05-14\",\"Open\":533.77002,\"High\":539,\"Low\":532.409973,\"Close\":538.400024,\"Volume\":1.3991e+06,\"AdjClose\":538.400024},{\"Date\":\"2015-05-13\",\"Open\":530.559998,\"High\":534.322021,\"Low\":528.655029,\"Close\":529.619995,\"Volume\":1.2523e+06,\"AdjClose\":529.619995},{\"Date\":\"2015-05-12\",\"Open\":531.599976,\"High\":533.208984,\"Low\":525.26001,\"Close\":529.039978,\"Volume\":1.6254e+06,\"AdjClose\":529.039978},{\"Date\":\"2015-05-11\",\"Open\":538.369995,\"High\":541.97998,\"Low\":535.400024,\"Close\":535.700012,\"Volume\":905300,\"AdjClose\":535.700012},{\"Date\":\"2015-05-08\",\"Open\":536.650024,\"High\":541.150024,\"Low\":525,\"Close\":538.219971,\"Volume\":1.5276e+06,\"AdjClose\":538.219971},{\"Date\":\"2015-05-07\",\"Open\":523.98999,\"High\":533.460022,\"Low\":521.75,\"Close\":530.700012,\"Volume\":1.5463e+06,\"AdjClose\":530.700012},{\"Date\":\"2015-05-06\",\"Open\":531.23999,\"High\":532.380005,\"Low\":521.085022,\"Close\":524.219971,\"Volume\":1.567e+06,\"AdjClose\":524.219971},{\"Date\":\"2015-05-05\",\"Open\":538.210022,\"High\":539.73999,\"Low\":530.390991,\"Close\":530.799988,\"Volume\":1.3831e+06,\"AdjClose\":530.799988},{\"Date\":\"2015-05-04\",\"Open\":538.530029,\"High\":544.070007,\"Low\":535.059998,\"Close\":540.780029,\"Volume\":1.308e+06,\"AdjClose\":540.780029},{\"Date\":\"2015-05-01\",\"Open\":538.429993,\"High\":539.539978,\"Low\":532.099976,\"Close\":537.900024,\"Volume\":1.7682e+06,\"AdjClose\":537.900024},{\"Date\":\"2015-04-30\",\"Open\":547.869995,\"High\":548.590027,\"Low\":535.049988,\"Close\":537.340027,\"Volume\":2.0822e+06,\"AdjClose\":537.340027},{\"Date\":\"2015-04-29\",\"Open\":550.469971,\"High\":553.679993,\"Low\":546.905029,\"Close\":549.080017,\"Volume\":1.6988e+06,\"AdjClose\":549.080017},{\"Date\":\"2015-04-28\",\"Open\":554.640015,\"High\":556.02002,\"Low\":550.366028,\"Close\":553.679993,\"Volume\":1.491e+06,\"AdjClose\":553.679993},{\"Date\":\"2015-04-27\",\"Open\":563.390015,\"High\":565.950012,\"Low\":553.200012,\"Close\":555.369995,\"Volume\":2.398e+06,\"AdjClose\":555.369995},{\"Date\":\"2015-04-24\",\"Open\":566.102522,\"High\":571.14259,\"Low\":557.252507,\"Close\":565.062561,\"Volume\":4.9325e+06,\"AdjClose\":565.062561},{\"Date\":\"2015-04-23\",\"Open\":541.002435,\"High\":550.96249,\"Low\":540.23244,\"Close\":547.002472,\"Volume\":4.1849e+06,\"AdjClose\":547.002472},{\"Date\":\"2015-04-22\",\"Open\":534.402426,\"High\":541.082489,\"Low\":531.752397,\"Close\":539.367458,\"Volume\":1.5936e+06,\"AdjClose\":539.367458},{\"Date\":\"2015-04-21\",\"Open\":537.512456,\"High\":539.392429,\"Low\":533.677415,\"Close\":533.972413,\"Volume\":1.8448e+06,\"AdjClose\":533.972413},{\"Date\":\"2015-04-20\",\"Open\":525.602352,\"High\":536.092424,\"Low\":524.50235,\"Close\":535.382408,\"Volume\":1.6793e+06,\"AdjClose\":535.382408},{\"Date\":\"2015-04-17\",\"Open\":528.662379,\"High\":529.842435,\"Low\":521.012371,\"Close\":524.052386,\"Volume\":2.1441e+06,\"AdjClose\":524.052386},{\"Date\":\"2015-04-16\",\"Open\":529.902414,\"High\":535.592457,\"Low\":529.612373,\"Close\":533.802391,\"Volume\":1.2999e+06,\"AdjClose\":533.802391},{\"Date\":\"2015-04-15\",\"Open\":528.702406,\"High\":534.732432,\"Low\":523.22235,\"Close\":532.532429,\"Volume\":2.3188e+06,\"AdjClose\":532.532429},{\"Date\":\"2015-04-14\",\"Open\":536.252409,\"High\":537.572435,\"Low\":528.094354,\"Close\":530.392405,\"Volume\":2.6041e+06,\"AdjClose\":530.392405},{\"Date\":\"2015-04-13\",\"Open\":538.412385,\"High\":544.062463,\"Low\":537.312445,\"Close\":539.172404,\"Volume\":1.6453e+06,\"AdjClose\":539.172404},{\"Date\":\"2015-04-10\",\"Open\":542.292411,\"High\":542.292411,\"Low\":537.312445,\"Close\":540.012477,\"Volume\":1.4095e+06,\"AdjClose\":540.012477},{\"Date\":\"2015-04-09\",\"Open\":541.032486,\"High\":541.95249,\"Low\":535.49239,\"Close\":540.782472,\"Volume\":1.5579e+06,\"AdjClose\":540.782472},{\"Date\":\"2015-04-08\",\"Open\":538.382457,\"High\":543.852415,\"Low\":538.382457,\"Close\":541.612446,\"Volume\":1.1785e+06,\"AdjClose\":541.612446},{\"Date\":\"2015-04-07\",\"Open\":538.08244,\"High\":542.692434,\"Low\":536.002395,\"Close\":537.022465,\"Volume\":1.3029e+06,\"AdjClose\":537.022465},{\"Date\":\"2015-04-06\",\"Open\":532.222375,\"High\":538.412385,\"Low\":529.572407,\"Close\":536.767432,\"Volume\":1.3244e+06,\"AdjClose\":536.767432},{\"Date\":\"2015-04-02\",\"Open\":540.852427,\"High\":540.852427,\"Low\":533.849395,\"Close\":535.532478,\"Volume\":1.7164e+06,\"AdjClose\":535.532478},{\"Date\":\"2015-04-01\",\"Open\":548.602441,\"High\":551.142488,\"Low\":539.502472,\"Close\":542.562439,\"Volume\":1.9631e+06,\"AdjClose\":542.562439},{\"Date\":\"2015-03-31\",\"Open\":550.00246,\"High\":554.712521,\"Low\":546.722468,\"Close\":548.002468,\"Volume\":1.588e+06,\"AdjClose\":548.002468},{\"Date\":\"2015-03-30\",\"Open\":551.622503,\"High\":553.472487,\"Low\":548.17249,\"Close\":552.032502,\"Volume\":1.2875e+06,\"AdjClose\":552.032502},{\"Date\":\"2015-03-27\",\"Open\":553.002509,\"High\":555.282565,\"Low\":548.132463,\"Close\":548.342512,\"Volume\":1.8975e+06,\"AdjClose\":548.342512},{\"Date\":\"2015-03-26\",\"Open\":557.59255,\"High\":558.90254,\"Low\":550.652497,\"Close\":555.172522,\"Volume\":1.5726e+06,\"AdjClose\":555.172522},{\"Date\":\"2015-03-25\",\"Open\":570.50259,\"High\":572.262605,\"Low\":558.742494,\"Close\":558.787478,\"Volume\":2.1523e+06,\"AdjClose\":558.787478},{\"Date\":\"2015-03-24\",\"Open\":562.562541,\"High\":574.592603,\"Low\":561.212586,\"Close\":570.192597,\"Volume\":2.5833e+06,\"AdjClose\":570.192597},{\"Date\":\"2015-03-23\",\"Open\":560.432554,\"High\":562.362529,\"Low\":555.832536,\"Close\":558.81251,\"Volume\":1.6438e+06,\"AdjClose\":558.81251},{\"Date\":\"2015-03-20\",\"Open\":561.652574,\"High\":561.722529,\"Low\":559.052548,\"Close\":560.362537,\"Volume\":2.6169e+06,\"AdjClose\":560.362537},{\"Date\":\"2015-03-19\",\"Open\":559.392531,\"High\":560.802526,\"Low\":556.147548,\"Close\":557.992512,\"Volume\":1.1973e+06,\"AdjClose\":557.992512},{\"Date\":\"2015-03-18\",\"Open\":552.50248,\"High\":559.782578,\"Low\":547.002472,\"Close\":559.502513,\"Volume\":2.1345e+06,\"AdjClose\":559.502513},{\"Date\":\"2015-03-17\",\"Open\":551.712533,\"High\":553.802493,\"Low\":548.002468,\"Close\":550.842532,\"Volume\":1.8055e+06,\"AdjClose\":550.842532},{\"Date\":\"2015-03-16\",\"Open\":550.952514,\"High\":556.852484,\"Low\":546.002476,\"Close\":554.512509,\"Volume\":1.641e+06,\"AdjClose\":554.512509},{\"Date\":\"2015-03-13\",\"Open\":553.502537,\"High\":558.402572,\"Low\":544.222448,\"Close\":547.322503,\"Volume\":1.7036e+06,\"AdjClose\":547.322503},{\"Date\":\"2015-03-12\",\"Open\":553.512513,\"High\":556.37253,\"Low\":550.462523,\"Close\":555.512505,\"Volume\":1.3896e+06,\"AdjClose\":555.512505},{\"Date\":\"2015-03-11\",\"Open\":555.142533,\"High\":558.142521,\"Low\":550.682486,\"Close\":551.182515,\"Volume\":1.8208e+06,\"AdjClose\":551.182515},{\"Date\":\"2015-03-10\",\"Open\":564.252539,\"High\":564.852512,\"Low\":554.732473,\"Close\":555.012538,\"Volume\":1.7923e+06,\"AdjClose\":555.012538},{\"Date\":\"2015-03-09\",\"Open\":566.862541,\"High\":570.272589,\"Low\":563.537504,\"Close\":568.852557,\"Volume\":1.0621e+06,\"AdjClose\":568.852557},{\"Date\":\"2015-03-06\",\"Open\":574.882583,\"High\":576.682625,\"Low\":566.762597,\"Close\":567.687558,\"Volume\":1.6591e+06,\"AdjClose\":567.687558},{\"Date\":\"2015-03-05\",\"Open\":575.022616,\"High\":577.912621,\"Low\":573.412548,\"Close\":575.332609,\"Volume\":1.3896e+06,\"AdjClose\":575.332609},{\"Date\":\"2015-03-04\",\"Open\":571.872558,\"High\":577.112576,\"Low\":568.012607,\"Close\":573.372583,\"Volume\":1.8768e+06,\"AdjClose\":573.372583},{\"Date\":\"2015-03-03\",\"Open\":570.452587,\"High\":575.392649,\"Low\":566.522559,\"Close\":573.64261,\"Volume\":1.7048e+06,\"AdjClose\":573.64261},{\"Date\":\"2015-03-02\",\"Open\":560.532559,\"High\":572.152623,\"Low\":558.752531,\"Close\":571.342601,\"Volume\":2.1296e+06,\"AdjClose\":571.342601},{\"Date\":\"2015-02-27\",\"Open\":554.242482,\"High\":564.712602,\"Low\":552.902503,\"Close\":558.402572,\"Volume\":2.4102e+06,\"AdjClose\":558.402572},{\"Date\":\"2015-02-26\",\"Open\":543.212476,\"High\":556.142529,\"Low\":541.502464,\"Close\":555.482516,\"Volume\":2.3115e+06,\"AdjClose\":555.482516},{\"Date\":\"2015-02-25\",\"Open\":535.90245,\"High\":546.22244,\"Low\":535.447406,\"Close\":543.872489,\"Volume\":1.826e+06,\"AdjClose\":543.872489},{\"Date\":\"2015-02-24\",\"Open\":530.002419,\"High\":536.792403,\"Low\":528.252381,\"Close\":536.092424,\"Volume\":1.0051e+06,\"AdjClose\":536.092424},{\"Date\":\"2015-02-23\",\"Open\":536.052398,\"High\":536.441465,\"Low\":529.412361,\"Close\":531.912381,\"Volume\":1.4579e+06,\"AdjClose\":531.912381},{\"Date\":\"2015-02-20\",\"Open\":543.132484,\"High\":543.75247,\"Low\":535.802444,\"Close\":538.952441,\"Volume\":1.4444e+06,\"AdjClose\":538.952441},{\"Date\":\"2015-02-19\",\"Open\":538.042413,\"High\":543.11247,\"Low\":538.012424,\"Close\":542.872432,\"Volume\":989100,\"AdjClose\":542.872432},{\"Date\":\"2015-02-18\",\"Open\":541.402458,\"High\":545.492471,\"Low\":537.512456,\"Close\":539.702422,\"Volume\":1.4531e+06,\"AdjClose\":539.702422},{\"Date\":\"2015-02-17\",\"Open\":546.832511,\"High\":550.00246,\"Low\":541.092465,\"Close\":542.842504,\"Volume\":1.6168e+06,\"AdjClose\":542.842504},{\"Date\":\"2015-02-13\",\"Open\":543.352447,\"High\":549.912491,\"Low\":543.132484,\"Close\":549.012501,\"Volume\":1.9003e+06,\"AdjClose\":549.012501},{\"Date\":\"2015-02-12\",\"Open\":537.252405,\"High\":544.822482,\"Low\":534.675391,\"Close\":542.932472,\"Volume\":1.6202e+06,\"AdjClose\":542.932472},{\"Date\":\"2015-02-11\",\"Open\":535.302416,\"High\":538.452473,\"Low\":533.380397,\"Close\":535.972405,\"Volume\":1.3778e+06,\"AdjClose\":535.972405},{\"Date\":\"2015-02-10\",\"Open\":529.302379,\"High\":537.702431,\"Low\":526.922378,\"Close\":536.942412,\"Volume\":1.7499e+06,\"AdjClose\":536.942412},{\"Date\":\"2015-02-09\",\"Open\":528.002366,\"High\":532.002411,\"Low\":526.022388,\"Close\":527.832406,\"Volume\":1.2678e+06,\"AdjClose\":527.832406},{\"Date\":\"2015-02-06\",\"Open\":527.642431,\"High\":537.202463,\"Low\":526.412373,\"Close\":531.002415,\"Volume\":1.7494e+06,\"AdjClose\":531.002415},{\"Date\":\"2015-02-05\",\"Open\":523.792334,\"High\":528.502395,\"Low\":522.092359,\"Close\":527.582391,\"Volume\":1.8498e+06,\"AdjClose\":527.582391},{\"Date\":\"2015-02-04\",\"Open\":529.2424,\"High\":532.67442,\"Low\":521.272361,\"Close\":522.762349,\"Volume\":1.6637e+06,\"AdjClose\":522.762349},{\"Date\":\"2015-02-03\",\"Open\":528.002366,\"High\":533.40243,\"Low\":523.262377,\"Close\":529.2424,\"Volume\":2.0387e+06,\"AdjClose\":529.2424},{\"Date\":\"2015-02-02\",\"Open\":531.732383,\"High\":533.002407,\"Low\":518.552316,\"Close\":528.482381,\"Volume\":2.8498e+06,\"AdjClose\":528.482381},{\"Date\":\"2015-01-30\",\"Open\":515.862322,\"High\":539.872444,\"Low\":515.522339,\"Close\":534.522445,\"Volume\":5.6064e+06,\"AdjClose\":534.522445},{\"Date\":\"2015-01-29\",\"Open\":511.002313,\"High\":511.092313,\"Low\":501.202274,\"Close\":510.662331,\"Volume\":4.1864e+06,\"AdjClose\":510.662331},{\"Date\":\"2015-01-28\",\"Open\":522.782423,\"High\":522.992349,\"Low\":510.002318,\"Close\":510.002318,\"Volume\":1.6838e+06,\"AdjClose\":510.002318},{\"Date\":\"2015-01-27\",\"Open\":529.972369,\"High\":530.702398,\"Low\":518.192381,\"Close\":518.63237,\"Volume\":1.904e+06,\"AdjClose\":518.63237},{\"Date\":\"2015-01-26\",\"Open\":538.532466,\"High\":539.002444,\"Low\":529.672413,\"Close\":535.212448,\"Volume\":1.5437e+06,\"AdjClose\":535.212448},{\"Date\":\"2015-01-23\",\"Open\":535.592457,\"High\":542.172453,\"Low\":533.002407,\"Close\":539.952437,\"Volume\":2.2817e+06,\"AdjClose\":539.952437},{\"Date\":\"2015-01-22\",\"Open\":521.482349,\"High\":536.332463,\"Low\":519.702382,\"Close\":534.39245,\"Volume\":2.6769e+06,\"AdjClose\":534.39245},{\"Date\":\"2015-01-21\",\"Open\":507.252283,\"High\":519.282407,\"Low\":506.202315,\"Close\":518.042312,\"Volume\":2.2687e+06,\"AdjClose\":518.042312},{\"Date\":\"2015-01-20\",\"Open\":511.002313,\"High\":512.502307,\"Low\":506.018277,\"Close\":506.902294,\"Volume\":2.2279e+06,\"AdjClose\":506.902294},{\"Date\":\"2015-01-16\",\"Open\":500.012273,\"High\":508.1923,\"Low\":500.002267,\"Close\":508.082288,\"Volume\":2.2983e+06,\"AdjClose\":508.082288},{\"Date\":\"2015-01-15\",\"Open\":505.572291,\"High\":505.682273,\"Low\":497.762267,\"Close\":501.792271,\"Volume\":2.7158e+06,\"AdjClose\":501.792271},{\"Date\":\"2015-01-14\",\"Open\":494.652237,\"High\":503.232286,\"Low\":493.002234,\"Close\":500.872267,\"Volume\":2.2357e+06,\"AdjClose\":500.872267},{\"Date\":\"2015-01-13\",\"Open\":498.842256,\"High\":502.982302,\"Low\":492.392254,\"Close\":496.182251,\"Volume\":2.3705e+06,\"AdjClose\":496.182251},{\"Date\":\"2015-01-12\",\"Open\":494.942247,\"High\":495.978261,\"Low\":487.562205,\"Close\":492.552209,\"Volume\":2.3224e+06,\"AdjClose\":492.552209},{\"Date\":\"2015-01-09\",\"Open\":504.7623,\"High\":504.922285,\"Low\":494.792239,\"Close\":496.172274,\"Volume\":2.0694e+06,\"AdjClose\":496.172274},{\"Date\":\"2015-01-08\",\"Open\":497.992238,\"High\":503.4823,\"Low\":491.002212,\"Close\":502.682255,\"Volume\":3.3536e+06,\"AdjClose\":502.682255},{\"Date\":\"2015-01-07\",\"Open\":507.002299,\"High\":507.246285,\"Low\":499.652247,\"Close\":501.102268,\"Volume\":2.0651e+06,\"AdjClose\":501.102268},{\"Date\":\"2015-01-06\",\"Open\":515.002358,\"High\":516.177334,\"Low\":501.052266,\"Close\":501.962262,\"Volume\":2.8999e+06,\"AdjClose\":501.962262},{\"Date\":\"2015-01-05\",\"Open\":523.262377,\"High\":524.332389,\"Low\":513.062315,\"Close\":513.872306,\"Volume\":2.0598e+06,\"AdjClose\":513.872306},{\"Date\":\"2015-01-02\",\"Open\":529.012399,\"High\":531.272443,\"Low\":524.102327,\"Close\":524.812404,\"Volume\":1.4476e+06,\"AdjClose\":524.812404},{\"Date\":\"2014-12-31\",\"Open\":531.252429,\"High\":532.602384,\"Low\":525.802363,\"Close\":526.402397,\"Volume\":1.3682e+06,\"AdjClose\":526.402397},{\"Date\":\"2014-12-30\",\"Open\":528.092396,\"High\":531.152424,\"Low\":527.132366,\"Close\":530.422394,\"Volume\":876300,\"AdjClose\":530.422394},{\"Date\":\"2014-12-29\",\"Open\":532.192446,\"High\":535.482414,\"Low\":530.013375,\"Close\":530.332426,\"Volume\":2.2785e+06,\"AdjClose\":530.332426},{\"Date\":\"2014-12-26\",\"Open\":528.772422,\"High\":534.252417,\"Low\":527.312364,\"Close\":534.032454,\"Volume\":1.036e+06,\"AdjClose\":534.032454},{\"Date\":\"2014-12-24\",\"Open\":530.512424,\"High\":531.761394,\"Low\":527.022384,\"Close\":528.772422,\"Volume\":705900,\"AdjClose\":528.772422},{\"Date\":\"2014-12-23\",\"Open\":527.00237,\"High\":534.56241,\"Low\":526.292354,\"Close\":530.592416,\"Volume\":2.1976e+06,\"AdjClose\":530.592416},{\"Date\":\"2014-12-22\",\"Open\":516.082347,\"High\":526.462376,\"Low\":516.082347,\"Close\":524.872383,\"Volume\":2.7238e+06,\"AdjClose\":524.872383},{\"Date\":\"2014-12-19\",\"Open\":511.512318,\"High\":517.722342,\"Low\":506.91331,\"Close\":516.352313,\"Volume\":3.6902e+06,\"AdjClose\":516.352313},{\"Date\":\"2014-12-18\",\"Open\":512.952333,\"High\":513.872306,\"Low\":504.70229,\"Close\":511.102319,\"Volume\":2.9267e+06,\"AdjClose\":511.102319},{\"Date\":\"2014-12-17\",\"Open\":497.002248,\"High\":507.002299,\"Low\":496.812244,\"Close\":504.892295,\"Volume\":2.8832e+06,\"AdjClose\":504.892295},{\"Date\":\"2014-12-16\",\"Open\":511.562321,\"High\":513.052308,\"Low\":489.00222,\"Close\":495.392273,\"Volume\":3.9643e+06,\"AdjClose\":495.392273},{\"Date\":\"2014-12-15\",\"Open\":522.742335,\"High\":523.102331,\"Low\":513.272333,\"Close\":513.80229,\"Volume\":2.8134e+06,\"AdjClose\":513.80229},{\"Date\":\"2014-12-12\",\"Open\":523.512391,\"High\":528.502395,\"Low\":518.662298,\"Close\":518.662298,\"Volume\":1.9946e+06,\"AdjClose\":518.662298},{\"Date\":\"2014-12-11\",\"Open\":527.802355,\"High\":533.922411,\"Low\":527.102376,\"Close\":528.34241,\"Volume\":1.6108e+06,\"AdjClose\":528.34241},{\"Date\":\"2014-12-10\",\"Open\":533.082399,\"High\":536.332463,\"Low\":525.562386,\"Close\":526.062353,\"Volume\":1.7123e+06,\"AdjClose\":526.062353},{\"Date\":\"2014-12-09\",\"Open\":522.142362,\"High\":534.192438,\"Low\":520.502366,\"Close\":533.37244,\"Volume\":1.8713e+06,\"AdjClose\":533.37244},{\"Date\":\"2014-12-08\",\"Open\":527.132366,\"High\":531.002415,\"Low\":523.792334,\"Close\":526.982357,\"Volume\":2.3294e+06,\"AdjClose\":526.982357},{\"Date\":\"2014-12-05\",\"Open\":531.002415,\"High\":532.892425,\"Low\":524.282386,\"Close\":525.262369,\"Volume\":2.5656e+06,\"AdjClose\":525.262369},{\"Date\":\"2014-12-04\",\"Open\":531.1624,\"High\":537.342434,\"Low\":528.592424,\"Close\":537.312445,\"Volume\":1.3921e+06,\"AdjClose\":537.312445},{\"Date\":\"2014-12-03\",\"Open\":531.442404,\"High\":535.998416,\"Low\":529.262414,\"Close\":531.322384,\"Volume\":1.278e+06,\"AdjClose\":531.322384},{\"Date\":\"2014-12-02\",\"Open\":533.512412,\"High\":535.502427,\"Low\":529.802408,\"Close\":533.752389,\"Volume\":1.5258e+06,\"AdjClose\":533.752389},{\"Date\":\"2014-12-01\",\"Open\":538.902438,\"High\":541.412434,\"Low\":531.862379,\"Close\":533.802391,\"Volume\":2.1154e+06,\"AdjClose\":533.802391},{\"Date\":\"2014-11-28\",\"Open\":540.622426,\"High\":542.002431,\"Low\":536.602429,\"Close\":541.832471,\"Volume\":1.1483e+06,\"AdjClose\":541.832471},{\"Date\":\"2014-11-26\",\"Open\":540.882478,\"High\":541.552406,\"Low\":537.044437,\"Close\":540.372412,\"Volume\":1.523e+06,\"AdjClose\":540.372412},{\"Date\":\"2014-11-25\",\"Open\":539.002444,\"High\":543.98241,\"Low\":538.60444,\"Close\":541.082489,\"Volume\":1.7891e+06,\"AdjClose\":541.082489},{\"Date\":\"2014-11-24\",\"Open\":537.652489,\"High\":542.702471,\"Low\":535.622446,\"Close\":539.272471,\"Volume\":1.706e+06,\"AdjClose\":539.272471},{\"Date\":\"2014-11-21\",\"Open\":541.612446,\"High\":542.142464,\"Low\":536.562402,\"Close\":537.502419,\"Volume\":2.2237e+06,\"AdjClose\":537.502419},{\"Date\":\"2014-11-20\",\"Open\":531.252429,\"High\":535.112381,\"Low\":531.082408,\"Close\":534.832438,\"Volume\":1.562e+06,\"AdjClose\":534.832438},{\"Date\":\"2014-11-19\",\"Open\":535.002399,\"High\":538.242425,\"Low\":530.082412,\"Close\":536.992415,\"Volume\":1.3916e+06,\"AdjClose\":536.992415},{\"Date\":\"2014-11-18\",\"Open\":537.502419,\"High\":541.942452,\"Low\":534.172425,\"Close\":535.032449,\"Volume\":1.9627e+06,\"AdjClose\":535.032449},{\"Date\":\"2014-11-17\",\"Open\":543.582448,\"High\":543.792436,\"Low\":534.063361,\"Close\":536.512461,\"Volume\":1.7258e+06,\"AdjClose\":536.512461},{\"Date\":\"2014-11-14\",\"Open\":546.682442,\"High\":546.682442,\"Low\":542.152501,\"Close\":544.402507,\"Volume\":1.2892e+06,\"AdjClose\":544.402507},{\"Date\":\"2014-11-13\",\"Open\":549.802448,\"High\":549.802448,\"Low\":543.482442,\"Close\":545.38249,\"Volume\":1.3394e+06,\"AdjClose\":545.38249},{\"Date\":\"2014-11-12\",\"Open\":550.392507,\"High\":550.462523,\"Low\":545.172441,\"Close\":547.312465,\"Volume\":1.1294e+06,\"AdjClose\":547.312465},{\"Date\":\"2014-11-11\",\"Open\":548.492459,\"High\":551.942473,\"Low\":546.302493,\"Close\":550.29244,\"Volume\":965500,\"AdjClose\":550.29244},{\"Date\":\"2014-11-10\",\"Open\":541.462498,\"High\":549.592522,\"Low\":541.022449,\"Close\":547.492463,\"Volume\":1.1346e+06,\"AdjClose\":547.492463},{\"Date\":\"2014-11-07\",\"Open\":546.212525,\"High\":546.212525,\"Low\":538.672437,\"Close\":541.012473,\"Volume\":1.6338e+06,\"AdjClose\":541.012473},{\"Date\":\"2014-11-06\",\"Open\":545.502448,\"High\":546.887472,\"Low\":540.972385,\"Close\":542.042458,\"Volume\":1.3333e+06,\"AdjClose\":542.042458},{\"Date\":\"2014-11-05\",\"Open\":556.802481,\"High\":556.802481,\"Low\":544.052426,\"Close\":545.922423,\"Volume\":2.0323e+06,\"AdjClose\":545.922423},{\"Date\":\"2014-11-04\",\"Open\":553.002509,\"High\":555.502529,\"Low\":549.302481,\"Close\":554.112486,\"Volume\":1.2442e+06,\"AdjClose\":554.112486},{\"Date\":\"2014-11-03\",\"Open\":555.502529,\"High\":557.902544,\"Low\":553.23251,\"Close\":555.222464,\"Volume\":1.3823e+06,\"AdjClose\":555.222464},{\"Date\":\"2014-10-31\",\"Open\":559.352504,\"High\":559.572529,\"Low\":554.752486,\"Close\":559.082538,\"Volume\":2.0351e+06,\"AdjClose\":559.082538},{\"Date\":\"2014-10-30\",\"Open\":548.952522,\"High\":552.802497,\"Low\":543.512493,\"Close\":550.312514,\"Volume\":1.4555e+06,\"AdjClose\":550.312514},{\"Date\":\"2014-10-29\",\"Open\":550.00246,\"High\":554.19254,\"Low\":546.982459,\"Close\":549.332532,\"Volume\":1.7705e+06,\"AdjClose\":549.332532},{\"Date\":\"2014-10-28\",\"Open\":543.002488,\"High\":548.98245,\"Low\":541.622422,\"Close\":548.902519,\"Volume\":1.271e+06,\"AdjClose\":548.902519},{\"Date\":\"2014-10-27\",\"Open\":537.032441,\"High\":544.412422,\"Low\":537.032441,\"Close\":540.772496,\"Volume\":1.1853e+06,\"AdjClose\":540.772496},{\"Date\":\"2014-10-24\",\"Open\":544.36248,\"High\":544.882461,\"Low\":535.792407,\"Close\":539.782476,\"Volume\":1.9731e+06,\"AdjClose\":539.782476},{\"Date\":\"2014-10-23\",\"Open\":539.322474,\"High\":547.222436,\"Low\":535.852386,\"Close\":543.98241,\"Volume\":2.3488e+06,\"AdjClose\":543.98241},{\"Date\":\"2014-10-22\",\"Open\":529.892437,\"High\":539.802428,\"Low\":528.802351,\"Close\":532.712427,\"Volume\":2.9193e+06,\"AdjClose\":532.712427},{\"Date\":\"2014-10-21\",\"Open\":525.192353,\"High\":526.792383,\"Low\":519.112324,\"Close\":526.542369,\"Volume\":2.3363e+06,\"AdjClose\":526.542369},{\"Date\":\"2014-10-20\",\"Open\":509.452317,\"High\":521.762353,\"Low\":508.102301,\"Close\":520.84241,\"Volume\":2.6075e+06,\"AdjClose\":520.84241},{\"Date\":\"2014-10-17\",\"Open\":527.252385,\"High\":530.982402,\"Low\":508.532313,\"Close\":511.172335,\"Volume\":5.5394e+06,\"AdjClose\":511.172335},{\"Date\":\"2014-10-16\",\"Open\":519.002342,\"High\":529.432374,\"Low\":515.002358,\"Close\":524.512387,\"Volume\":3.7086e+06,\"AdjClose\":524.512387},{\"Date\":\"2014-10-15\",\"Open\":531.012391,\"High\":532.802396,\"Low\":518.302363,\"Close\":530.032409,\"Volume\":3.7194e+06,\"AdjClose\":530.032409},{\"Date\":\"2014-10-14\",\"Open\":538.902438,\"High\":547.192507,\"Low\":533.172368,\"Close\":537.942408,\"Volume\":2.2226e+06,\"AdjClose\":537.942408},{\"Date\":\"2014-10-13\",\"Open\":544.992443,\"High\":549.502492,\"Low\":533.102413,\"Close\":533.212456,\"Volume\":2.5817e+06,\"AdjClose\":533.212456},{\"Date\":\"2014-10-10\",\"Open\":557.722484,\"High\":565.132577,\"Low\":544.052426,\"Close\":544.492476,\"Volume\":3.0819e+06,\"AdjClose\":544.492476},{\"Date\":\"2014-10-09\",\"Open\":571.182555,\"High\":571.492549,\"Low\":559.062524,\"Close\":560.882579,\"Volume\":2.5248e+06,\"AdjClose\":560.882579},{\"Date\":\"2014-10-08\",\"Open\":565.572566,\"High\":573.882587,\"Low\":557.492484,\"Close\":572.502582,\"Volume\":1.9909e+06,\"AdjClose\":572.502582},{\"Date\":\"2014-10-07\",\"Open\":574.402629,\"High\":575.27263,\"Low\":563.742534,\"Close\":563.742534,\"Volume\":1.9113e+06,\"AdjClose\":563.742534},{\"Date\":\"2014-10-06\",\"Open\":578.802574,\"High\":581.002639,\"Low\":574.442595,\"Close\":577.352614,\"Volume\":1.2146e+06,\"AdjClose\":577.352614},{\"Date\":\"2014-10-03\",\"Open\":573.052613,\"High\":577.227576,\"Low\":572.502582,\"Close\":575.282606,\"Volume\":1.1417e+06,\"AdjClose\":575.282606},{\"Date\":\"2014-10-02\",\"Open\":567.312567,\"High\":571.912585,\"Low\":563.322559,\"Close\":570.082615,\"Volume\":1.1784e+06,\"AdjClose\":570.082615},{\"Date\":\"2014-10-01\",\"Open\":576.012635,\"High\":577.582615,\"Low\":567.01255,\"Close\":568.272597,\"Volume\":1.4455e+06,\"AdjClose\":568.272597},{\"Date\":\"2014-09-30\",\"Open\":576.932578,\"High\":579.852634,\"Low\":572.852541,\"Close\":577.36259,\"Volume\":1.6217e+06,\"AdjClose\":577.36259},{\"Date\":\"2014-09-29\",\"Open\":571.7526,\"High\":578.192625,\"Low\":571.172579,\"Close\":576.362594,\"Volume\":1.2824e+06,\"AdjClose\":576.362594},{\"Date\":\"2014-09-26\",\"Open\":576.062638,\"High\":579.2526,\"Low\":574.662558,\"Close\":577.1026,\"Volume\":1.4437e+06,\"AdjClose\":577.1026},{\"Date\":\"2014-09-25\",\"Open\":587.552646,\"High\":587.982658,\"Low\":574.182604,\"Close\":575.062581,\"Volume\":1.926e+06,\"AdjClose\":575.062581},{\"Date\":\"2014-09-24\",\"Open\":581.462641,\"High\":589.632691,\"Low\":580.522624,\"Close\":587.992634,\"Volume\":1.7281e+06,\"AdjClose\":587.992634},{\"Date\":\"2014-09-23\",\"Open\":586.852606,\"High\":586.852606,\"Low\":581.002639,\"Close\":581.132634,\"Volume\":1.4714e+06,\"AdjClose\":581.132634},{\"Date\":\"2014-09-22\",\"Open\":593.82271,\"High\":593.951665,\"Low\":583.462694,\"Close\":587.372648,\"Volume\":1.6895e+06,\"AdjClose\":587.372648},{\"Date\":\"2014-09-19\",\"Open\":591.502688,\"High\":596.482654,\"Low\":589.502696,\"Close\":596.082692,\"Volume\":3.7366e+06,\"AdjClose\":596.082692},{\"Date\":\"2014-09-18\",\"Open\":587.002675,\"High\":589.542661,\"Low\":585.002622,\"Close\":589.272695,\"Volume\":1.4446e+06,\"AdjClose\":589.272695},{\"Date\":\"2014-09-17\",\"Open\":580.012619,\"High\":587.522656,\"Low\":578.777665,\"Close\":584.772683,\"Volume\":1.6928e+06,\"AdjClose\":584.772683},{\"Date\":\"2014-09-16\",\"Open\":572.762572,\"High\":581.502606,\"Low\":572.662566,\"Close\":579.95264,\"Volume\":1.4804e+06,\"AdjClose\":579.95264},{\"Date\":\"2014-09-15\",\"Open\":572.94257,\"High\":574.952599,\"Low\":568.212618,\"Close\":573.102555,\"Volume\":1.5976e+06,\"AdjClose\":573.102555},{\"Date\":\"2014-09-12\",\"Open\":581.002639,\"High\":581.642639,\"Low\":574.462608,\"Close\":575.622589,\"Volume\":1.6017e+06,\"AdjClose\":575.622589},{\"Date\":\"2014-09-11\",\"Open\":580.362639,\"High\":581.812599,\"Low\":576.262588,\"Close\":581.352598,\"Volume\":1.221e+06,\"AdjClose\":581.352598},{\"Date\":\"2014-09-10\",\"Open\":581.502606,\"High\":583.502659,\"Low\":576.942615,\"Close\":583.102636,\"Volume\":977400,\"AdjClose\":583.102636},{\"Date\":\"2014-09-09\",\"Open\":588.902723,\"High\":589.002667,\"Low\":580.002643,\"Close\":581.012615,\"Volume\":1.2872e+06,\"AdjClose\":581.012615},{\"Date\":\"2014-09-08\",\"Open\":586.602653,\"High\":591.772715,\"Low\":586.302635,\"Close\":589.722659,\"Volume\":1.431e+06,\"AdjClose\":589.722659},{\"Date\":\"2014-09-05\",\"Open\":583.982613,\"High\":586.55265,\"Low\":581.952632,\"Close\":586.082672,\"Volume\":1.6324e+06,\"AdjClose\":586.082672},{\"Date\":\"2014-09-04\",\"Open\":580.002643,\"High\":586.00268,\"Low\":579.222611,\"Close\":581.982621,\"Volume\":1.4582e+06,\"AdjClose\":581.982621},{\"Date\":\"2014-09-03\",\"Open\":580.002643,\"High\":582.992655,\"Low\":575.002602,\"Close\":577.942611,\"Volume\":1.2151e+06,\"AdjClose\":577.942611},{\"Date\":\"2014-09-02\",\"Open\":571.852545,\"High\":577.832629,\"Low\":571.192593,\"Close\":577.332662,\"Volume\":1.5784e+06,\"AdjClose\":577.332662},{\"Date\":\"2014-08-29\",\"Open\":571.332625,\"High\":572.04258,\"Low\":567.07155,\"Close\":571.60253,\"Volume\":1.0838e+06,\"AdjClose\":571.60253},{\"Date\":\"2014-08-28\",\"Open\":569.562573,\"High\":573.252563,\"Low\":567.102518,\"Close\":569.202577,\"Volume\":1.2929e+06,\"AdjClose\":569.202577},{\"Date\":\"2014-08-27\",\"Open\":577.272622,\"High\":578.492581,\"Low\":570.105627,\"Close\":571.002557,\"Volume\":1.7034e+06,\"AdjClose\":571.002557},{\"Date\":\"2014-08-26\",\"Open\":581.262629,\"High\":581.802623,\"Low\":576.582619,\"Close\":577.862619,\"Volume\":1.6397e+06,\"AdjClose\":577.862619},{\"Date\":\"2014-08-25\",\"Open\":584.722619,\"High\":585.002622,\"Low\":579.002647,\"Close\":580.202654,\"Volume\":1.3614e+06,\"AdjClose\":580.202654},{\"Date\":\"2014-08-22\",\"Open\":583.592689,\"High\":585.238682,\"Low\":580.642643,\"Close\":582.562642,\"Volume\":789100,\"AdjClose\":582.562642},{\"Date\":\"2014-08-21\",\"Open\":583.822628,\"High\":584.502655,\"Low\":581.142671,\"Close\":583.372664,\"Volume\":914800,\"AdjClose\":583.372664},{\"Date\":\"2014-08-20\",\"Open\":585.88266,\"High\":586.702658,\"Low\":582.572618,\"Close\":584.492618,\"Volume\":1.0367e+06,\"AdjClose\":584.492618},{\"Date\":\"2014-08-19\",\"Open\":585.002622,\"High\":587.342658,\"Low\":584.002627,\"Close\":586.862643,\"Volume\":978700,\"AdjClose\":586.862643},{\"Date\":\"2014-08-18\",\"Open\":576.11258,\"High\":584.512631,\"Low\":576.002598,\"Close\":582.162619,\"Volume\":1.2841e+06,\"AdjClose\":582.162619},{\"Date\":\"2014-08-15\",\"Open\":577.862619,\"High\":579.382595,\"Low\":570.522603,\"Close\":573.482564,\"Volume\":1.5192e+06,\"AdjClose\":573.482564},{\"Date\":\"2014-08-14\",\"Open\":576.182596,\"High\":577.902645,\"Low\":570.882599,\"Close\":574.652643,\"Volume\":985500,\"AdjClose\":574.652643},{\"Date\":\"2014-08-13\",\"Open\":567.312567,\"High\":575.002602,\"Low\":565.752564,\"Close\":574.782639,\"Volume\":1.4418e+06,\"AdjClose\":574.782639},{\"Date\":\"2014-08-12\",\"Open\":564.522567,\"High\":565.902572,\"Low\":560.882579,\"Close\":562.732562,\"Volume\":1.542e+06,\"AdjClose\":562.732562},{\"Date\":\"2014-08-11\",\"Open\":569.992585,\"High\":570.492553,\"Low\":566.002578,\"Close\":567.882551,\"Volume\":1.2147e+06,\"AdjClose\":567.882551},{\"Date\":\"2014-08-08\",\"Open\":563.562536,\"High\":570.252576,\"Low\":560.3525,\"Close\":568.772626,\"Volume\":1.4948e+06,\"AdjClose\":568.772626},{\"Date\":\"2014-08-07\",\"Open\":568.00257,\"High\":569.89258,\"Low\":561.102482,\"Close\":563.362525,\"Volume\":1.1109e+06,\"AdjClose\":563.362525},{\"Date\":\"2014-08-06\",\"Open\":561.782569,\"High\":570.702601,\"Low\":560.002541,\"Close\":566.376589,\"Volume\":1.3344e+06,\"AdjClose\":566.376589},{\"Date\":\"2014-08-05\",\"Open\":570.052564,\"High\":571.982601,\"Low\":562.612543,\"Close\":565.072598,\"Volume\":1.5512e+06,\"AdjClose\":565.072598},{\"Date\":\"2014-08-04\",\"Open\":569.042531,\"High\":575.352561,\"Low\":564.102531,\"Close\":573.152619,\"Volume\":1.4273e+06,\"AdjClose\":573.152619},{\"Date\":\"2014-08-01\",\"Open\":570.402584,\"High\":575.962633,\"Low\":562.85252,\"Close\":566.072594,\"Volume\":1.9553e+06,\"AdjClose\":566.072594},{\"Date\":\"2014-07-31\",\"Open\":580.602616,\"High\":583.652668,\"Low\":570.002561,\"Close\":571.60253,\"Volume\":2.1028e+06,\"AdjClose\":571.60253},{\"Date\":\"2014-07-30\",\"Open\":586.55265,\"High\":589.502696,\"Low\":584.002627,\"Close\":587.42265,\"Volume\":1.0165e+06,\"AdjClose\":587.42265},{\"Date\":\"2014-07-29\",\"Open\":588.752653,\"High\":589.702707,\"Low\":583.517654,\"Close\":585.612633,\"Volume\":1.3499e+06,\"AdjClose\":585.612633},{\"Date\":\"2014-07-28\",\"Open\":588.072688,\"High\":592.502683,\"Low\":584.755668,\"Close\":590.602636,\"Volume\":986800,\"AdjClose\":590.602636},{\"Date\":\"2014-07-25\",\"Open\":590.402686,\"High\":591.862684,\"Low\":587.032665,\"Close\":589.022681,\"Volume\":932500,\"AdjClose\":589.022681},{\"Date\":\"2014-07-24\",\"Open\":596.452725,\"High\":599.502716,\"Low\":591.772715,\"Close\":593.352671,\"Volume\":1.0351e+06,\"AdjClose\":593.352671},{\"Date\":\"2014-07-23\",\"Open\":593.232652,\"High\":597.852683,\"Low\":592.502683,\"Close\":595.982686,\"Volume\":1.2332e+06,\"AdjClose\":595.982686},{\"Date\":\"2014-07-22\",\"Open\":590.722655,\"High\":599.652725,\"Low\":590.602636,\"Close\":594.742652,\"Volume\":1.6992e+06,\"AdjClose\":594.742652},{\"Date\":\"2014-07-21\",\"Open\":591.752702,\"High\":594.402731,\"Low\":585.235622,\"Close\":589.472645,\"Volume\":2.0621e+06,\"AdjClose\":589.472645},{\"Date\":\"2014-07-18\",\"Open\":593.002712,\"High\":596.802684,\"Low\":582.002635,\"Close\":595.082696,\"Volume\":4.0142e+06,\"AdjClose\":595.082696},{\"Date\":\"2014-07-17\",\"Open\":579.532665,\"High\":580.992601,\"Low\":568.61258,\"Close\":573.732579,\"Volume\":3.0166e+06,\"AdjClose\":573.732579},{\"Date\":\"2014-07-16\",\"Open\":588.002671,\"High\":588.402694,\"Low\":582.202646,\"Close\":582.662587,\"Volume\":1.3971e+06,\"AdjClose\":582.662587},{\"Date\":\"2014-07-15\",\"Open\":585.742628,\"High\":585.807626,\"Low\":576.562606,\"Close\":584.782659,\"Volume\":1.623e+06,\"AdjClose\":584.782659},{\"Date\":\"2014-07-14\",\"Open\":582.602608,\"High\":585.212671,\"Low\":578.032641,\"Close\":584.872627,\"Volume\":1.8541e+06,\"AdjClose\":584.872627},{\"Date\":\"2014-07-11\",\"Open\":571.912585,\"High\":580.85263,\"Low\":571.422594,\"Close\":579.182645,\"Volume\":1.6217e+06,\"AdjClose\":579.182645},{\"Date\":\"2014-07-10\",\"Open\":565.912548,\"High\":576.592656,\"Low\":565.012558,\"Close\":571.102563,\"Volume\":1.3567e+06,\"AdjClose\":571.102563},{\"Date\":\"2014-07-09\",\"Open\":571.582578,\"High\":576.72259,\"Low\":569.378536,\"Close\":576.082652,\"Volume\":1.1168e+06,\"AdjClose\":576.082652},{\"Date\":\"2014-07-08\",\"Open\":577.662607,\"High\":579.530645,\"Low\":566.137592,\"Close\":571.092587,\"Volume\":1.9095e+06,\"AdjClose\":571.092587},{\"Date\":\"2014-07-07\",\"Open\":583.76265,\"High\":586.432631,\"Low\":579.592644,\"Close\":582.252649,\"Volume\":1.0646e+06,\"AdjClose\":582.252649},{\"Date\":\"2014-07-03\",\"Open\":583.352589,\"High\":585.01266,\"Low\":580.922585,\"Close\":584.732656,\"Volume\":714200,\"AdjClose\":584.732656},{\"Date\":\"2014-07-02\",\"Open\":583.352589,\"High\":585.442672,\"Low\":580.392628,\"Close\":582.33766,\"Volume\":1.0564e+06,\"AdjClose\":582.33766},{\"Date\":\"2014-07-01\",\"Open\":578.32262,\"High\":584.402649,\"Low\":576.652635,\"Close\":582.672624,\"Volume\":1.448e+06,\"AdjClose\":582.672624},{\"Date\":\"2014-06-30\",\"Open\":578.662603,\"High\":579.572631,\"Low\":574.752588,\"Close\":575.282606,\"Volume\":1.3138e+06,\"AdjClose\":575.282606},{\"Date\":\"2014-06-27\",\"Open\":577.182592,\"High\":579.872648,\"Low\":573.802595,\"Close\":577.242632,\"Volume\":2.2369e+06,\"AdjClose\":577.242632},{\"Date\":\"2014-06-26\",\"Open\":581.002639,\"High\":582.45266,\"Low\":571.852545,\"Close\":576.002598,\"Volume\":1.742e+06,\"AdjClose\":576.002598},{\"Date\":\"2014-06-25\",\"Open\":565.262572,\"High\":579.962616,\"Low\":565.222546,\"Close\":578.652627,\"Volume\":1.9694e+06,\"AdjClose\":578.652627},{\"Date\":\"2014-06-24\",\"Open\":565.192556,\"High\":572.648612,\"Low\":561.012574,\"Close\":564.622572,\"Volume\":2.2071e+06,\"AdjClose\":564.622572},{\"Date\":\"2014-06-23\",\"Open\":555.152509,\"High\":565.002582,\"Low\":554.252519,\"Close\":564.952579,\"Volume\":1.5368e+06,\"AdjClose\":564.952579},{\"Date\":\"2014-06-20\",\"Open\":556.852484,\"High\":557.582513,\"Low\":550.394526,\"Close\":556.362492,\"Volume\":4.5083e+06,\"AdjClose\":556.362492},{\"Date\":\"2014-06-19\",\"Open\":554.242482,\"High\":555.0025,\"Low\":548.512473,\"Close\":554.902556,\"Volume\":2.4568e+06,\"AdjClose\":554.902556},{\"Date\":\"2014-06-18\",\"Open\":544.862448,\"High\":553.562516,\"Low\":544.002484,\"Close\":553.372481,\"Volume\":1.7418e+06,\"AdjClose\":553.372481},{\"Date\":\"2014-06-17\",\"Open\":544.202496,\"High\":545.32245,\"Low\":539.33245,\"Close\":543.012465,\"Volume\":1.4446e+06,\"AdjClose\":543.012465},{\"Date\":\"2014-06-16\",\"Open\":549.262515,\"High\":549.62245,\"Low\":541.522477,\"Close\":544.282488,\"Volume\":1.7026e+06,\"AdjClose\":544.282488},{\"Date\":\"2014-06-13\",\"Open\":552.262503,\"High\":552.302469,\"Low\":545.562488,\"Close\":551.762536,\"Volume\":1.2205e+06,\"AdjClose\":551.762536},{\"Date\":\"2014-06-12\",\"Open\":557.302509,\"High\":557.992512,\"Low\":548.462531,\"Close\":551.352476,\"Volume\":1.4585e+06,\"AdjClose\":551.352476},{\"Date\":\"2014-06-11\",\"Open\":558.002549,\"High\":559.882522,\"Low\":555.022514,\"Close\":558.842561,\"Volume\":1.1001e+06,\"AdjClose\":558.842561},{\"Date\":\"2014-06-10\",\"Open\":560.512546,\"High\":563.602502,\"Low\":557.902544,\"Close\":560.552511,\"Volume\":1.3517e+06,\"AdjClose\":560.552511},{\"Date\":\"2014-06-09\",\"Open\":557.152562,\"High\":562.902584,\"Low\":556.042523,\"Close\":562.122552,\"Volume\":1.4675e+06,\"AdjClose\":562.122552},{\"Date\":\"2014-06-06\",\"Open\":558.062528,\"High\":558.062528,\"Low\":548.932448,\"Close\":556.332564,\"Volume\":1.7368e+06,\"AdjClose\":556.332564},{\"Date\":\"2014-06-05\",\"Open\":546.402499,\"High\":554.952498,\"Low\":544.452449,\"Close\":553.90256,\"Volume\":1.6891e+06,\"AdjClose\":553.90256},{\"Date\":\"2014-06-04\",\"Open\":541.502464,\"High\":548.612478,\"Low\":538.752429,\"Close\":544.662436,\"Volume\":1.8165e+06,\"AdjClose\":544.662436},{\"Date\":\"2014-06-03\",\"Open\":550.99248,\"High\":552.342557,\"Low\":542.552463,\"Close\":544.942501,\"Volume\":1.8666e+06,\"AdjClose\":544.942501},{\"Date\":\"2014-06-02\",\"Open\":560.702581,\"High\":560.902593,\"Low\":545.732448,\"Close\":553.932488,\"Volume\":1.435e+06,\"AdjClose\":553.932488},{\"Date\":\"2014-05-30\",\"Open\":560.802526,\"High\":561.352496,\"Low\":555.912467,\"Close\":559.892559,\"Volume\":1.7711e+06,\"AdjClose\":559.892559},{\"Date\":\"2014-05-29\",\"Open\":563.352549,\"High\":564.002525,\"Low\":558.712565,\"Close\":560.082534,\"Volume\":1.3541e+06,\"AdjClose\":560.082534},{\"Date\":\"2014-05-28\",\"Open\":564.57257,\"High\":567.842585,\"Low\":561.002537,\"Close\":561.682502,\"Volume\":1.652e+06,\"AdjClose\":561.682502},{\"Date\":\"2014-05-27\",\"Open\":556.002496,\"High\":566.002578,\"Low\":554.352463,\"Close\":565.952575,\"Volume\":2.1042e+06,\"AdjClose\":565.952575},{\"Date\":\"2014-05-23\",\"Open\":547.262462,\"High\":553.642508,\"Low\":543.702467,\"Close\":552.702492,\"Volume\":1.9322e+06,\"AdjClose\":552.702492},{\"Date\":\"2014-05-22\",\"Open\":541.132431,\"High\":547.602445,\"Low\":540.782472,\"Close\":545.062459,\"Volume\":1.6158e+06,\"AdjClose\":545.062459},{\"Date\":\"2014-05-21\",\"Open\":532.902462,\"High\":539.185441,\"Low\":531.912381,\"Close\":538.942465,\"Volume\":1.1963e+06,\"AdjClose\":538.942465},{\"Date\":\"2014-05-20\",\"Open\":529.742368,\"High\":536.232396,\"Low\":526.302392,\"Close\":529.772418,\"Volume\":1.7848e+06,\"AdjClose\":529.772418},{\"Date\":\"2014-05-19\",\"Open\":519.702382,\"High\":529.782456,\"Low\":517.58537,\"Close\":528.862391,\"Volume\":1.2778e+06,\"AdjClose\":528.862391},{\"Date\":\"2014-05-16\",\"Open\":521.39238,\"High\":521.802379,\"Low\":515.442347,\"Close\":520.632362,\"Volume\":1.4853e+06,\"AdjClose\":520.632362},{\"Date\":\"2014-05-15\",\"Open\":525.702357,\"High\":525.872379,\"Low\":517.422325,\"Close\":519.982324,\"Volume\":1.7044e+06,\"AdjClose\":519.982324},{\"Date\":\"2014-05-14\",\"Open\":533.002407,\"High\":533.002407,\"Low\":525.292358,\"Close\":526.652412,\"Volume\":1.1918e+06,\"AdjClose\":526.652412},{\"Date\":\"2014-05-13\",\"Open\":530.892433,\"High\":536.072411,\"Low\":529.512428,\"Close\":533.092437,\"Volume\":1.6534e+06,\"AdjClose\":533.092437},{\"Date\":\"2014-05-12\",\"Open\":523.512391,\"High\":530.192393,\"Low\":519.012379,\"Close\":529.922366,\"Volume\":1.9125e+06,\"AdjClose\":529.922366},{\"Date\":\"2014-05-09\",\"Open\":510.75233,\"High\":519.902393,\"Low\":504.202292,\"Close\":518.732314,\"Volume\":2.4395e+06,\"AdjClose\":518.732314},{\"Date\":\"2014-05-08\",\"Open\":508.462297,\"High\":517.23229,\"Low\":506.452298,\"Close\":511.002313,\"Volume\":2.0213e+06,\"AdjClose\":511.002313},{\"Date\":\"2014-05-07\",\"Open\":515.792305,\"High\":516.68232,\"Low\":503.302272,\"Close\":509.962291,\"Volume\":3.2243e+06,\"AdjClose\":509.962291},{\"Date\":\"2014-05-06\",\"Open\":525.232379,\"High\":526.812396,\"Low\":515.062337,\"Close\":515.14233,\"Volume\":1.689e+06,\"AdjClose\":515.14233},{\"Date\":\"2014-05-05\",\"Open\":524.822381,\"High\":528.902418,\"Low\":521.322364,\"Close\":527.812392,\"Volume\":1.0241e+06,\"AdjClose\":527.812392},{\"Date\":\"2014-05-02\",\"Open\":533.762426,\"High\":534.002403,\"Low\":525.612389,\"Close\":527.932411,\"Volume\":1.6885e+06,\"AdjClose\":527.932411},{\"Date\":\"2014-05-01\",\"Open\":527.112352,\"High\":532.932391,\"Low\":523.882364,\"Close\":531.352374,\"Volume\":1.9055e+06,\"AdjClose\":531.352374},{\"Date\":\"2014-04-30\",\"Open\":527.602343,\"High\":528.002366,\"Low\":522.522372,\"Close\":526.662388,\"Volume\":1.7512e+06,\"AdjClose\":526.662388},{\"Date\":\"2014-04-29\",\"Open\":516.902344,\"High\":529.462425,\"Low\":516.322324,\"Close\":527.70241,\"Volume\":2.6991e+06,\"AdjClose\":527.70241},{\"Date\":\"2014-04-28\",\"Open\":517.182348,\"High\":518.602319,\"Low\":502.802274,\"Close\":517.152359,\"Volume\":3.3355e+06,\"AdjClose\":517.152359},{\"Date\":\"2014-04-25\",\"Open\":522.512395,\"High\":524.702361,\"Low\":515.422333,\"Close\":516.182352,\"Volume\":2.1004e+06,\"AdjClose\":516.182352},{\"Date\":\"2014-04-24\",\"Open\":530.072374,\"High\":531.652452,\"Low\":522.122349,\"Close\":525.162363,\"Volume\":1.8832e+06,\"AdjClose\":525.162363},{\"Date\":\"2014-04-23\",\"Open\":533.792415,\"High\":533.872408,\"Low\":526.252389,\"Close\":526.942391,\"Volume\":2.0523e+06,\"AdjClose\":526.942391},{\"Date\":\"2014-04-22\",\"Open\":528.642427,\"High\":537.232391,\"Low\":527.512375,\"Close\":534.812425,\"Volume\":2.3654e+06,\"AdjClose\":534.812425},{\"Date\":\"2014-04-21\",\"Open\":536.1024,\"High\":536.702435,\"Low\":525.602352,\"Close\":528.622414,\"Volume\":2.5667e+06,\"AdjClose\":528.622414},{\"Date\":\"2014-04-17\",\"Open\":548.81249,\"High\":549.502492,\"Low\":531.152424,\"Close\":536.1024,\"Volume\":6.8095e+06,\"AdjClose\":536.1024},{\"Date\":\"2014-04-16\",\"Open\":543.002488,\"High\":557.002492,\"Low\":540.00244,\"Close\":556.54249,\"Volume\":4.8933e+06,\"AdjClose\":556.54249},{\"Date\":\"2014-04-15\",\"Open\":536.822454,\"High\":538.452473,\"Low\":518.462348,\"Close\":536.442444,\"Volume\":3.8551e+06,\"AdjClose\":536.442444},{\"Date\":\"2014-04-14\",\"Open\":538.252462,\"High\":544.102429,\"Low\":529.56237,\"Close\":532.522453,\"Volume\":2.5751e+06,\"AdjClose\":532.522453},{\"Date\":\"2014-04-11\",\"Open\":532.552381,\"High\":540.00244,\"Low\":526.532392,\"Close\":530.602392,\"Volume\":3.9248e+06,\"AdjClose\":530.602392},{\"Date\":\"2014-04-10\",\"Open\":565.002582,\"High\":565.002582,\"Low\":539.902495,\"Close\":540.952433,\"Volume\":4.0369e+06,\"AdjClose\":540.952433},{\"Date\":\"2014-04-09\",\"Open\":559.622532,\"High\":565.372554,\"Low\":552.952506,\"Close\":564.142557,\"Volume\":3.3308e+06,\"AdjClose\":564.142557},{\"Date\":\"2014-04-08\",\"Open\":542.602466,\"High\":555.0025,\"Low\":541.612446,\"Close\":554.902556,\"Volume\":3.1512e+06,\"AdjClose\":554.902556},{\"Date\":\"2014-04-07\",\"Open\":540.742445,\"High\":548.482483,\"Low\":527.15244,\"Close\":538.152456,\"Volume\":4.4017e+06,\"AdjClose\":538.152456},{\"Date\":\"2014-04-04\",\"Open\":574.652643,\"High\":577.77265,\"Low\":543.002488,\"Close\":543.14246,\"Volume\":6.3693e+06,\"AdjClose\":543.14246},{\"Date\":\"2014-04-03\",\"Open\":569.852553,\"High\":587.282679,\"Low\":564.132581,\"Close\":569.742571,\"Volume\":5.0992e+06,\"AdjClose\":569.742571},{\"Date\":\"2014-04-02\",\"Open\":599.992707,\"High\":604.832763,\"Low\":562.192568,\"Close\":567.002574,\"Volume\":147100,\"AdjClose\":567.002574},{\"Date\":\"2014-04-01\",\"Open\":558.712565,\"High\":568.452595,\"Low\":558.712565,\"Close\":567.162558,\"Volume\":7900,\"AdjClose\":567.162558},{\"Date\":\"2014-03-31\",\"Open\":566.892592,\"High\":567.002574,\"Low\":556.932537,\"Close\":556.972503,\"Volume\":10800,\"AdjClose\":556.972503},{\"Date\":\"2014-03-28\",\"Open\":561.202549,\"High\":566.43259,\"Low\":558.672477,\"Close\":559.992504,\"Volume\":41200,\"AdjClose\":559.992504},{\"Date\":\"2014-03-27\",\"Open\":568.00257,\"High\":568.00257,\"Low\":552.922516,\"Close\":558.462551,\"Volume\":13100,\"AdjClose\":558.462551}]\n"
  },
  {
    "path": "27_code-in-process/38_JSON/15_exercise_csv-to-JSON/01/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t//\t\"fmt\"\n\t\"encoding/json\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\n\t//open file\n\tsrc, err := os.Open(\"../table.csv\")\n\tif err != nil {\n\t\tlog.Fatalln(\"couldn't open file\", err.Error())\n\t}\n\tdefer src.Close()\n\n\t// reader for csv file\n\trdr := csv.NewReader(src)\n\n\t// read csv file\n\tdata, err := rdr.ReadAll()\n\tif err != nil {\n\t\tlog.Fatalln(\"couldn't readall\", err.Error())\n\t}\n\n\t// convert to JSON\n\tb, err := json.Marshal(data)\n\tif err != nil {\n\t\tlog.Fatalln(\"couldn't marshall\", err.Error())\n\t}\n\n\t// show\n\tos.Stdout.Write(b)\n\t//\tfmt.Println(b)\n\n}\n"
  },
  {
    "path": "27_code-in-process/38_JSON/15_exercise_csv-to-JSON/02/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t\"encoding/json\"\n\t\"log\"\n\t\"os\"\n\t\"strconv\"\n)\n\ntype StockData struct {\n\tDate     string\n\tOpen     float64\n\tHigh     float64\n\tLow      float64\n\tClose    float64\n\tVolume   float64\n\tAdjClose float64\n}\n\nfunc toFloat(str string) float64 {\n\tv, _ := strconv.ParseFloat(str, 64)\n\treturn v\n}\n\nfunc main() {\n\tsrc, err := os.Open(\"../resources/table.csv\")\n\tif err != nil {\n\t\tlog.Fatalln(\"couldn't open file\", err.Error())\n\t}\n\tdefer src.Close()\n\n\tdst, err := os.Create(\"output.txt\")\n\tif err != nil {\n\t\tlog.Fatalln(\"couldn't open file\", err.Error())\n\t}\n\tdefer dst.Close()\n\n\trdr := csv.NewReader(src)\n\n\tdata, err := rdr.ReadAll()\n\tif err != nil {\n\t\tlog.Fatalln(\"couldn't readall\", err.Error())\n\t}\n\n\tlistOfStockData := []StockData{}\n\t// put data into struct\n\tfor _, row := range data {\n\t\tsd := StockData{\n\t\t\tDate:     row[0],\n\t\t\tOpen:     toFloat(row[1]),\n\t\t\tHigh:     toFloat(row[2]),\n\t\t\tLow:      toFloat(row[3]),\n\t\t\tClose:    toFloat(row[4]),\n\t\t\tVolume:   toFloat(row[5]),\n\t\t\tAdjClose: toFloat(row[6]),\n\t\t}\n\t\tlistOfStockData = append(listOfStockData, sd)\n\t}\n\n\t//convert to JSON\n\terr = json.NewEncoder(dst).Encode(listOfStockData)\n\tif err != nil {\n\t\tlog.Fatalln(\"couldn't encode\", err.Error())\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/38_JSON/15_exercise_csv-to-JSON/02/output.txt",
    "content": "[{\"Date\":\"Date\",\"Open\":0,\"High\":0,\"Low\":0,\"Close\":0,\"Volume\":0,\"AdjClose\":0},{\"Date\":\"2015-07-09\",\"Open\":523.119995,\"High\":523.77002,\"Low\":520.349976,\"Close\":520.679993,\"Volume\":1.8394e+06,\"AdjClose\":520.679993},{\"Date\":\"2015-07-08\",\"Open\":521.049988,\"High\":522.734009,\"Low\":516.109985,\"Close\":516.830017,\"Volume\":1.2646e+06,\"AdjClose\":516.830017},{\"Date\":\"2015-07-07\",\"Open\":523.130005,\"High\":526.179993,\"Low\":515.179993,\"Close\":525.02002,\"Volume\":1.5957e+06,\"AdjClose\":525.02002},{\"Date\":\"2015-07-06\",\"Open\":519.5,\"High\":525.25,\"Low\":519,\"Close\":522.859985,\"Volume\":1.2765e+06,\"AdjClose\":522.859985},{\"Date\":\"2015-07-02\",\"Open\":521.080017,\"High\":524.650024,\"Low\":521.080017,\"Close\":523.400024,\"Volume\":1.234e+06,\"AdjClose\":523.400024},{\"Date\":\"2015-07-01\",\"Open\":524.72998,\"High\":525.690002,\"Low\":518.22998,\"Close\":521.840027,\"Volume\":1.961e+06,\"AdjClose\":521.840027},{\"Date\":\"2015-06-30\",\"Open\":526.02002,\"High\":526.25,\"Low\":520.5,\"Close\":520.51001,\"Volume\":2.2172e+06,\"AdjClose\":520.51001},{\"Date\":\"2015-06-29\",\"Open\":525.01001,\"High\":528.609985,\"Low\":520.539978,\"Close\":521.52002,\"Volume\":1.9309e+06,\"AdjClose\":521.52002},{\"Date\":\"2015-06-26\",\"Open\":537.26001,\"High\":537.76001,\"Low\":531.349976,\"Close\":531.690002,\"Volume\":2.0115e+06,\"AdjClose\":531.690002},{\"Date\":\"2015-06-25\",\"Open\":538.869995,\"High\":540.900024,\"Low\":535.22998,\"Close\":535.22998,\"Volume\":1.3315e+06,\"AdjClose\":535.22998},{\"Date\":\"2015-06-24\",\"Open\":540,\"High\":540,\"Low\":535.659973,\"Close\":537.840027,\"Volume\":1.2834e+06,\"AdjClose\":537.840027},{\"Date\":\"2015-06-23\",\"Open\":539.640015,\"High\":541.499023,\"Low\":535.25,\"Close\":540.47998,\"Volume\":1.196e+06,\"AdjClose\":540.47998},{\"Date\":\"2015-06-22\",\"Open\":539.590027,\"High\":543.73999,\"Low\":537.530029,\"Close\":538.190002,\"Volume\":1.2425e+06,\"AdjClose\":538.190002},{\"Date\":\"2015-06-19\",\"Open\":537.210022,\"High\":538.25,\"Low\":533.01001,\"Close\":536.690002,\"Volume\":1.8857e+06,\"AdjClose\":536.690002},{\"Date\":\"2015-06-18\",\"Open\":531,\"High\":538.150024,\"Low\":530.789978,\"Close\":536.72998,\"Volume\":1.8281e+06,\"AdjClose\":536.72998},{\"Date\":\"2015-06-17\",\"Open\":529.369995,\"High\":530.97998,\"Low\":525.099976,\"Close\":529.26001,\"Volume\":1.2686e+06,\"AdjClose\":529.26001},{\"Date\":\"2015-06-16\",\"Open\":528.400024,\"High\":529.640015,\"Low\":525.559998,\"Close\":528.150024,\"Volume\":1.0693e+06,\"AdjClose\":528.150024},{\"Date\":\"2015-06-15\",\"Open\":528,\"High\":528.299988,\"Low\":524,\"Close\":527.200012,\"Volume\":1.6307e+06,\"AdjClose\":527.200012},{\"Date\":\"2015-06-12\",\"Open\":531.599976,\"High\":533.119995,\"Low\":530.159973,\"Close\":532.330017,\"Volume\":952400,\"AdjClose\":532.330017},{\"Date\":\"2015-06-11\",\"Open\":538.424988,\"High\":538.97998,\"Low\":533.02002,\"Close\":534.609985,\"Volume\":1.205e+06,\"AdjClose\":534.609985},{\"Date\":\"2015-06-10\",\"Open\":529.359985,\"High\":538.359985,\"Low\":529.349976,\"Close\":536.690002,\"Volume\":1.8114e+06,\"AdjClose\":536.690002},{\"Date\":\"2015-06-09\",\"Open\":527.559998,\"High\":529.200012,\"Low\":523.01001,\"Close\":526.690002,\"Volume\":1.4416e+06,\"AdjClose\":526.690002},{\"Date\":\"2015-06-08\",\"Open\":533.309998,\"High\":534.119995,\"Low\":526.23999,\"Close\":526.830017,\"Volume\":1.5206e+06,\"AdjClose\":526.830017},{\"Date\":\"2015-06-05\",\"Open\":536.349976,\"High\":537.200012,\"Low\":532.52002,\"Close\":533.330017,\"Volume\":1.375e+06,\"AdjClose\":533.330017},{\"Date\":\"2015-06-04\",\"Open\":537.76001,\"High\":540.590027,\"Low\":534.320007,\"Close\":536.700012,\"Volume\":1.3356e+06,\"AdjClose\":536.700012},{\"Date\":\"2015-06-03\",\"Open\":539.909973,\"High\":543.5,\"Low\":537.109985,\"Close\":540.309998,\"Volume\":1.7145e+06,\"AdjClose\":540.309998},{\"Date\":\"2015-06-02\",\"Open\":532.929993,\"High\":543,\"Low\":531.330017,\"Close\":539.179993,\"Volume\":1.9347e+06,\"AdjClose\":539.179993},{\"Date\":\"2015-06-01\",\"Open\":536.789978,\"High\":536.789978,\"Low\":529.76001,\"Close\":533.98999,\"Volume\":1.8996e+06,\"AdjClose\":533.98999},{\"Date\":\"2015-05-29\",\"Open\":537.369995,\"High\":538.630005,\"Low\":531.450012,\"Close\":532.109985,\"Volume\":2.5849e+06,\"AdjClose\":532.109985},{\"Date\":\"2015-05-28\",\"Open\":538.01001,\"High\":540.609985,\"Low\":536.25,\"Close\":539.780029,\"Volume\":1.0279e+06,\"AdjClose\":539.780029},{\"Date\":\"2015-05-27\",\"Open\":532.799988,\"High\":540.549988,\"Low\":531.710022,\"Close\":539.789978,\"Volume\":1.5204e+06,\"AdjClose\":539.789978},{\"Date\":\"2015-05-26\",\"Open\":538.119995,\"High\":539,\"Low\":529.880005,\"Close\":532.320007,\"Volume\":2.4034e+06,\"AdjClose\":532.320007},{\"Date\":\"2015-05-22\",\"Open\":540.150024,\"High\":544.190002,\"Low\":539.51001,\"Close\":540.109985,\"Volume\":1.1733e+06,\"AdjClose\":540.109985},{\"Date\":\"2015-05-21\",\"Open\":537.950012,\"High\":543.840027,\"Low\":535.97998,\"Close\":542.51001,\"Volume\":1.4614e+06,\"AdjClose\":542.51001},{\"Date\":\"2015-05-20\",\"Open\":538.48999,\"High\":542.919983,\"Low\":532.971985,\"Close\":539.27002,\"Volume\":1.4291e+06,\"AdjClose\":539.27002},{\"Date\":\"2015-05-19\",\"Open\":533.97998,\"High\":540.659973,\"Low\":533.039978,\"Close\":537.359985,\"Volume\":1.9633e+06,\"AdjClose\":537.359985},{\"Date\":\"2015-05-18\",\"Open\":532.01001,\"High\":534.820007,\"Low\":528.849976,\"Close\":532.299988,\"Volume\":1.9986e+06,\"AdjClose\":532.299988},{\"Date\":\"2015-05-15\",\"Open\":539.179993,\"High\":539.273987,\"Low\":530.380005,\"Close\":533.849976,\"Volume\":1.9627e+06,\"AdjClose\":533.849976},{\"Date\":\"2015-05-14\",\"Open\":533.77002,\"High\":539,\"Low\":532.409973,\"Close\":538.400024,\"Volume\":1.3991e+06,\"AdjClose\":538.400024},{\"Date\":\"2015-05-13\",\"Open\":530.559998,\"High\":534.322021,\"Low\":528.655029,\"Close\":529.619995,\"Volume\":1.2523e+06,\"AdjClose\":529.619995},{\"Date\":\"2015-05-12\",\"Open\":531.599976,\"High\":533.208984,\"Low\":525.26001,\"Close\":529.039978,\"Volume\":1.6254e+06,\"AdjClose\":529.039978},{\"Date\":\"2015-05-11\",\"Open\":538.369995,\"High\":541.97998,\"Low\":535.400024,\"Close\":535.700012,\"Volume\":905300,\"AdjClose\":535.700012},{\"Date\":\"2015-05-08\",\"Open\":536.650024,\"High\":541.150024,\"Low\":525,\"Close\":538.219971,\"Volume\":1.5276e+06,\"AdjClose\":538.219971},{\"Date\":\"2015-05-07\",\"Open\":523.98999,\"High\":533.460022,\"Low\":521.75,\"Close\":530.700012,\"Volume\":1.5463e+06,\"AdjClose\":530.700012},{\"Date\":\"2015-05-06\",\"Open\":531.23999,\"High\":532.380005,\"Low\":521.085022,\"Close\":524.219971,\"Volume\":1.567e+06,\"AdjClose\":524.219971},{\"Date\":\"2015-05-05\",\"Open\":538.210022,\"High\":539.73999,\"Low\":530.390991,\"Close\":530.799988,\"Volume\":1.3831e+06,\"AdjClose\":530.799988},{\"Date\":\"2015-05-04\",\"Open\":538.530029,\"High\":544.070007,\"Low\":535.059998,\"Close\":540.780029,\"Volume\":1.308e+06,\"AdjClose\":540.780029},{\"Date\":\"2015-05-01\",\"Open\":538.429993,\"High\":539.539978,\"Low\":532.099976,\"Close\":537.900024,\"Volume\":1.7682e+06,\"AdjClose\":537.900024},{\"Date\":\"2015-04-30\",\"Open\":547.869995,\"High\":548.590027,\"Low\":535.049988,\"Close\":537.340027,\"Volume\":2.0822e+06,\"AdjClose\":537.340027},{\"Date\":\"2015-04-29\",\"Open\":550.469971,\"High\":553.679993,\"Low\":546.905029,\"Close\":549.080017,\"Volume\":1.6988e+06,\"AdjClose\":549.080017},{\"Date\":\"2015-04-28\",\"Open\":554.640015,\"High\":556.02002,\"Low\":550.366028,\"Close\":553.679993,\"Volume\":1.491e+06,\"AdjClose\":553.679993},{\"Date\":\"2015-04-27\",\"Open\":563.390015,\"High\":565.950012,\"Low\":553.200012,\"Close\":555.369995,\"Volume\":2.398e+06,\"AdjClose\":555.369995},{\"Date\":\"2015-04-24\",\"Open\":566.102522,\"High\":571.14259,\"Low\":557.252507,\"Close\":565.062561,\"Volume\":4.9325e+06,\"AdjClose\":565.062561},{\"Date\":\"2015-04-23\",\"Open\":541.002435,\"High\":550.96249,\"Low\":540.23244,\"Close\":547.002472,\"Volume\":4.1849e+06,\"AdjClose\":547.002472},{\"Date\":\"2015-04-22\",\"Open\":534.402426,\"High\":541.082489,\"Low\":531.752397,\"Close\":539.367458,\"Volume\":1.5936e+06,\"AdjClose\":539.367458},{\"Date\":\"2015-04-21\",\"Open\":537.512456,\"High\":539.392429,\"Low\":533.677415,\"Close\":533.972413,\"Volume\":1.8448e+06,\"AdjClose\":533.972413},{\"Date\":\"2015-04-20\",\"Open\":525.602352,\"High\":536.092424,\"Low\":524.50235,\"Close\":535.382408,\"Volume\":1.6793e+06,\"AdjClose\":535.382408},{\"Date\":\"2015-04-17\",\"Open\":528.662379,\"High\":529.842435,\"Low\":521.012371,\"Close\":524.052386,\"Volume\":2.1441e+06,\"AdjClose\":524.052386},{\"Date\":\"2015-04-16\",\"Open\":529.902414,\"High\":535.592457,\"Low\":529.612373,\"Close\":533.802391,\"Volume\":1.2999e+06,\"AdjClose\":533.802391},{\"Date\":\"2015-04-15\",\"Open\":528.702406,\"High\":534.732432,\"Low\":523.22235,\"Close\":532.532429,\"Volume\":2.3188e+06,\"AdjClose\":532.532429},{\"Date\":\"2015-04-14\",\"Open\":536.252409,\"High\":537.572435,\"Low\":528.094354,\"Close\":530.392405,\"Volume\":2.6041e+06,\"AdjClose\":530.392405},{\"Date\":\"2015-04-13\",\"Open\":538.412385,\"High\":544.062463,\"Low\":537.312445,\"Close\":539.172404,\"Volume\":1.6453e+06,\"AdjClose\":539.172404},{\"Date\":\"2015-04-10\",\"Open\":542.292411,\"High\":542.292411,\"Low\":537.312445,\"Close\":540.012477,\"Volume\":1.4095e+06,\"AdjClose\":540.012477},{\"Date\":\"2015-04-09\",\"Open\":541.032486,\"High\":541.95249,\"Low\":535.49239,\"Close\":540.782472,\"Volume\":1.5579e+06,\"AdjClose\":540.782472},{\"Date\":\"2015-04-08\",\"Open\":538.382457,\"High\":543.852415,\"Low\":538.382457,\"Close\":541.612446,\"Volume\":1.1785e+06,\"AdjClose\":541.612446},{\"Date\":\"2015-04-07\",\"Open\":538.08244,\"High\":542.692434,\"Low\":536.002395,\"Close\":537.022465,\"Volume\":1.3029e+06,\"AdjClose\":537.022465},{\"Date\":\"2015-04-06\",\"Open\":532.222375,\"High\":538.412385,\"Low\":529.572407,\"Close\":536.767432,\"Volume\":1.3244e+06,\"AdjClose\":536.767432},{\"Date\":\"2015-04-02\",\"Open\":540.852427,\"High\":540.852427,\"Low\":533.849395,\"Close\":535.532478,\"Volume\":1.7164e+06,\"AdjClose\":535.532478},{\"Date\":\"2015-04-01\",\"Open\":548.602441,\"High\":551.142488,\"Low\":539.502472,\"Close\":542.562439,\"Volume\":1.9631e+06,\"AdjClose\":542.562439},{\"Date\":\"2015-03-31\",\"Open\":550.00246,\"High\":554.712521,\"Low\":546.722468,\"Close\":548.002468,\"Volume\":1.588e+06,\"AdjClose\":548.002468},{\"Date\":\"2015-03-30\",\"Open\":551.622503,\"High\":553.472487,\"Low\":548.17249,\"Close\":552.032502,\"Volume\":1.2875e+06,\"AdjClose\":552.032502},{\"Date\":\"2015-03-27\",\"Open\":553.002509,\"High\":555.282565,\"Low\":548.132463,\"Close\":548.342512,\"Volume\":1.8975e+06,\"AdjClose\":548.342512},{\"Date\":\"2015-03-26\",\"Open\":557.59255,\"High\":558.90254,\"Low\":550.652497,\"Close\":555.172522,\"Volume\":1.5726e+06,\"AdjClose\":555.172522},{\"Date\":\"2015-03-25\",\"Open\":570.50259,\"High\":572.262605,\"Low\":558.742494,\"Close\":558.787478,\"Volume\":2.1523e+06,\"AdjClose\":558.787478},{\"Date\":\"2015-03-24\",\"Open\":562.562541,\"High\":574.592603,\"Low\":561.212586,\"Close\":570.192597,\"Volume\":2.5833e+06,\"AdjClose\":570.192597},{\"Date\":\"2015-03-23\",\"Open\":560.432554,\"High\":562.362529,\"Low\":555.832536,\"Close\":558.81251,\"Volume\":1.6438e+06,\"AdjClose\":558.81251},{\"Date\":\"2015-03-20\",\"Open\":561.652574,\"High\":561.722529,\"Low\":559.052548,\"Close\":560.362537,\"Volume\":2.6169e+06,\"AdjClose\":560.362537},{\"Date\":\"2015-03-19\",\"Open\":559.392531,\"High\":560.802526,\"Low\":556.147548,\"Close\":557.992512,\"Volume\":1.1973e+06,\"AdjClose\":557.992512},{\"Date\":\"2015-03-18\",\"Open\":552.50248,\"High\":559.782578,\"Low\":547.002472,\"Close\":559.502513,\"Volume\":2.1345e+06,\"AdjClose\":559.502513},{\"Date\":\"2015-03-17\",\"Open\":551.712533,\"High\":553.802493,\"Low\":548.002468,\"Close\":550.842532,\"Volume\":1.8055e+06,\"AdjClose\":550.842532},{\"Date\":\"2015-03-16\",\"Open\":550.952514,\"High\":556.852484,\"Low\":546.002476,\"Close\":554.512509,\"Volume\":1.641e+06,\"AdjClose\":554.512509},{\"Date\":\"2015-03-13\",\"Open\":553.502537,\"High\":558.402572,\"Low\":544.222448,\"Close\":547.322503,\"Volume\":1.7036e+06,\"AdjClose\":547.322503},{\"Date\":\"2015-03-12\",\"Open\":553.512513,\"High\":556.37253,\"Low\":550.462523,\"Close\":555.512505,\"Volume\":1.3896e+06,\"AdjClose\":555.512505},{\"Date\":\"2015-03-11\",\"Open\":555.142533,\"High\":558.142521,\"Low\":550.682486,\"Close\":551.182515,\"Volume\":1.8208e+06,\"AdjClose\":551.182515},{\"Date\":\"2015-03-10\",\"Open\":564.252539,\"High\":564.852512,\"Low\":554.732473,\"Close\":555.012538,\"Volume\":1.7923e+06,\"AdjClose\":555.012538},{\"Date\":\"2015-03-09\",\"Open\":566.862541,\"High\":570.272589,\"Low\":563.537504,\"Close\":568.852557,\"Volume\":1.0621e+06,\"AdjClose\":568.852557},{\"Date\":\"2015-03-06\",\"Open\":574.882583,\"High\":576.682625,\"Low\":566.762597,\"Close\":567.687558,\"Volume\":1.6591e+06,\"AdjClose\":567.687558},{\"Date\":\"2015-03-05\",\"Open\":575.022616,\"High\":577.912621,\"Low\":573.412548,\"Close\":575.332609,\"Volume\":1.3896e+06,\"AdjClose\":575.332609},{\"Date\":\"2015-03-04\",\"Open\":571.872558,\"High\":577.112576,\"Low\":568.012607,\"Close\":573.372583,\"Volume\":1.8768e+06,\"AdjClose\":573.372583},{\"Date\":\"2015-03-03\",\"Open\":570.452587,\"High\":575.392649,\"Low\":566.522559,\"Close\":573.64261,\"Volume\":1.7048e+06,\"AdjClose\":573.64261},{\"Date\":\"2015-03-02\",\"Open\":560.532559,\"High\":572.152623,\"Low\":558.752531,\"Close\":571.342601,\"Volume\":2.1296e+06,\"AdjClose\":571.342601},{\"Date\":\"2015-02-27\",\"Open\":554.242482,\"High\":564.712602,\"Low\":552.902503,\"Close\":558.402572,\"Volume\":2.4102e+06,\"AdjClose\":558.402572},{\"Date\":\"2015-02-26\",\"Open\":543.212476,\"High\":556.142529,\"Low\":541.502464,\"Close\":555.482516,\"Volume\":2.3115e+06,\"AdjClose\":555.482516},{\"Date\":\"2015-02-25\",\"Open\":535.90245,\"High\":546.22244,\"Low\":535.447406,\"Close\":543.872489,\"Volume\":1.826e+06,\"AdjClose\":543.872489},{\"Date\":\"2015-02-24\",\"Open\":530.002419,\"High\":536.792403,\"Low\":528.252381,\"Close\":536.092424,\"Volume\":1.0051e+06,\"AdjClose\":536.092424},{\"Date\":\"2015-02-23\",\"Open\":536.052398,\"High\":536.441465,\"Low\":529.412361,\"Close\":531.912381,\"Volume\":1.4579e+06,\"AdjClose\":531.912381},{\"Date\":\"2015-02-20\",\"Open\":543.132484,\"High\":543.75247,\"Low\":535.802444,\"Close\":538.952441,\"Volume\":1.4444e+06,\"AdjClose\":538.952441},{\"Date\":\"2015-02-19\",\"Open\":538.042413,\"High\":543.11247,\"Low\":538.012424,\"Close\":542.872432,\"Volume\":989100,\"AdjClose\":542.872432},{\"Date\":\"2015-02-18\",\"Open\":541.402458,\"High\":545.492471,\"Low\":537.512456,\"Close\":539.702422,\"Volume\":1.4531e+06,\"AdjClose\":539.702422},{\"Date\":\"2015-02-17\",\"Open\":546.832511,\"High\":550.00246,\"Low\":541.092465,\"Close\":542.842504,\"Volume\":1.6168e+06,\"AdjClose\":542.842504},{\"Date\":\"2015-02-13\",\"Open\":543.352447,\"High\":549.912491,\"Low\":543.132484,\"Close\":549.012501,\"Volume\":1.9003e+06,\"AdjClose\":549.012501},{\"Date\":\"2015-02-12\",\"Open\":537.252405,\"High\":544.822482,\"Low\":534.675391,\"Close\":542.932472,\"Volume\":1.6202e+06,\"AdjClose\":542.932472},{\"Date\":\"2015-02-11\",\"Open\":535.302416,\"High\":538.452473,\"Low\":533.380397,\"Close\":535.972405,\"Volume\":1.3778e+06,\"AdjClose\":535.972405},{\"Date\":\"2015-02-10\",\"Open\":529.302379,\"High\":537.702431,\"Low\":526.922378,\"Close\":536.942412,\"Volume\":1.7499e+06,\"AdjClose\":536.942412},{\"Date\":\"2015-02-09\",\"Open\":528.002366,\"High\":532.002411,\"Low\":526.022388,\"Close\":527.832406,\"Volume\":1.2678e+06,\"AdjClose\":527.832406},{\"Date\":\"2015-02-06\",\"Open\":527.642431,\"High\":537.202463,\"Low\":526.412373,\"Close\":531.002415,\"Volume\":1.7494e+06,\"AdjClose\":531.002415},{\"Date\":\"2015-02-05\",\"Open\":523.792334,\"High\":528.502395,\"Low\":522.092359,\"Close\":527.582391,\"Volume\":1.8498e+06,\"AdjClose\":527.582391},{\"Date\":\"2015-02-04\",\"Open\":529.2424,\"High\":532.67442,\"Low\":521.272361,\"Close\":522.762349,\"Volume\":1.6637e+06,\"AdjClose\":522.762349},{\"Date\":\"2015-02-03\",\"Open\":528.002366,\"High\":533.40243,\"Low\":523.262377,\"Close\":529.2424,\"Volume\":2.0387e+06,\"AdjClose\":529.2424},{\"Date\":\"2015-02-02\",\"Open\":531.732383,\"High\":533.002407,\"Low\":518.552316,\"Close\":528.482381,\"Volume\":2.8498e+06,\"AdjClose\":528.482381},{\"Date\":\"2015-01-30\",\"Open\":515.862322,\"High\":539.872444,\"Low\":515.522339,\"Close\":534.522445,\"Volume\":5.6064e+06,\"AdjClose\":534.522445},{\"Date\":\"2015-01-29\",\"Open\":511.002313,\"High\":511.092313,\"Low\":501.202274,\"Close\":510.662331,\"Volume\":4.1864e+06,\"AdjClose\":510.662331},{\"Date\":\"2015-01-28\",\"Open\":522.782423,\"High\":522.992349,\"Low\":510.002318,\"Close\":510.002318,\"Volume\":1.6838e+06,\"AdjClose\":510.002318},{\"Date\":\"2015-01-27\",\"Open\":529.972369,\"High\":530.702398,\"Low\":518.192381,\"Close\":518.63237,\"Volume\":1.904e+06,\"AdjClose\":518.63237},{\"Date\":\"2015-01-26\",\"Open\":538.532466,\"High\":539.002444,\"Low\":529.672413,\"Close\":535.212448,\"Volume\":1.5437e+06,\"AdjClose\":535.212448},{\"Date\":\"2015-01-23\",\"Open\":535.592457,\"High\":542.172453,\"Low\":533.002407,\"Close\":539.952437,\"Volume\":2.2817e+06,\"AdjClose\":539.952437},{\"Date\":\"2015-01-22\",\"Open\":521.482349,\"High\":536.332463,\"Low\":519.702382,\"Close\":534.39245,\"Volume\":2.6769e+06,\"AdjClose\":534.39245},{\"Date\":\"2015-01-21\",\"Open\":507.252283,\"High\":519.282407,\"Low\":506.202315,\"Close\":518.042312,\"Volume\":2.2687e+06,\"AdjClose\":518.042312},{\"Date\":\"2015-01-20\",\"Open\":511.002313,\"High\":512.502307,\"Low\":506.018277,\"Close\":506.902294,\"Volume\":2.2279e+06,\"AdjClose\":506.902294},{\"Date\":\"2015-01-16\",\"Open\":500.012273,\"High\":508.1923,\"Low\":500.002267,\"Close\":508.082288,\"Volume\":2.2983e+06,\"AdjClose\":508.082288},{\"Date\":\"2015-01-15\",\"Open\":505.572291,\"High\":505.682273,\"Low\":497.762267,\"Close\":501.792271,\"Volume\":2.7158e+06,\"AdjClose\":501.792271},{\"Date\":\"2015-01-14\",\"Open\":494.652237,\"High\":503.232286,\"Low\":493.002234,\"Close\":500.872267,\"Volume\":2.2357e+06,\"AdjClose\":500.872267},{\"Date\":\"2015-01-13\",\"Open\":498.842256,\"High\":502.982302,\"Low\":492.392254,\"Close\":496.182251,\"Volume\":2.3705e+06,\"AdjClose\":496.182251},{\"Date\":\"2015-01-12\",\"Open\":494.942247,\"High\":495.978261,\"Low\":487.562205,\"Close\":492.552209,\"Volume\":2.3224e+06,\"AdjClose\":492.552209},{\"Date\":\"2015-01-09\",\"Open\":504.7623,\"High\":504.922285,\"Low\":494.792239,\"Close\":496.172274,\"Volume\":2.0694e+06,\"AdjClose\":496.172274},{\"Date\":\"2015-01-08\",\"Open\":497.992238,\"High\":503.4823,\"Low\":491.002212,\"Close\":502.682255,\"Volume\":3.3536e+06,\"AdjClose\":502.682255},{\"Date\":\"2015-01-07\",\"Open\":507.002299,\"High\":507.246285,\"Low\":499.652247,\"Close\":501.102268,\"Volume\":2.0651e+06,\"AdjClose\":501.102268},{\"Date\":\"2015-01-06\",\"Open\":515.002358,\"High\":516.177334,\"Low\":501.052266,\"Close\":501.962262,\"Volume\":2.8999e+06,\"AdjClose\":501.962262},{\"Date\":\"2015-01-05\",\"Open\":523.262377,\"High\":524.332389,\"Low\":513.062315,\"Close\":513.872306,\"Volume\":2.0598e+06,\"AdjClose\":513.872306},{\"Date\":\"2015-01-02\",\"Open\":529.012399,\"High\":531.272443,\"Low\":524.102327,\"Close\":524.812404,\"Volume\":1.4476e+06,\"AdjClose\":524.812404},{\"Date\":\"2014-12-31\",\"Open\":531.252429,\"High\":532.602384,\"Low\":525.802363,\"Close\":526.402397,\"Volume\":1.3682e+06,\"AdjClose\":526.402397},{\"Date\":\"2014-12-30\",\"Open\":528.092396,\"High\":531.152424,\"Low\":527.132366,\"Close\":530.422394,\"Volume\":876300,\"AdjClose\":530.422394},{\"Date\":\"2014-12-29\",\"Open\":532.192446,\"High\":535.482414,\"Low\":530.013375,\"Close\":530.332426,\"Volume\":2.2785e+06,\"AdjClose\":530.332426},{\"Date\":\"2014-12-26\",\"Open\":528.772422,\"High\":534.252417,\"Low\":527.312364,\"Close\":534.032454,\"Volume\":1.036e+06,\"AdjClose\":534.032454},{\"Date\":\"2014-12-24\",\"Open\":530.512424,\"High\":531.761394,\"Low\":527.022384,\"Close\":528.772422,\"Volume\":705900,\"AdjClose\":528.772422},{\"Date\":\"2014-12-23\",\"Open\":527.00237,\"High\":534.56241,\"Low\":526.292354,\"Close\":530.592416,\"Volume\":2.1976e+06,\"AdjClose\":530.592416},{\"Date\":\"2014-12-22\",\"Open\":516.082347,\"High\":526.462376,\"Low\":516.082347,\"Close\":524.872383,\"Volume\":2.7238e+06,\"AdjClose\":524.872383},{\"Date\":\"2014-12-19\",\"Open\":511.512318,\"High\":517.722342,\"Low\":506.91331,\"Close\":516.352313,\"Volume\":3.6902e+06,\"AdjClose\":516.352313},{\"Date\":\"2014-12-18\",\"Open\":512.952333,\"High\":513.872306,\"Low\":504.70229,\"Close\":511.102319,\"Volume\":2.9267e+06,\"AdjClose\":511.102319},{\"Date\":\"2014-12-17\",\"Open\":497.002248,\"High\":507.002299,\"Low\":496.812244,\"Close\":504.892295,\"Volume\":2.8832e+06,\"AdjClose\":504.892295},{\"Date\":\"2014-12-16\",\"Open\":511.562321,\"High\":513.052308,\"Low\":489.00222,\"Close\":495.392273,\"Volume\":3.9643e+06,\"AdjClose\":495.392273},{\"Date\":\"2014-12-15\",\"Open\":522.742335,\"High\":523.102331,\"Low\":513.272333,\"Close\":513.80229,\"Volume\":2.8134e+06,\"AdjClose\":513.80229},{\"Date\":\"2014-12-12\",\"Open\":523.512391,\"High\":528.502395,\"Low\":518.662298,\"Close\":518.662298,\"Volume\":1.9946e+06,\"AdjClose\":518.662298},{\"Date\":\"2014-12-11\",\"Open\":527.802355,\"High\":533.922411,\"Low\":527.102376,\"Close\":528.34241,\"Volume\":1.6108e+06,\"AdjClose\":528.34241},{\"Date\":\"2014-12-10\",\"Open\":533.082399,\"High\":536.332463,\"Low\":525.562386,\"Close\":526.062353,\"Volume\":1.7123e+06,\"AdjClose\":526.062353},{\"Date\":\"2014-12-09\",\"Open\":522.142362,\"High\":534.192438,\"Low\":520.502366,\"Close\":533.37244,\"Volume\":1.8713e+06,\"AdjClose\":533.37244},{\"Date\":\"2014-12-08\",\"Open\":527.132366,\"High\":531.002415,\"Low\":523.792334,\"Close\":526.982357,\"Volume\":2.3294e+06,\"AdjClose\":526.982357},{\"Date\":\"2014-12-05\",\"Open\":531.002415,\"High\":532.892425,\"Low\":524.282386,\"Close\":525.262369,\"Volume\":2.5656e+06,\"AdjClose\":525.262369},{\"Date\":\"2014-12-04\",\"Open\":531.1624,\"High\":537.342434,\"Low\":528.592424,\"Close\":537.312445,\"Volume\":1.3921e+06,\"AdjClose\":537.312445},{\"Date\":\"2014-12-03\",\"Open\":531.442404,\"High\":535.998416,\"Low\":529.262414,\"Close\":531.322384,\"Volume\":1.278e+06,\"AdjClose\":531.322384},{\"Date\":\"2014-12-02\",\"Open\":533.512412,\"High\":535.502427,\"Low\":529.802408,\"Close\":533.752389,\"Volume\":1.5258e+06,\"AdjClose\":533.752389},{\"Date\":\"2014-12-01\",\"Open\":538.902438,\"High\":541.412434,\"Low\":531.862379,\"Close\":533.802391,\"Volume\":2.1154e+06,\"AdjClose\":533.802391},{\"Date\":\"2014-11-28\",\"Open\":540.622426,\"High\":542.002431,\"Low\":536.602429,\"Close\":541.832471,\"Volume\":1.1483e+06,\"AdjClose\":541.832471},{\"Date\":\"2014-11-26\",\"Open\":540.882478,\"High\":541.552406,\"Low\":537.044437,\"Close\":540.372412,\"Volume\":1.523e+06,\"AdjClose\":540.372412},{\"Date\":\"2014-11-25\",\"Open\":539.002444,\"High\":543.98241,\"Low\":538.60444,\"Close\":541.082489,\"Volume\":1.7891e+06,\"AdjClose\":541.082489},{\"Date\":\"2014-11-24\",\"Open\":537.652489,\"High\":542.702471,\"Low\":535.622446,\"Close\":539.272471,\"Volume\":1.706e+06,\"AdjClose\":539.272471},{\"Date\":\"2014-11-21\",\"Open\":541.612446,\"High\":542.142464,\"Low\":536.562402,\"Close\":537.502419,\"Volume\":2.2237e+06,\"AdjClose\":537.502419},{\"Date\":\"2014-11-20\",\"Open\":531.252429,\"High\":535.112381,\"Low\":531.082408,\"Close\":534.832438,\"Volume\":1.562e+06,\"AdjClose\":534.832438},{\"Date\":\"2014-11-19\",\"Open\":535.002399,\"High\":538.242425,\"Low\":530.082412,\"Close\":536.992415,\"Volume\":1.3916e+06,\"AdjClose\":536.992415},{\"Date\":\"2014-11-18\",\"Open\":537.502419,\"High\":541.942452,\"Low\":534.172425,\"Close\":535.032449,\"Volume\":1.9627e+06,\"AdjClose\":535.032449},{\"Date\":\"2014-11-17\",\"Open\":543.582448,\"High\":543.792436,\"Low\":534.063361,\"Close\":536.512461,\"Volume\":1.7258e+06,\"AdjClose\":536.512461},{\"Date\":\"2014-11-14\",\"Open\":546.682442,\"High\":546.682442,\"Low\":542.152501,\"Close\":544.402507,\"Volume\":1.2892e+06,\"AdjClose\":544.402507},{\"Date\":\"2014-11-13\",\"Open\":549.802448,\"High\":549.802448,\"Low\":543.482442,\"Close\":545.38249,\"Volume\":1.3394e+06,\"AdjClose\":545.38249},{\"Date\":\"2014-11-12\",\"Open\":550.392507,\"High\":550.462523,\"Low\":545.172441,\"Close\":547.312465,\"Volume\":1.1294e+06,\"AdjClose\":547.312465},{\"Date\":\"2014-11-11\",\"Open\":548.492459,\"High\":551.942473,\"Low\":546.302493,\"Close\":550.29244,\"Volume\":965500,\"AdjClose\":550.29244},{\"Date\":\"2014-11-10\",\"Open\":541.462498,\"High\":549.592522,\"Low\":541.022449,\"Close\":547.492463,\"Volume\":1.1346e+06,\"AdjClose\":547.492463},{\"Date\":\"2014-11-07\",\"Open\":546.212525,\"High\":546.212525,\"Low\":538.672437,\"Close\":541.012473,\"Volume\":1.6338e+06,\"AdjClose\":541.012473},{\"Date\":\"2014-11-06\",\"Open\":545.502448,\"High\":546.887472,\"Low\":540.972385,\"Close\":542.042458,\"Volume\":1.3333e+06,\"AdjClose\":542.042458},{\"Date\":\"2014-11-05\",\"Open\":556.802481,\"High\":556.802481,\"Low\":544.052426,\"Close\":545.922423,\"Volume\":2.0323e+06,\"AdjClose\":545.922423},{\"Date\":\"2014-11-04\",\"Open\":553.002509,\"High\":555.502529,\"Low\":549.302481,\"Close\":554.112486,\"Volume\":1.2442e+06,\"AdjClose\":554.112486},{\"Date\":\"2014-11-03\",\"Open\":555.502529,\"High\":557.902544,\"Low\":553.23251,\"Close\":555.222464,\"Volume\":1.3823e+06,\"AdjClose\":555.222464},{\"Date\":\"2014-10-31\",\"Open\":559.352504,\"High\":559.572529,\"Low\":554.752486,\"Close\":559.082538,\"Volume\":2.0351e+06,\"AdjClose\":559.082538},{\"Date\":\"2014-10-30\",\"Open\":548.952522,\"High\":552.802497,\"Low\":543.512493,\"Close\":550.312514,\"Volume\":1.4555e+06,\"AdjClose\":550.312514},{\"Date\":\"2014-10-29\",\"Open\":550.00246,\"High\":554.19254,\"Low\":546.982459,\"Close\":549.332532,\"Volume\":1.7705e+06,\"AdjClose\":549.332532},{\"Date\":\"2014-10-28\",\"Open\":543.002488,\"High\":548.98245,\"Low\":541.622422,\"Close\":548.902519,\"Volume\":1.271e+06,\"AdjClose\":548.902519},{\"Date\":\"2014-10-27\",\"Open\":537.032441,\"High\":544.412422,\"Low\":537.032441,\"Close\":540.772496,\"Volume\":1.1853e+06,\"AdjClose\":540.772496},{\"Date\":\"2014-10-24\",\"Open\":544.36248,\"High\":544.882461,\"Low\":535.792407,\"Close\":539.782476,\"Volume\":1.9731e+06,\"AdjClose\":539.782476},{\"Date\":\"2014-10-23\",\"Open\":539.322474,\"High\":547.222436,\"Low\":535.852386,\"Close\":543.98241,\"Volume\":2.3488e+06,\"AdjClose\":543.98241},{\"Date\":\"2014-10-22\",\"Open\":529.892437,\"High\":539.802428,\"Low\":528.802351,\"Close\":532.712427,\"Volume\":2.9193e+06,\"AdjClose\":532.712427},{\"Date\":\"2014-10-21\",\"Open\":525.192353,\"High\":526.792383,\"Low\":519.112324,\"Close\":526.542369,\"Volume\":2.3363e+06,\"AdjClose\":526.542369},{\"Date\":\"2014-10-20\",\"Open\":509.452317,\"High\":521.762353,\"Low\":508.102301,\"Close\":520.84241,\"Volume\":2.6075e+06,\"AdjClose\":520.84241},{\"Date\":\"2014-10-17\",\"Open\":527.252385,\"High\":530.982402,\"Low\":508.532313,\"Close\":511.172335,\"Volume\":5.5394e+06,\"AdjClose\":511.172335},{\"Date\":\"2014-10-16\",\"Open\":519.002342,\"High\":529.432374,\"Low\":515.002358,\"Close\":524.512387,\"Volume\":3.7086e+06,\"AdjClose\":524.512387},{\"Date\":\"2014-10-15\",\"Open\":531.012391,\"High\":532.802396,\"Low\":518.302363,\"Close\":530.032409,\"Volume\":3.7194e+06,\"AdjClose\":530.032409},{\"Date\":\"2014-10-14\",\"Open\":538.902438,\"High\":547.192507,\"Low\":533.172368,\"Close\":537.942408,\"Volume\":2.2226e+06,\"AdjClose\":537.942408},{\"Date\":\"2014-10-13\",\"Open\":544.992443,\"High\":549.502492,\"Low\":533.102413,\"Close\":533.212456,\"Volume\":2.5817e+06,\"AdjClose\":533.212456},{\"Date\":\"2014-10-10\",\"Open\":557.722484,\"High\":565.132577,\"Low\":544.052426,\"Close\":544.492476,\"Volume\":3.0819e+06,\"AdjClose\":544.492476},{\"Date\":\"2014-10-09\",\"Open\":571.182555,\"High\":571.492549,\"Low\":559.062524,\"Close\":560.882579,\"Volume\":2.5248e+06,\"AdjClose\":560.882579},{\"Date\":\"2014-10-08\",\"Open\":565.572566,\"High\":573.882587,\"Low\":557.492484,\"Close\":572.502582,\"Volume\":1.9909e+06,\"AdjClose\":572.502582},{\"Date\":\"2014-10-07\",\"Open\":574.402629,\"High\":575.27263,\"Low\":563.742534,\"Close\":563.742534,\"Volume\":1.9113e+06,\"AdjClose\":563.742534},{\"Date\":\"2014-10-06\",\"Open\":578.802574,\"High\":581.002639,\"Low\":574.442595,\"Close\":577.352614,\"Volume\":1.2146e+06,\"AdjClose\":577.352614},{\"Date\":\"2014-10-03\",\"Open\":573.052613,\"High\":577.227576,\"Low\":572.502582,\"Close\":575.282606,\"Volume\":1.1417e+06,\"AdjClose\":575.282606},{\"Date\":\"2014-10-02\",\"Open\":567.312567,\"High\":571.912585,\"Low\":563.322559,\"Close\":570.082615,\"Volume\":1.1784e+06,\"AdjClose\":570.082615},{\"Date\":\"2014-10-01\",\"Open\":576.012635,\"High\":577.582615,\"Low\":567.01255,\"Close\":568.272597,\"Volume\":1.4455e+06,\"AdjClose\":568.272597},{\"Date\":\"2014-09-30\",\"Open\":576.932578,\"High\":579.852634,\"Low\":572.852541,\"Close\":577.36259,\"Volume\":1.6217e+06,\"AdjClose\":577.36259},{\"Date\":\"2014-09-29\",\"Open\":571.7526,\"High\":578.192625,\"Low\":571.172579,\"Close\":576.362594,\"Volume\":1.2824e+06,\"AdjClose\":576.362594},{\"Date\":\"2014-09-26\",\"Open\":576.062638,\"High\":579.2526,\"Low\":574.662558,\"Close\":577.1026,\"Volume\":1.4437e+06,\"AdjClose\":577.1026},{\"Date\":\"2014-09-25\",\"Open\":587.552646,\"High\":587.982658,\"Low\":574.182604,\"Close\":575.062581,\"Volume\":1.926e+06,\"AdjClose\":575.062581},{\"Date\":\"2014-09-24\",\"Open\":581.462641,\"High\":589.632691,\"Low\":580.522624,\"Close\":587.992634,\"Volume\":1.7281e+06,\"AdjClose\":587.992634},{\"Date\":\"2014-09-23\",\"Open\":586.852606,\"High\":586.852606,\"Low\":581.002639,\"Close\":581.132634,\"Volume\":1.4714e+06,\"AdjClose\":581.132634},{\"Date\":\"2014-09-22\",\"Open\":593.82271,\"High\":593.951665,\"Low\":583.462694,\"Close\":587.372648,\"Volume\":1.6895e+06,\"AdjClose\":587.372648},{\"Date\":\"2014-09-19\",\"Open\":591.502688,\"High\":596.482654,\"Low\":589.502696,\"Close\":596.082692,\"Volume\":3.7366e+06,\"AdjClose\":596.082692},{\"Date\":\"2014-09-18\",\"Open\":587.002675,\"High\":589.542661,\"Low\":585.002622,\"Close\":589.272695,\"Volume\":1.4446e+06,\"AdjClose\":589.272695},{\"Date\":\"2014-09-17\",\"Open\":580.012619,\"High\":587.522656,\"Low\":578.777665,\"Close\":584.772683,\"Volume\":1.6928e+06,\"AdjClose\":584.772683},{\"Date\":\"2014-09-16\",\"Open\":572.762572,\"High\":581.502606,\"Low\":572.662566,\"Close\":579.95264,\"Volume\":1.4804e+06,\"AdjClose\":579.95264},{\"Date\":\"2014-09-15\",\"Open\":572.94257,\"High\":574.952599,\"Low\":568.212618,\"Close\":573.102555,\"Volume\":1.5976e+06,\"AdjClose\":573.102555},{\"Date\":\"2014-09-12\",\"Open\":581.002639,\"High\":581.642639,\"Low\":574.462608,\"Close\":575.622589,\"Volume\":1.6017e+06,\"AdjClose\":575.622589},{\"Date\":\"2014-09-11\",\"Open\":580.362639,\"High\":581.812599,\"Low\":576.262588,\"Close\":581.352598,\"Volume\":1.221e+06,\"AdjClose\":581.352598},{\"Date\":\"2014-09-10\",\"Open\":581.502606,\"High\":583.502659,\"Low\":576.942615,\"Close\":583.102636,\"Volume\":977400,\"AdjClose\":583.102636},{\"Date\":\"2014-09-09\",\"Open\":588.902723,\"High\":589.002667,\"Low\":580.002643,\"Close\":581.012615,\"Volume\":1.2872e+06,\"AdjClose\":581.012615},{\"Date\":\"2014-09-08\",\"Open\":586.602653,\"High\":591.772715,\"Low\":586.302635,\"Close\":589.722659,\"Volume\":1.431e+06,\"AdjClose\":589.722659},{\"Date\":\"2014-09-05\",\"Open\":583.982613,\"High\":586.55265,\"Low\":581.952632,\"Close\":586.082672,\"Volume\":1.6324e+06,\"AdjClose\":586.082672},{\"Date\":\"2014-09-04\",\"Open\":580.002643,\"High\":586.00268,\"Low\":579.222611,\"Close\":581.982621,\"Volume\":1.4582e+06,\"AdjClose\":581.982621},{\"Date\":\"2014-09-03\",\"Open\":580.002643,\"High\":582.992655,\"Low\":575.002602,\"Close\":577.942611,\"Volume\":1.2151e+06,\"AdjClose\":577.942611},{\"Date\":\"2014-09-02\",\"Open\":571.852545,\"High\":577.832629,\"Low\":571.192593,\"Close\":577.332662,\"Volume\":1.5784e+06,\"AdjClose\":577.332662},{\"Date\":\"2014-08-29\",\"Open\":571.332625,\"High\":572.04258,\"Low\":567.07155,\"Close\":571.60253,\"Volume\":1.0838e+06,\"AdjClose\":571.60253},{\"Date\":\"2014-08-28\",\"Open\":569.562573,\"High\":573.252563,\"Low\":567.102518,\"Close\":569.202577,\"Volume\":1.2929e+06,\"AdjClose\":569.202577},{\"Date\":\"2014-08-27\",\"Open\":577.272622,\"High\":578.492581,\"Low\":570.105627,\"Close\":571.002557,\"Volume\":1.7034e+06,\"AdjClose\":571.002557},{\"Date\":\"2014-08-26\",\"Open\":581.262629,\"High\":581.802623,\"Low\":576.582619,\"Close\":577.862619,\"Volume\":1.6397e+06,\"AdjClose\":577.862619},{\"Date\":\"2014-08-25\",\"Open\":584.722619,\"High\":585.002622,\"Low\":579.002647,\"Close\":580.202654,\"Volume\":1.3614e+06,\"AdjClose\":580.202654},{\"Date\":\"2014-08-22\",\"Open\":583.592689,\"High\":585.238682,\"Low\":580.642643,\"Close\":582.562642,\"Volume\":789100,\"AdjClose\":582.562642},{\"Date\":\"2014-08-21\",\"Open\":583.822628,\"High\":584.502655,\"Low\":581.142671,\"Close\":583.372664,\"Volume\":914800,\"AdjClose\":583.372664},{\"Date\":\"2014-08-20\",\"Open\":585.88266,\"High\":586.702658,\"Low\":582.572618,\"Close\":584.492618,\"Volume\":1.0367e+06,\"AdjClose\":584.492618},{\"Date\":\"2014-08-19\",\"Open\":585.002622,\"High\":587.342658,\"Low\":584.002627,\"Close\":586.862643,\"Volume\":978700,\"AdjClose\":586.862643},{\"Date\":\"2014-08-18\",\"Open\":576.11258,\"High\":584.512631,\"Low\":576.002598,\"Close\":582.162619,\"Volume\":1.2841e+06,\"AdjClose\":582.162619},{\"Date\":\"2014-08-15\",\"Open\":577.862619,\"High\":579.382595,\"Low\":570.522603,\"Close\":573.482564,\"Volume\":1.5192e+06,\"AdjClose\":573.482564},{\"Date\":\"2014-08-14\",\"Open\":576.182596,\"High\":577.902645,\"Low\":570.882599,\"Close\":574.652643,\"Volume\":985500,\"AdjClose\":574.652643},{\"Date\":\"2014-08-13\",\"Open\":567.312567,\"High\":575.002602,\"Low\":565.752564,\"Close\":574.782639,\"Volume\":1.4418e+06,\"AdjClose\":574.782639},{\"Date\":\"2014-08-12\",\"Open\":564.522567,\"High\":565.902572,\"Low\":560.882579,\"Close\":562.732562,\"Volume\":1.542e+06,\"AdjClose\":562.732562},{\"Date\":\"2014-08-11\",\"Open\":569.992585,\"High\":570.492553,\"Low\":566.002578,\"Close\":567.882551,\"Volume\":1.2147e+06,\"AdjClose\":567.882551},{\"Date\":\"2014-08-08\",\"Open\":563.562536,\"High\":570.252576,\"Low\":560.3525,\"Close\":568.772626,\"Volume\":1.4948e+06,\"AdjClose\":568.772626},{\"Date\":\"2014-08-07\",\"Open\":568.00257,\"High\":569.89258,\"Low\":561.102482,\"Close\":563.362525,\"Volume\":1.1109e+06,\"AdjClose\":563.362525},{\"Date\":\"2014-08-06\",\"Open\":561.782569,\"High\":570.702601,\"Low\":560.002541,\"Close\":566.376589,\"Volume\":1.3344e+06,\"AdjClose\":566.376589},{\"Date\":\"2014-08-05\",\"Open\":570.052564,\"High\":571.982601,\"Low\":562.612543,\"Close\":565.072598,\"Volume\":1.5512e+06,\"AdjClose\":565.072598},{\"Date\":\"2014-08-04\",\"Open\":569.042531,\"High\":575.352561,\"Low\":564.102531,\"Close\":573.152619,\"Volume\":1.4273e+06,\"AdjClose\":573.152619},{\"Date\":\"2014-08-01\",\"Open\":570.402584,\"High\":575.962633,\"Low\":562.85252,\"Close\":566.072594,\"Volume\":1.9553e+06,\"AdjClose\":566.072594},{\"Date\":\"2014-07-31\",\"Open\":580.602616,\"High\":583.652668,\"Low\":570.002561,\"Close\":571.60253,\"Volume\":2.1028e+06,\"AdjClose\":571.60253},{\"Date\":\"2014-07-30\",\"Open\":586.55265,\"High\":589.502696,\"Low\":584.002627,\"Close\":587.42265,\"Volume\":1.0165e+06,\"AdjClose\":587.42265},{\"Date\":\"2014-07-29\",\"Open\":588.752653,\"High\":589.702707,\"Low\":583.517654,\"Close\":585.612633,\"Volume\":1.3499e+06,\"AdjClose\":585.612633},{\"Date\":\"2014-07-28\",\"Open\":588.072688,\"High\":592.502683,\"Low\":584.755668,\"Close\":590.602636,\"Volume\":986800,\"AdjClose\":590.602636},{\"Date\":\"2014-07-25\",\"Open\":590.402686,\"High\":591.862684,\"Low\":587.032665,\"Close\":589.022681,\"Volume\":932500,\"AdjClose\":589.022681},{\"Date\":\"2014-07-24\",\"Open\":596.452725,\"High\":599.502716,\"Low\":591.772715,\"Close\":593.352671,\"Volume\":1.0351e+06,\"AdjClose\":593.352671},{\"Date\":\"2014-07-23\",\"Open\":593.232652,\"High\":597.852683,\"Low\":592.502683,\"Close\":595.982686,\"Volume\":1.2332e+06,\"AdjClose\":595.982686},{\"Date\":\"2014-07-22\",\"Open\":590.722655,\"High\":599.652725,\"Low\":590.602636,\"Close\":594.742652,\"Volume\":1.6992e+06,\"AdjClose\":594.742652},{\"Date\":\"2014-07-21\",\"Open\":591.752702,\"High\":594.402731,\"Low\":585.235622,\"Close\":589.472645,\"Volume\":2.0621e+06,\"AdjClose\":589.472645},{\"Date\":\"2014-07-18\",\"Open\":593.002712,\"High\":596.802684,\"Low\":582.002635,\"Close\":595.082696,\"Volume\":4.0142e+06,\"AdjClose\":595.082696},{\"Date\":\"2014-07-17\",\"Open\":579.532665,\"High\":580.992601,\"Low\":568.61258,\"Close\":573.732579,\"Volume\":3.0166e+06,\"AdjClose\":573.732579},{\"Date\":\"2014-07-16\",\"Open\":588.002671,\"High\":588.402694,\"Low\":582.202646,\"Close\":582.662587,\"Volume\":1.3971e+06,\"AdjClose\":582.662587},{\"Date\":\"2014-07-15\",\"Open\":585.742628,\"High\":585.807626,\"Low\":576.562606,\"Close\":584.782659,\"Volume\":1.623e+06,\"AdjClose\":584.782659},{\"Date\":\"2014-07-14\",\"Open\":582.602608,\"High\":585.212671,\"Low\":578.032641,\"Close\":584.872627,\"Volume\":1.8541e+06,\"AdjClose\":584.872627},{\"Date\":\"2014-07-11\",\"Open\":571.912585,\"High\":580.85263,\"Low\":571.422594,\"Close\":579.182645,\"Volume\":1.6217e+06,\"AdjClose\":579.182645},{\"Date\":\"2014-07-10\",\"Open\":565.912548,\"High\":576.592656,\"Low\":565.012558,\"Close\":571.102563,\"Volume\":1.3567e+06,\"AdjClose\":571.102563},{\"Date\":\"2014-07-09\",\"Open\":571.582578,\"High\":576.72259,\"Low\":569.378536,\"Close\":576.082652,\"Volume\":1.1168e+06,\"AdjClose\":576.082652},{\"Date\":\"2014-07-08\",\"Open\":577.662607,\"High\":579.530645,\"Low\":566.137592,\"Close\":571.092587,\"Volume\":1.9095e+06,\"AdjClose\":571.092587},{\"Date\":\"2014-07-07\",\"Open\":583.76265,\"High\":586.432631,\"Low\":579.592644,\"Close\":582.252649,\"Volume\":1.0646e+06,\"AdjClose\":582.252649},{\"Date\":\"2014-07-03\",\"Open\":583.352589,\"High\":585.01266,\"Low\":580.922585,\"Close\":584.732656,\"Volume\":714200,\"AdjClose\":584.732656},{\"Date\":\"2014-07-02\",\"Open\":583.352589,\"High\":585.442672,\"Low\":580.392628,\"Close\":582.33766,\"Volume\":1.0564e+06,\"AdjClose\":582.33766},{\"Date\":\"2014-07-01\",\"Open\":578.32262,\"High\":584.402649,\"Low\":576.652635,\"Close\":582.672624,\"Volume\":1.448e+06,\"AdjClose\":582.672624},{\"Date\":\"2014-06-30\",\"Open\":578.662603,\"High\":579.572631,\"Low\":574.752588,\"Close\":575.282606,\"Volume\":1.3138e+06,\"AdjClose\":575.282606},{\"Date\":\"2014-06-27\",\"Open\":577.182592,\"High\":579.872648,\"Low\":573.802595,\"Close\":577.242632,\"Volume\":2.2369e+06,\"AdjClose\":577.242632},{\"Date\":\"2014-06-26\",\"Open\":581.002639,\"High\":582.45266,\"Low\":571.852545,\"Close\":576.002598,\"Volume\":1.742e+06,\"AdjClose\":576.002598},{\"Date\":\"2014-06-25\",\"Open\":565.262572,\"High\":579.962616,\"Low\":565.222546,\"Close\":578.652627,\"Volume\":1.9694e+06,\"AdjClose\":578.652627},{\"Date\":\"2014-06-24\",\"Open\":565.192556,\"High\":572.648612,\"Low\":561.012574,\"Close\":564.622572,\"Volume\":2.2071e+06,\"AdjClose\":564.622572},{\"Date\":\"2014-06-23\",\"Open\":555.152509,\"High\":565.002582,\"Low\":554.252519,\"Close\":564.952579,\"Volume\":1.5368e+06,\"AdjClose\":564.952579},{\"Date\":\"2014-06-20\",\"Open\":556.852484,\"High\":557.582513,\"Low\":550.394526,\"Close\":556.362492,\"Volume\":4.5083e+06,\"AdjClose\":556.362492},{\"Date\":\"2014-06-19\",\"Open\":554.242482,\"High\":555.0025,\"Low\":548.512473,\"Close\":554.902556,\"Volume\":2.4568e+06,\"AdjClose\":554.902556},{\"Date\":\"2014-06-18\",\"Open\":544.862448,\"High\":553.562516,\"Low\":544.002484,\"Close\":553.372481,\"Volume\":1.7418e+06,\"AdjClose\":553.372481},{\"Date\":\"2014-06-17\",\"Open\":544.202496,\"High\":545.32245,\"Low\":539.33245,\"Close\":543.012465,\"Volume\":1.4446e+06,\"AdjClose\":543.012465},{\"Date\":\"2014-06-16\",\"Open\":549.262515,\"High\":549.62245,\"Low\":541.522477,\"Close\":544.282488,\"Volume\":1.7026e+06,\"AdjClose\":544.282488},{\"Date\":\"2014-06-13\",\"Open\":552.262503,\"High\":552.302469,\"Low\":545.562488,\"Close\":551.762536,\"Volume\":1.2205e+06,\"AdjClose\":551.762536},{\"Date\":\"2014-06-12\",\"Open\":557.302509,\"High\":557.992512,\"Low\":548.462531,\"Close\":551.352476,\"Volume\":1.4585e+06,\"AdjClose\":551.352476},{\"Date\":\"2014-06-11\",\"Open\":558.002549,\"High\":559.882522,\"Low\":555.022514,\"Close\":558.842561,\"Volume\":1.1001e+06,\"AdjClose\":558.842561},{\"Date\":\"2014-06-10\",\"Open\":560.512546,\"High\":563.602502,\"Low\":557.902544,\"Close\":560.552511,\"Volume\":1.3517e+06,\"AdjClose\":560.552511},{\"Date\":\"2014-06-09\",\"Open\":557.152562,\"High\":562.902584,\"Low\":556.042523,\"Close\":562.122552,\"Volume\":1.4675e+06,\"AdjClose\":562.122552},{\"Date\":\"2014-06-06\",\"Open\":558.062528,\"High\":558.062528,\"Low\":548.932448,\"Close\":556.332564,\"Volume\":1.7368e+06,\"AdjClose\":556.332564},{\"Date\":\"2014-06-05\",\"Open\":546.402499,\"High\":554.952498,\"Low\":544.452449,\"Close\":553.90256,\"Volume\":1.6891e+06,\"AdjClose\":553.90256},{\"Date\":\"2014-06-04\",\"Open\":541.502464,\"High\":548.612478,\"Low\":538.752429,\"Close\":544.662436,\"Volume\":1.8165e+06,\"AdjClose\":544.662436},{\"Date\":\"2014-06-03\",\"Open\":550.99248,\"High\":552.342557,\"Low\":542.552463,\"Close\":544.942501,\"Volume\":1.8666e+06,\"AdjClose\":544.942501},{\"Date\":\"2014-06-02\",\"Open\":560.702581,\"High\":560.902593,\"Low\":545.732448,\"Close\":553.932488,\"Volume\":1.435e+06,\"AdjClose\":553.932488},{\"Date\":\"2014-05-30\",\"Open\":560.802526,\"High\":561.352496,\"Low\":555.912467,\"Close\":559.892559,\"Volume\":1.7711e+06,\"AdjClose\":559.892559},{\"Date\":\"2014-05-29\",\"Open\":563.352549,\"High\":564.002525,\"Low\":558.712565,\"Close\":560.082534,\"Volume\":1.3541e+06,\"AdjClose\":560.082534},{\"Date\":\"2014-05-28\",\"Open\":564.57257,\"High\":567.842585,\"Low\":561.002537,\"Close\":561.682502,\"Volume\":1.652e+06,\"AdjClose\":561.682502},{\"Date\":\"2014-05-27\",\"Open\":556.002496,\"High\":566.002578,\"Low\":554.352463,\"Close\":565.952575,\"Volume\":2.1042e+06,\"AdjClose\":565.952575},{\"Date\":\"2014-05-23\",\"Open\":547.262462,\"High\":553.642508,\"Low\":543.702467,\"Close\":552.702492,\"Volume\":1.9322e+06,\"AdjClose\":552.702492},{\"Date\":\"2014-05-22\",\"Open\":541.132431,\"High\":547.602445,\"Low\":540.782472,\"Close\":545.062459,\"Volume\":1.6158e+06,\"AdjClose\":545.062459},{\"Date\":\"2014-05-21\",\"Open\":532.902462,\"High\":539.185441,\"Low\":531.912381,\"Close\":538.942465,\"Volume\":1.1963e+06,\"AdjClose\":538.942465},{\"Date\":\"2014-05-20\",\"Open\":529.742368,\"High\":536.232396,\"Low\":526.302392,\"Close\":529.772418,\"Volume\":1.7848e+06,\"AdjClose\":529.772418},{\"Date\":\"2014-05-19\",\"Open\":519.702382,\"High\":529.782456,\"Low\":517.58537,\"Close\":528.862391,\"Volume\":1.2778e+06,\"AdjClose\":528.862391},{\"Date\":\"2014-05-16\",\"Open\":521.39238,\"High\":521.802379,\"Low\":515.442347,\"Close\":520.632362,\"Volume\":1.4853e+06,\"AdjClose\":520.632362},{\"Date\":\"2014-05-15\",\"Open\":525.702357,\"High\":525.872379,\"Low\":517.422325,\"Close\":519.982324,\"Volume\":1.7044e+06,\"AdjClose\":519.982324},{\"Date\":\"2014-05-14\",\"Open\":533.002407,\"High\":533.002407,\"Low\":525.292358,\"Close\":526.652412,\"Volume\":1.1918e+06,\"AdjClose\":526.652412},{\"Date\":\"2014-05-13\",\"Open\":530.892433,\"High\":536.072411,\"Low\":529.512428,\"Close\":533.092437,\"Volume\":1.6534e+06,\"AdjClose\":533.092437},{\"Date\":\"2014-05-12\",\"Open\":523.512391,\"High\":530.192393,\"Low\":519.012379,\"Close\":529.922366,\"Volume\":1.9125e+06,\"AdjClose\":529.922366},{\"Date\":\"2014-05-09\",\"Open\":510.75233,\"High\":519.902393,\"Low\":504.202292,\"Close\":518.732314,\"Volume\":2.4395e+06,\"AdjClose\":518.732314},{\"Date\":\"2014-05-08\",\"Open\":508.462297,\"High\":517.23229,\"Low\":506.452298,\"Close\":511.002313,\"Volume\":2.0213e+06,\"AdjClose\":511.002313},{\"Date\":\"2014-05-07\",\"Open\":515.792305,\"High\":516.68232,\"Low\":503.302272,\"Close\":509.962291,\"Volume\":3.2243e+06,\"AdjClose\":509.962291},{\"Date\":\"2014-05-06\",\"Open\":525.232379,\"High\":526.812396,\"Low\":515.062337,\"Close\":515.14233,\"Volume\":1.689e+06,\"AdjClose\":515.14233},{\"Date\":\"2014-05-05\",\"Open\":524.822381,\"High\":528.902418,\"Low\":521.322364,\"Close\":527.812392,\"Volume\":1.0241e+06,\"AdjClose\":527.812392},{\"Date\":\"2014-05-02\",\"Open\":533.762426,\"High\":534.002403,\"Low\":525.612389,\"Close\":527.932411,\"Volume\":1.6885e+06,\"AdjClose\":527.932411},{\"Date\":\"2014-05-01\",\"Open\":527.112352,\"High\":532.932391,\"Low\":523.882364,\"Close\":531.352374,\"Volume\":1.9055e+06,\"AdjClose\":531.352374},{\"Date\":\"2014-04-30\",\"Open\":527.602343,\"High\":528.002366,\"Low\":522.522372,\"Close\":526.662388,\"Volume\":1.7512e+06,\"AdjClose\":526.662388},{\"Date\":\"2014-04-29\",\"Open\":516.902344,\"High\":529.462425,\"Low\":516.322324,\"Close\":527.70241,\"Volume\":2.6991e+06,\"AdjClose\":527.70241},{\"Date\":\"2014-04-28\",\"Open\":517.182348,\"High\":518.602319,\"Low\":502.802274,\"Close\":517.152359,\"Volume\":3.3355e+06,\"AdjClose\":517.152359},{\"Date\":\"2014-04-25\",\"Open\":522.512395,\"High\":524.702361,\"Low\":515.422333,\"Close\":516.182352,\"Volume\":2.1004e+06,\"AdjClose\":516.182352},{\"Date\":\"2014-04-24\",\"Open\":530.072374,\"High\":531.652452,\"Low\":522.122349,\"Close\":525.162363,\"Volume\":1.8832e+06,\"AdjClose\":525.162363},{\"Date\":\"2014-04-23\",\"Open\":533.792415,\"High\":533.872408,\"Low\":526.252389,\"Close\":526.942391,\"Volume\":2.0523e+06,\"AdjClose\":526.942391},{\"Date\":\"2014-04-22\",\"Open\":528.642427,\"High\":537.232391,\"Low\":527.512375,\"Close\":534.812425,\"Volume\":2.3654e+06,\"AdjClose\":534.812425},{\"Date\":\"2014-04-21\",\"Open\":536.1024,\"High\":536.702435,\"Low\":525.602352,\"Close\":528.622414,\"Volume\":2.5667e+06,\"AdjClose\":528.622414},{\"Date\":\"2014-04-17\",\"Open\":548.81249,\"High\":549.502492,\"Low\":531.152424,\"Close\":536.1024,\"Volume\":6.8095e+06,\"AdjClose\":536.1024},{\"Date\":\"2014-04-16\",\"Open\":543.002488,\"High\":557.002492,\"Low\":540.00244,\"Close\":556.54249,\"Volume\":4.8933e+06,\"AdjClose\":556.54249},{\"Date\":\"2014-04-15\",\"Open\":536.822454,\"High\":538.452473,\"Low\":518.462348,\"Close\":536.442444,\"Volume\":3.8551e+06,\"AdjClose\":536.442444},{\"Date\":\"2014-04-14\",\"Open\":538.252462,\"High\":544.102429,\"Low\":529.56237,\"Close\":532.522453,\"Volume\":2.5751e+06,\"AdjClose\":532.522453},{\"Date\":\"2014-04-11\",\"Open\":532.552381,\"High\":540.00244,\"Low\":526.532392,\"Close\":530.602392,\"Volume\":3.9248e+06,\"AdjClose\":530.602392},{\"Date\":\"2014-04-10\",\"Open\":565.002582,\"High\":565.002582,\"Low\":539.902495,\"Close\":540.952433,\"Volume\":4.0369e+06,\"AdjClose\":540.952433},{\"Date\":\"2014-04-09\",\"Open\":559.622532,\"High\":565.372554,\"Low\":552.952506,\"Close\":564.142557,\"Volume\":3.3308e+06,\"AdjClose\":564.142557},{\"Date\":\"2014-04-08\",\"Open\":542.602466,\"High\":555.0025,\"Low\":541.612446,\"Close\":554.902556,\"Volume\":3.1512e+06,\"AdjClose\":554.902556},{\"Date\":\"2014-04-07\",\"Open\":540.742445,\"High\":548.482483,\"Low\":527.15244,\"Close\":538.152456,\"Volume\":4.4017e+06,\"AdjClose\":538.152456},{\"Date\":\"2014-04-04\",\"Open\":574.652643,\"High\":577.77265,\"Low\":543.002488,\"Close\":543.14246,\"Volume\":6.3693e+06,\"AdjClose\":543.14246},{\"Date\":\"2014-04-03\",\"Open\":569.852553,\"High\":587.282679,\"Low\":564.132581,\"Close\":569.742571,\"Volume\":5.0992e+06,\"AdjClose\":569.742571},{\"Date\":\"2014-04-02\",\"Open\":599.992707,\"High\":604.832763,\"Low\":562.192568,\"Close\":567.002574,\"Volume\":147100,\"AdjClose\":567.002574},{\"Date\":\"2014-04-01\",\"Open\":558.712565,\"High\":568.452595,\"Low\":558.712565,\"Close\":567.162558,\"Volume\":7900,\"AdjClose\":567.162558},{\"Date\":\"2014-03-31\",\"Open\":566.892592,\"High\":567.002574,\"Low\":556.932537,\"Close\":556.972503,\"Volume\":10800,\"AdjClose\":556.972503},{\"Date\":\"2014-03-28\",\"Open\":561.202549,\"High\":566.43259,\"Low\":558.672477,\"Close\":559.992504,\"Volume\":41200,\"AdjClose\":559.992504},{\"Date\":\"2014-03-27\",\"Open\":568.00257,\"High\":568.00257,\"Low\":552.922516,\"Close\":558.462551,\"Volume\":13100,\"AdjClose\":558.462551}]\n"
  },
  {
    "path": "27_code-in-process/38_JSON/15_exercise_csv-to-JSON/table.csv",
    "content": "Date,Open,High,Low,Close,Volume,Adj Close\n2015-07-09,523.119995,523.77002,520.349976,520.679993,1839400,520.679993\n2015-07-08,521.049988,522.734009,516.109985,516.830017,1264600,516.830017\n2015-07-07,523.130005,526.179993,515.179993,525.02002,1595700,525.02002\n2015-07-06,519.50,525.25,519.00,522.859985,1276500,522.859985\n2015-07-02,521.080017,524.650024,521.080017,523.400024,1234000,523.400024\n2015-07-01,524.72998,525.690002,518.22998,521.840027,1961000,521.840027\n2015-06-30,526.02002,526.25,520.50,520.51001,2217200,520.51001\n2015-06-29,525.01001,528.609985,520.539978,521.52002,1930900,521.52002\n2015-06-26,537.26001,537.76001,531.349976,531.690002,2011500,531.690002\n2015-06-25,538.869995,540.900024,535.22998,535.22998,1331500,535.22998\n2015-06-24,540.00,540.00,535.659973,537.840027,1283400,537.840027\n2015-06-23,539.640015,541.499023,535.25,540.47998,1196000,540.47998\n2015-06-22,539.590027,543.73999,537.530029,538.190002,1242500,538.190002\n2015-06-19,537.210022,538.25,533.01001,536.690002,1885700,536.690002\n2015-06-18,531.00,538.150024,530.789978,536.72998,1828100,536.72998\n2015-06-17,529.369995,530.97998,525.099976,529.26001,1268600,529.26001\n2015-06-16,528.400024,529.640015,525.559998,528.150024,1069300,528.150024\n2015-06-15,528.00,528.299988,524.00,527.200012,1630700,527.200012\n2015-06-12,531.599976,533.119995,530.159973,532.330017,952400,532.330017\n2015-06-11,538.424988,538.97998,533.02002,534.609985,1205000,534.609985\n2015-06-10,529.359985,538.359985,529.349976,536.690002,1811400,536.690002\n2015-06-09,527.559998,529.200012,523.01001,526.690002,1441600,526.690002\n2015-06-08,533.309998,534.119995,526.23999,526.830017,1520600,526.830017\n2015-06-05,536.349976,537.200012,532.52002,533.330017,1375000,533.330017\n2015-06-04,537.76001,540.590027,534.320007,536.700012,1335600,536.700012\n2015-06-03,539.909973,543.50,537.109985,540.309998,1714500,540.309998\n2015-06-02,532.929993,543.00,531.330017,539.179993,1934700,539.179993\n2015-06-01,536.789978,536.789978,529.76001,533.98999,1899600,533.98999\n2015-05-29,537.369995,538.630005,531.450012,532.109985,2584900,532.109985\n2015-05-28,538.01001,540.609985,536.25,539.780029,1027900,539.780029\n2015-05-27,532.799988,540.549988,531.710022,539.789978,1520400,539.789978\n2015-05-26,538.119995,539.00,529.880005,532.320007,2403400,532.320007\n2015-05-22,540.150024,544.190002,539.51001,540.109985,1173300,540.109985\n2015-05-21,537.950012,543.840027,535.97998,542.51001,1461400,542.51001\n2015-05-20,538.48999,542.919983,532.971985,539.27002,1429100,539.27002\n2015-05-19,533.97998,540.659973,533.039978,537.359985,1963300,537.359985\n2015-05-18,532.01001,534.820007,528.849976,532.299988,1998600,532.299988\n2015-05-15,539.179993,539.273987,530.380005,533.849976,1962700,533.849976\n2015-05-14,533.77002,539.00,532.409973,538.400024,1399100,538.400024\n2015-05-13,530.559998,534.322021,528.655029,529.619995,1252300,529.619995\n2015-05-12,531.599976,533.208984,525.26001,529.039978,1625400,529.039978\n2015-05-11,538.369995,541.97998,535.400024,535.700012,905300,535.700012\n2015-05-08,536.650024,541.150024,525.00,538.219971,1527600,538.219971\n2015-05-07,523.98999,533.460022,521.75,530.700012,1546300,530.700012\n2015-05-06,531.23999,532.380005,521.085022,524.219971,1567000,524.219971\n2015-05-05,538.210022,539.73999,530.390991,530.799988,1383100,530.799988\n2015-05-04,538.530029,544.070007,535.059998,540.780029,1308000,540.780029\n2015-05-01,538.429993,539.539978,532.099976,537.900024,1768200,537.900024\n2015-04-30,547.869995,548.590027,535.049988,537.340027,2082200,537.340027\n2015-04-29,550.469971,553.679993,546.905029,549.080017,1698800,549.080017\n2015-04-28,554.640015,556.02002,550.366028,553.679993,1491000,553.679993\n2015-04-27,563.390015,565.950012,553.200012,555.369995,2398000,555.369995\n2015-04-24,566.102522,571.14259,557.252507,565.062561,4932500,565.062561\n2015-04-23,541.002435,550.96249,540.23244,547.002472,4184900,547.002472\n2015-04-22,534.402426,541.082489,531.752397,539.367458,1593600,539.367458\n2015-04-21,537.512456,539.392429,533.677415,533.972413,1844800,533.972413\n2015-04-20,525.602352,536.092424,524.50235,535.382408,1679300,535.382408\n2015-04-17,528.662379,529.842435,521.012371,524.052386,2144100,524.052386\n2015-04-16,529.902414,535.592457,529.612373,533.802391,1299900,533.802391\n2015-04-15,528.702406,534.732432,523.22235,532.532429,2318800,532.532429\n2015-04-14,536.252409,537.572435,528.094354,530.392405,2604100,530.392405\n2015-04-13,538.412385,544.062463,537.312445,539.172404,1645300,539.172404\n2015-04-10,542.292411,542.292411,537.312445,540.012477,1409500,540.012477\n2015-04-09,541.032486,541.95249,535.49239,540.782472,1557900,540.782472\n2015-04-08,538.382457,543.852415,538.382457,541.612446,1178500,541.612446\n2015-04-07,538.08244,542.692434,536.002395,537.022465,1302900,537.022465\n2015-04-06,532.222375,538.412385,529.572407,536.767432,1324400,536.767432\n2015-04-02,540.852427,540.852427,533.849395,535.532478,1716400,535.532478\n2015-04-01,548.602441,551.142488,539.502472,542.562439,1963100,542.562439\n2015-03-31,550.00246,554.712521,546.722468,548.002468,1588000,548.002468\n2015-03-30,551.622503,553.472487,548.17249,552.032502,1287500,552.032502\n2015-03-27,553.002509,555.282565,548.132463,548.342512,1897500,548.342512\n2015-03-26,557.59255,558.90254,550.652497,555.172522,1572600,555.172522\n2015-03-25,570.50259,572.262605,558.742494,558.787478,2152300,558.787478\n2015-03-24,562.562541,574.592603,561.212586,570.192597,2583300,570.192597\n2015-03-23,560.432554,562.362529,555.832536,558.81251,1643800,558.81251\n2015-03-20,561.652574,561.722529,559.052548,560.362537,2616900,560.362537\n2015-03-19,559.392531,560.802526,556.147548,557.992512,1197300,557.992512\n2015-03-18,552.50248,559.782578,547.002472,559.502513,2134500,559.502513\n2015-03-17,551.712533,553.802493,548.002468,550.842532,1805500,550.842532\n2015-03-16,550.952514,556.852484,546.002476,554.512509,1641000,554.512509\n2015-03-13,553.502537,558.402572,544.222448,547.322503,1703600,547.322503\n2015-03-12,553.512513,556.37253,550.462523,555.512505,1389600,555.512505\n2015-03-11,555.142533,558.142521,550.682486,551.182515,1820800,551.182515\n2015-03-10,564.252539,564.852512,554.732473,555.012538,1792300,555.012538\n2015-03-09,566.862541,570.272589,563.537504,568.852557,1062100,568.852557\n2015-03-06,574.882583,576.682625,566.762597,567.687558,1659100,567.687558\n2015-03-05,575.022616,577.912621,573.412548,575.332609,1389600,575.332609\n2015-03-04,571.872558,577.112576,568.012607,573.372583,1876800,573.372583\n2015-03-03,570.452587,575.392649,566.522559,573.64261,1704800,573.64261\n2015-03-02,560.532559,572.152623,558.752531,571.342601,2129600,571.342601\n2015-02-27,554.242482,564.712602,552.902503,558.402572,2410200,558.402572\n2015-02-26,543.212476,556.142529,541.502464,555.482516,2311500,555.482516\n2015-02-25,535.90245,546.22244,535.447406,543.872489,1826000,543.872489\n2015-02-24,530.002419,536.792403,528.252381,536.092424,1005100,536.092424\n2015-02-23,536.052398,536.441465,529.412361,531.912381,1457900,531.912381\n2015-02-20,543.132484,543.75247,535.802444,538.952441,1444400,538.952441\n2015-02-19,538.042413,543.11247,538.012424,542.872432,989100,542.872432\n2015-02-18,541.402458,545.492471,537.512456,539.702422,1453100,539.702422\n2015-02-17,546.832511,550.00246,541.092465,542.842504,1616800,542.842504\n2015-02-13,543.352447,549.912491,543.132484,549.012501,1900300,549.012501\n2015-02-12,537.252405,544.822482,534.675391,542.932472,1620200,542.932472\n2015-02-11,535.302416,538.452473,533.380397,535.972405,1377800,535.972405\n2015-02-10,529.302379,537.702431,526.922378,536.942412,1749900,536.942412\n2015-02-09,528.002366,532.002411,526.022388,527.832406,1267800,527.832406\n2015-02-06,527.642431,537.202463,526.412373,531.002415,1749400,531.002415\n2015-02-05,523.792334,528.502395,522.092359,527.582391,1849800,527.582391\n2015-02-04,529.2424,532.67442,521.272361,522.762349,1663700,522.762349\n2015-02-03,528.002366,533.40243,523.262377,529.2424,2038700,529.2424\n2015-02-02,531.732383,533.002407,518.552316,528.482381,2849800,528.482381\n2015-01-30,515.862322,539.872444,515.522339,534.522445,5606400,534.522445\n2015-01-29,511.002313,511.092313,501.202274,510.662331,4186400,510.662331\n2015-01-28,522.782423,522.992349,510.002318,510.002318,1683800,510.002318\n2015-01-27,529.972369,530.702398,518.192381,518.63237,1904000,518.63237\n2015-01-26,538.532466,539.002444,529.672413,535.212448,1543700,535.212448\n2015-01-23,535.592457,542.172453,533.002407,539.952437,2281700,539.952437\n2015-01-22,521.482349,536.332463,519.702382,534.39245,2676900,534.39245\n2015-01-21,507.252283,519.282407,506.202315,518.042312,2268700,518.042312\n2015-01-20,511.002313,512.502307,506.018277,506.902294,2227900,506.902294\n2015-01-16,500.012273,508.1923,500.002267,508.082288,2298300,508.082288\n2015-01-15,505.572291,505.682273,497.762267,501.792271,2715800,501.792271\n2015-01-14,494.652237,503.232286,493.002234,500.872267,2235700,500.872267\n2015-01-13,498.842256,502.982302,492.392254,496.182251,2370500,496.182251\n2015-01-12,494.942247,495.978261,487.562205,492.552209,2322400,492.552209\n2015-01-09,504.7623,504.922285,494.792239,496.172274,2069400,496.172274\n2015-01-08,497.992238,503.4823,491.002212,502.682255,3353600,502.682255\n2015-01-07,507.002299,507.246285,499.652247,501.102268,2065100,501.102268\n2015-01-06,515.002358,516.177334,501.052266,501.962262,2899900,501.962262\n2015-01-05,523.262377,524.332389,513.062315,513.872306,2059800,513.872306\n2015-01-02,529.012399,531.272443,524.102327,524.812404,1447600,524.812404\n2014-12-31,531.252429,532.602384,525.802363,526.402397,1368200,526.402397\n2014-12-30,528.092396,531.152424,527.132366,530.422394,876300,530.422394\n2014-12-29,532.192446,535.482414,530.013375,530.332426,2278500,530.332426\n2014-12-26,528.772422,534.252417,527.312364,534.032454,1036000,534.032454\n2014-12-24,530.512424,531.761394,527.022384,528.772422,705900,528.772422\n2014-12-23,527.00237,534.56241,526.292354,530.592416,2197600,530.592416\n2014-12-22,516.082347,526.462376,516.082347,524.872383,2723800,524.872383\n2014-12-19,511.512318,517.722342,506.91331,516.352313,3690200,516.352313\n2014-12-18,512.952333,513.872306,504.70229,511.102319,2926700,511.102319\n2014-12-17,497.002248,507.002299,496.812244,504.892295,2883200,504.892295\n2014-12-16,511.562321,513.052308,489.00222,495.392273,3964300,495.392273\n2014-12-15,522.742335,523.102331,513.272333,513.80229,2813400,513.80229\n2014-12-12,523.512391,528.502395,518.662298,518.662298,1994600,518.662298\n2014-12-11,527.802355,533.922411,527.102376,528.34241,1610800,528.34241\n2014-12-10,533.082399,536.332463,525.562386,526.062353,1712300,526.062353\n2014-12-09,522.142362,534.192438,520.502366,533.37244,1871300,533.37244\n2014-12-08,527.132366,531.002415,523.792334,526.982357,2329400,526.982357\n2014-12-05,531.002415,532.892425,524.282386,525.262369,2565600,525.262369\n2014-12-04,531.1624,537.342434,528.592424,537.312445,1392100,537.312445\n2014-12-03,531.442404,535.998416,529.262414,531.322384,1278000,531.322384\n2014-12-02,533.512412,535.502427,529.802408,533.752389,1525800,533.752389\n2014-12-01,538.902438,541.412434,531.862379,533.802391,2115400,533.802391\n2014-11-28,540.622426,542.002431,536.602429,541.832471,1148300,541.832471\n2014-11-26,540.882478,541.552406,537.044437,540.372412,1523000,540.372412\n2014-11-25,539.002444,543.98241,538.60444,541.082489,1789100,541.082489\n2014-11-24,537.652489,542.702471,535.622446,539.272471,1706000,539.272471\n2014-11-21,541.612446,542.142464,536.562402,537.502419,2223700,537.502419\n2014-11-20,531.252429,535.112381,531.082408,534.832438,1562000,534.832438\n2014-11-19,535.002399,538.242425,530.082412,536.992415,1391600,536.992415\n2014-11-18,537.502419,541.942452,534.172425,535.032449,1962700,535.032449\n2014-11-17,543.582448,543.792436,534.063361,536.512461,1725800,536.512461\n2014-11-14,546.682442,546.682442,542.152501,544.402507,1289200,544.402507\n2014-11-13,549.802448,549.802448,543.482442,545.38249,1339400,545.38249\n2014-11-12,550.392507,550.462523,545.172441,547.312465,1129400,547.312465\n2014-11-11,548.492459,551.942473,546.302493,550.29244,965500,550.29244\n2014-11-10,541.462498,549.592522,541.022449,547.492463,1134600,547.492463\n2014-11-07,546.212525,546.212525,538.672437,541.012473,1633800,541.012473\n2014-11-06,545.502448,546.887472,540.972385,542.042458,1333300,542.042458\n2014-11-05,556.802481,556.802481,544.052426,545.922423,2032300,545.922423\n2014-11-04,553.002509,555.502529,549.302481,554.112486,1244200,554.112486\n2014-11-03,555.502529,557.902544,553.23251,555.222464,1382300,555.222464\n2014-10-31,559.352504,559.572529,554.752486,559.082538,2035100,559.082538\n2014-10-30,548.952522,552.802497,543.512493,550.312514,1455500,550.312514\n2014-10-29,550.00246,554.19254,546.982459,549.332532,1770500,549.332532\n2014-10-28,543.002488,548.98245,541.622422,548.902519,1271000,548.902519\n2014-10-27,537.032441,544.412422,537.032441,540.772496,1185300,540.772496\n2014-10-24,544.36248,544.882461,535.792407,539.782476,1973100,539.782476\n2014-10-23,539.322474,547.222436,535.852386,543.98241,2348800,543.98241\n2014-10-22,529.892437,539.802428,528.802351,532.712427,2919300,532.712427\n2014-10-21,525.192353,526.792383,519.112324,526.542369,2336300,526.542369\n2014-10-20,509.452317,521.762353,508.102301,520.84241,2607500,520.84241\n2014-10-17,527.252385,530.982402,508.532313,511.172335,5539400,511.172335\n2014-10-16,519.002342,529.432374,515.002358,524.512387,3708600,524.512387\n2014-10-15,531.012391,532.802396,518.302363,530.032409,3719400,530.032409\n2014-10-14,538.902438,547.192507,533.172368,537.942408,2222600,537.942408\n2014-10-13,544.992443,549.502492,533.102413,533.212456,2581700,533.212456\n2014-10-10,557.722484,565.132577,544.052426,544.492476,3081900,544.492476\n2014-10-09,571.182555,571.492549,559.062524,560.882579,2524800,560.882579\n2014-10-08,565.572566,573.882587,557.492484,572.502582,1990900,572.502582\n2014-10-07,574.402629,575.27263,563.742534,563.742534,1911300,563.742534\n2014-10-06,578.802574,581.002639,574.442595,577.352614,1214600,577.352614\n2014-10-03,573.052613,577.227576,572.502582,575.282606,1141700,575.282606\n2014-10-02,567.312567,571.912585,563.322559,570.082615,1178400,570.082615\n2014-10-01,576.012635,577.582615,567.01255,568.272597,1445500,568.272597\n2014-09-30,576.932578,579.852634,572.852541,577.36259,1621700,577.36259\n2014-09-29,571.7526,578.192625,571.172579,576.362594,1282400,576.362594\n2014-09-26,576.062638,579.2526,574.662558,577.1026,1443700,577.1026\n2014-09-25,587.552646,587.982658,574.182604,575.062581,1926000,575.062581\n2014-09-24,581.462641,589.632691,580.522624,587.992634,1728100,587.992634\n2014-09-23,586.852606,586.852606,581.002639,581.132634,1471400,581.132634\n2014-09-22,593.82271,593.951665,583.462694,587.372648,1689500,587.372648\n2014-09-19,591.502688,596.482654,589.502696,596.082692,3736600,596.082692\n2014-09-18,587.002675,589.542661,585.002622,589.272695,1444600,589.272695\n2014-09-17,580.012619,587.522656,578.777665,584.772683,1692800,584.772683\n2014-09-16,572.762572,581.502606,572.662566,579.95264,1480400,579.95264\n2014-09-15,572.94257,574.952599,568.212618,573.102555,1597600,573.102555\n2014-09-12,581.002639,581.642639,574.462608,575.622589,1601700,575.622589\n2014-09-11,580.362639,581.812599,576.262588,581.352598,1221000,581.352598\n2014-09-10,581.502606,583.502659,576.942615,583.102636,977400,583.102636\n2014-09-09,588.902723,589.002667,580.002643,581.012615,1287200,581.012615\n2014-09-08,586.602653,591.772715,586.302635,589.722659,1431000,589.722659\n2014-09-05,583.982613,586.55265,581.952632,586.082672,1632400,586.082672\n2014-09-04,580.002643,586.00268,579.222611,581.982621,1458200,581.982621\n2014-09-03,580.002643,582.992655,575.002602,577.942611,1215100,577.942611\n2014-09-02,571.852545,577.832629,571.192593,577.332662,1578400,577.332662\n2014-08-29,571.332625,572.04258,567.07155,571.60253,1083800,571.60253\n2014-08-28,569.562573,573.252563,567.102518,569.202577,1292900,569.202577\n2014-08-27,577.272622,578.492581,570.105627,571.002557,1703400,571.002557\n2014-08-26,581.262629,581.802623,576.582619,577.862619,1639700,577.862619\n2014-08-25,584.722619,585.002622,579.002647,580.202654,1361400,580.202654\n2014-08-22,583.592689,585.238682,580.642643,582.562642,789100,582.562642\n2014-08-21,583.822628,584.502655,581.142671,583.372664,914800,583.372664\n2014-08-20,585.88266,586.702658,582.572618,584.492618,1036700,584.492618\n2014-08-19,585.002622,587.342658,584.002627,586.862643,978700,586.862643\n2014-08-18,576.11258,584.512631,576.002598,582.162619,1284100,582.162619\n2014-08-15,577.862619,579.382595,570.522603,573.482564,1519200,573.482564\n2014-08-14,576.182596,577.902645,570.882599,574.652643,985500,574.652643\n2014-08-13,567.312567,575.002602,565.752564,574.782639,1441800,574.782639\n2014-08-12,564.522567,565.902572,560.882579,562.732562,1542000,562.732562\n2014-08-11,569.992585,570.492553,566.002578,567.882551,1214700,567.882551\n2014-08-08,563.562536,570.252576,560.3525,568.772626,1494800,568.772626\n2014-08-07,568.00257,569.89258,561.102482,563.362525,1110900,563.362525\n2014-08-06,561.782569,570.702601,560.002541,566.376589,1334400,566.376589\n2014-08-05,570.052564,571.982601,562.612543,565.072598,1551200,565.072598\n2014-08-04,569.042531,575.352561,564.102531,573.152619,1427300,573.152619\n2014-08-01,570.402584,575.962633,562.85252,566.072594,1955300,566.072594\n2014-07-31,580.602616,583.652668,570.002561,571.60253,2102800,571.60253\n2014-07-30,586.55265,589.502696,584.002627,587.42265,1016500,587.42265\n2014-07-29,588.752653,589.702707,583.517654,585.612633,1349900,585.612633\n2014-07-28,588.072688,592.502683,584.755668,590.602636,986800,590.602636\n2014-07-25,590.402686,591.862684,587.032665,589.022681,932500,589.022681\n2014-07-24,596.452725,599.502716,591.772715,593.352671,1035100,593.352671\n2014-07-23,593.232652,597.852683,592.502683,595.982686,1233200,595.982686\n2014-07-22,590.722655,599.652725,590.602636,594.742652,1699200,594.742652\n2014-07-21,591.752702,594.402731,585.235622,589.472645,2062100,589.472645\n2014-07-18,593.002712,596.802684,582.002635,595.082696,4014200,595.082696\n2014-07-17,579.532665,580.992601,568.61258,573.732579,3016600,573.732579\n2014-07-16,588.002671,588.402694,582.202646,582.662587,1397100,582.662587\n2014-07-15,585.742628,585.807626,576.562606,584.782659,1623000,584.782659\n2014-07-14,582.602608,585.212671,578.032641,584.872627,1854100,584.872627\n2014-07-11,571.912585,580.85263,571.422594,579.182645,1621700,579.182645\n2014-07-10,565.912548,576.592656,565.012558,571.102563,1356700,571.102563\n2014-07-09,571.582578,576.72259,569.378536,576.082652,1116800,576.082652\n2014-07-08,577.662607,579.530645,566.137592,571.092587,1909500,571.092587\n2014-07-07,583.76265,586.432631,579.592644,582.252649,1064600,582.252649\n2014-07-03,583.352589,585.01266,580.922585,584.732656,714200,584.732656\n2014-07-02,583.352589,585.442672,580.392628,582.33766,1056400,582.33766\n2014-07-01,578.32262,584.402649,576.652635,582.672624,1448000,582.672624\n2014-06-30,578.662603,579.572631,574.752588,575.282606,1313800,575.282606\n2014-06-27,577.182592,579.872648,573.802595,577.242632,2236900,577.242632\n2014-06-26,581.002639,582.45266,571.852545,576.002598,1742000,576.002598\n2014-06-25,565.262572,579.962616,565.222546,578.652627,1969400,578.652627\n2014-06-24,565.192556,572.648612,561.012574,564.622572,2207100,564.622572\n2014-06-23,555.152509,565.002582,554.252519,564.952579,1536800,564.952579\n2014-06-20,556.852484,557.582513,550.394526,556.362492,4508300,556.362492\n2014-06-19,554.242482,555.0025,548.512473,554.902556,2456800,554.902556\n2014-06-18,544.862448,553.562516,544.002484,553.372481,1741800,553.372481\n2014-06-17,544.202496,545.32245,539.33245,543.012465,1444600,543.012465\n2014-06-16,549.262515,549.62245,541.522477,544.282488,1702600,544.282488\n2014-06-13,552.262503,552.302469,545.562488,551.762536,1220500,551.762536\n2014-06-12,557.302509,557.992512,548.462531,551.352476,1458500,551.352476\n2014-06-11,558.002549,559.882522,555.022514,558.842561,1100100,558.842561\n2014-06-10,560.512546,563.602502,557.902544,560.552511,1351700,560.552511\n2014-06-09,557.152562,562.902584,556.042523,562.122552,1467500,562.122552\n2014-06-06,558.062528,558.062528,548.932448,556.332564,1736800,556.332564\n2014-06-05,546.402499,554.952498,544.452449,553.90256,1689100,553.90256\n2014-06-04,541.502464,548.612478,538.752429,544.662436,1816500,544.662436\n2014-06-03,550.99248,552.342557,542.552463,544.942501,1866600,544.942501\n2014-06-02,560.702581,560.902593,545.732448,553.932488,1435000,553.932488\n2014-05-30,560.802526,561.352496,555.912467,559.892559,1771100,559.892559\n2014-05-29,563.352549,564.002525,558.712565,560.082534,1354100,560.082534\n2014-05-28,564.57257,567.842585,561.002537,561.682502,1652000,561.682502\n2014-05-27,556.002496,566.002578,554.352463,565.952575,2104200,565.952575\n2014-05-23,547.262462,553.642508,543.702467,552.702492,1932200,552.702492\n2014-05-22,541.132431,547.602445,540.782472,545.062459,1615800,545.062459\n2014-05-21,532.902462,539.185441,531.912381,538.942465,1196300,538.942465\n2014-05-20,529.742368,536.232396,526.302392,529.772418,1784800,529.772418\n2014-05-19,519.702382,529.782456,517.58537,528.862391,1277800,528.862391\n2014-05-16,521.39238,521.802379,515.442347,520.632362,1485300,520.632362\n2014-05-15,525.702357,525.872379,517.422325,519.982324,1704400,519.982324\n2014-05-14,533.002407,533.002407,525.292358,526.652412,1191800,526.652412\n2014-05-13,530.892433,536.072411,529.512428,533.092437,1653400,533.092437\n2014-05-12,523.512391,530.192393,519.012379,529.922366,1912500,529.922366\n2014-05-09,510.75233,519.902393,504.202292,518.732314,2439500,518.732314\n2014-05-08,508.462297,517.23229,506.452298,511.002313,2021300,511.002313\n2014-05-07,515.792305,516.68232,503.302272,509.962291,3224300,509.962291\n2014-05-06,525.232379,526.812396,515.062337,515.14233,1689000,515.14233\n2014-05-05,524.822381,528.902418,521.322364,527.812392,1024100,527.812392\n2014-05-02,533.762426,534.002403,525.612389,527.932411,1688500,527.932411\n2014-05-01,527.112352,532.932391,523.882364,531.352374,1905500,531.352374\n2014-04-30,527.602343,528.002366,522.522372,526.662388,1751200,526.662388\n2014-04-29,516.902344,529.462425,516.322324,527.70241,2699100,527.70241\n2014-04-28,517.182348,518.602319,502.802274,517.152359,3335500,517.152359\n2014-04-25,522.512395,524.702361,515.422333,516.182352,2100400,516.182352\n2014-04-24,530.072374,531.652452,522.122349,525.162363,1883200,525.162363\n2014-04-23,533.792415,533.872408,526.252389,526.942391,2052300,526.942391\n2014-04-22,528.642427,537.232391,527.512375,534.812425,2365400,534.812425\n2014-04-21,536.1024,536.702435,525.602352,528.622414,2566700,528.622414\n2014-04-17,548.81249,549.502492,531.152424,536.1024,6809500,536.1024\n2014-04-16,543.002488,557.002492,540.00244,556.54249,4893300,556.54249\n2014-04-15,536.822454,538.452473,518.462348,536.442444,3855100,536.442444\n2014-04-14,538.252462,544.102429,529.56237,532.522453,2575100,532.522453\n2014-04-11,532.552381,540.00244,526.532392,530.602392,3924800,530.602392\n2014-04-10,565.002582,565.002582,539.902495,540.952433,4036900,540.952433\n2014-04-09,559.622532,565.372554,552.952506,564.142557,3330800,564.142557\n2014-04-08,542.602466,555.0025,541.612446,554.902556,3151200,554.902556\n2014-04-07,540.742445,548.482483,527.15244,538.152456,4401700,538.152456\n2014-04-04,574.652643,577.77265,543.002488,543.14246,6369300,543.14246\n2014-04-03,569.852553,587.282679,564.132581,569.742571,5099200,569.742571\n2014-04-02,599.992707,604.832763,562.192568,567.002574,147100,567.002574\n2014-04-01,558.712565,568.452595,558.712565,567.162558,7900,567.162558\n2014-03-31,566.892592,567.002574,556.932537,556.972503,10800,556.972503\n2014-03-28,561.202549,566.43259,558.672477,559.992504,41200,559.992504\n2014-03-27,568.00257,568.00257,552.922516,558.462551,13100,558.462551\n"
  },
  {
    "path": "27_code-in-process/38_JSON/16/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n)\n\ntype Article struct {\n\tName  string\n\tdraft bool\n}\n\nfunc main() {\n\tmyArticle := Article{\n\t\tName:  \"Once And Then Again\",\n\t\tdraft: false,\n\t}\n\n\tdata, err := json.Marshal(myArticle)\n\tif err != nil {\n\t\tlog.Fatalln(\"couldn't marshall\", err.Error())\n\t} else {\n\t\tfmt.Println(string(data))\n\t\tos.Stdout.Write(data)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/38_JSON/17/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t\"encoding/json\"\n\t\"os\"\n\t\"strconv\"\n\t\"time\"\n)\n\ntype Record struct {\n\tDate time.Time\n\tOpen float64\n\t// High, Low, Close\n}\n\nfunc main() {\n\tsrc, err := os.Open(\"../../../resources/table.csv\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer src.Close()\n\n\tdst, err := os.Create(\"table.json\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer dst.Close()\n\n\trows, err := csv.NewReader(src).ReadAll()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\trecords := make([]Record, 0, len(rows))\n\tfor _, row := range rows {\n\t\tdate, _ := time.Parse(\"2006-01-01_this-does-not-compile\", row[0])\n\t\topen, _ := strconv.ParseFloat(row[1], 64)\n\n\t\trecords = append(records, Record{\n\t\t\tDate: date,\n\t\t\tOpen: open,\n\t\t})\n\t}\n\n\terr = json.NewEncoder(dst).Encode(records)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n}\n"
  },
  {
    "path": "27_code-in-process/38_JSON/17/table.json",
    "content": "[{\"Date\":\"0001-01-01T00:00:00Z\",\"Open\":0},{\"Date\":\"2015-07-09T00:00:00Z\",\"Open\":523.119995},{\"Date\":\"2015-07-08T00:00:00Z\",\"Open\":521.049988},{\"Date\":\"2015-07-07T00:00:00Z\",\"Open\":523.130005},{\"Date\":\"2015-07-06T00:00:00Z\",\"Open\":519.5},{\"Date\":\"2015-07-02T00:00:00Z\",\"Open\":521.080017},{\"Date\":\"2015-07-01T00:00:00Z\",\"Open\":524.72998},{\"Date\":\"2015-06-30T00:00:00Z\",\"Open\":526.02002},{\"Date\":\"2015-06-29T00:00:00Z\",\"Open\":525.01001},{\"Date\":\"2015-06-26T00:00:00Z\",\"Open\":537.26001},{\"Date\":\"2015-06-25T00:00:00Z\",\"Open\":538.869995},{\"Date\":\"2015-06-24T00:00:00Z\",\"Open\":540},{\"Date\":\"2015-06-23T00:00:00Z\",\"Open\":539.640015},{\"Date\":\"2015-06-22T00:00:00Z\",\"Open\":539.590027},{\"Date\":\"2015-06-19T00:00:00Z\",\"Open\":537.210022},{\"Date\":\"2015-06-18T00:00:00Z\",\"Open\":531},{\"Date\":\"2015-06-17T00:00:00Z\",\"Open\":529.369995},{\"Date\":\"2015-06-16T00:00:00Z\",\"Open\":528.400024},{\"Date\":\"2015-06-15T00:00:00Z\",\"Open\":528},{\"Date\":\"2015-06-12T00:00:00Z\",\"Open\":531.599976},{\"Date\":\"2015-06-11T00:00:00Z\",\"Open\":538.424988},{\"Date\":\"2015-06-10T00:00:00Z\",\"Open\":529.359985},{\"Date\":\"2015-06-09T00:00:00Z\",\"Open\":527.559998},{\"Date\":\"2015-06-08T00:00:00Z\",\"Open\":533.309998},{\"Date\":\"2015-06-05T00:00:00Z\",\"Open\":536.349976},{\"Date\":\"2015-06-04T00:00:00Z\",\"Open\":537.76001},{\"Date\":\"2015-06-03T00:00:00Z\",\"Open\":539.909973},{\"Date\":\"2015-06-02T00:00:00Z\",\"Open\":532.929993},{\"Date\":\"2015-06-01T00:00:00Z\",\"Open\":536.789978},{\"Date\":\"2015-05-29T00:00:00Z\",\"Open\":537.369995},{\"Date\":\"2015-05-28T00:00:00Z\",\"Open\":538.01001},{\"Date\":\"2015-05-27T00:00:00Z\",\"Open\":532.799988},{\"Date\":\"2015-05-26T00:00:00Z\",\"Open\":538.119995},{\"Date\":\"2015-05-22T00:00:00Z\",\"Open\":540.150024},{\"Date\":\"2015-05-21T00:00:00Z\",\"Open\":537.950012},{\"Date\":\"2015-05-20T00:00:00Z\",\"Open\":538.48999},{\"Date\":\"2015-05-19T00:00:00Z\",\"Open\":533.97998},{\"Date\":\"2015-05-18T00:00:00Z\",\"Open\":532.01001},{\"Date\":\"2015-05-15T00:00:00Z\",\"Open\":539.179993},{\"Date\":\"2015-05-14T00:00:00Z\",\"Open\":533.77002},{\"Date\":\"2015-05-13T00:00:00Z\",\"Open\":530.559998},{\"Date\":\"2015-05-12T00:00:00Z\",\"Open\":531.599976},{\"Date\":\"2015-05-11T00:00:00Z\",\"Open\":538.369995},{\"Date\":\"2015-05-08T00:00:00Z\",\"Open\":536.650024},{\"Date\":\"2015-05-07T00:00:00Z\",\"Open\":523.98999},{\"Date\":\"2015-05-06T00:00:00Z\",\"Open\":531.23999},{\"Date\":\"2015-05-05T00:00:00Z\",\"Open\":538.210022},{\"Date\":\"2015-05-04T00:00:00Z\",\"Open\":538.530029},{\"Date\":\"2015-05-01T00:00:00Z\",\"Open\":538.429993},{\"Date\":\"2015-04-30T00:00:00Z\",\"Open\":547.869995},{\"Date\":\"2015-04-29T00:00:00Z\",\"Open\":550.469971},{\"Date\":\"2015-04-28T00:00:00Z\",\"Open\":554.640015},{\"Date\":\"2015-04-27T00:00:00Z\",\"Open\":563.390015},{\"Date\":\"2015-04-24T00:00:00Z\",\"Open\":566.102522},{\"Date\":\"2015-04-23T00:00:00Z\",\"Open\":541.002435},{\"Date\":\"2015-04-22T00:00:00Z\",\"Open\":534.402426},{\"Date\":\"2015-04-21T00:00:00Z\",\"Open\":537.512456},{\"Date\":\"2015-04-20T00:00:00Z\",\"Open\":525.602352},{\"Date\":\"2015-04-17T00:00:00Z\",\"Open\":528.662379},{\"Date\":\"2015-04-16T00:00:00Z\",\"Open\":529.902414},{\"Date\":\"2015-04-15T00:00:00Z\",\"Open\":528.702406},{\"Date\":\"2015-04-14T00:00:00Z\",\"Open\":536.252409},{\"Date\":\"2015-04-13T00:00:00Z\",\"Open\":538.412385},{\"Date\":\"2015-04-10T00:00:00Z\",\"Open\":542.292411},{\"Date\":\"2015-04-09T00:00:00Z\",\"Open\":541.032486},{\"Date\":\"2015-04-08T00:00:00Z\",\"Open\":538.382457},{\"Date\":\"2015-04-07T00:00:00Z\",\"Open\":538.08244},{\"Date\":\"2015-04-06T00:00:00Z\",\"Open\":532.222375},{\"Date\":\"2015-04-02T00:00:00Z\",\"Open\":540.852427},{\"Date\":\"2015-04-01T00:00:00Z\",\"Open\":548.602441},{\"Date\":\"2015-03-31T00:00:00Z\",\"Open\":550.00246},{\"Date\":\"2015-03-30T00:00:00Z\",\"Open\":551.622503},{\"Date\":\"2015-03-27T00:00:00Z\",\"Open\":553.002509},{\"Date\":\"2015-03-26T00:00:00Z\",\"Open\":557.59255},{\"Date\":\"2015-03-25T00:00:00Z\",\"Open\":570.50259},{\"Date\":\"2015-03-24T00:00:00Z\",\"Open\":562.562541},{\"Date\":\"2015-03-23T00:00:00Z\",\"Open\":560.432554},{\"Date\":\"2015-03-20T00:00:00Z\",\"Open\":561.652574},{\"Date\":\"2015-03-19T00:00:00Z\",\"Open\":559.392531},{\"Date\":\"2015-03-18T00:00:00Z\",\"Open\":552.50248},{\"Date\":\"2015-03-17T00:00:00Z\",\"Open\":551.712533},{\"Date\":\"2015-03-16T00:00:00Z\",\"Open\":550.952514},{\"Date\":\"2015-03-13T00:00:00Z\",\"Open\":553.502537},{\"Date\":\"2015-03-12T00:00:00Z\",\"Open\":553.512513},{\"Date\":\"2015-03-11T00:00:00Z\",\"Open\":555.142533},{\"Date\":\"2015-03-10T00:00:00Z\",\"Open\":564.252539},{\"Date\":\"2015-03-09T00:00:00Z\",\"Open\":566.862541},{\"Date\":\"2015-03-06T00:00:00Z\",\"Open\":574.882583},{\"Date\":\"2015-03-05T00:00:00Z\",\"Open\":575.022616},{\"Date\":\"2015-03-04T00:00:00Z\",\"Open\":571.872558},{\"Date\":\"2015-03-03T00:00:00Z\",\"Open\":570.452587},{\"Date\":\"2015-03-02T00:00:00Z\",\"Open\":560.532559},{\"Date\":\"2015-02-27T00:00:00Z\",\"Open\":554.242482},{\"Date\":\"2015-02-26T00:00:00Z\",\"Open\":543.212476},{\"Date\":\"2015-02-25T00:00:00Z\",\"Open\":535.90245},{\"Date\":\"2015-02-24T00:00:00Z\",\"Open\":530.002419},{\"Date\":\"2015-02-23T00:00:00Z\",\"Open\":536.052398},{\"Date\":\"2015-02-20T00:00:00Z\",\"Open\":543.132484},{\"Date\":\"2015-02-19T00:00:00Z\",\"Open\":538.042413},{\"Date\":\"2015-02-18T00:00:00Z\",\"Open\":541.402458},{\"Date\":\"2015-02-17T00:00:00Z\",\"Open\":546.832511},{\"Date\":\"2015-02-13T00:00:00Z\",\"Open\":543.352447},{\"Date\":\"2015-02-12T00:00:00Z\",\"Open\":537.252405},{\"Date\":\"2015-02-11T00:00:00Z\",\"Open\":535.302416},{\"Date\":\"2015-02-10T00:00:00Z\",\"Open\":529.302379},{\"Date\":\"2015-02-09T00:00:00Z\",\"Open\":528.002366},{\"Date\":\"2015-02-06T00:00:00Z\",\"Open\":527.642431},{\"Date\":\"2015-02-05T00:00:00Z\",\"Open\":523.792334},{\"Date\":\"2015-02-04T00:00:00Z\",\"Open\":529.2424},{\"Date\":\"2015-02-03T00:00:00Z\",\"Open\":528.002366},{\"Date\":\"2015-02-02T00:00:00Z\",\"Open\":531.732383},{\"Date\":\"2015-01-30T00:00:00Z\",\"Open\":515.862322},{\"Date\":\"2015-01-29T00:00:00Z\",\"Open\":511.002313},{\"Date\":\"2015-01-28T00:00:00Z\",\"Open\":522.782423},{\"Date\":\"2015-01-27T00:00:00Z\",\"Open\":529.972369},{\"Date\":\"2015-01-26T00:00:00Z\",\"Open\":538.532466},{\"Date\":\"2015-01-23T00:00:00Z\",\"Open\":535.592457},{\"Date\":\"2015-01-22T00:00:00Z\",\"Open\":521.482349},{\"Date\":\"2015-01-21T00:00:00Z\",\"Open\":507.252283},{\"Date\":\"2015-01-20T00:00:00Z\",\"Open\":511.002313},{\"Date\":\"2015-01-16T00:00:00Z\",\"Open\":500.012273},{\"Date\":\"2015-01-15T00:00:00Z\",\"Open\":505.572291},{\"Date\":\"2015-01-14T00:00:00Z\",\"Open\":494.652237},{\"Date\":\"2015-01-13T00:00:00Z\",\"Open\":498.842256},{\"Date\":\"2015-01-12T00:00:00Z\",\"Open\":494.942247},{\"Date\":\"2015-01-09T00:00:00Z\",\"Open\":504.7623},{\"Date\":\"2015-01-08T00:00:00Z\",\"Open\":497.992238},{\"Date\":\"2015-01-07T00:00:00Z\",\"Open\":507.002299},{\"Date\":\"2015-01-06T00:00:00Z\",\"Open\":515.002358},{\"Date\":\"2015-01-05T00:00:00Z\",\"Open\":523.262377},{\"Date\":\"2015-01-02T00:00:00Z\",\"Open\":529.012399},{\"Date\":\"2014-12-31T00:00:00Z\",\"Open\":531.252429},{\"Date\":\"2014-12-30T00:00:00Z\",\"Open\":528.092396},{\"Date\":\"2014-12-29T00:00:00Z\",\"Open\":532.192446},{\"Date\":\"2014-12-26T00:00:00Z\",\"Open\":528.772422},{\"Date\":\"2014-12-24T00:00:00Z\",\"Open\":530.512424},{\"Date\":\"2014-12-23T00:00:00Z\",\"Open\":527.00237},{\"Date\":\"2014-12-22T00:00:00Z\",\"Open\":516.082347},{\"Date\":\"2014-12-19T00:00:00Z\",\"Open\":511.512318},{\"Date\":\"2014-12-18T00:00:00Z\",\"Open\":512.952333},{\"Date\":\"2014-12-17T00:00:00Z\",\"Open\":497.002248},{\"Date\":\"2014-12-16T00:00:00Z\",\"Open\":511.562321},{\"Date\":\"2014-12-15T00:00:00Z\",\"Open\":522.742335},{\"Date\":\"2014-12-12T00:00:00Z\",\"Open\":523.512391},{\"Date\":\"2014-12-11T00:00:00Z\",\"Open\":527.802355},{\"Date\":\"2014-12-10T00:00:00Z\",\"Open\":533.082399},{\"Date\":\"2014-12-09T00:00:00Z\",\"Open\":522.142362},{\"Date\":\"2014-12-08T00:00:00Z\",\"Open\":527.132366},{\"Date\":\"2014-12-05T00:00:00Z\",\"Open\":531.002415},{\"Date\":\"2014-12-04T00:00:00Z\",\"Open\":531.1624},{\"Date\":\"2014-12-03T00:00:00Z\",\"Open\":531.442404},{\"Date\":\"2014-12-02T00:00:00Z\",\"Open\":533.512412},{\"Date\":\"2014-12-01T00:00:00Z\",\"Open\":538.902438},{\"Date\":\"2014-11-28T00:00:00Z\",\"Open\":540.622426},{\"Date\":\"2014-11-26T00:00:00Z\",\"Open\":540.882478},{\"Date\":\"2014-11-25T00:00:00Z\",\"Open\":539.002444},{\"Date\":\"2014-11-24T00:00:00Z\",\"Open\":537.652489},{\"Date\":\"2014-11-21T00:00:00Z\",\"Open\":541.612446},{\"Date\":\"2014-11-20T00:00:00Z\",\"Open\":531.252429},{\"Date\":\"2014-11-19T00:00:00Z\",\"Open\":535.002399},{\"Date\":\"2014-11-18T00:00:00Z\",\"Open\":537.502419},{\"Date\":\"2014-11-17T00:00:00Z\",\"Open\":543.582448},{\"Date\":\"2014-11-14T00:00:00Z\",\"Open\":546.682442},{\"Date\":\"2014-11-13T00:00:00Z\",\"Open\":549.802448},{\"Date\":\"2014-11-12T00:00:00Z\",\"Open\":550.392507},{\"Date\":\"2014-11-11T00:00:00Z\",\"Open\":548.492459},{\"Date\":\"2014-11-10T00:00:00Z\",\"Open\":541.462498},{\"Date\":\"2014-11-07T00:00:00Z\",\"Open\":546.212525},{\"Date\":\"2014-11-06T00:00:00Z\",\"Open\":545.502448},{\"Date\":\"2014-11-05T00:00:00Z\",\"Open\":556.802481},{\"Date\":\"2014-11-04T00:00:00Z\",\"Open\":553.002509},{\"Date\":\"2014-11-03T00:00:00Z\",\"Open\":555.502529},{\"Date\":\"2014-10-31T00:00:00Z\",\"Open\":559.352504},{\"Date\":\"2014-10-30T00:00:00Z\",\"Open\":548.952522},{\"Date\":\"2014-10-29T00:00:00Z\",\"Open\":550.00246},{\"Date\":\"2014-10-28T00:00:00Z\",\"Open\":543.002488},{\"Date\":\"2014-10-27T00:00:00Z\",\"Open\":537.032441},{\"Date\":\"2014-10-24T00:00:00Z\",\"Open\":544.36248},{\"Date\":\"2014-10-23T00:00:00Z\",\"Open\":539.322474},{\"Date\":\"2014-10-22T00:00:00Z\",\"Open\":529.892437},{\"Date\":\"2014-10-21T00:00:00Z\",\"Open\":525.192353},{\"Date\":\"2014-10-20T00:00:00Z\",\"Open\":509.452317},{\"Date\":\"2014-10-17T00:00:00Z\",\"Open\":527.252385},{\"Date\":\"2014-10-16T00:00:00Z\",\"Open\":519.002342},{\"Date\":\"2014-10-15T00:00:00Z\",\"Open\":531.012391},{\"Date\":\"2014-10-14T00:00:00Z\",\"Open\":538.902438},{\"Date\":\"2014-10-13T00:00:00Z\",\"Open\":544.992443},{\"Date\":\"2014-10-10T00:00:00Z\",\"Open\":557.722484},{\"Date\":\"2014-10-09T00:00:00Z\",\"Open\":571.182555},{\"Date\":\"2014-10-08T00:00:00Z\",\"Open\":565.572566},{\"Date\":\"2014-10-07T00:00:00Z\",\"Open\":574.402629},{\"Date\":\"2014-10-06T00:00:00Z\",\"Open\":578.802574},{\"Date\":\"2014-10-03T00:00:00Z\",\"Open\":573.052613},{\"Date\":\"2014-10-02T00:00:00Z\",\"Open\":567.312567},{\"Date\":\"2014-10-01T00:00:00Z\",\"Open\":576.012635},{\"Date\":\"2014-09-30T00:00:00Z\",\"Open\":576.932578},{\"Date\":\"2014-09-29T00:00:00Z\",\"Open\":571.7526},{\"Date\":\"2014-09-26T00:00:00Z\",\"Open\":576.062638},{\"Date\":\"2014-09-25T00:00:00Z\",\"Open\":587.552646},{\"Date\":\"2014-09-24T00:00:00Z\",\"Open\":581.462641},{\"Date\":\"2014-09-23T00:00:00Z\",\"Open\":586.852606},{\"Date\":\"2014-09-22T00:00:00Z\",\"Open\":593.82271},{\"Date\":\"2014-09-19T00:00:00Z\",\"Open\":591.502688},{\"Date\":\"2014-09-18T00:00:00Z\",\"Open\":587.002675},{\"Date\":\"2014-09-17T00:00:00Z\",\"Open\":580.012619},{\"Date\":\"2014-09-16T00:00:00Z\",\"Open\":572.762572},{\"Date\":\"2014-09-15T00:00:00Z\",\"Open\":572.94257},{\"Date\":\"2014-09-12T00:00:00Z\",\"Open\":581.002639},{\"Date\":\"2014-09-11T00:00:00Z\",\"Open\":580.362639},{\"Date\":\"2014-09-10T00:00:00Z\",\"Open\":581.502606},{\"Date\":\"2014-09-09T00:00:00Z\",\"Open\":588.902723},{\"Date\":\"2014-09-08T00:00:00Z\",\"Open\":586.602653},{\"Date\":\"2014-09-05T00:00:00Z\",\"Open\":583.982613},{\"Date\":\"2014-09-04T00:00:00Z\",\"Open\":580.002643},{\"Date\":\"2014-09-03T00:00:00Z\",\"Open\":580.002643},{\"Date\":\"2014-09-02T00:00:00Z\",\"Open\":571.852545},{\"Date\":\"2014-08-29T00:00:00Z\",\"Open\":571.332625},{\"Date\":\"2014-08-28T00:00:00Z\",\"Open\":569.562573},{\"Date\":\"2014-08-27T00:00:00Z\",\"Open\":577.272622},{\"Date\":\"2014-08-26T00:00:00Z\",\"Open\":581.262629},{\"Date\":\"2014-08-25T00:00:00Z\",\"Open\":584.722619},{\"Date\":\"2014-08-22T00:00:00Z\",\"Open\":583.592689},{\"Date\":\"2014-08-21T00:00:00Z\",\"Open\":583.822628},{\"Date\":\"2014-08-20T00:00:00Z\",\"Open\":585.88266},{\"Date\":\"2014-08-19T00:00:00Z\",\"Open\":585.002622},{\"Date\":\"2014-08-18T00:00:00Z\",\"Open\":576.11258},{\"Date\":\"2014-08-15T00:00:00Z\",\"Open\":577.862619},{\"Date\":\"2014-08-14T00:00:00Z\",\"Open\":576.182596},{\"Date\":\"2014-08-13T00:00:00Z\",\"Open\":567.312567},{\"Date\":\"2014-08-12T00:00:00Z\",\"Open\":564.522567},{\"Date\":\"2014-08-11T00:00:00Z\",\"Open\":569.992585},{\"Date\":\"2014-08-08T00:00:00Z\",\"Open\":563.562536},{\"Date\":\"2014-08-07T00:00:00Z\",\"Open\":568.00257},{\"Date\":\"2014-08-06T00:00:00Z\",\"Open\":561.782569},{\"Date\":\"2014-08-05T00:00:00Z\",\"Open\":570.052564},{\"Date\":\"2014-08-04T00:00:00Z\",\"Open\":569.042531},{\"Date\":\"2014-08-01T00:00:00Z\",\"Open\":570.402584},{\"Date\":\"2014-07-31T00:00:00Z\",\"Open\":580.602616},{\"Date\":\"2014-07-30T00:00:00Z\",\"Open\":586.55265},{\"Date\":\"2014-07-29T00:00:00Z\",\"Open\":588.752653},{\"Date\":\"2014-07-28T00:00:00Z\",\"Open\":588.072688},{\"Date\":\"2014-07-25T00:00:00Z\",\"Open\":590.402686},{\"Date\":\"2014-07-24T00:00:00Z\",\"Open\":596.452725},{\"Date\":\"2014-07-23T00:00:00Z\",\"Open\":593.232652},{\"Date\":\"2014-07-22T00:00:00Z\",\"Open\":590.722655},{\"Date\":\"2014-07-21T00:00:00Z\",\"Open\":591.752702},{\"Date\":\"2014-07-18T00:00:00Z\",\"Open\":593.002712},{\"Date\":\"2014-07-17T00:00:00Z\",\"Open\":579.532665},{\"Date\":\"2014-07-16T00:00:00Z\",\"Open\":588.002671},{\"Date\":\"2014-07-15T00:00:00Z\",\"Open\":585.742628},{\"Date\":\"2014-07-14T00:00:00Z\",\"Open\":582.602608},{\"Date\":\"2014-07-11T00:00:00Z\",\"Open\":571.912585},{\"Date\":\"2014-07-10T00:00:00Z\",\"Open\":565.912548},{\"Date\":\"2014-07-09T00:00:00Z\",\"Open\":571.582578},{\"Date\":\"2014-07-08T00:00:00Z\",\"Open\":577.662607},{\"Date\":\"2014-07-07T00:00:00Z\",\"Open\":583.76265},{\"Date\":\"2014-07-03T00:00:00Z\",\"Open\":583.352589},{\"Date\":\"2014-07-02T00:00:00Z\",\"Open\":583.352589},{\"Date\":\"2014-07-01T00:00:00Z\",\"Open\":578.32262},{\"Date\":\"2014-06-30T00:00:00Z\",\"Open\":578.662603},{\"Date\":\"2014-06-27T00:00:00Z\",\"Open\":577.182592},{\"Date\":\"2014-06-26T00:00:00Z\",\"Open\":581.002639},{\"Date\":\"2014-06-25T00:00:00Z\",\"Open\":565.262572},{\"Date\":\"2014-06-24T00:00:00Z\",\"Open\":565.192556},{\"Date\":\"2014-06-23T00:00:00Z\",\"Open\":555.152509},{\"Date\":\"2014-06-20T00:00:00Z\",\"Open\":556.852484},{\"Date\":\"2014-06-19T00:00:00Z\",\"Open\":554.242482},{\"Date\":\"2014-06-18T00:00:00Z\",\"Open\":544.862448},{\"Date\":\"2014-06-17T00:00:00Z\",\"Open\":544.202496},{\"Date\":\"2014-06-16T00:00:00Z\",\"Open\":549.262515},{\"Date\":\"2014-06-13T00:00:00Z\",\"Open\":552.262503},{\"Date\":\"2014-06-12T00:00:00Z\",\"Open\":557.302509},{\"Date\":\"2014-06-11T00:00:00Z\",\"Open\":558.002549},{\"Date\":\"2014-06-10T00:00:00Z\",\"Open\":560.512546},{\"Date\":\"2014-06-09T00:00:00Z\",\"Open\":557.152562},{\"Date\":\"2014-06-06T00:00:00Z\",\"Open\":558.062528},{\"Date\":\"2014-06-05T00:00:00Z\",\"Open\":546.402499},{\"Date\":\"2014-06-04T00:00:00Z\",\"Open\":541.502464},{\"Date\":\"2014-06-03T00:00:00Z\",\"Open\":550.99248},{\"Date\":\"2014-06-02T00:00:00Z\",\"Open\":560.702581},{\"Date\":\"2014-05-30T00:00:00Z\",\"Open\":560.802526},{\"Date\":\"2014-05-29T00:00:00Z\",\"Open\":563.352549},{\"Date\":\"2014-05-28T00:00:00Z\",\"Open\":564.57257},{\"Date\":\"2014-05-27T00:00:00Z\",\"Open\":556.002496},{\"Date\":\"2014-05-23T00:00:00Z\",\"Open\":547.262462},{\"Date\":\"2014-05-22T00:00:00Z\",\"Open\":541.132431},{\"Date\":\"2014-05-21T00:00:00Z\",\"Open\":532.902462},{\"Date\":\"2014-05-20T00:00:00Z\",\"Open\":529.742368},{\"Date\":\"2014-05-19T00:00:00Z\",\"Open\":519.702382},{\"Date\":\"2014-05-16T00:00:00Z\",\"Open\":521.39238},{\"Date\":\"2014-05-15T00:00:00Z\",\"Open\":525.702357},{\"Date\":\"2014-05-14T00:00:00Z\",\"Open\":533.002407},{\"Date\":\"2014-05-13T00:00:00Z\",\"Open\":530.892433},{\"Date\":\"2014-05-12T00:00:00Z\",\"Open\":523.512391},{\"Date\":\"2014-05-09T00:00:00Z\",\"Open\":510.75233},{\"Date\":\"2014-05-08T00:00:00Z\",\"Open\":508.462297},{\"Date\":\"2014-05-07T00:00:00Z\",\"Open\":515.792305},{\"Date\":\"2014-05-06T00:00:00Z\",\"Open\":525.232379},{\"Date\":\"2014-05-05T00:00:00Z\",\"Open\":524.822381},{\"Date\":\"2014-05-02T00:00:00Z\",\"Open\":533.762426},{\"Date\":\"2014-05-01T00:00:00Z\",\"Open\":527.112352},{\"Date\":\"2014-04-30T00:00:00Z\",\"Open\":527.602343},{\"Date\":\"2014-04-29T00:00:00Z\",\"Open\":516.902344},{\"Date\":\"2014-04-28T00:00:00Z\",\"Open\":517.182348},{\"Date\":\"2014-04-25T00:00:00Z\",\"Open\":522.512395},{\"Date\":\"2014-04-24T00:00:00Z\",\"Open\":530.072374},{\"Date\":\"2014-04-23T00:00:00Z\",\"Open\":533.792415},{\"Date\":\"2014-04-22T00:00:00Z\",\"Open\":528.642427},{\"Date\":\"2014-04-21T00:00:00Z\",\"Open\":536.1024},{\"Date\":\"2014-04-17T00:00:00Z\",\"Open\":548.81249},{\"Date\":\"2014-04-16T00:00:00Z\",\"Open\":543.002488},{\"Date\":\"2014-04-15T00:00:00Z\",\"Open\":536.822454},{\"Date\":\"2014-04-14T00:00:00Z\",\"Open\":538.252462},{\"Date\":\"2014-04-11T00:00:00Z\",\"Open\":532.552381},{\"Date\":\"2014-04-10T00:00:00Z\",\"Open\":565.002582},{\"Date\":\"2014-04-09T00:00:00Z\",\"Open\":559.622532},{\"Date\":\"2014-04-08T00:00:00Z\",\"Open\":542.602466},{\"Date\":\"2014-04-07T00:00:00Z\",\"Open\":540.742445},{\"Date\":\"2014-04-04T00:00:00Z\",\"Open\":574.652643},{\"Date\":\"2014-04-03T00:00:00Z\",\"Open\":569.852553},{\"Date\":\"2014-04-02T00:00:00Z\",\"Open\":599.992707},{\"Date\":\"2014-04-01T00:00:00Z\",\"Open\":558.712565},{\"Date\":\"2014-03-31T00:00:00Z\",\"Open\":566.892592},{\"Date\":\"2014-03-28T00:00:00Z\",\"Open\":561.202549},{\"Date\":\"2014-03-27T00:00:00Z\",\"Open\":568.00257}]\n"
  },
  {
    "path": "27_code-in-process/39_packages/hello/bye.go",
    "content": "package hello\n\nimport \"fmt\"\n\nfunc ByeBye() {\n\tfmt.Println(looper(\"Bye! \"))\n}\n\nfunc looper(str string) string {\n\tvar newString string\n\tx := 7\n\tfor i := 0; i < 100; i++ {\n\t\tnewString += str\n\t\tx := 9\n\t\tfmt.Println(x)\n\t}\n\tfmt.Println(x)\n\treturn newString\n}\n"
  },
  {
    "path": "27_code-in-process/39_packages/hello/hello.go",
    "content": "package hello\n\nimport \"fmt\"\n\nfunc Hello() {\n\tfmt.Println(\"Hello\")\n}\n"
  },
  {
    "path": "27_code-in-process/39_packages/main/main.go",
    "content": "package main\n\nimport \"github.com/GoesToEleven/SummerBootCamp/05_golang/02/01/07_packages/hello\"\n\nfunc main() {\n\thello.Hello()\n\thello.ByeBye()\n}\n"
  },
  {
    "path": "27_code-in-process/40_testing/01/example/sum.go",
    "content": "package example\n\nimport (\n\t\"fmt\"\n)\n\nfunc Sum(nums ...int) int {\n\tfmt.Print(nums, \" \")\n\ttotal := 0\n\tfor _, num := range nums {\n\t\ttotal += num\n\t}\n\tfmt.Println(total)\n\treturn total\n}\n"
  },
  {
    "path": "27_code-in-process/40_testing/01/example/sum_test.go",
    "content": "package example\n\nimport \"testing\"\n\nfunc TestSum(t *testing.T) {\n\tvar n int\n\tn = Sum(1, 2)\n\tif n != 3 {\n\t\tt.Error(\"Expected 3, got \", n)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/40_testing/01/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/GoesToEleven/SummerBootCamp/05_golang/02/01/13_01_testing/example\"\n)\n\nfunc main() {\n\texample.Sum(7, 5, 3, 1)\n}\n"
  },
  {
    "path": "27_code-in-process/40_testing/02/example/sum.go",
    "content": "package example\n\nimport (\n\t\"fmt\"\n)\n\nfunc Sum(nums ...int) int {\n\tfmt.Print(nums, \" \")\n\ttotal := 0\n\tfor _, num := range nums {\n\t\ttotal += num\n\t}\n\tfmt.Println(total)\n\treturn total\n}\n"
  },
  {
    "path": "27_code-in-process/40_testing/02/example/sum_test.go",
    "content": "package example\n\nimport \"testing\"\n\ntype testpair struct {\n\tvalues []int\n\tsum    int\n}\n\nvar tests = []testpair{\n\t{[]int{1, 2}, 3},\n\t{[]int{1, 1, 1, 1, 1, 1}, 6},\n\t{[]int{-1, 1}, 0},\n}\n\nfunc TestSum(t *testing.T) {\n\tfor _, pair := range tests {\n\t\tv := Sum(pair.values...)\n\t\tif v != pair.sum {\n\t\t\tt.Error(\n\t\t\t\t\"For\", pair.values,\n\t\t\t\t\"expected\", pair.sum,\n\t\t\t\t\"got\", v,\n\t\t\t)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/40_testing/02/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/GoesToEleven/SummerBootCamp/05_golang/02/01/13_02_testing/example\"\n)\n\nfunc main() {\n\texample.Sum(7, 5, 3, 1)\n}\n"
  },
  {
    "path": "27_code-in-process/41_TCP/01/00_notes.txt",
    "content": "at terminal:\ndig www.google.com\n\n\nat terminal:\ndig google.com\n\n\n(1) buy domain\nfor example: namecheap\nfor example: google domains\n\ndomains come from ICANN originally\n\n(2) associate domain with nameserver\nadd your \"A\" record\neg, cloudflare\n\n(3) other stuff\n\n\nyou can use google chrome dev tools / network\nyou can use CURL at the command line\neg, at terminal:\n\tcurl -v golang.org\n\n\nTCP\nwireshark\ntraceroute\n\nSTACKS\n- reverse proxies / load balancers (nginx, haproxy)\n- web servers (nginx, apache, IIS, ...)\n- backend servers (databases, mail servers, ...)\n- cloud services\n- queues\n\n\n"
  },
  {
    "path": "27_code-in-process/41_TCP/02_listen/00_notes.txt",
    "content": "on windows you can install telnet\non Mac, should be there\n\nstart main.go (go run main.go) then ...\ntelnet localhost 9000\n\n"
  },
  {
    "path": "27_code-in-process/41_TCP/02_listen/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"time\"\n)\n\nfunc main() {\n\tln, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer ln.Close()\n\n\tfor {\n\t\tconn, err := ln.Accept()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\n\t\tio.WriteString(conn, fmt.Sprint(\"Hello World\\n\", time.Now(), \"\\n\"))\n\n\t\tconn.Close()\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/41_TCP/03_dial/00_notes.txt",
    "content": "start the file in 02_listen (go run main.go)\n\nthen run the main.go file in this folder\n"
  },
  {
    "path": "27_code-in-process/41_TCP/03_dial/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"net\"\n)\n\nfunc main() {\n\tconn, err := net.Dial(\"tcp\", \"localhost:9000\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer conn.Close()\n\n\tbs, _ := ioutil.ReadAll(conn)\n\tfmt.Println(string(bs))\n\n}\n\n// see \"notes.txt\" to run this\n"
  },
  {
    "path": "27_code-in-process/41_TCP/04_echo-server/v01/00_notes.txt",
    "content": "on windows you can install telnet\non Mac, should be there\n\nstart main.go (go run main.go) then ...\ntelnet localhost 9000\n\n"
  },
  {
    "path": "27_code-in-process/41_TCP/04_echo-server/v01/main.go",
    "content": "package main\n\nimport \"net\"\n\nfunc main() {\n\tln, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer ln.Close()\n\n\tfor {\n\t\tconn, err := ln.Accept()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\n\t\tfor {\n\t\t\tbs := make([]byte, 1024)\n\t\t\tn, err := conn.Read(bs)\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\t_, err = conn.Write(bs[:n])\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tconn.Close()\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/41_TCP/04_echo-server/v02/00_notes.txt",
    "content": "on windows you can install telnet\non Mac, should be there\n\nstart main.go (go run main.go) then ...\ntelnet localhost 9000\n\n"
  },
  {
    "path": "27_code-in-process/41_TCP/04_echo-server/v02/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"io\"\n\t\"net\"\n)\n\nfunc main() {\n\tln, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer ln.Close()\n\n\tfor {\n\t\tconn, err := ln.Accept()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\n\t\tscanner := bufio.NewScanner(conn)\n\t\tfor scanner.Scan() {\n\t\t\tio.WriteString(conn, scanner.Text())\n\t\t}\n\n\t\tconn.Close()\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/41_TCP/04_echo-server/v03/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net\"\n)\n\nfunc main() {\n\tln, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer ln.Close()\n\n\tfor {\n\t\tconn, err := ln.Accept()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\n\t\t// handles only one connection\n\t\tio.Copy(conn, conn)\n\t\tconn.Close()\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/41_TCP/04_echo-server/v04/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net\"\n)\n\nfunc main() {\n\tln, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer ln.Close()\n\n\tfor {\n\t\tconn, err := ln.Accept()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\n\t\t// handles unlimited connections\n\t\tgo func() {\n\t\t\tio.Copy(conn, conn)\n\t\t\tconn.Close()\n\t\t}()\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/41_TCP/05_redis-clone/i01/i01_notes.txt",
    "content": "on windows you can install telnet\non Mac, should be there\n\nstart main.go (go run main.go) then ...\ntelnet localhost 9000\n\n"
  },
  {
    "path": "27_code-in-process/41_TCP/05_redis-clone/i01/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n)\n\nfunc handle(conn net.Conn) {\n\tdefer conn.Close()\n\n\tscanner := bufio.NewScanner(conn)\n\tfor scanner.Scan() {\n\t\tln := scanner.Text()\n\t\tfmt.Println(ln)\n\t}\n}\n\nfunc main() {\n\tli, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer li.Close()\n\n\tfor {\n\t\tconn, err := li.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\t\thandle(conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/41_TCP/05_redis-clone/i02/i02_notes.txt",
    "content": "on windows you can install telnet\non Mac, should be there\n\nstart main.go (go run main.go) then ...\ntelnet localhost 9000\n\nyou should be able to test your case logic\n\nwhen you enter GET or SET or DEL, nothing will happen\nanything else entered will return \"INVALID COMMAND\"\n"
  },
  {
    "path": "27_code-in-process/41_TCP/05_redis-clone/i02/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n)\n\nfunc handle(conn net.Conn) {\n\tdefer conn.Close()\n\n\tscanner := bufio.NewScanner(conn)\n\tfor scanner.Scan() {\n\t\tln := scanner.Text()\n\t\tfs := strings.Fields(ln)\n\t\t// skip blank lines\n\t\tif len(fs) < 1 {\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch fs[0] {\n\t\tcase \"GET\":\n\t\tcase \"SET\":\n\t\tcase \"DEL\":\n\t\tdefault:\n\t\t\tio.WriteString(conn, \"INVALID COMMAND \"+fs[0]+\"\\n\")\n\t\t}\n\t}\n}\n\nfunc main() {\n\tli, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer li.Close()\n\n\tfor {\n\t\tconn, err := li.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\t\thandle(conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/41_TCP/05_redis-clone/i03/i03_notes.txt",
    "content": "on windows you can install telnet\non Mac, should be there\n\nstart main.go (go run main.go) then ...\ntelnet localhost 9000\n\nyou should be able to test your case logic\n\n\nyou can now SET and GET\n\n~ $ telnet localhost 9000\n\nSET key val\nGET key\nval\n\n"
  },
  {
    "path": "27_code-in-process/41_TCP/05_redis-clone/i03/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n)\n\nvar data = make(map[string]string)\n\nfunc handle(conn net.Conn) {\n\tdefer conn.Close()\n\n\tscanner := bufio.NewScanner(conn)\n\tfor scanner.Scan() {\n\t\tln := scanner.Text()\n\t\tfs := strings.Fields(ln)\n\t\t// skip blank lines\n\t\tif len(fs) < 2 {\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch fs[0] {\n\t\tcase \"GET\":\n\t\t\tkey := fs[1]\n\t\t\tvalue := data[key]\n\t\t\tfmt.Fprintf(conn, \"%s\\n\", value)\n\t\tcase \"SET\":\n\t\t\tif len(fs) != 3 {\n\t\t\t\tio.WriteString(conn, \"EXPECTED VALUE\\n\")\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tkey := fs[1]\n\t\t\tvalue := fs[2]\n\t\t\tdata[key] = value\n\t\tcase \"DEL\":\n\t\tdefault:\n\t\t\tio.WriteString(conn, \"INVALID COMMAND \"+fs[0]+\"\\n\")\n\t\t}\n\t}\n}\n\nfunc main() {\n\tli, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer li.Close()\n\n\tfor {\n\t\tconn, err := li.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\t\thandle(conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/41_TCP/05_redis-clone/i04/i04_notes.txt",
    "content": "on windows you can install telnet\non Mac, should be there\n\nstart main.go (go run main.go) then ...\ntelnet localhost 9000\n\nyou should be able to test your case logic\n\n\nyou can now SET and GET and DEL\n\n~ $ telnet localhost 9000\n\nSET fav pop\nGET fav\npop\nDEL fav\nGET fav\n\n"
  },
  {
    "path": "27_code-in-process/41_TCP/05_redis-clone/i04/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n)\n\nvar data = make(map[string]string)\n\nfunc handle(conn net.Conn) {\n\tdefer conn.Close()\n\n\tscanner := bufio.NewScanner(conn)\n\tfor scanner.Scan() {\n\t\tln := scanner.Text()\n\t\tfs := strings.Fields(ln)\n\n\t\tif len(fs) < 2 {\n\t\t\tio.WriteString(conn, \"This is an in-memory database \\n\"+\n\t\t\t\t\"Use SET, GET, DEL like this: \\n\"+\n\t\t\t\t\"SET key value \\n\"+\n\t\t\t\t\"GET key \\n\"+\n\t\t\t\t\"DEL key \\n\\n\"+\n\t\t\t\t\"For example - try these commands: \\n\"+\n\t\t\t\t\"SET fav chocolate \\n\"+\n\t\t\t\t\"GET fav \\n\\n\\n\")\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch fs[0] {\n\t\tcase \"GET\":\n\t\t\tkey := fs[1]\n\t\t\tvalue := data[key]\n\t\t\tfmt.Fprintf(conn, \"%s\\n\", value)\n\t\tcase \"SET\":\n\t\t\tif len(fs) != 3 {\n\t\t\t\tio.WriteString(conn, \"EXPECTED VALUE\\n\")\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tkey := fs[1]\n\t\t\tvalue := fs[2]\n\t\t\tdata[key] = value\n\t\tcase \"DEL\":\n\t\t\tkey := fs[1]\n\t\t\tdelete(data, key)\n\t\tdefault:\n\t\t\tio.WriteString(conn, \"INVALID COMMAND \"+fs[0]+\"\\n\")\n\t\t}\n\t}\n}\n\nfunc main() {\n\tli, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer li.Close()\n\n\tfor {\n\t\tconn, err := li.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\t\thandle(conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/41_TCP/05_redis-clone/i05_code-issue/i04_notes.txt",
    "content": "on windows you can install telnet\non Mac, should be there\n\nstart main.go (go run main.go) then ...\ntelnet localhost 9000\n\nyou should be able to test your case logic\n\n\nyou can now SET and GET and DEL\n\n~ $ telnet localhost 9000\n\nSET fav pop\nGET fav\npop\nDEL fav\nGET fav\n\n"
  },
  {
    "path": "27_code-in-process/41_TCP/05_redis-clone/i05_code-issue/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n)\n\nvar data = make(map[string]string)\n\nfunc handle(conn net.Conn) {\n\tdefer conn.Close()\n\n\tscanner := bufio.NewScanner(conn)\n\tfor scanner.Scan() {\n\t\tln := scanner.Text()\n\t\tfs := strings.Fields(ln)\n\t\t// skip blank lines\n\t\tif len(fs) < 2 {\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch fs[0] {\n\t\tcase \"GET\":\n\t\t\tkey := fs[1]\n\t\t\tvalue := data[key]\n\t\t\tfmt.Fprintf(conn, \"%s\\n\", value)\n\t\tcase \"SET\":\n\t\t\tif len(fs) != 3 {\n\t\t\t\tio.WriteString(conn, \"EXPECTED VALUE\\n\")\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tkey := fs[1]\n\t\t\tvalue := fs[2]\n\t\t\tdata[key] = value\n\t\tcase \"DEL\":\n\t\t\tkey := fs[1]\n\t\t\tdelete(data, key)\n\t\tdefault:\n\t\t\tio.WriteString(conn, \"INVALID COMMAND \"+fs[0]+\"\\n\")\n\t\t}\n\t}\n}\n\nfunc main() {\n\tli, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer li.Close()\n\n\tfor {\n\t\tconn, err := li.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\t\thandle(conn)\n\t\t// ONLY HANDLES ONE CONNECTION AT A TIME\n\t\t// Could we make it concurrent? How?\n\t\t// What are the considerations?\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/41_TCP/05_redis-clone/i06/i04_notes.txt",
    "content": "on windows you can install telnet\non Mac, should be there\n\nstart main.go (go run main.go) then ...\ntelnet localhost 9000\n\nyou should be able to test your case logic\n\n\nyou can now SET and GET and DEL\n\n~ $ telnet localhost 9000\n\nSET fav pop\nGET fav\npop\nDEL fav\nGET fav\n\n"
  },
  {
    "path": "27_code-in-process/41_TCP/05_redis-clone/i06/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n)\n\ntype Command struct {\n\tFields []string\n\tResult chan string\n}\n\nfunc redisServer(commands chan Command) {\n\tvar data = make(map[string]string)\n\tfor cmd := range commands {\n\t\tif len(cmd.Fields) < 2 {\n\t\t\tcmd.Result <- \"Expected at least 2 arguments\"\n\t\t\tcontinue\n\t\t}\n\n\t\tfmt.Println(\"GOT COMMAND\", cmd)\n\n\t\tswitch cmd.Fields[0] {\n\t\t// GET <KEY>\n\t\tcase \"GET\":\n\t\t\tkey := cmd.Fields[1]\n\t\t\tvalue := data[key]\n\n\t\t\tcmd.Result <- value\n\n\t\t// SET <KEY> <VALUE>\n\t\tcase \"SET\":\n\t\t\tif len(cmd.Fields) != 3 {\n\t\t\t\tcmd.Result <- \"EXPECTED VALUE\"\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tkey := cmd.Fields[1]\n\t\t\tvalue := cmd.Fields[2]\n\t\t\tdata[key] = value\n\t\t\tcmd.Result <- \"\"\n\t\t// DEL <KEY>\n\t\tcase \"DEL\":\n\t\t\tkey := cmd.Fields[1]\n\t\t\tdelete(data, key)\n\t\t\tcmd.Result <- \"\"\n\t\tdefault:\n\t\t\tcmd.Result <- \"INVALID COMMAND \" + cmd.Fields[0] + \"\\n\"\n\t\t}\n\t}\n}\n\nfunc handle(commands chan Command, conn net.Conn) {\n\tdefer conn.Close()\n\n\tscanner := bufio.NewScanner(conn)\n\tfor scanner.Scan() {\n\t\tln := scanner.Text()\n\t\tfs := strings.Fields(ln)\n\n\t\tresult := make(chan string)\n\t\tcommands <- Command{\n\t\t\tFields: fs,\n\t\t\tResult: result,\n\t\t}\n\n\t\tio.WriteString(conn, <-result+\"\\n\")\n\t}\n\n}\n\nfunc main() {\n\tli, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer li.Close()\n\n\tcommands := make(chan Command)\n\tgo redisServer(commands)\n\n\tfor {\n\t\tconn, err := li.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\n\t\tgo handle(commands, conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/41_TCP/06_rot13-server/v01-todd/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n)\n\nfunc main() {\n\tln, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer ln.Close()\n\n\tfor {\n\t\tconn, err := ln.Accept()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\n\t\tscanner := bufio.NewScanner(conn)\n\t\tfor scanner.Scan() {\n\t\t\tline := strings.ToLower(scanner.Text())\n\t\t\tbs := []byte(line)\n\t\t\tvar rot13 = make([]byte, len(bs))\n\t\t\tfor k, v := range bs {\n\t\t\t\t// ascii 97 - 122\n\t\t\t\t/// 109 + 13 = 122\n\t\t\t\tif v <= 109 {\n\t\t\t\t\trot13[k] = v + 13\n\t\t\t\t} else {\n\t\t\t\t\t// 110 + 13 = 123\n\t\t\t\t\t//123 - 26 = 97\n\t\t\t\t\trot13[k] = v - 26 + 13\n\t\t\t\t}\n\t\t\t}\n\t\t\tfmt.Fprintf(conn, \"rot13: %s\\n\", rot13)\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/41_TCP/06_rot13-server/v02-caleb/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"net\"\n)\n\ntype Rot13Reader struct {\n\tio.Reader\n}\n\nfunc (rot13 *Rot13Reader) Read(p []byte) (int, error) {\n\tn, err := rot13.Reader.Read(p)\n\tfor i, v := range p[:n] {\n\t\tif v <= 'z' && v >= 'a' {\n\t\t\tp[i] = v + 13\n\t\t\tif p[i] > 'z' {\n\t\t\t\tp[i] -= 26\n\t\t\t}\n\t\t} else if v <= 'Z' && v >= 'A' {\n\t\t\tp[i] = v + 13\n\t\t\tif p[i] > 'Z' {\n\t\t\t\tp[i] -= 26\n\t\t\t}\n\t\t} else {\n\t\t\tp[i] = v\n\t\t}\n\t}\n\treturn n, err\n}\n\nfunc rot13(rdr io.Reader) io.Reader {\n\treturn &Rot13Reader{rdr}\n}\n\nfunc handleConn(conn net.Conn) {\n\tdefer conn.Close()\n\tio.Copy(conn, rot13(conn))\n}\n\nfunc main() {\n\tserver, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\tdefer server.Close()\n\n\tfor {\n\t\tconn, err := server.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err.Error())\n\t\t}\n\t\tgo handleConn(conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/41_TCP/06_rot13-server/v03-daniel/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n)\n\nfunc handleConn(conn net.Conn) {\n\tdefer conn.Close()\n\tscn := bufio.NewScanner(conn)\n\tfor scn.Scan() {\n\t\tline := scn.Text()\n\t\tbs := []byte(line)\n\t\tresult := make([]byte, len(bs))\n\t\tfor i, v := range bs {\n\t\t\tif v <= 'z' && v >= 'a' {\n\t\t\t\tresult[i] = v + 13\n\t\t\t\tif result[i] > 'z' {\n\t\t\t\t\tresult[i] -= 26\n\t\t\t\t}\n\t\t\t} else if v <= 'Z' && v >= 'A' {\n\t\t\t\tresult[i] = v + 13\n\t\t\t\tif result[i] > 'Z' {\n\t\t\t\t\tresult[i] -= 26\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tresult[i] = v\n\t\t\t}\n\t\t}\n\t\tfmt.Fprintf(conn, \"%s\\n%s\\n\", result, bs)\n\t}\n}\n\nfunc main() {\n\tserver, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\tdefer server.Close()\n\n\tfor {\n\t\tconn, err := server.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err.Error())\n\t\t}\n\t\tgo handleConn(conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/41_TCP/07_chat-server/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n)\n\ntype User struct {\n\tName   string\n\tOutput chan Message\n}\n\ntype Message struct {\n\tUsername string\n\tText     string\n}\n\ntype ChatServer struct {\n\tUsers map[string]User\n\tJoin  chan User\n\tLeave chan User\n\tInput chan Message\n}\n\nfunc (cs *ChatServer) Run() {\n\tfor {\n\t\tselect {\n\t\tcase user := <-cs.Join:\n\t\t\tcs.Users[user.Name] = user\n\t\t\tgo func() {\n\t\t\t\tcs.Input <- Message{\n\t\t\t\t\tUsername: \"SYSTEM\",\n\t\t\t\t\tText:     fmt.Sprintf(\"%s joined\", user.Name),\n\t\t\t\t}\n\t\t\t}()\n\t\tcase user := <-cs.Leave:\n\t\t\tdelete(cs.Users, user.Name)\n\t\t\tgo func() {\n\t\t\t\tcs.Input <- Message{\n\t\t\t\t\tUsername: \"SYSTEM\",\n\t\t\t\t\tText:     fmt.Sprintf(\"%s left\", user.Name),\n\t\t\t\t}\n\t\t\t}()\n\t\tcase msg := <-cs.Input:\n\t\t\tfor _, user := range cs.Users {\n\t\t\t\tselect {\n\t\t\t\tcase user.Output <- msg:\n\t\t\t\tdefault:\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc handleConn(chatServer *ChatServer, conn net.Conn) {\n\tdefer conn.Close()\n\n\tio.WriteString(conn, \"Enter your Username:\")\n\n\tscanner := bufio.NewScanner(conn)\n\tscanner.Scan()\n\tuser := User{\n\t\tName:   scanner.Text(),\n\t\tOutput: make(chan Message, 10),\n\t}\n\tchatServer.Join <- user\n\tdefer func() {\n\t\tchatServer.Leave <- user\n\t}()\n\n\t// Read from conn\n\tgo func() {\n\t\tfor scanner.Scan() {\n\t\t\tln := scanner.Text()\n\t\t\tchatServer.Input <- Message{user.Name, ln}\n\t\t}\n\t}()\n\n\t// write to conn\n\tfor msg := range user.Output {\n\t\tif msg.Username != user.Name {\n\t\t\t_, err := io.WriteString(conn, msg.Username+\": \"+msg.Text+\"\\n\")\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc main() {\n\tserver, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\tdefer server.Close()\n\n\tchatServer := &ChatServer{\n\t\tUsers: make(map[string]User),\n\t\tJoin:  make(chan User),\n\t\tLeave: make(chan User),\n\t\tInput: make(chan Message),\n\t}\n\tgo chatServer.Run()\n\n\tfor {\n\t\tconn, err := server.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err.Error())\n\t\t}\n\t\tgo handleConn(chatServer, conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/42_HTTP/01_header/00_notes.txt",
    "content": "\nstart main.go (go run main.go) then ...\ngo to your browser and go to localhost:9000\n\n"
  },
  {
    "path": "27_code-in-process/42_HTTP/01_header/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n)\n\nfunc handleConn(conn net.Conn) {\n\tdefer conn.Close()\n\tscanner := bufio.NewScanner(conn)\n\tfor scanner.Scan() {\n\t\tfmt.Println(scanner.Text())\n\t}\n}\n\nfunc main() {\n\tserver, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\tdefer server.Close()\n\n\tfor {\n\t\tconn, err := server.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err.Error())\n\t\t}\n\t\tgo handleConn(conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/42_HTTP/02_http-server/i01/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n)\n\nfunc handleConn(conn net.Conn) {\n\tdefer conn.Close()\n\tscanner := bufio.NewScanner(conn)\n\ti := 0\n\tfor scanner.Scan() {\n\t\tln := scanner.Text()\n\t\tfmt.Println(ln)\n\n\t\tif i == 0 {\n\t\t\tmethod := strings.Fields(ln)[0]\n\t\t\tfmt.Println(\"METHOD\", method)\n\t\t} else {\n\n\t\t}\n\n\t\ti++\n\t}\n}\n\nfunc main() {\n\tserver, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\tdefer server.Close()\n\n\tfor {\n\t\tconn, err := server.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err.Error())\n\t\t}\n\t\tgo handleConn(conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/42_HTTP/02_http-server/i02/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n)\n\nfunc handleConn(conn net.Conn) {\n\tdefer conn.Close()\n\tscanner := bufio.NewScanner(conn)\n\ti := 0\n\tfor scanner.Scan() {\n\t\tln := scanner.Text()\n\t\tfmt.Println(ln)\n\n\t\tif i == 0 {\n\t\t\tmethod := strings.Fields(ln)[0]\n\t\t\tfmt.Println(\"METHOD\", method)\n\t\t} else {\n\t\t\t// in headers now\n\t\t\t// when line is empty, header is done\n\t\t\tif ln == \"\" {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\ti++\n\t}\n}\n\nfunc main() {\n\tserver, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\tdefer server.Close()\n\n\tfor {\n\t\tconn, err := server.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err.Error())\n\t\t}\n\t\tgo handleConn(conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/42_HTTP/02_http-server/i03/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n)\n\nfunc handleConn(conn net.Conn) {\n\tdefer conn.Close()\n\tscanner := bufio.NewScanner(conn)\n\ti := 0\n\tfor scanner.Scan() {\n\t\tln := scanner.Text()\n\t\tfmt.Println(ln)\n\n\t\tif i == 0 {\n\t\t\tmethod := strings.Fields(ln)[0]\n\t\t\tfmt.Println(\"METHOD\", method)\n\t\t} else {\n\t\t\t// in headers now\n\t\t\t// when line is empty, header is done\n\t\t\tif ln == \"\" {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\ti++\n\t}\n\n\t// response\n\tbody := \"hello world 2\"\n\n\tio.WriteString(conn, \"HTTP/1.1 200 OK\\r\\n\")\n\tfmt.Fprintf(conn, \"Content-Length: %d\\r\\n\", len(body))\n\tio.WriteString(conn, \"\\r\\n\")\n\tio.WriteString(conn, body)\n}\n\nfunc main() {\n\tserver, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\tdefer server.Close()\n\n\tfor {\n\t\tconn, err := server.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err.Error())\n\t\t}\n\t\tgo handleConn(conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/42_HTTP/02_http-server/i04_POST/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n)\n\nfunc handleConn(conn net.Conn) {\n\tdefer conn.Close()\n\tscanner := bufio.NewScanner(conn)\n\ti := 0\n\tfor scanner.Scan() {\n\t\tln := scanner.Text()\n\t\tfmt.Println(ln)\n\n\t\tif i == 0 {\n\t\t\tmethod := strings.Fields(ln)[0]\n\t\t\tfmt.Println(\"METHOD\", method)\n\t\t} else {\n\t\t\t// in headers now\n\t\t\t// when line is empty, header is done\n\t\t\tif ln == \"\" {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\ti++\n\t}\n\n\t// response\n\tbody := `\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n</head>\n<body>\n\t<form method=\"POST\">\n\t\t<input type=\"text\" name=\"key\" value=\"\">\n\t\t<input type=\"submit\">\n\t</form>\n</body>\n</html>\n\t`\n\n\tio.WriteString(conn, \"HTTP/1.1 200 OK\\r\\n\")\n\tfmt.Fprintf(conn, \"Content-Length: %d\\r\\n\", len(body))\n\tio.WriteString(conn, \"\\r\\n\")\n\tio.WriteString(conn, body)\n}\n\nfunc main() {\n\tserver, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\tdefer server.Close()\n\n\tfor {\n\t\tconn, err := server.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err.Error())\n\t\t}\n\t\tgo handleConn(conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/42_HTTP/02_http-server/i05_not-writing_error-in-code/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nfunc handleConn(conn net.Conn) {\n\tdefer conn.Close()\n\tscanner := bufio.NewScanner(conn)\n\ti := 0\n\theaders := map[string]string{}\n\tvar url, method string\n\tfor scanner.Scan() {\n\t\tln := scanner.Text()\n\t\tfmt.Println(ln)\n\n\t\tif i == 0 {\n\t\t\tfs := strings.Fields(ln)\n\t\t\tmethod := fs[0]\n\t\t\turl = fs[1]\n\t\t\tfmt.Println(\"METHOD\", method)\n\t\t\tfmt.Println(\"URL\", url)\n\t\t} else {\n\t\t\t// in headers now\n\t\t\t// when line is empty, header is done\n\t\t\tif ln == \"\" {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tfs := strings.SplitN(ln, \": \", 2)\n\t\t\theaders[fs[0]] = fs[1]\n\t\t}\n\n\t\ti++\n\t}\n\n\t// parse body\n\tif method == \"POST\" || method == \"PUT\" {\n\t\tamt, _ := strconv.Atoi(headers[\"Content-Length\"])\n\t\tbuf := make([]byte, amt)\n\t\tio.ReadFull(conn, buf)\n\t\t// in buf we will have the POST content\n\t\tfmt.Println(\"BODY:\", string(buf))\n\t}\n\n\t// response\n\tbody := `\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n</head>\n<body>\n\t<form method=\"POST\">\n\t\t<input type=\"text\" name=\"key\" value=\"\">\n\t\t<input type=\"submit\">\n\t</form>\n</body>\n</html>\n\t`\n\n\tio.WriteString(conn, \"HTTP/1.1 200 OK\\r\\n\")\n\tfmt.Fprintf(conn, \"Content-Length: %d\\r\\n\", len(body))\n\tio.WriteString(conn, \"\\r\\n\")\n\tio.WriteString(conn, body)\n}\n\nfunc main() {\n\tserver, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\tdefer server.Close()\n\n\tfor {\n\t\tconn, err := server.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err.Error())\n\t\t}\n\t\tgo handleConn(conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/42_HTTP/02_http-server/i06_PLAIN-TEXT/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n)\n\nfunc handleConn(conn net.Conn) {\n\tdefer conn.Close()\n\tscanner := bufio.NewScanner(conn)\n\ti := 0\n\tfor scanner.Scan() {\n\t\tln := scanner.Text()\n\t\tfmt.Println(ln)\n\n\t\tif i == 0 {\n\t\t\tmethod := strings.Fields(ln)[0]\n\t\t\tfmt.Println(\"METHOD\", method)\n\t\t} else {\n\t\t\t// in headers now\n\t\t\t// when line is empty, header is done\n\t\t\tif ln == \"\" {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\ti++\n\t}\n\n\t// response\n\tbody := `\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n</head>\n<body>\n\t<strong>Hello World</strong>\n</body>\n</html>\n\t`\n\n\tio.WriteString(conn, \"HTTP/1.1 200 OK\\r\\n\")\n\tfmt.Fprintf(conn, \"Content-Length: %d\\r\\n\", len(body))\n\tfmt.Fprintf(conn, \"Content-Type: text/plain\\r\\n\")\n\tio.WriteString(conn, \"\\r\\n\")\n\tio.WriteString(conn, body)\n}\n\nfunc main() {\n\tserver, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\tdefer server.Close()\n\n\tfor {\n\t\tconn, err := server.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err.Error())\n\t\t}\n\t\tgo handleConn(conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/42_HTTP/02_http-server/i07_Location/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n)\n\nfunc handleConn(conn net.Conn) {\n\tdefer conn.Close()\n\tscanner := bufio.NewScanner(conn)\n\ti := 0\n\tfor scanner.Scan() {\n\t\tln := scanner.Text()\n\t\tfmt.Println(ln)\n\n\t\tif i == 0 {\n\t\t\tmethod := strings.Fields(ln)[0]\n\t\t\tfmt.Println(\"METHOD\", method)\n\t\t} else {\n\t\t\t// in headers now\n\t\t\t// when line is empty, header is done\n\t\t\tif ln == \"\" {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\ti++\n\t}\n\n\t// response\n\tbody := `\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n</head>\n<body>\n\t<strong>Hello World</strong>\n</body>\n</html>\n\t`\n\n\tio.WriteString(conn, \"HTTP/1.1 302 OK\\r\\n\")\n\tfmt.Fprintf(conn, \"Content-Length: %d\\r\\n\", len(body))\n\tfmt.Fprintf(conn, \"Content-Type: text/plain\\r\\n\")\n\tfmt.Fprintf(conn, \"Location: http://www.google.com\\r\\n\")\n\tio.WriteString(conn, \"\\r\\n\")\n\tio.WriteString(conn, body)\n}\n\nfunc main() {\n\tserver, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\tdefer server.Close()\n\n\tfor {\n\t\tconn, err := server.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err.Error())\n\t\t}\n\t\tgo handleConn(conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/42_HTTP/03_http-server_return-URL/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n)\n\nfunc handleConn(conn net.Conn) {\n\tdefer conn.Close()\n\tscanner := bufio.NewScanner(conn)\n\n\ti := 0\n\tvar url string\n\n\tfor scanner.Scan() {\n\t\tln := scanner.Text()\n\t\tfmt.Println(ln)\n\n\t\tif i == 0 {\n\t\t\tmethod := strings.Fields(ln)[0]\n\t\t\turl = strings.Fields(ln)[1]\n\t\t\tfmt.Println(\"METHOD\", method)\n\t\t} else {\n\t\t\t// in headers now\n\t\t\tif ln == \"\" {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\ti++\n\t}\n\n\tbody := url\n\n\tio.WriteString(conn, \"HTTP/1.1 200 OK\\r\\n\")\n\tfmt.Fprintf(conn, \"Content-Length: %d\\r\\n\", len(body))\n\tio.WriteString(conn, \"\\r\\n\")\n\tio.WriteString(conn, body)\n}\n\nfunc main() {\n\tserver, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\tdefer server.Close()\n\n\tfor {\n\t\tconn, err := server.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err.Error())\n\t\t}\n\t\tgo handleConn(conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/43_HTTP-server/01/i01/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n)\n\ntype MyHandler int\n\nfunc (h MyHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {\n\n}\n\nfunc main() {\n\tvar h MyHandler\n\n\thttp.ListenAndServe(\":9000\", h)\n}\n"
  },
  {
    "path": "27_code-in-process/43_HTTP-server/01/i02/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\ntype MyHandler int\n\nfunc (h MyHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, \"Hello World\")\n}\n\nfunc main() {\n\tvar h MyHandler\n\n\thttp.ListenAndServe(\":9000\", h)\n}\n"
  },
  {
    "path": "27_code-in-process/43_HTTP-server/02_requestURI/01/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\ntype myHandler int\n\nfunc (h myHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {\n\tio.WriteString(resp, req.URL.RequestURI())\n}\n\nfunc main() {\n\n\tvar h myHandler\n\thttp.ListenAndServe(\":9000\", h)\n}\n"
  },
  {
    "path": "27_code-in-process/43_HTTP-server/02_requestURI/02/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\ntype myHandler int\n\nfunc (h myHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {\n\tio.WriteString(resp, req.RequestURI)\n}\n\nfunc main() {\n\n\tvar h myHandler\n\thttp.ListenAndServe(\":9000\", h)\n}\n"
  },
  {
    "path": "27_code-in-process/43_HTTP-server/03_restful/01/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\ntype myHandler int\n\nfunc (h myHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {\n\tswitch req.URL.Path {\n\tcase \"/cat\":\n\t\tio.WriteString(res, \"kitty kitty kitty\")\n\tcase \"/dog\":\n\t\tio.WriteString(res, \"doggy doggy doggy\")\n\t}\n}\n\nfunc main() {\n\n\tvar h myHandler\n\thttp.ListenAndServe(\":9000\", h)\n}\n"
  },
  {
    "path": "27_code-in-process/43_HTTP-server/03_restful/02/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\ntype myHandler int\n\nfunc (h myHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {\n\tres.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\tswitch req.URL.Path {\n\tcase \"/cat\":\n\t\tio.WriteString(res, \"<strong>kitty kitty kitty<strong>\")\n\tcase \"/dog\":\n\t\tio.WriteString(res, \"<strong>doggy doggy doggy<strong>\")\n\t}\n}\n\nfunc main() {\n\n\tvar h myHandler\n\thttp.ListenAndServe(\":9000\", h)\n}\n"
  },
  {
    "path": "27_code-in-process/43_HTTP-server/03_restful/03/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\ntype myHandler int\n\nfunc (h myHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {\n\tres.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\tswitch req.URL.Path {\n\tcase \"/cat\":\n\t\tio.WriteString(res, `<img src=\"https://upload.wikimedia.org/wikipedia/commons/0/06/Kitten_in_Rizal_Park%2C_Manila.jpg\">`)\n\tcase \"/dog\":\n\t\tio.WriteString(res, `<img src=\"https://upload.wikimedia.org/wikipedia/commons/6/6e/Golde33443.jpg\">`)\n\t}\n}\n\nfunc main() {\n\n\tvar h myHandler\n\thttp.ListenAndServe(\":9000\", h)\n}\n"
  },
  {
    "path": "27_code-in-process/44_MUX_routing/01/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\ntype DogHandler int\n\nfunc (h DogHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, \"doggy doggy doggy\")\n}\n\ntype CatHandler int\n\nfunc (h CatHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, \"catty catty catty\")\n}\n\nfunc main() {\n\tvar dog DogHandler\n\tvar cat CatHandler\n\n\tmux := http.NewServeMux()\n\tmux.Handle(\"/dog/\", dog)\n\tmux.Handle(\"/cat/\", cat)\n\n\thttp.ListenAndServe(\":9000\", mux)\n}\n\n/*\nif route ends in slash\n/dog/\nit includes anything beneath\n\nif route ends in no-slash\n/dog\nit only includes that\n\n*/\n"
  },
  {
    "path": "27_code-in-process/44_MUX_routing/02/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\ntype DogHandler int\n\nfunc (h DogHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, \"doggy doggy doggy\")\n}\n\ntype CatHandler int\n\nfunc (h CatHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, \"catty catty catty\")\n}\n\nfunc main() {\n\tvar dog DogHandler\n\tvar cat CatHandler\n\n\tmux := http.NewServeMux()\n\tmux.Handle(\"/\", dog)\n\tmux.Handle(\"/cat/\", cat)\n\n\thttp.ListenAndServe(\":9000\", mux)\n}\n\n/*\nif route ends in slash\n/dog/\nit includes anything beneath\n\nif route ends in no-slash\n/dog\nit only includes that\n\n*/\n"
  },
  {
    "path": "27_code-in-process/44_MUX_routing/03/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\ntype DogHandler int\n\nfunc (h DogHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, \"doggy doggy doggy\")\n}\n\ntype CatHandler int\n\nfunc (h CatHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, \"catty catty catty\")\n}\n\nfunc main() {\n\tvar dog DogHandler\n\tvar cat CatHandler\n\n\tmux := http.NewServeMux()\n\tmux.Handle(\"/dog/\", dog)\n\tmux.Handle(\"/cat/\", cat)\n\n\thttp.ListenAndServe(\":9000\", mux)\n}\n\n/*\nif route ends in slash\n/dog/\nit includes anything beneath\n\nif route ends in no-slash\n/dog\nit only includes that\n\n*/\n"
  },
  {
    "path": "27_code-in-process/44_MUX_routing/04/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\ntype DogHandler int\n\nfunc (h DogHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {\n\tres.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\tio.WriteString(res, `<img src=\"https://upload.wikimedia.org/wikipedia/commons/6/6e/Golde33443.jpg\">`)\n}\n\ntype CatHandler int\n\nfunc (h CatHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {\n\tres.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\tio.WriteString(res, `<img src=\"https://upload.wikimedia.org/wikipedia/commons/0/06/Kitten_in_Rizal_Park%2C_Manila.jpg\">`)\n}\n\nfunc main() {\n\tvar dog DogHandler\n\tvar cat CatHandler\n\n\tmux := http.NewServeMux()\n\tmux.Handle(\"/\", dog)\n\tmux.Handle(\"/cat/\", cat)\n\n\thttp.ListenAndServe(\":9000\", mux)\n}\n"
  },
  {
    "path": "27_code-in-process/44_MUX_routing/05/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n)\n\ntype DogHandler int\n\nfunc (h DogHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {\n\tres.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\tvar dogName string\n\tfs := strings.Split(req.URL.Path, \"/\")\n\tif len(fs) >= 3 {\n\t\tdogName = fs[2]\n\t}\n\tio.WriteString(res, `\n\tDog Name: <strong>`+dogName+`</strong><br>\n\t<img src=\"https://upload.wikimedia.org/wikipedia/commons/6/6e/Golde33443.jpg\">\n\t`)\n}\n\ntype CatHandler int\n\nfunc (h CatHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {\n\tres.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\tvar catName string\n\tfs := strings.Split(req.URL.Path, \"/\")\n\tif len(fs) >= 3 {\n\t\tcatName = fs[2]\n\t}\n\tio.WriteString(res, `\n\tCat Name: <strong>`+catName+`</strong><br>\n\t<img src=\"https://upload.wikimedia.org/wikipedia/commons/0/06/Kitten_in_Rizal_Park%2C_Manila.jpg\">\n\t`)\n}\n\nfunc main() {\n\tvar dog DogHandler\n\tvar cat CatHandler\n\n\tmux := http.NewServeMux()\n\tmux.Handle(\"/\", dog)\n\tmux.Handle(\"/cat/\", cat)\n\n\thttp.ListenAndServe(\":9000\", mux)\n}\n"
  },
  {
    "path": "27_code-in-process/44_MUX_routing/06_HandleFunc/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc main() {\n\n\tmux := http.NewServeMux()\n\n\tmux.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\tio.WriteString(res, \"doggy doggy doggy\")\n\t})\n\n\tmux.HandleFunc(\"/cat/\", func(res http.ResponseWriter, req *http.Request) {\n\t\tio.WriteString(res, \"catty catty catty\")\n\t})\n\n\thttp.ListenAndServe(\":9000\", mux)\n}\n"
  },
  {
    "path": "27_code-in-process/44_MUX_routing/07_HandleFunc/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc upTown(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, \"doggy doggy doggy\")\n}\n\nfunc youUp(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, \"catty catty catty\")\n}\n\nfunc main() {\n\n\tmux := http.NewServeMux()\n\tmux.HandleFunc(\"/\", upTown)\n\tmux.HandleFunc(\"/cat/\", youUp)\n\n\thttp.ListenAndServe(\":9000\", mux)\n}\n"
  },
  {
    "path": "27_code-in-process/44_MUX_routing/08_HandleFunc/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc upTown(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, \"doggy doggy doggy\")\n}\n\nfunc youUp(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, \"catty catty catty\")\n}\n\nfunc main() {\n\n\thttp.HandleFunc(\"/\", upTown)\n\thttp.HandleFunc(\"/cat/\", youUp)\n\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/45_serving-files/01/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc upTown(res http.ResponseWriter, req *http.Request) {\n\tres.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\tvar dogName string\n\tfs := strings.Split(req.URL.Path, \"/\")\n\tif len(fs) >= 3 {\n\t\tdogName = fs[2]\n\t}\n\t// the image file is not coming from our server but from wikimedia\n\t// in the next code samples, we'll learn how to serve it ourselves\n\tio.WriteString(res, `\n\tDog Name: <strong>`+dogName+`</strong><br>\n\t<img src=\"https://upload.wikimedia.org/wikipedia/commons/6/6e/Golde33443.jpg\">\n\t`)\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/dog/\", upTown)\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/45_serving-files/02/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc upTown(res http.ResponseWriter, req *http.Request) {\n\tres.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\tvar dogName string\n\tfs := strings.Split(req.URL.Path, \"/\")\n\tif len(fs) >= 3 {\n\t\tdogName = fs[2]\n\t}\n\t// the image doesn't serve\n\tio.WriteString(res, `\n\tDog Name: <strong>`+dogName+`</strong><br>\n\t<img src=\"/toby.jpg\">\n\t`)\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/dog/\", upTown)\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/45_serving-files/03/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc upTown(res http.ResponseWriter, req *http.Request) {\n\tres.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\tvar dogName string\n\tfs := strings.Split(req.URL.Path, \"/\")\n\tif len(fs) >= 3 {\n\t\tdogName = fs[2]\n\t}\n\t// the image doesn't serve\n\tio.WriteString(res, `\n\tDog Name: <strong>`+dogName+`</strong><br>\n\t<img src=\"/toby.jpg\">\n\t`)\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\tfmt.Println(req.URL)\n\t})\n\thttp.HandleFunc(\"/dog/\", upTown)\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/45_serving-files/04_io-Copy/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc upTown(res http.ResponseWriter, req *http.Request) {\n\tres.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\tvar dogName string\n\tfs := strings.Split(req.URL.Path, \"/\")\n\tif len(fs) >= 3 {\n\t\tdogName = fs[2]\n\t}\n\t// the image doesn't serve\n\tio.WriteString(res, `\n\tDog Name: <strong>`+dogName+`</strong><br>\n\t<img src=\"/toby.jpg\">\n\t`)\n}\n\nfunc dogPic(res http.ResponseWriter, req *http.Request) {\n\tf, err := os.Open(\"toby.jpg\")\n\tif err != nil {\n\t\thttp.Error(res, \"file not found\", 404)\n\t\treturn\n\t}\n\tdefer f.Close()\n\n\tio.Copy(res, f)\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/toby.jpg\", dogPic)\n\thttp.HandleFunc(\"/dog/\", upTown)\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/45_serving-files/05_ServeContent/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc upTown(res http.ResponseWriter, req *http.Request) {\n\tres.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\tvar dogName string\n\tfs := strings.Split(req.URL.Path, \"/\")\n\tif len(fs) >= 3 {\n\t\tdogName = fs[2]\n\t}\n\t// the image doesn't serve\n\tio.WriteString(res, `\n\tDog Name: <strong>`+dogName+`</strong><br>\n\t<img src=\"/toby.jpg\">\n\t`)\n}\n\nfunc dogPic(res http.ResponseWriter, req *http.Request) {\n\tf, err := os.Open(\"toby.jpg\")\n\tif err != nil {\n\t\thttp.Error(res, \"file not found\", 404)\n\t\treturn\n\t}\n\tdefer f.Close()\n\n\tfi, err := f.Stat()\n\tif err != nil {\n\t\thttp.Error(res, \"file not found\", 404)\n\t\treturn\n\t}\n\n\thttp.ServeContent(res, req, f.Name(), fi.ModTime(), f)\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/toby.jpg\", dogPic)\n\thttp.HandleFunc(\"/dog/\", upTown)\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/45_serving-files/06_ServeFile/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc upTown(res http.ResponseWriter, req *http.Request) {\n\tres.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\tvar dogName string\n\tfs := strings.Split(req.URL.Path, \"/\")\n\tif len(fs) >= 3 {\n\t\tdogName = fs[2]\n\t}\n\t// the image doesn't serve\n\tio.WriteString(res, `\n\tDog Name: <strong>`+dogName+`</strong><br>\n\t<img src=\"/toby.jpg\">\n\t`)\n}\n\nfunc dogPic(res http.ResponseWriter, req *http.Request) {\n\thttp.ServeFile(res, req, \"toby.jpg\")\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/toby.jpg\", dogPic)\n\thttp.HandleFunc(\"/dog/\", upTown)\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/45_serving-files/07_FileServer/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc upTown(res http.ResponseWriter, req *http.Request) {\n\tres.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\tvar dogName string\n\tfs := strings.Split(req.URL.Path, \"/\")\n\tif len(fs) >= 3 {\n\t\tdogName = fs[2]\n\t}\n\t// the image doesn't serve\n\tio.WriteString(res, `\n\tDog Name: <strong>`+dogName+`</strong><br>\n\t<img src=\"/toby.jpg\">\n\t`)\n}\n\nfunc main() {\n\thttp.Handle(\"/\", http.FileServer(http.Dir(\".\")))\n\thttp.HandleFunc(\"/dog/\", upTown)\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/45_serving-files/08_FileServer/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc upTown(res http.ResponseWriter, req *http.Request) {\n\tres.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\tvar dogName string\n\tfs := strings.Split(req.URL.Path, \"/\")\n\tif len(fs) >= 3 {\n\t\tdogName = fs[2]\n\t}\n\t// the image doesn't serve\n\tio.WriteString(res, `\n\tDog Name: <strong>`+dogName+`</strong><br>\n\t<img src=\"/assets/toby.jpg\">\n\t`)\n}\n\nfunc main() {\n\thttp.Handle(\"/assets/\", http.StripPrefix(\"/assets\", http.FileServer(http.Dir(\"./assets\"))))\n\thttp.HandleFunc(\"/dog/\", upTown)\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/45_serving-files/09_FileServer/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc upTown(res http.ResponseWriter, req *http.Request) {\n\tres.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\tvar dogName string\n\tfs := strings.Split(req.URL.Path, \"/\")\n\tif len(fs) >= 3 {\n\t\tdogName = fs[2]\n\t}\n\t// the image doesn't serve\n\tio.WriteString(res, `\n\tDog Name: <strong>`+dogName+`</strong><br>\n\t<img src=\"/resources/toby.jpg\">\n\t`)\n}\n\nfunc main() {\n\thttp.Handle(\"/resources/\", http.StripPrefix(\"/resources\", http.FileServer(http.Dir(\"./assets\"))))\n\thttp.HandleFunc(\"/dog/\", upTown)\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/45_serving-files/10_static-file-server/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n)\n\nfunc main() {\n\thttp.ListenAndServe(\":9000\", http.FileServer(http.Dir(\".\")))\n}\n"
  },
  {
    "path": "27_code-in-process/45_serving-files/11_static-file-server/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tlog.Fatal(http.ListenAndServe(\":9000\", http.FileServer(http.Dir(\".\"))))\n}\n"
  },
  {
    "path": "27_code-in-process/46_errata/01_set-header/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\tres.Header().Set(\"Content-Type\", \"text/plain\")\n\t\tres.Header()[\"Content-Type\"] = []string{\"text/plain\"} // same as line 10\n\t\tfmt.Fprint(res, \"Dog\")\n\t})\n\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/46_errata/02_URL/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\tres.Header().Set(\"Content-Type\", \"text/plain\")\n\t\tfmt.Fprintf(res, \"RequestURI: %v\\n\", req.RequestURI)\n\t\tfmt.Fprintf(res, \"req.URL: %v\\n\", req.URL)\n\t\tfmt.Fprintf(res, \"String(): %v\\n\", req.URL.String())\n\t\tfmt.Fprintf(res, \"Path: %v\\n\", req.URL.Path)\n\t\tfmt.Fprintf(res, \"RequestURI: %v\\n\", req.URL.RequestURI())\n\t\tfmt.Fprintf(res, \"Opaque: %v\\n\", req.URL.Opaque)\n\t\tfmt.Fprintf(res, \"RawPath: %v\\n\", req.URL.RawPath)\n\t\tfmt.Fprintf(res, \"RawQuery: %v\\n\", req.URL.RawQuery)\n\t\tfmt.Fprintf(res, \"User: %v\\n\", req.URL.User)\n\t\tfmt.Fprintf(res, \"IsAbs(): %v\\n\", req.URL.IsAbs())\n\t\tfmt.Fprintf(res, \"Scheme: %v\\n\", req.URL.Scheme)\n\t})\n\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/46_errata/03_URL/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\tres.Header().Set(\"Content-Type\", \"text/plain\")\n\t\tfmt.Fprint(res, req.URL.Path)\n\t})\n\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/46_errata/04_URL/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\tres.Header().Set(\"Content-Type\", \"text/plain\")\n\t\tfmt.Fprintln(res, req.URL.EscapedPath())\n\t\tfmt.Fprintln(res, req.URL.RawQuery)\n\t})\n\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/46_errata/05_ServeFile/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc upTown(res http.ResponseWriter, req *http.Request) {\n\tres.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\tvar dogName string\n\tfs := strings.Split(req.URL.Path, \"/\")\n\tif len(fs) >= 3 {\n\t\tdogName = fs[2]\n\t}\n\t// the image doesn't serve\n\tio.WriteString(res, `\n\tDog Name: <strong>`+dogName+`</strong><br>\n\t<img src=\"/toby.jpg\">\n\t`)\n}\n\nfunc dogPic(res http.ResponseWriter, req *http.Request) {\n\thttp.ServeFile(res, req, \"toby.jpg\")\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/toby.jpg\", dogPic)\n\thttp.HandleFunc(\"/dog/\", upTown)\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/47_templates/01_text-templates/01/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"text/template\"\n)\n\nfunc main() {\n\ttpl, err := template.ParseFiles(\"tpl.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\terr = tpl.Execute(os.Stdout, nil)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/47_templates/01_text-templates/01/tpl.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Document</title>\n</head>\n<body>\n<h1>Hello</h1>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/47_templates/01_text-templates/02/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"text/template\"\n)\n\nfunc main() {\n\ttpl, err := template.ParseFiles(\"tpl.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\terr = tpl.Execute(os.Stdout, nil)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/47_templates/01_text-templates/02/tpl.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Document</title>\n</head>\n<body>\n<h1>{{5}}</h1>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/47_templates/01_text-templates/03/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"text/template\"\n)\n\nfunc main() {\n\ttpl, err := template.ParseFiles(\"tpl.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\terr = tpl.Execute(os.Stdout, 10)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/47_templates/01_text-templates/03/tpl.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Document</title>\n</head>\n<body>\n<h1>{{.}}</h1>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/47_templates/01_text-templates/04/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"text/template\"\n)\n\nfunc main() {\n\ttpl, err := template.ParseFiles(\"tpl.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\terr = tpl.Execute(os.Stdout, 5*5)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/47_templates/01_text-templates/04/tpl.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Document</title>\n</head>\n<body>\n<h1>{{.}}</h1>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/47_templates/01_text-templates/05/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"text/template\"\n)\n\nfunc main() {\n\ttpl, err := template.ParseFiles(\"tpl.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\terr = tpl.Execute(os.Stdout, []int{1, 2, 3, 4, 5})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/47_templates/01_text-templates/05/tpl.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Document</title>\n</head>\n<body>\n<ul>\n    {{ range . }}\n    <li>{{ . }}</li>\n    {{ end }}\n</ul>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/47_templates/01_text-templates/06/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"text/template\"\n)\n\nfunc main() {\n\ttpl, err := template.ParseFiles(\"tpl.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\terr = tpl.Execute(os.Stdout, []int{})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/47_templates/01_text-templates/06/tpl.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Document</title>\n</head>\n<body>\n<ul>\n    {{ range . }}\n    <li>{{ . }}</li>\n    {{ else }}\n    <li>NO ITEMS</li>\n    {{ end }}\n</ul>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/47_templates/01_text-templates/07/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"text/template\"\n)\n\nfunc main() {\n\ttpl, err := template.ParseFiles(\"tpl.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\terr = tpl.Execute(os.Stdout, nil)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/47_templates/01_text-templates/07/tpl.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Document</title>\n</head>\n<body>\n<ul>\n    {{ range . }}\n    <li>{{ . }}</li>\n    {{ else }}\n    <li>NO ITEMS</li>\n    {{ end }}\n</ul>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/47_templates/01_text-templates/08/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"text/template\"\n)\n\ntype Page struct {\n\tTitle string\n\tBody  string\n}\n\nfunc main() {\n\ttpl, err := template.ParseFiles(\"tpl.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\terr = tpl.Execute(os.Stdout, Page{\n\t\tTitle: \"My Title 2\",\n\t})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/47_templates/01_text-templates/08/tpl.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>{{ .Title }}</title>\n</head>\n<body>\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/47_templates/01_text-templates/09_function/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"text/template\"\n)\n\ntype Page struct {\n\tTitle string\n\tBody  string\n}\n\nfunc main() {\n\tvar err error\n\n\ttpl := template.New(\"tpl.gohtml\")\n\ttpl = tpl.Funcs(template.FuncMap{\n\t\t\"mycustomfunc\": func() string {\n\t\t\treturn \"This should work\"\n\t\t},\n\t})\n\ttpl, err = tpl.ParseFiles(\"tpl.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\terr = tpl.Execute(os.Stdout, Page{\n\t\tTitle: \"My Title\",\n\t})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/47_templates/01_text-templates/09_function/tpl.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>{{ .Title }}</title>\n</head>\n<body>\n{{mycustomfunc}}\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/47_templates/01_text-templates/10_function/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\t\"text/template\"\n)\n\ntype Page struct {\n\tTitle string\n\tBody  string\n}\n\nfunc main() {\n\tvar err error\n\n\ttpl := template.New(\"tpl.gohtml\")\n\ttpl = tpl.Funcs(template.FuncMap{\n\t\t\"uppercase\": func(str string) string {\n\t\t\treturn strings.ToUpper(str)\n\t\t},\n\t})\n\ttpl, err = tpl.ParseFiles(\"tpl.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\terr = tpl.Execute(os.Stdout, Page{\n\t\tTitle: \"My Title 2\",\n\t})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/47_templates/01_text-templates/10_function/tpl.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>{{ .Title }}</title>\n</head>\n<body>\n{{uppercase .Title}}\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/47_templates/01_text-templates/11/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\t\"text/template\"\n)\n\ntype Page struct {\n\tTitle string\n\tBody  string\n}\n\nfunc main() {\n\tvar err error\n\n\ttpl := template.New(\"tpl.gohtml\")\n\ttpl = tpl.Funcs(template.FuncMap{\n\t\t\"uppercase\": func(str string) string {\n\t\t\treturn strings.ToUpper(str)\n\t\t},\n\t})\n\ttpl, err = tpl.ParseFiles(\"tpl.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\terr = tpl.Execute(os.Stdout, Page{\n\t\tTitle: \"My Title 2\",\n\t\tBody:  `hello world <script>alert(\"Yow!\");</script>`,\n\t})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/47_templates/01_text-templates/11/tpl.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>{{ .Title }}</title>\n</head>\n<body>\n{{uppercase .Title}}\n{{ .Body }}\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/47_templates/02_html-templates/01/main.go",
    "content": "package main\n\nimport (\n\t\"html/template\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n)\n\ntype Page struct {\n\tTitle string\n\tBody  string\n}\n\nfunc main() {\n\tvar err error\n\n\ttpl := template.New(\"tpl.gohtml\")\n\ttpl = tpl.Funcs(template.FuncMap{\n\t\t\"uppercase\": func(str string) string {\n\t\t\treturn strings.ToUpper(str)\n\t\t},\n\t})\n\ttpl, err = tpl.ParseFiles(\"tpl.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\terr = tpl.Execute(os.Stdout, Page{\n\t\tTitle: \"My Title 2\",\n\t\tBody:  `hello world <script>alert(\"Yow!\");</script>`,\n\t})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/47_templates/02_html-templates/01/tpl.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>{{ .Title }}</title>\n</head>\n<body>\n{{uppercase .Title}}\n{{ .Body }}\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/47_templates/02_html-templates/02/main.go",
    "content": "package main\n\nimport (\n\t\"html/template\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n)\n\ntype Page struct {\n\tTitle string\n\tBody  template.HTML\n}\n\nfunc main() {\n\tlog.SetFlags(0)\n\n\tvar err error\n\n\ttpl := template.New(\"tpl.gohtml\")\n\ttpl = tpl.Funcs(template.FuncMap{\n\t\t\"uppercase\": func(str string) string {\n\t\t\treturn strings.ToUpper(str)\n\t\t},\n\t})\n\ttpl, err = tpl.ParseFiles(\"tpl.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\terr = tpl.Execute(os.Stdout, Page{\n\t\tTitle: \"My Title 2\",\n\t\tBody:  template.HTML(`hello world <script>alert(\"Yow!\");</script>`),\n\t})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/47_templates/02_html-templates/02/tpl.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>{{ .Title }}</title>\n</head>\n<body>\n{{uppercase .Title}}\n{{ .Body }}\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/47_templates/02_html-templates/03/main.go",
    "content": "package main\n\nimport (\n\t\"html/template\"\n\t\"log\"\n\t\"os\"\n)\n\ntype Page struct {\n\tTitle string\n\tBody  string\n}\n\nfunc main() {\n\tvar err error\n\n\ttpl := template.New(\"tpl2.gohtml\")\n\ttpl, err = tpl.ParseFiles(\"tpl.gohtml\", \"tpl2.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\terr = tpl.Execute(os.Stdout, Page{\n\t\tTitle: \"My Title 2\",\n\t\tBody:  `hello world <script>alert(\"Yow!\");</script>`,\n\t})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/47_templates/02_html-templates/03/tpl.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>{{ .Title }}</title>\n</head>\n<body>\n<p>from tpl: {{ .Title}}</p>\n<p>from tpl: {{ .Body }}</p>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/47_templates/02_html-templates/03/tpl2.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>{{ .Title }}</title>\n</head>\n<body>\n<p>This is the title from tpl2: {{ .Title}}</p>\n<p>This is the body from tpl2: {{ .Body }}</p>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/47_templates/02_html-templates/04/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"html/template\"\n\t\"log\"\n\t\"os\"\n)\n\ntype Page struct {\n\tTitle string\n\tBody  string\n}\n\nfunc main() {\n\tvar err error\n\tvar tpl *template.Template\n\ttpl, err = tpl.ParseFiles(\"tpl.gohtml\", \"tpl2.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\terr = tpl.Execute(os.Stdout, Page{\n\t\tTitle: \"My Title 2\",\n\t\tBody:  \"hello world\",\n\t})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tfmt.Println(\"\\n***************\")\n\n\terr = tpl.ExecuteTemplate(os.Stdout, \"tpl.gohtml\", Page{\n\t\tTitle: \"My Title 2\",\n\t\tBody:  \"hello world\",\n\t})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tfmt.Println(\"\\n***************\")\n\n\terr = tpl.ExecuteTemplate(os.Stdout, \"tpl2.gohtml\", Page{\n\t\tTitle: \"My Title 2\",\n\t\tBody:  \"hello world\",\n\t})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/47_templates/02_html-templates/04/tpl.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>{{ .Title }}</title>\n</head>\n<body>\n<p>from tpl: {{ .Title}}</p>\n<p>from tpl: {{ .Body }}</p>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/47_templates/02_html-templates/04/tpl2.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>{{ .Title }}</title>\n</head>\n<body>\n<p>This is the title from tpl2: {{ .Title}}</p>\n<p>This is the body from tpl2: {{ .Body }}</p>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/47_templates/02_html-templates/05/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"html/template\"\n\t\"log\"\n\t\"os\"\n)\n\ntype Page struct {\n\tTitle string\n\tBody  string\n}\n\nfunc main() {\n\tvar err error\n\tvar tpl *template.Template\n\ttpl, err = tpl.ParseGlob(\"templates/*.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\terr = tpl.Execute(os.Stdout, Page{\n\t\tTitle: \"My Title 2\",\n\t\tBody:  \"hello world\",\n\t})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tfmt.Println(\"\\n***************\")\n\n\terr = tpl.ExecuteTemplate(os.Stdout, \"tpl.gohtml\", Page{\n\t\tTitle: \"My Title 2\",\n\t\tBody:  \"hello world\",\n\t})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tfmt.Println(\"\\n***************\")\n\n\terr = tpl.ExecuteTemplate(os.Stdout, \"tpl2.gohtml\", Page{\n\t\tTitle: \"My Title 2\",\n\t\tBody:  \"hello world\",\n\t})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/47_templates/02_html-templates/05/templates/tpl.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>{{ .Title }}</title>\n</head>\n<body>\n<p>from tpl: {{ .Title}}</p>\n<p>from tpl: {{ .Body }}</p>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/47_templates/02_html-templates/05/templates/tpl2.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>{{ .Title }}</title>\n</head>\n<body>\n<p>This is the title from tpl2: {{ .Title}}</p>\n<p>This is the body from tpl2: {{ .Body }}</p>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/47_templates/x03_exercises/01/hw.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Document</title>\n</head>\n<body>\nHello {{ . }}\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/47_templates/x03_exercises/01/main.go",
    "content": "package main\n\nimport (\n\t\"html/template\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\n\tname := \"Todd\"\n\n\t// parse template\n\ttpl, err := template.ParseFiles(\"hw.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\t// execute template\n\terr = tpl.Execute(os.Stdout, name)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/47_templates/x03_exercises/02/hw.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Document</title>\n</head>\n<body>\n<h1>FIRST TEMPLATE</h1>\n{{ . }}\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/47_templates/x03_exercises/02/main.go",
    "content": "package main\n\nimport (\n\t\"html/template\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc main() {\n\t// parse template\n\ttpl, err := template.ParseFiles(\"hw.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\t// function\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\t// execute template\n\t\terr = tpl.Execute(res, req.RequestURI)\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\t})\n\n\t// create server\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/47_templates/x03_exercises/03_template_csv-parse/hw.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Document</title>\n</head>\n<body>\n<h1>STOCK DATA TEMPLATE</h1>\n<ul>\n    {{ range . }}\n    <li>{{ .Date }} - {{ .Open }}</li>\n    {{ end }}\n</ul>\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/47_templates/x03_exercises/03_template_csv-parse/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/GoesToEleven/GolangTraining/47_templates/04_template_csv-parse/parse\"\n\t\"html/template\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc main() {\n\t// parse csv\n\trecords := parse.Parse(\"table.csv\")\n\n\t// parse template\n\ttpl, err := template.ParseFiles(\"hw.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\t// function\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\t// execute template\n\t\terr = tpl.Execute(res, records)\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\t})\n\n\t// create server\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/47_templates/x03_exercises/03_template_csv-parse/parse/parse.go",
    "content": "package parse\n\nimport (\n\t\"encoding/csv\"\n\t\"os\"\n\t\"strconv\"\n\t\"time\"\n)\n\ntype Record struct {\n\tDate time.Time\n\tOpen float64\n}\n\nfunc Parse(filePath string) []Record {\n\tsrc, err := os.Open(filePath)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer src.Close()\n\n\trows, err := csv.NewReader(src).ReadAll()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\trecords := make([]Record, 0, len(rows))\n\n\tfor _, row := range rows {\n\t\tdate, _ := time.Parse(\"2006-01-01_this-does-not-compile\", row[0])\n\t\topen, _ := strconv.ParseFloat(row[1], 64)\n\n\t\trecords = append(records, Record{\n\t\t\tDate: date,\n\t\t\tOpen: open,\n\t\t})\n\t}\n\n\treturn records\n\n}\n"
  },
  {
    "path": "27_code-in-process/47_templates/x03_exercises/03_template_csv-parse/table.csv",
    "content": "Date,Open,High,Low,Close,Volume,Adj Close\n2015-07-09,523.119995,523.77002,520.349976,520.679993,1839400,520.679993\n2015-07-08,521.049988,522.734009,516.109985,516.830017,1264600,516.830017\n2015-07-07,523.130005,526.179993,515.179993,525.02002,1595700,525.02002\n2015-07-06,519.50,525.25,519.00,522.859985,1276500,522.859985\n2015-07-02,521.080017,524.650024,521.080017,523.400024,1234000,523.400024\n2015-07-01,524.72998,525.690002,518.22998,521.840027,1961000,521.840027\n2015-06-30,526.02002,526.25,520.50,520.51001,2217200,520.51001\n2015-06-29,525.01001,528.609985,520.539978,521.52002,1930900,521.52002\n2015-06-26,537.26001,537.76001,531.349976,531.690002,2011500,531.690002\n2015-06-25,538.869995,540.900024,535.22998,535.22998,1331500,535.22998\n2015-06-24,540.00,540.00,535.659973,537.840027,1283400,537.840027\n2015-06-23,539.640015,541.499023,535.25,540.47998,1196000,540.47998\n2015-06-22,539.590027,543.73999,537.530029,538.190002,1242500,538.190002\n2015-06-19,537.210022,538.25,533.01001,536.690002,1885700,536.690002\n2015-06-18,531.00,538.150024,530.789978,536.72998,1828100,536.72998\n2015-06-17,529.369995,530.97998,525.099976,529.26001,1268600,529.26001\n2015-06-16,528.400024,529.640015,525.559998,528.150024,1069300,528.150024\n2015-06-15,528.00,528.299988,524.00,527.200012,1630700,527.200012\n2015-06-12,531.599976,533.119995,530.159973,532.330017,952400,532.330017\n2015-06-11,538.424988,538.97998,533.02002,534.609985,1205000,534.609985\n2015-06-10,529.359985,538.359985,529.349976,536.690002,1811400,536.690002\n2015-06-09,527.559998,529.200012,523.01001,526.690002,1441600,526.690002\n2015-06-08,533.309998,534.119995,526.23999,526.830017,1520600,526.830017\n2015-06-05,536.349976,537.200012,532.52002,533.330017,1375000,533.330017\n2015-06-04,537.76001,540.590027,534.320007,536.700012,1335600,536.700012\n2015-06-03,539.909973,543.50,537.109985,540.309998,1714500,540.309998\n2015-06-02,532.929993,543.00,531.330017,539.179993,1934700,539.179993\n2015-06-01,536.789978,536.789978,529.76001,533.98999,1899600,533.98999\n2015-05-29,537.369995,538.630005,531.450012,532.109985,2584900,532.109985\n2015-05-28,538.01001,540.609985,536.25,539.780029,1027900,539.780029\n2015-05-27,532.799988,540.549988,531.710022,539.789978,1520400,539.789978\n2015-05-26,538.119995,539.00,529.880005,532.320007,2403400,532.320007\n2015-05-22,540.150024,544.190002,539.51001,540.109985,1173300,540.109985\n2015-05-21,537.950012,543.840027,535.97998,542.51001,1461400,542.51001\n2015-05-20,538.48999,542.919983,532.971985,539.27002,1429100,539.27002\n2015-05-19,533.97998,540.659973,533.039978,537.359985,1963300,537.359985\n2015-05-18,532.01001,534.820007,528.849976,532.299988,1998600,532.299988\n2015-05-15,539.179993,539.273987,530.380005,533.849976,1962700,533.849976\n2015-05-14,533.77002,539.00,532.409973,538.400024,1399100,538.400024\n2015-05-13,530.559998,534.322021,528.655029,529.619995,1252300,529.619995\n2015-05-12,531.599976,533.208984,525.26001,529.039978,1625400,529.039978\n2015-05-11,538.369995,541.97998,535.400024,535.700012,905300,535.700012\n2015-05-08,536.650024,541.150024,525.00,538.219971,1527600,538.219971\n2015-05-07,523.98999,533.460022,521.75,530.700012,1546300,530.700012\n2015-05-06,531.23999,532.380005,521.085022,524.219971,1567000,524.219971\n2015-05-05,538.210022,539.73999,530.390991,530.799988,1383100,530.799988\n2015-05-04,538.530029,544.070007,535.059998,540.780029,1308000,540.780029\n2015-05-01,538.429993,539.539978,532.099976,537.900024,1768200,537.900024\n2015-04-30,547.869995,548.590027,535.049988,537.340027,2082200,537.340027\n2015-04-29,550.469971,553.679993,546.905029,549.080017,1698800,549.080017\n2015-04-28,554.640015,556.02002,550.366028,553.679993,1491000,553.679993\n2015-04-27,563.390015,565.950012,553.200012,555.369995,2398000,555.369995\n2015-04-24,566.102522,571.14259,557.252507,565.062561,4932500,565.062561\n2015-04-23,541.002435,550.96249,540.23244,547.002472,4184900,547.002472\n2015-04-22,534.402426,541.082489,531.752397,539.367458,1593600,539.367458\n2015-04-21,537.512456,539.392429,533.677415,533.972413,1844800,533.972413\n2015-04-20,525.602352,536.092424,524.50235,535.382408,1679300,535.382408\n2015-04-17,528.662379,529.842435,521.012371,524.052386,2144100,524.052386\n2015-04-16,529.902414,535.592457,529.612373,533.802391,1299900,533.802391\n2015-04-15,528.702406,534.732432,523.22235,532.532429,2318800,532.532429\n2015-04-14,536.252409,537.572435,528.094354,530.392405,2604100,530.392405\n2015-04-13,538.412385,544.062463,537.312445,539.172404,1645300,539.172404\n2015-04-10,542.292411,542.292411,537.312445,540.012477,1409500,540.012477\n2015-04-09,541.032486,541.95249,535.49239,540.782472,1557900,540.782472\n2015-04-08,538.382457,543.852415,538.382457,541.612446,1178500,541.612446\n2015-04-07,538.08244,542.692434,536.002395,537.022465,1302900,537.022465\n2015-04-06,532.222375,538.412385,529.572407,536.767432,1324400,536.767432\n2015-04-02,540.852427,540.852427,533.849395,535.532478,1716400,535.532478\n2015-04-01,548.602441,551.142488,539.502472,542.562439,1963100,542.562439\n2015-03-31,550.00246,554.712521,546.722468,548.002468,1588000,548.002468\n2015-03-30,551.622503,553.472487,548.17249,552.032502,1287500,552.032502\n2015-03-27,553.002509,555.282565,548.132463,548.342512,1897500,548.342512\n2015-03-26,557.59255,558.90254,550.652497,555.172522,1572600,555.172522\n2015-03-25,570.50259,572.262605,558.742494,558.787478,2152300,558.787478\n2015-03-24,562.562541,574.592603,561.212586,570.192597,2583300,570.192597\n2015-03-23,560.432554,562.362529,555.832536,558.81251,1643800,558.81251\n2015-03-20,561.652574,561.722529,559.052548,560.362537,2616900,560.362537\n2015-03-19,559.392531,560.802526,556.147548,557.992512,1197300,557.992512\n2015-03-18,552.50248,559.782578,547.002472,559.502513,2134500,559.502513\n2015-03-17,551.712533,553.802493,548.002468,550.842532,1805500,550.842532\n2015-03-16,550.952514,556.852484,546.002476,554.512509,1641000,554.512509\n2015-03-13,553.502537,558.402572,544.222448,547.322503,1703600,547.322503\n2015-03-12,553.512513,556.37253,550.462523,555.512505,1389600,555.512505\n2015-03-11,555.142533,558.142521,550.682486,551.182515,1820800,551.182515\n2015-03-10,564.252539,564.852512,554.732473,555.012538,1792300,555.012538\n2015-03-09,566.862541,570.272589,563.537504,568.852557,1062100,568.852557\n2015-03-06,574.882583,576.682625,566.762597,567.687558,1659100,567.687558\n2015-03-05,575.022616,577.912621,573.412548,575.332609,1389600,575.332609\n2015-03-04,571.872558,577.112576,568.012607,573.372583,1876800,573.372583\n2015-03-03,570.452587,575.392649,566.522559,573.64261,1704800,573.64261\n2015-03-02,560.532559,572.152623,558.752531,571.342601,2129600,571.342601\n2015-02-27,554.242482,564.712602,552.902503,558.402572,2410200,558.402572\n2015-02-26,543.212476,556.142529,541.502464,555.482516,2311500,555.482516\n2015-02-25,535.90245,546.22244,535.447406,543.872489,1826000,543.872489\n2015-02-24,530.002419,536.792403,528.252381,536.092424,1005100,536.092424\n2015-02-23,536.052398,536.441465,529.412361,531.912381,1457900,531.912381\n2015-02-20,543.132484,543.75247,535.802444,538.952441,1444400,538.952441\n2015-02-19,538.042413,543.11247,538.012424,542.872432,989100,542.872432\n2015-02-18,541.402458,545.492471,537.512456,539.702422,1453100,539.702422\n2015-02-17,546.832511,550.00246,541.092465,542.842504,1616800,542.842504\n2015-02-13,543.352447,549.912491,543.132484,549.012501,1900300,549.012501\n2015-02-12,537.252405,544.822482,534.675391,542.932472,1620200,542.932472\n2015-02-11,535.302416,538.452473,533.380397,535.972405,1377800,535.972405\n2015-02-10,529.302379,537.702431,526.922378,536.942412,1749900,536.942412\n2015-02-09,528.002366,532.002411,526.022388,527.832406,1267800,527.832406\n2015-02-06,527.642431,537.202463,526.412373,531.002415,1749400,531.002415\n2015-02-05,523.792334,528.502395,522.092359,527.582391,1849800,527.582391\n2015-02-04,529.2424,532.67442,521.272361,522.762349,1663700,522.762349\n2015-02-03,528.002366,533.40243,523.262377,529.2424,2038700,529.2424\n2015-02-02,531.732383,533.002407,518.552316,528.482381,2849800,528.482381\n2015-01-30,515.862322,539.872444,515.522339,534.522445,5606400,534.522445\n2015-01-29,511.002313,511.092313,501.202274,510.662331,4186400,510.662331\n2015-01-28,522.782423,522.992349,510.002318,510.002318,1683800,510.002318\n2015-01-27,529.972369,530.702398,518.192381,518.63237,1904000,518.63237\n2015-01-26,538.532466,539.002444,529.672413,535.212448,1543700,535.212448\n2015-01-23,535.592457,542.172453,533.002407,539.952437,2281700,539.952437\n2015-01-22,521.482349,536.332463,519.702382,534.39245,2676900,534.39245\n2015-01-21,507.252283,519.282407,506.202315,518.042312,2268700,518.042312\n2015-01-20,511.002313,512.502307,506.018277,506.902294,2227900,506.902294\n2015-01-16,500.012273,508.1923,500.002267,508.082288,2298300,508.082288\n2015-01-15,505.572291,505.682273,497.762267,501.792271,2715800,501.792271\n2015-01-14,494.652237,503.232286,493.002234,500.872267,2235700,500.872267\n2015-01-13,498.842256,502.982302,492.392254,496.182251,2370500,496.182251\n2015-01-12,494.942247,495.978261,487.562205,492.552209,2322400,492.552209\n2015-01-09,504.7623,504.922285,494.792239,496.172274,2069400,496.172274\n2015-01-08,497.992238,503.4823,491.002212,502.682255,3353600,502.682255\n2015-01-07,507.002299,507.246285,499.652247,501.102268,2065100,501.102268\n2015-01-06,515.002358,516.177334,501.052266,501.962262,2899900,501.962262\n2015-01-05,523.262377,524.332389,513.062315,513.872306,2059800,513.872306\n2015-01-02,529.012399,531.272443,524.102327,524.812404,1447600,524.812404\n2014-12-31,531.252429,532.602384,525.802363,526.402397,1368200,526.402397\n2014-12-30,528.092396,531.152424,527.132366,530.422394,876300,530.422394\n2014-12-29,532.192446,535.482414,530.013375,530.332426,2278500,530.332426\n2014-12-26,528.772422,534.252417,527.312364,534.032454,1036000,534.032454\n2014-12-24,530.512424,531.761394,527.022384,528.772422,705900,528.772422\n2014-12-23,527.00237,534.56241,526.292354,530.592416,2197600,530.592416\n2014-12-22,516.082347,526.462376,516.082347,524.872383,2723800,524.872383\n2014-12-19,511.512318,517.722342,506.91331,516.352313,3690200,516.352313\n2014-12-18,512.952333,513.872306,504.70229,511.102319,2926700,511.102319\n2014-12-17,497.002248,507.002299,496.812244,504.892295,2883200,504.892295\n2014-12-16,511.562321,513.052308,489.00222,495.392273,3964300,495.392273\n2014-12-15,522.742335,523.102331,513.272333,513.80229,2813400,513.80229\n2014-12-12,523.512391,528.502395,518.662298,518.662298,1994600,518.662298\n2014-12-11,527.802355,533.922411,527.102376,528.34241,1610800,528.34241\n2014-12-10,533.082399,536.332463,525.562386,526.062353,1712300,526.062353\n2014-12-09,522.142362,534.192438,520.502366,533.37244,1871300,533.37244\n2014-12-08,527.132366,531.002415,523.792334,526.982357,2329400,526.982357\n2014-12-05,531.002415,532.892425,524.282386,525.262369,2565600,525.262369\n2014-12-04,531.1624,537.342434,528.592424,537.312445,1392100,537.312445\n2014-12-03,531.442404,535.998416,529.262414,531.322384,1278000,531.322384\n2014-12-02,533.512412,535.502427,529.802408,533.752389,1525800,533.752389\n2014-12-01,538.902438,541.412434,531.862379,533.802391,2115400,533.802391\n2014-11-28,540.622426,542.002431,536.602429,541.832471,1148300,541.832471\n2014-11-26,540.882478,541.552406,537.044437,540.372412,1523000,540.372412\n2014-11-25,539.002444,543.98241,538.60444,541.082489,1789100,541.082489\n2014-11-24,537.652489,542.702471,535.622446,539.272471,1706000,539.272471\n2014-11-21,541.612446,542.142464,536.562402,537.502419,2223700,537.502419\n2014-11-20,531.252429,535.112381,531.082408,534.832438,1562000,534.832438\n2014-11-19,535.002399,538.242425,530.082412,536.992415,1391600,536.992415\n2014-11-18,537.502419,541.942452,534.172425,535.032449,1962700,535.032449\n2014-11-17,543.582448,543.792436,534.063361,536.512461,1725800,536.512461\n2014-11-14,546.682442,546.682442,542.152501,544.402507,1289200,544.402507\n2014-11-13,549.802448,549.802448,543.482442,545.38249,1339400,545.38249\n2014-11-12,550.392507,550.462523,545.172441,547.312465,1129400,547.312465\n2014-11-11,548.492459,551.942473,546.302493,550.29244,965500,550.29244\n2014-11-10,541.462498,549.592522,541.022449,547.492463,1134600,547.492463\n2014-11-07,546.212525,546.212525,538.672437,541.012473,1633800,541.012473\n2014-11-06,545.502448,546.887472,540.972385,542.042458,1333300,542.042458\n2014-11-05,556.802481,556.802481,544.052426,545.922423,2032300,545.922423\n2014-11-04,553.002509,555.502529,549.302481,554.112486,1244200,554.112486\n2014-11-03,555.502529,557.902544,553.23251,555.222464,1382300,555.222464\n2014-10-31,559.352504,559.572529,554.752486,559.082538,2035100,559.082538\n2014-10-30,548.952522,552.802497,543.512493,550.312514,1455500,550.312514\n2014-10-29,550.00246,554.19254,546.982459,549.332532,1770500,549.332532\n2014-10-28,543.002488,548.98245,541.622422,548.902519,1271000,548.902519\n2014-10-27,537.032441,544.412422,537.032441,540.772496,1185300,540.772496\n2014-10-24,544.36248,544.882461,535.792407,539.782476,1973100,539.782476\n2014-10-23,539.322474,547.222436,535.852386,543.98241,2348800,543.98241\n2014-10-22,529.892437,539.802428,528.802351,532.712427,2919300,532.712427\n2014-10-21,525.192353,526.792383,519.112324,526.542369,2336300,526.542369\n2014-10-20,509.452317,521.762353,508.102301,520.84241,2607500,520.84241\n2014-10-17,527.252385,530.982402,508.532313,511.172335,5539400,511.172335\n2014-10-16,519.002342,529.432374,515.002358,524.512387,3708600,524.512387\n2014-10-15,531.012391,532.802396,518.302363,530.032409,3719400,530.032409\n2014-10-14,538.902438,547.192507,533.172368,537.942408,2222600,537.942408\n2014-10-13,544.992443,549.502492,533.102413,533.212456,2581700,533.212456\n2014-10-10,557.722484,565.132577,544.052426,544.492476,3081900,544.492476\n2014-10-09,571.182555,571.492549,559.062524,560.882579,2524800,560.882579\n2014-10-08,565.572566,573.882587,557.492484,572.502582,1990900,572.502582\n2014-10-07,574.402629,575.27263,563.742534,563.742534,1911300,563.742534\n2014-10-06,578.802574,581.002639,574.442595,577.352614,1214600,577.352614\n2014-10-03,573.052613,577.227576,572.502582,575.282606,1141700,575.282606\n2014-10-02,567.312567,571.912585,563.322559,570.082615,1178400,570.082615\n2014-10-01,576.012635,577.582615,567.01255,568.272597,1445500,568.272597\n2014-09-30,576.932578,579.852634,572.852541,577.36259,1621700,577.36259\n2014-09-29,571.7526,578.192625,571.172579,576.362594,1282400,576.362594\n2014-09-26,576.062638,579.2526,574.662558,577.1026,1443700,577.1026\n2014-09-25,587.552646,587.982658,574.182604,575.062581,1926000,575.062581\n2014-09-24,581.462641,589.632691,580.522624,587.992634,1728100,587.992634\n2014-09-23,586.852606,586.852606,581.002639,581.132634,1471400,581.132634\n2014-09-22,593.82271,593.951665,583.462694,587.372648,1689500,587.372648\n2014-09-19,591.502688,596.482654,589.502696,596.082692,3736600,596.082692\n2014-09-18,587.002675,589.542661,585.002622,589.272695,1444600,589.272695\n2014-09-17,580.012619,587.522656,578.777665,584.772683,1692800,584.772683\n2014-09-16,572.762572,581.502606,572.662566,579.95264,1480400,579.95264\n2014-09-15,572.94257,574.952599,568.212618,573.102555,1597600,573.102555\n2014-09-12,581.002639,581.642639,574.462608,575.622589,1601700,575.622589\n2014-09-11,580.362639,581.812599,576.262588,581.352598,1221000,581.352598\n2014-09-10,581.502606,583.502659,576.942615,583.102636,977400,583.102636\n2014-09-09,588.902723,589.002667,580.002643,581.012615,1287200,581.012615\n2014-09-08,586.602653,591.772715,586.302635,589.722659,1431000,589.722659\n2014-09-05,583.982613,586.55265,581.952632,586.082672,1632400,586.082672\n2014-09-04,580.002643,586.00268,579.222611,581.982621,1458200,581.982621\n2014-09-03,580.002643,582.992655,575.002602,577.942611,1215100,577.942611\n2014-09-02,571.852545,577.832629,571.192593,577.332662,1578400,577.332662\n2014-08-29,571.332625,572.04258,567.07155,571.60253,1083800,571.60253\n2014-08-28,569.562573,573.252563,567.102518,569.202577,1292900,569.202577\n2014-08-27,577.272622,578.492581,570.105627,571.002557,1703400,571.002557\n2014-08-26,581.262629,581.802623,576.582619,577.862619,1639700,577.862619\n2014-08-25,584.722619,585.002622,579.002647,580.202654,1361400,580.202654\n2014-08-22,583.592689,585.238682,580.642643,582.562642,789100,582.562642\n2014-08-21,583.822628,584.502655,581.142671,583.372664,914800,583.372664\n2014-08-20,585.88266,586.702658,582.572618,584.492618,1036700,584.492618\n2014-08-19,585.002622,587.342658,584.002627,586.862643,978700,586.862643\n2014-08-18,576.11258,584.512631,576.002598,582.162619,1284100,582.162619\n2014-08-15,577.862619,579.382595,570.522603,573.482564,1519200,573.482564\n2014-08-14,576.182596,577.902645,570.882599,574.652643,985500,574.652643\n2014-08-13,567.312567,575.002602,565.752564,574.782639,1441800,574.782639\n2014-08-12,564.522567,565.902572,560.882579,562.732562,1542000,562.732562\n2014-08-11,569.992585,570.492553,566.002578,567.882551,1214700,567.882551\n2014-08-08,563.562536,570.252576,560.3525,568.772626,1494800,568.772626\n2014-08-07,568.00257,569.89258,561.102482,563.362525,1110900,563.362525\n2014-08-06,561.782569,570.702601,560.002541,566.376589,1334400,566.376589\n2014-08-05,570.052564,571.982601,562.612543,565.072598,1551200,565.072598\n2014-08-04,569.042531,575.352561,564.102531,573.152619,1427300,573.152619\n2014-08-01,570.402584,575.962633,562.85252,566.072594,1955300,566.072594\n2014-07-31,580.602616,583.652668,570.002561,571.60253,2102800,571.60253\n2014-07-30,586.55265,589.502696,584.002627,587.42265,1016500,587.42265\n2014-07-29,588.752653,589.702707,583.517654,585.612633,1349900,585.612633\n2014-07-28,588.072688,592.502683,584.755668,590.602636,986800,590.602636\n2014-07-25,590.402686,591.862684,587.032665,589.022681,932500,589.022681\n2014-07-24,596.452725,599.502716,591.772715,593.352671,1035100,593.352671\n2014-07-23,593.232652,597.852683,592.502683,595.982686,1233200,595.982686\n2014-07-22,590.722655,599.652725,590.602636,594.742652,1699200,594.742652\n2014-07-21,591.752702,594.402731,585.235622,589.472645,2062100,589.472645\n2014-07-18,593.002712,596.802684,582.002635,595.082696,4014200,595.082696\n2014-07-17,579.532665,580.992601,568.61258,573.732579,3016600,573.732579\n2014-07-16,588.002671,588.402694,582.202646,582.662587,1397100,582.662587\n2014-07-15,585.742628,585.807626,576.562606,584.782659,1623000,584.782659\n2014-07-14,582.602608,585.212671,578.032641,584.872627,1854100,584.872627\n2014-07-11,571.912585,580.85263,571.422594,579.182645,1621700,579.182645\n2014-07-10,565.912548,576.592656,565.012558,571.102563,1356700,571.102563\n2014-07-09,571.582578,576.72259,569.378536,576.082652,1116800,576.082652\n2014-07-08,577.662607,579.530645,566.137592,571.092587,1909500,571.092587\n2014-07-07,583.76265,586.432631,579.592644,582.252649,1064600,582.252649\n2014-07-03,583.352589,585.01266,580.922585,584.732656,714200,584.732656\n2014-07-02,583.352589,585.442672,580.392628,582.33766,1056400,582.33766\n2014-07-01,578.32262,584.402649,576.652635,582.672624,1448000,582.672624\n2014-06-30,578.662603,579.572631,574.752588,575.282606,1313800,575.282606\n2014-06-27,577.182592,579.872648,573.802595,577.242632,2236900,577.242632\n2014-06-26,581.002639,582.45266,571.852545,576.002598,1742000,576.002598\n2014-06-25,565.262572,579.962616,565.222546,578.652627,1969400,578.652627\n2014-06-24,565.192556,572.648612,561.012574,564.622572,2207100,564.622572\n2014-06-23,555.152509,565.002582,554.252519,564.952579,1536800,564.952579\n2014-06-20,556.852484,557.582513,550.394526,556.362492,4508300,556.362492\n2014-06-19,554.242482,555.0025,548.512473,554.902556,2456800,554.902556\n2014-06-18,544.862448,553.562516,544.002484,553.372481,1741800,553.372481\n2014-06-17,544.202496,545.32245,539.33245,543.012465,1444600,543.012465\n2014-06-16,549.262515,549.62245,541.522477,544.282488,1702600,544.282488\n2014-06-13,552.262503,552.302469,545.562488,551.762536,1220500,551.762536\n2014-06-12,557.302509,557.992512,548.462531,551.352476,1458500,551.352476\n2014-06-11,558.002549,559.882522,555.022514,558.842561,1100100,558.842561\n2014-06-10,560.512546,563.602502,557.902544,560.552511,1351700,560.552511\n2014-06-09,557.152562,562.902584,556.042523,562.122552,1467500,562.122552\n2014-06-06,558.062528,558.062528,548.932448,556.332564,1736800,556.332564\n2014-06-05,546.402499,554.952498,544.452449,553.90256,1689100,553.90256\n2014-06-04,541.502464,548.612478,538.752429,544.662436,1816500,544.662436\n2014-06-03,550.99248,552.342557,542.552463,544.942501,1866600,544.942501\n2014-06-02,560.702581,560.902593,545.732448,553.932488,1435000,553.932488\n2014-05-30,560.802526,561.352496,555.912467,559.892559,1771100,559.892559\n2014-05-29,563.352549,564.002525,558.712565,560.082534,1354100,560.082534\n2014-05-28,564.57257,567.842585,561.002537,561.682502,1652000,561.682502\n2014-05-27,556.002496,566.002578,554.352463,565.952575,2104200,565.952575\n2014-05-23,547.262462,553.642508,543.702467,552.702492,1932200,552.702492\n2014-05-22,541.132431,547.602445,540.782472,545.062459,1615800,545.062459\n2014-05-21,532.902462,539.185441,531.912381,538.942465,1196300,538.942465\n2014-05-20,529.742368,536.232396,526.302392,529.772418,1784800,529.772418\n2014-05-19,519.702382,529.782456,517.58537,528.862391,1277800,528.862391\n2014-05-16,521.39238,521.802379,515.442347,520.632362,1485300,520.632362\n2014-05-15,525.702357,525.872379,517.422325,519.982324,1704400,519.982324\n2014-05-14,533.002407,533.002407,525.292358,526.652412,1191800,526.652412\n2014-05-13,530.892433,536.072411,529.512428,533.092437,1653400,533.092437\n2014-05-12,523.512391,530.192393,519.012379,529.922366,1912500,529.922366\n2014-05-09,510.75233,519.902393,504.202292,518.732314,2439500,518.732314\n2014-05-08,508.462297,517.23229,506.452298,511.002313,2021300,511.002313\n2014-05-07,515.792305,516.68232,503.302272,509.962291,3224300,509.962291\n2014-05-06,525.232379,526.812396,515.062337,515.14233,1689000,515.14233\n2014-05-05,524.822381,528.902418,521.322364,527.812392,1024100,527.812392\n2014-05-02,533.762426,534.002403,525.612389,527.932411,1688500,527.932411\n2014-05-01,527.112352,532.932391,523.882364,531.352374,1905500,531.352374\n2014-04-30,527.602343,528.002366,522.522372,526.662388,1751200,526.662388\n2014-04-29,516.902344,529.462425,516.322324,527.70241,2699100,527.70241\n2014-04-28,517.182348,518.602319,502.802274,517.152359,3335500,517.152359\n2014-04-25,522.512395,524.702361,515.422333,516.182352,2100400,516.182352\n2014-04-24,530.072374,531.652452,522.122349,525.162363,1883200,525.162363\n2014-04-23,533.792415,533.872408,526.252389,526.942391,2052300,526.942391\n2014-04-22,528.642427,537.232391,527.512375,534.812425,2365400,534.812425\n2014-04-21,536.1024,536.702435,525.602352,528.622414,2566700,528.622414\n2014-04-17,548.81249,549.502492,531.152424,536.1024,6809500,536.1024\n2014-04-16,543.002488,557.002492,540.00244,556.54249,4893300,556.54249\n2014-04-15,536.822454,538.452473,518.462348,536.442444,3855100,536.442444\n2014-04-14,538.252462,544.102429,529.56237,532.522453,2575100,532.522453\n2014-04-11,532.552381,540.00244,526.532392,530.602392,3924800,530.602392\n2014-04-10,565.002582,565.002582,539.902495,540.952433,4036900,540.952433\n2014-04-09,559.622532,565.372554,552.952506,564.142557,3330800,564.142557\n2014-04-08,542.602466,555.0025,541.612446,554.902556,3151200,554.902556\n2014-04-07,540.742445,548.482483,527.15244,538.152456,4401700,538.152456\n2014-04-04,574.652643,577.77265,543.002488,543.14246,6369300,543.14246\n2014-04-03,569.852553,587.282679,564.132581,569.742571,5099200,569.742571\n2014-04-02,599.992707,604.832763,562.192568,567.002574,147100,567.002574\n2014-04-01,558.712565,568.452595,558.712565,567.162558,7900,567.162558\n2014-03-31,566.892592,567.002574,556.932537,556.972503,10800,556.972503\n2014-03-28,561.202549,566.43259,558.672477,559.992504,41200,559.992504\n2014-03-27,568.00257,568.00257,552.922516,558.462551,13100,558.462551\n"
  },
  {
    "path": "27_code-in-process/48_passing-data/01_URL-values/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\tkey := \"q\"\n\t\tval := req.URL.Query().Get(key)\n\t\tio.WriteString(res, \"Do my search:\"+val)\n\t})\n\thttp.ListenAndServe(\":9000\", nil)\n}\n\n// visit this page:\n// http://localhost:9000/?q=\"dog\"\n"
  },
  {
    "path": "27_code-in-process/48_passing-data/02_form-values/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\tkey := \"q\"\n\t\tval := req.FormValue(key)\n\t\tfmt.Println(\"value: \", val)\n\t\tres.Header().Set(\"Content-Type\", \"text/html\")\n\t\tio.WriteString(res, `<form method=\"POST\">\n\n\t\t <input type=\"text\" name=\"q\">\n\t\t <input type=\"submit\">\n\n\t\t</form>`)\n\t})\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/48_passing-data/03_form-values/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\tkey := \"q\"\n\t\tval := req.FormValue(key)\n\t\tfmt.Println(\"value: \", val)\n\t\tres.Header().Set(\"Content-Type\", \"text/html\")\n\t\tio.WriteString(res, `<form method=\"GET\">\n\n\t\t <input type=\"text\" name=\"q\">\n\t\t <input type=\"submit\">\n\n\t\t</form>`+val)\n\t})\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/48_passing-data/04_form-values/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\tkey := \"q\"\n\t\tval := req.FormValue(key)\n\t\tfmt.Println(\"value: \", val)\n\t\tres.Header().Set(\"Content-Type\", \"text/html\")\n\t\tio.WriteString(res, `<form method=\"POST\">\n\n\t\t<input type=\"checkbox\" name=\"q\">\n\t\t<input type=\"submit\">\n\n\t\t</form>`+val)\n\t})\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/48_passing-data/05_form-values/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\tkey := \"q\"\n\t\tfile, hdr, err := req.FormFile(key)\n\t\tfmt.Println(file, hdr, err)\n\t\tres.Header().Set(\"Content-Type\", \"text/html\")\n\n\t\t// you have to put this enctype for uploading files\n\t\tio.WriteString(res, `<form method=\"POST\" enctype=\"multipart/form-data\">\n      <input type=\"file\" name=\"q\">\n      <input type=\"submit\">\n    </form>`)\n\t})\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/48_passing-data/06_form-values/01/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"net/http\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\tkey := \"q\"\n\t\tfile, _, err := req.FormFile(key)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tdefer file.Close()\n\n\t\tbs, _ := ioutil.ReadAll(file)\n\n\t\tfmt.Println(string(bs))\n\t\tres.Header().Set(\"Content-Type\", \"text/html\")\n\t\t// you have to put this enctype for uploading files\n\t\tio.WriteString(res, `<form method=\"POST\" enctype=\"multipart/form-data\">\n      <input type=\"file\" name=\"q\">\n      <input type=\"submit\">\n    </form>`)\n\t})\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/48_passing-data/06_form-values/02/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\tif req.Method == \"POST\" {\n\t\t\tkey := \"q\"\n\t\t\tfile, _, err := req.FormFile(key)\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\tdefer file.Close()\n\n\t\t\tio.Copy(os.Stdout, file)\n\t\t}\n\n\t\tres.Header().Set(\"Content-Type\", \"text/html\")\n\t\t// you have to put this enctype for uploading files\n\t\tio.WriteString(res, `<form method=\"POST\" enctype=\"multipart/form-data\">\n      <input type=\"file\" name=\"q\">\n      <input type=\"submit\">\n    </form>`)\n\t})\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/48_passing-data/07_form-data/form.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Document</title>\n</head>\n<body>\n\n<form method=\"POST\">\n    <label for=\"firstName\">First Name</label>\n    <input type=\"text\" id=\"firstName\" name=\"first\">\n    <br>\n    <label for=\"lastName\">Last Name</label>\n    <input type=\"text\" id=\"lastName\" name=\"last\">\n    <br>\n    <input type=\"submit\">\n</form>\n\n<h1>{{ .FirstName }} {{ .LastName }}</h1>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/48_passing-data/07_form-data/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"html/template\"\n\t\"log\"\n\t\"net/http\"\n\t\"reflect\"\n)\n\ntype Person struct {\n\tFirstName string\n\tLastName  string\n}\n\nfunc main() {\n\n\t// parse template\n\ttpl, err := template.ParseFiles(\"form.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\t// receive form submission\n\t\tfName := req.FormValue(\"first\")\n\t\tlName := req.FormValue(\"last\")\n\t\tfmt.Println(\"fName: \", fName)\n\t\tfmt.Println(\"[]byte(fName): \", []byte(fName))\n\t\tfmt.Println(\"typeOf: \", reflect.TypeOf(fName))\n\n\t\t// execute template\n\t\terr = tpl.Execute(res, Person{fName, lName})\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\tlog.Fatalln(err)\n\t\t}\n\t})\n\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/48_passing-data/07_form-data/sample.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Document</title>\n</head>\n<body>\n\n<form method=\"POST\">\n    <label for=\"firstName\">First Name</label>\n    <input type=\"text\" id=\"firstName\" name=\"first\">\n    <br>\n    <label for=\"lastName\">Last Name</label>\n    <input type=\"text\" id=\"lastName\" name=\"last\">\n    <br>\n    <input type=\"submit\">\n</form>\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/48_passing-data/08_form_file-upload/01/form.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Document</title>\n</head>\n<body>\n\n<form method=\"POST\" enctype=\"multipart/form-data\">\n    <label for=\"file\">Choose File To Upload</label>\n    <input type=\"file\" id=\"file\" name=\"file\">\n    <br>\n    <input type=\"submit\">\n</form>\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/48_passing-data/08_form_file-upload/01/main.go",
    "content": "package main\n\nimport (\n\t\"html/template\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\nfunc main() {\n\n\t// parse template\n\ttpl, err := template.ParseFiles(\"form.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\t// handler\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\t// receive form submission\n\t\tif req.Method == \"POST\" {\n\t\t\tsrc, _, err := req.FormFile(\"file\")\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\tdefer src.Close()\n\n\t\t\tdst, err := os.Create(filepath.Join(\"./\", \"file.txt\"))\n\t\t\tif err != nil {\n\t\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tdefer dst.Close()\n\n\t\t\tio.Copy(dst, src)\n\t\t}\n\n\t\t// execute template\n\t\terr = tpl.Execute(res, nil)\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\tlog.Fatalln(err)\n\t\t}\n\t})\n\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/48_passing-data/08_form_file-upload/01/sample.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Document</title>\n</head>\n<body>\n\n<form method=\"POST\">\n    <label for=\"firstName\">First Name</label>\n    <input type=\"text\" id=\"firstName\" name=\"first\">\n    <br>\n    <label for=\"lastName\">Last Name</label>\n    <input type=\"text\" id=\"lastName\" name=\"last\">\n    <br>\n    <input type=\"submit\">\n</form>\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/48_passing-data/08_form_file-upload/02/form.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Document</title>\n</head>\n<body>\n\n<form method=\"POST\" enctype=\"multipart/form-data\">\n    <label for=\"file\">Choose File To Upload</label>\n    <input type=\"file\" id=\"file\" name=\"file\">\n    <br>\n    <input type=\"submit\">\n</form>\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/48_passing-data/08_form_file-upload/02/main.go",
    "content": "package main\n\nimport (\n\t\"html/template\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\n\t// parse template\n\ttpl, err := template.ParseFiles(\"form.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\t// handler\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\t// receive form submission\n\t\tif req.Method == \"POST\" {\n\t\t\tsrc, _, err := req.FormFile(\"file\")\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\tdefer src.Close()\n\n\t\t\tdst, err := os.Create(\"file.txt\")\n\t\t\tif err != nil {\n\t\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tdefer dst.Close()\n\n\t\t\tio.Copy(dst, src)\n\t\t}\n\n\t\t// execute template\n\t\terr = tpl.Execute(res, nil)\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\tlog.Fatalln(err)\n\t\t}\n\t})\n\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/48_passing-data/08_form_file-upload/02/sample.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Document</title>\n</head>\n<body>\n\n<form method=\"POST\">\n    <label for=\"firstName\">First Name</label>\n    <input type=\"text\" id=\"firstName\" name=\"first\">\n    <br>\n    <label for=\"lastName\">Last Name</label>\n    <input type=\"text\" id=\"lastName\" name=\"last\">\n    <br>\n    <input type=\"submit\">\n</form>\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/48_passing-data/08_form_file-upload/03/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\nfunc main() {\n\tfmt.Println(\"TEMP DIR:\", os.TempDir())\n\thttp.ListenAndServe(\":9000\", http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {\n\t\tif req.Method == \"POST\" {\n\t\t\tsrc, _, err := req.FormFile(\"my-file\")\n\t\t\tif err != nil {\n\t\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tdefer src.Close()\n\n\t\t\tdst, err := os.Create(filepath.Join(os.TempDir(), \"file.txt\"))\n\t\t\tif err != nil {\n\t\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tdefer dst.Close()\n\n\t\t\tio.Copy(dst, src)\n\t\t}\n\n\t\tres.Header().Set(\"Content-Type\", \"text/html\")\n\t\tio.WriteString(res, `\n      <form method=\"POST\" enctype=\"multipart/form-data\">\n        <input type=\"file\" name=\"my-file\">\n        <input type=\"submit\">\n      </form>\n      `)\n\t}))\n}\n"
  },
  {
    "path": "27_code-in-process/48_passing-data/08_form_file-upload/04/file.txt",
    "content": "package main\n\n\nimport (\n\t\"net/http\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n)\nfunc main() {\n\thttp.ListenAndServe(\":9000\", http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {\n\t\tif req.Method == \"POST\" {\n\t\t\tfile, _, err := req.FormFile(\"my-file\")\n\t\t\tif err != nil {\n\t\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tdefer file.Close()\n\n\t\t\tsrc := io.LimitReader(file, 400)\n\n\t\t\tdst, err := os"
  },
  {
    "path": "27_code-in-process/48_passing-data/08_form_file-upload/04/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\nfunc main() {\n\thttp.ListenAndServe(\":9000\", http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {\n\t\tif req.Method == \"POST\" {\n\t\t\tfile, _, err := req.FormFile(\"my-file\")\n\t\t\tif err != nil {\n\t\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tdefer file.Close()\n\n\t\t\tsrc := io.LimitReader(file, 400)\n\n\t\t\tdst, err := os.Create(filepath.Join(\".\", \"file.txt\"))\n\t\t\tif err != nil {\n\t\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tdefer dst.Close()\n\n\t\t\tio.Copy(dst, src)\n\t\t}\n\n\t\tres.Header().Set(\"Content-Type\", \"text/html\")\n\t\tio.WriteString(res, `\n      <form method=\"POST\" enctype=\"multipart/form-data\">\n        <input type=\"file\" name=\"my-file\">\n        <input type=\"submit\">\n      </form>\n      `)\n\t}))\n}\n"
  },
  {
    "path": "27_code-in-process/49_cookies-sessions/01_set-cookie/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\n\t\thttp.SetCookie(res, &http.Cookie{\n\t\t\tName:  \"my-cookie\",\n\t\t\tValue: \"some value\",\n\t\t})\n\t})\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/49_cookies-sessions/02_get-cookie/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\tcookie, err := req.Cookie(\"my-cookie\")\n\t\tfmt.Println(cookie, err)\n\n\t\thttp.SetCookie(res, &http.Cookie{\n\t\t\tName:  \"my-cookie\",\n\t\t\tValue: \"some value\",\n\t\t})\n\t})\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/49_cookies-sessions/03_sessions/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"net/http\"\n)\n\nfunc main() {\n\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\tcookie, err := req.Cookie(\"session-id\")\n\t\t// cookie is not set\n\t\tif err != nil {\n\t\t\tid, _ := uuid.NewV4()\n\t\t\tcookie = &http.Cookie{\n\t\t\t\tName:  \"session-id\",\n\t\t\t\tValue: id.String() + \" email=jon@email.com\" + \" JSON data\" + \" Whatever\",\n\t\t\t}\n\t\t\thttp.SetCookie(res, cookie)\n\t\t}\n\t\tfmt.Println(cookie)\n\n\t})\n\thttp.ListenAndServe(\":9000\", nil)\n}\n\n// go get uuid\n// https://github.com/nu7hatch/gouuid\n// NewV4\n"
  },
  {
    "path": "27_code-in-process/49_cookies-sessions/04_sessions/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc main() {\n\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\tcookie, err := req.Cookie(\"session-id\")\n\t\t// cookie is not set\n\t\tif err != nil {\n\t\t\t//id, _ := uuid.NewV4()\n\t\t\tcookie = &http.Cookie{\n\t\t\t\tName: \"session-id\",\n\t\t\t}\n\t\t}\n\n\t\tif req.FormValue(\"email\") != \"\" {\n\t\t\tcookie.Value = req.FormValue(\"email\")\n\t\t}\n\n\t\thttp.SetCookie(res, cookie)\n\n\t\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <body>\n    <form>\n    `+cookie.Value+`\n      <input type=\"email\" name=\"email\">\n      <input type=\"submit\">\n    </form>\n  </body>\n</html>`)\n\n\t})\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/49_cookies-sessions/05_sessions-HMAC/01/main.go",
    "content": "package main\n\nimport (\n\t\"crypto/hmac\"\n\t\"crypto/sha256\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc getCode(data string) string {\n\th := hmac.New(sha256.New, []byte(\"ourkey\"))\n\tio.WriteString(h, data)\n\treturn fmt.Sprintf(\"%x\", h.Sum(nil))\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\tcookie, err := req.Cookie(\"session-id\")\n\t\t// cookie is not set\n\t\tif err != nil {\n\t\t\t//id, _ := uuid.NewV4()\n\t\t\tcookie = &http.Cookie{\n\t\t\t\tName: \"session-id\",\n\t\t\t}\n\t\t}\n\n\t\tif req.FormValue(\"email\") != \"\" {\n\t\t\tcookie.Value = req.FormValue(\"email\")\n\t\t}\n\n\t\tfmt.Println(getCode(cookie.Value))\n\t\thttp.SetCookie(res, cookie)\n\t\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <body>\n    <form method=\"POST\">\n    `+cookie.Value+`\n      <input type=\"email\" name=\"email\">\n      <input type=\"password\" name=\"password\">\n      <input type=\"submit\">\n    </form>\n  </body>\n</html>`)\n\n\t})\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/49_cookies-sessions/05_sessions-HMAC/02/main.go",
    "content": "package main\n\nimport (\n\t\"crypto/hmac\"\n\t\"crypto/sha256\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc getCode(data string) string {\n\th := hmac.New(sha256.New, []byte(\"ourkey\"))\n\tio.WriteString(h, data)\n\treturn fmt.Sprintf(\"%x\", h.Sum(nil))\n\n}\n\nfunc main() {\n\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\tcookie, err := req.Cookie(\"session-id\")\n\t\t// cookie is not set\n\t\tif err != nil {\n\t\t\t//id, _ := uuid.NewV4()\n\t\t\tcookie = &http.Cookie{\n\t\t\t\tName: \"session-id\",\n\t\t\t}\n\t\t}\n\n\t\tif req.FormValue(\"email\") != \"\" {\n\t\t\tcookie.Value = req.FormValue(\"email\")\n\t\t}\n\n\t\tcode := getCode(cookie.Value)\n\t\tcookie.Value = code + \"|\" + cookie.Value\n\n\t\t// this doesn't run\n\t\t// need more code added to work\n\t\t// just shown for example of how to do auth with HMAC\n\n\t\thttp.SetCookie(res, cookie)\n\n\t\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <body>\n    <form method=\"POST\">\n    `+cookie.Value+`\n      <input type=\"email\" name=\"email\">\n      <input type=\"password\" name=\"password\">\n      <input type=\"submit\">\n    </form>\n  </body>\n</html>`)\n\n\t})\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/49_cookies-sessions/06_sessions_GORILLA/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/gorilla/sessions\"\n\t\"io\"\n\t\"net/http\"\n)\n\nvar store = sessions.NewCookieStore([]byte(\"secret-password\"))\n\nfunc main() {\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\tsession, _ := store.Get(req, \"session\")\n\t\tif req.FormValue(\"email\") != \"\" {\n\t\t\t// check password\n\t\t\tsession.Values[\"email\"] = req.FormValue(\"email\")\n\t\t}\n\t\tsession.Save(req, res)\n\n\t\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <body>\n    <form method=\"POST\">\n    `+fmt.Sprint(session.Values[\"email\"])+`\n      <input type=\"email\" name=\"email\">\n      <input type=\"password\" name=\"password\">\n      <input type=\"submit\">\n    </form>\n  </body>\n</html>`)\n\n\t})\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/49_cookies-sessions/07_cookies_show-visits/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\tcookie, err := req.Cookie(\"my-cookie\")\n\t\t// there is no cookie\n\t\tif err == http.ErrNoCookie {\n\t\t\tcookie = &http.Cookie{\n\t\t\t\tName:  \"my-cookie\",\n\t\t\t\tValue: \"0\",\n\t\t\t}\n\t\t}\n\t\t// there is a cookie\n\t\tcount, _ := strconv.Atoi(cookie.Value)\n\t\tcount++\n\t\tcookie.Value = strconv.Itoa(count)\n\n\t\thttp.SetCookie(res, cookie)\n\n\t\tio.WriteString(res, cookie.Value)\n\t})\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/49_cookies-sessions/08_log-in-out/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/\", func(res http.ResponseWriter, req *http.Request) {\n\t\tcookie, err := req.Cookie(\"logged-in\")\n\t\t// no cookie\n\t\tif err == http.ErrNoCookie {\n\t\t\tcookie = &http.Cookie{\n\t\t\t\tName:  \"logged-in\",\n\t\t\t\tValue: \"0\",\n\t\t\t}\n\t\t}\n\n\t\t// check log in\n\t\tif req.Method == \"POST\" {\n\t\t\tpassword := req.FormValue(\"password\")\n\t\t\tif password == \"secret\" {\n\t\t\t\tcookie = &http.Cookie{\n\t\t\t\t\tName:  \"logged-in\",\n\t\t\t\t\tValue: \"1\",\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// if logout, then logout\n\t\tif req.URL.Path == \"/logout\" {\n\t\t\tcookie = &http.Cookie{\n\t\t\t\tName:   \"logged-in\",\n\t\t\t\tValue:  \"0\",\n\t\t\t\tMaxAge: -1,\n\t\t\t}\n\t\t}\n\n\t\thttp.SetCookie(res, cookie)\n\t\tvar html string\n\n\t\t// not logged in\n\t\tif cookie.Value == strconv.Itoa(0) {\n\t\t\thtml = `\n\t\t\t<!DOCTYPE html>\n\t\t\t<html lang=\"en\">\n\t\t\t<head>\n\t\t\t\t<meta charset=\"UTF-8\">\n\t\t\t\t<title></title>\n\t\t\t</head>\n\t\t\t<body>\n\t\t\t<h1>LOG IN</h1>\n\t\t\t<form method=\"post\" action=\"http://localhost:9000/\">\n\t\t\t\t<h3>User name</h3>\n\t\t\t\t<input type=\"text\" name=\"userName\" id=\"userName\">\n\t\t\t\t<h3>Password</h3>\n\t\t\t\t<input type=\"text\" name=\"password\" id=\"password\">\n\t\t\t\t<br>\n\t\t\t\t<input type=\"submit\">\n\t\t\t\t<input type=\"submit\" name=\"logout\" value=\"logout\">\n\t\t\t</form>\n\t\t\t</body>\n\t\t\t</html>`\n\t\t}\n\n\t\t// logged in\n\t\tif cookie.Value == strconv.Itoa(1) {\n\t\t\thtml = `\n\t\t\t<!DOCTYPE html>\n\t\t\t<html lang=\"en\">\n\t\t\t<head>\n\t\t\t\t<meta charset=\"UTF-8\">\n\t\t\t\t<title></title>\n\t\t\t</head>\n\t\t\t<body>\n\t\t\t<h1><a href=\"http://localhost:9000/logout\">LOG OUT</a></h1>\n\t\t\t</body>\n\t\t\t</html>`\n\t\t}\n\n\t\tio.WriteString(res, html)\n\t})\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/49_cookies-sessions/09_HTTPS-TLS/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc handler(w http.ResponseWriter, req *http.Request) {\n\tw.Header().Set(\"Content-Type\", \"text/plain\")\n\tw.Write([]byte(\"This is an example server.\\n\"))\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", handler)\n\tlog.Printf(\"About to listen on 10443. Go to https://127.0.0.1:10443/\")\n\n\tgo http.ListenAndServe(\":9999\", nil)\n\terr := http.ListenAndServeTLS(\":10443\", \"cert.pem\", \"key.pem\", nil)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n}\n"
  },
  {
    "path": "27_code-in-process/49_cookies-sessions/10_HTTPS-TLS/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc handler(w http.ResponseWriter, req *http.Request) {\n\tw.Header().Set(\"Content-Type\", \"text/plain\")\n\tw.Write([]byte(\"This is an example server.\\n\"))\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", handler)\n\tlog.Printf(\"About to listen on 10443. Go to https://127.0.0.1:10443/\")\n\n\tgo http.ListenAndServe(\":9999\", http.RedirectHandler(\"https://127.0.0.1:10443/\", 301))\n\terr := http.ListenAndServeTLS(\":10443\", \"cert.pem\", \"key.pem\", nil)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n}\n"
  },
  {
    "path": "27_code-in-process/49_cookies-sessions/11_HTTPS-TLS/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc handler(w http.ResponseWriter, req *http.Request) {\n\tw.Header().Set(\"Content-Type\", \"text/plain\")\n\tw.Write([]byte(\"This is an example server.\\n\"))\n}\n\nfunc redir(w http.ResponseWriter, req *http.Request) {\n\thttp.Redirect(w, req, \"https://127.0.0.1:10443/\"+req.RequestURI, http.StatusMovedPermanently)\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", handler)\n\tlog.Printf(\"About to listen on 10443. Go to https://127.0.0.1:10443/\")\n\n\tgo http.ListenAndServe(\":9999\", http.HandlerFunc(redir))\n\terr := http.ListenAndServeTLS(\":10443\", \"cert.pem\", \"key.pem\", nil)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n}\n"
  },
  {
    "path": "27_code-in-process/49_cookies-sessions/12_GORILLA_photo-blog/assets/templates/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n</head>\n<body>\n<h1><a href=\"http://localhost:8080/logout\">LOG OUT</a></h1>\n<p><img src=\"/assets/imgs/01.jpg\"></p>\n<h1>ADD PHOTO</h1>\n<form method=\"POST\" action=\"http://localhost:8080/\" enctype=\"multipart/form-data\">\n    <input type=\"file\" name=\"data\" id=\"data\">\n    <input type=\"submit\">\n</form>\n<p>\n    {{range .}}\n    <img src=\"/assets/imgs/{{.}}\">\n    {{end}}\n</p>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/49_cookies-sessions/12_GORILLA_photo-blog/assets/templates/login.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n</head>\n<body>\n<h1>LOG IN</h1>\n<form method=\"post\" action=\"http://localhost:8080/login\">\n    <h3>User name</h3>\n    <input type=\"text\" name=\"userName\" id=\"userName\">\n    <h3>Password</h3>\n    <input type=\"text\" name=\"password\" id=\"password\">\n    <br>\n    <input type=\"submit\">\n    <input type=\"submit\" name=\"logout\" value=\"logout\">\n</form>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/49_cookies-sessions/12_GORILLA_photo-blog/main.go",
    "content": "package main\n\nimport (\n\t\"crypto/sha1\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/gorilla/context\"\n\t\"github.com/gorilla/sessions\"\n\t\"html/template\"\n\t\"io\"\n\t\"mime/multipart\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\nvar tpl *template.Template\nvar store = sessions.NewCookieStore([]byte(\"secret-password\"))\n\nfunc init() {\n\ttpl, _ = template.ParseGlob(\"assets/templates/*.html\")\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", index)\n\thttp.HandleFunc(\"/login\", login)\n\thttp.HandleFunc(\"/logout\", logout)\n\thttp.Handle(\"/assets/imgs/\", http.StripPrefix(\"/assets/imgs\", http.FileServer(http.Dir(\"./assets/imgs\"))))\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.ListenAndServe(\":8080\", context.ClearHandler(http.DefaultServeMux))\n}\n\nfunc index(res http.ResponseWriter, req *http.Request) {\n\tsession, _ := store.Get(req, \"session\")\n\t// authenticate\n\tif session.Values[\"loggedin\"] == \"false\" || session.Values[\"loggedin\"] == nil {\n\t\thttp.Redirect(res, req, \"/login\", 302)\n\t\treturn\n\t}\n\t// upload photo\n\tsrc, hdr, err := req.FormFile(\"data\")\n\tif req.Method == \"POST\" && err == nil {\n\t\tuploadPhoto(src, hdr, session)\n\t}\n\t// save session\n\tsession.Save(req, res)\n\t// get photos\n\tdata := getPhotos(session)\n\t// execute template\n\ttpl.ExecuteTemplate(res, \"index.html\", data)\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request) {\n\tsession, _ := store.Get(req, \"session\")\n\tsession.Values[\"loggedin\"] = \"false\"\n\tsession.Save(req, res)\n\thttp.Redirect(res, req, \"/login\", 302)\n}\n\nfunc login(res http.ResponseWriter, req *http.Request) {\n\tsession, _ := store.Get(req, \"session\")\n\tif req.Method == \"POST\" && req.FormValue(\"password\") == \"secret\" {\n\t\tsession.Values[\"loggedin\"] = \"true\"\n\t\tsession.Save(req, res)\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t\treturn\n\t}\n\t// execute template\n\ttpl.ExecuteTemplate(res, \"login.html\", nil)\n}\n\nfunc uploadPhoto(src multipart.File, hdr *multipart.FileHeader, session *sessions.Session) {\n\tdefer src.Close()\n\tfName := getSha(src) + \".jpg\"\n\twd, _ := os.Getwd()\n\tpath := filepath.Join(wd, \"assets\", \"imgs\", fName)\n\tdst, _ := os.Create(path)\n\tdefer dst.Close()\n\tsrc.Seek(0, 0)\n\tio.Copy(dst, src)\n\taddPhoto(fName, session)\n}\n\nfunc getSha(src multipart.File) string {\n\th := sha1.New()\n\tio.Copy(h, src)\n\treturn fmt.Sprintf(\"%x\", h.Sum(nil))\n}\n\nfunc addPhoto(fName string, session *sessions.Session) {\n\tdata := getPhotos(session)\n\tdata = append(data, fName)\n\tbs, _ := json.Marshal(data)\n\tsession.Values[\"data\"] = string(bs)\n}\n\nfunc getPhotos(session *sessions.Session) []string {\n\tvar data []string\n\tjsonData := session.Values[\"data\"]\n\tif jsonData != nil {\n\t\tjson.Unmarshal([]byte(jsonData.(string)), &data)\n\t}\n\treturn data\n}\n"
  },
  {
    "path": "27_code-in-process/50_exif/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/rwcarlsen/goexif/exif\"\n\t\"github.com/rwcarlsen/goexif/mknote\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\tfname := \"01.jpg\"\n\n\tf, err := os.Open(fname)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\t// Optionally register camera makenote data parsing - currently Nikon and\n\t// Canon are supported.\n\texif.RegisterParsers(mknote.All...)\n\n\tx, err := exif.Decode(f)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tcamModel, _ := x.Get(exif.Model) // normally, don't ignore errors!\n\tfmt.Println(camModel.StringVal())\n\n\tfocal, _ := x.Get(exif.FocalLength)\n\tnumer, denom, _ := focal.Rat2(0) // retrieve first (only) rat. value\n\tfmt.Printf(\"%v/%v\", numer, denom)\n\n\t// Two convenience functions exist for date/time taken and GPS coords:\n\ttm, _ := x.DateTime()\n\tfmt.Println(\"Taken: \", tm)\n\n\tlat, long, _ := x.LatLong()\n\tfmt.Println(\"lat, long: \", lat, \", \", long)\n}\n"
  },
  {
    "path": "27_code-in-process/51_appengine-introduction/01_hello-world/app.yaml",
    "content": "application: helloworld\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app"
  },
  {
    "path": "27_code-in-process/51_appengine-introduction/01_hello-world/hello.go",
    "content": "package hello\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handler)\n}\n\nfunc handler(w http.ResponseWriter, r *http.Request) {\n\tfmt.Fprint(w, \"Hello, worlddddddddxxxxxx!\")\n\tw.Write([]byte(\"Hello, world!\"))\n}\n"
  },
  {
    "path": "27_code-in-process/51_appengine-introduction/02_photo-blog_somewhat-crappy-code-FYI/app.yaml",
    "content": "application: photoblog-1008\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app"
  },
  {
    "path": "27_code-in-process/51_appengine-introduction/02_photo-blog_somewhat-crappy-code-FYI/assets/tpl/admin_login.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Document</title>\n</head>\n<body>\n<form method=\"post\">\n    <h3>User name</h3>\n    <input type=\"text\" name=\"userName\" id=\"userName\">\n    <h3>Password</h3>\n    <input type=\"text\" name=\"password\" id=\"password\">\n    <br>\n    <input type=\"submit\">\n</form>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/51_appengine-introduction/02_photo-blog_somewhat-crappy-code-FYI/assets/tpl/admin_upload.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Document</title>\n</head>\n<body>\n{{ if . }}\n<a href=\"/admin/logout\">Log Out</a>\n{{ . }}\n{{ else }}\n{{ . }}\n<p>We are in the else</p>\n{{ end }}\n\n\n<form method=\"POST\" enctype=\"multipart/form-data\">\n    <label for=\"file\">Choose File To Upload</label>\n    <input type=\"file\" id=\"file\" name=\"file\">\n    <br>\n    <input type=\"submit\">\n\n</form>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/51_appengine-introduction/02_photo-blog_somewhat-crappy-code-FYI/assets/tpl/index.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Pictures</title>\n</head>\n<body>\n<h1>PICTURES</h1>\n\n{{ if .LoggedIn }}\n<a href=\"/admin/logout\">Log Out</a>\n{{ .LoggedIn }}\n{{ else }}\n{{ .LoggedIn }}\n<p>We are in the else</p>\n{{ end }}\n\n<a href=\"/admin\">admin</a>\n{{ range .Photos }}\n<br/>\n<a href=\"#\" download=\"{{ .PhotoPath }}\"><img src=\"{{ .PhotoPath }}\" alt=\"ocean\"></a>\n\n<img src=\"https://maps.googleapis.com/maps/api/\nstaticmap?center={{.Lat}},{{.Long}}&zoom=15&size=700x700&maptype=roadmap&markers=color:red%7Clabel:C%7C{{.Lat}},{{.Long}}\" alt=\"map\">\n\n{{ end }}\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/51_appengine-introduction/02_photo-blog_somewhat-crappy-code-FYI/photos.go",
    "content": "package photos\n\nimport (\n\t\"fmt\"\n\t\"github.com/gorilla/sessions\"\n\t\"github.com/rwcarlsen/goexif/exif\"\n\t\"github.com/rwcarlsen/goexif/mknote\"\n\t\"html/template\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\nvar tpl *template.Template\nvar store = sessions.NewCookieStore([]byte(\"something-very-secret\"))\n\nfunc init() {\n\tvar err error\n\ttpl, err = template.ParseFiles(\"assets/tpl/index.gohtml\", \"assets/tpl/admin_login.gohtml\", \"assets/tpl/admin_upload.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(\"couldn't parse\", err)\n\t}\n\n\thttp.HandleFunc(\"/\", home)\n\thttp.HandleFunc(\"/admin\", admin)\n\thttp.HandleFunc(\"/admin/upload\", upload)\n\thttp.HandleFunc(\"/admin/logout\", logout)\n\thttp.Handle(\"/assets/imgs/\", http.StripPrefix(\"/assets/imgs/\", http.FileServer(http.Dir(\"assets/imgs/\"))))\n}\n\nfunc home(res http.ResponseWriter, req *http.Request) {\n\n\ttype Photo struct {\n\t\tPhotoPath string\n\t\tLat       float64\n\t\tLong      float64\n\t}\n\n\tvar model struct {\n\t\tPhotos   []Photo\n\t\tLoggedIn bool\n\t}\n\n\tsession, _ := store.Get(req, \"session-name\")\n\t_, model.LoggedIn = session.Values[\"loggedin\"]\n\n\tfilepath.Walk(\"assets/imgs\", func(path string, info os.FileInfo, err error) error {\n\t\tif !info.IsDir() {\n\n\t\t\tfmt.Println(\"WALKING\", path)\n\n\t\t\tvar currentPhoto Photo\n\n\t\t\tcurrentPhoto.PhotoPath = path\n\n\t\t\tf, err := os.Open(path)\n\t\t\tif err != nil {\n\t\t\t\tlog.Fatal(err)\n\t\t\t}\n\n\t\t\texif.RegisterParsers(mknote.All...)\n\n\t\t\tx, err := exif.Decode(f)\n\t\t\tif err != nil {\n\t\t\t\tlog.Println(\"no info\")\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tcurrentPhoto.Lat, currentPhoto.Long, _ = x.LatLong()\n\t\t\tfmt.Println(\"lat, long: \", currentPhoto.Lat, \", \", currentPhoto.Long)\n\n\t\t\tmodel.Photos = append(model.Photos, currentPhoto)\n\t\t}\n\t\treturn nil\n\t})\n\n\terr := tpl.ExecuteTemplate(res, \"index.gohtml\", model)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t}\n}\n\nfunc admin(res http.ResponseWriter, req *http.Request) {\n\tuserName := req.FormValue(\"userName\")\n\tpassword := req.FormValue(\"password\")\n\n\tif userName == \"You\" && password == \"Me\" {\n\t\tsession, _ := store.Get(req, \"session-name\")\n\t\tsession.Values[\"loggedin\"] = \"true\"\n\t\tsession.Save(req, res)\n\t\thttp.Redirect(res, req, \"/admin/upload\", 302)\n\t\treturn\n\t}\n\n\ttpl.ExecuteTemplate(res, \"admin_login.gohtml\", nil)\n}\n\nfunc upload(res http.ResponseWriter, req *http.Request) {\n\tsession, _ := store.Get(req, \"session-name\")\n\t_, ok := session.Values[\"loggedin\"]\n\tif !ok {\n\t\thttp.Redirect(res, req, \"/admin\", 302)\n\t\treturn\n\t}\n\n\tif req.Method == \"POST\" {\n\t\tsrc, hdr, err := req.FormFile(\"file\")\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tdefer src.Close()\n\n\t\tfileName := hdr.Filename\n\t\tdst, err := os.Create(\"assets/imgs/\" + fileName)\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\tdefer dst.Close()\n\n\t\tio.Copy(dst, src)\n\t}\n\ttpl.ExecuteTemplate(res, \"admin_upload.gohtml\", ok)\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request) {\n\tsession, _ := store.Get(req, \"session-name\")\n\tdelete(session.Values, \"loggedin\")\n\tsession.Save(req, res)\n\thttp.Redirect(res, req, \"/admin\", 302)\n\treturn\n}\n"
  },
  {
    "path": "27_code-in-process/51_appengine-introduction/03_google-maps-api/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/51_appengine-introduction/03_google-maps-api/assets/templates/index.gohtml",
    "content": "<!DOCTYPE html>\n<html>\n<body>\n  <iframe\n    width=\"600\"\n    height=\"450\"\n    frameborder=\"0\"\n    style=\"border:0\"\n    src=\"https://www.google.com/maps/embed/v1/place?q={{.Latitude}}%20{{.Longitude}}&key={{.Key}}\" \n    allowfullscreen></iframe>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/51_appengine-introduction/03_google-maps-api/hello.go",
    "content": "package main\n\nimport (\n\t\"github.com/rwcarlsen/goexif/exif\"\n\t\"html/template\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n)\n\nconst GoogleAPIKey = \"AIzaSyDpMNCWNz2UENVGQOS6zMFvtLsXn0zMBf4\"\n\nvar tpls *template.Template\n\nfunc init() {\n\tvar err error\n\ttpls, err = template.ParseFiles(\"assets/templates/index.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\thttp.HandleFunc(\"/\", handleIndex)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\n\tsrc, _ := os.Open(\"assets/img/IMG_20150714_191905.jpg\")\n\tdefer src.Close()\n\tx, _ := exif.Decode(src)\n\tlat, lon, _ := x.LatLong()\n\n\tvar model struct {\n\t\tLatitude, Longitude float64\n\t\tKey                 string\n\t}\n\tmodel.Latitude = lat\n\tmodel.Longitude = lon\n\tmodel.Key = GoogleAPIKey\n\terr := tpls.ExecuteTemplate(res, \"index.gohtml\", model)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/51_appengine-introduction/04_SERVICE_users/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /admin/.*\n  script: _go_app\n  login: admin\n- url: /.*\n  script: _go_app\n  login: required\n"
  },
  {
    "path": "27_code-in-process/51_appengine-introduction/04_SERVICE_users/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/user\"\n)\n\nfunc index(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\turl, _ := user.LogoutURL(ctx, \"/\")\n\tres.Header().Set(\"Content-Type\", \"text/html\")\n\tfmt.Fprintf(res, `Welcome, %s! (<a href=\"%s\">sign out</a>)`, u, url)\n\n}\n\nfunc admin(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\turl, _ := user.LogoutURL(ctx, \"/\")\n\tres.Header().Set(\"Content-Type\", \"text/html\")\n\tfmt.Fprintf(res, `Welcome ADMIN, %s! (<a href=\"%s\">sign out</a>)`, u, url)\n\n}\n\nfunc init() {\n\thttp.HandleFunc(\"/\", index)\n\thttp.HandleFunc(\"/admin/\", admin)\n}\n"
  },
  {
    "path": "27_code-in-process/51_appengine-introduction/05_GORILLA_photo-blog/app.yaml",
    "content": "application: photoblog-1008\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app"
  },
  {
    "path": "27_code-in-process/51_appengine-introduction/05_GORILLA_photo-blog/assets/templates/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n</head>\n<body>\n<h1><a href=\"http://localhost:8080/logout\">LOG OUT</a></h1>\n<p><img src=\"/assets/imgs/01.jpg\"></p>\n<h1>ADD PHOTO</h1>\n<form method=\"POST\" action=\"http://localhost:8080/\" enctype=\"multipart/form-data\">\n    <input type=\"file\" name=\"data\" id=\"data\">\n    <input type=\"submit\">\n</form>\n<p>\n    {{range .}}\n    <img src=\"/assets/imgs/{{.}}\">\n    {{end}}\n</p>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/51_appengine-introduction/05_GORILLA_photo-blog/assets/templates/login.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n</head>\n<body>\n<h1>LOG IN</h1>\n<form method=\"post\" action=\"http://localhost:8080/login\">\n    <h3>User name</h3>\n    <input type=\"text\" name=\"userName\" id=\"userName\">\n    <h3>Password</h3>\n    <input type=\"text\" name=\"password\" id=\"password\">\n    <br>\n    <input type=\"submit\">\n    <input type=\"submit\" name=\"logout\" value=\"logout\">\n</form>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/51_appengine-introduction/05_GORILLA_photo-blog/main.go",
    "content": "package blog\n\nimport (\n\t\"crypto/sha1\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/gorilla/context\"\n\t\"github.com/gorilla/sessions\"\n\t\"html/template\"\n\t\"io\"\n\t\"mime/multipart\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\nvar tpl *template.Template\nvar store = sessions.NewCookieStore([]byte(\"secret-password\"))\n\nfunc init() {\n\ttpl, _ = template.ParseGlob(\"assets/templates/*.html\")\n\tmux := http.DefaultServeMux\n\tmux.HandleFunc(\"/\", index)\n\tmux.HandleFunc(\"/login\", login)\n\tmux.HandleFunc(\"/logout\", logout)\n\tmux.Handle(\"/assets/imgs/\", http.StripPrefix(\"/assets/imgs\", http.FileServer(http.Dir(\"./assets/imgs\"))))\n\tmux.Handle(\"/favicon.ico\", http.NotFoundHandler())\n}\n\nfunc index(res http.ResponseWriter, req *http.Request) {\n\tdefer context.Clear(req)\n\tsession, _ := store.Get(req, \"session\")\n\t// authenticate\n\tif session.Values[\"loggedin\"] == \"false\" || session.Values[\"loggedin\"] == nil {\n\t\thttp.Redirect(res, req, \"/login\", 302)\n\t\treturn\n\t}\n\t// upload photo\n\tsrc, hdr, err := req.FormFile(\"data\")\n\tif req.Method == \"POST\" && err == nil {\n\t\tuploadPhoto(src, hdr, session)\n\t}\n\t// save session\n\tsession.Save(req, res)\n\t// get photos\n\tdata := getPhotos(session)\n\t// execute template\n\ttpl.ExecuteTemplate(res, \"index.html\", data)\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request) {\n\tdefer context.Clear(req)\n\tsession, _ := store.Get(req, \"session\")\n\tsession.Values[\"loggedin\"] = \"false\"\n\tsession.Save(req, res)\n\thttp.Redirect(res, req, \"/login\", 302)\n}\n\nfunc login(res http.ResponseWriter, req *http.Request) {\n\tdefer context.Clear(req)\n\tsession, _ := store.Get(req, \"session\")\n\tif req.Method == \"POST\" && req.FormValue(\"password\") == \"secret\" {\n\t\tsession.Values[\"loggedin\"] = \"true\"\n\t\tsession.Save(req, res)\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t\treturn\n\t}\n\t// execute template\n\ttpl.ExecuteTemplate(res, \"login.html\", nil)\n}\n\nfunc uploadPhoto(src multipart.File, hdr *multipart.FileHeader, session *sessions.Session) {\n\tdefer src.Close()\n\tfName := getSha(src) + \".jpg\"\n\twd, _ := os.Getwd()\n\tpath := filepath.Join(wd, \"assets\", \"imgs\", fName)\n\tdst, _ := os.Create(path)\n\tdefer dst.Close()\n\tsrc.Seek(0, 0)\n\tio.Copy(dst, src)\n\taddPhoto(fName, session)\n}\n\nfunc getSha(src multipart.File) string {\n\th := sha1.New()\n\tio.Copy(h, src)\n\treturn fmt.Sprintf(\"%x\", h.Sum(nil))\n}\n\nfunc addPhoto(fName string, session *sessions.Session) {\n\tdata := getPhotos(session)\n\tdata = append(data, fName)\n\tbs, _ := json.Marshal(data)\n\tsession.Values[\"data\"] = string(bs)\n}\n\nfunc getPhotos(session *sessions.Session) []string {\n\tvar data []string\n\tjsonData := session.Values[\"data\"]\n\tif jsonData != nil {\n\t\tjson.Unmarshal([]byte(jsonData.(string)), &data)\n\t}\n\treturn data\n}\n"
  },
  {
    "path": "27_code-in-process/52_memcache/01_get-nil/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/52_memcache/01_get-nil/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n)\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\titem, _ := memcache.Get(ctx, \"some-key\")\n\tfmt.Fprintln(res, item)\n}\n"
  },
  {
    "path": "27_code-in-process/52_memcache/02_set_get/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/52_memcache/02_set_get/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n)\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\n\titem1 := memcache.Item{\n\t\tKey:   \"foo\",\n\t\tValue: []byte(\"bar\"),\n\t}\n\n\tmemcache.Set(ctx, &item1)\n\n\titem, _ := memcache.Get(ctx, \"foo\")\n\tif item != nil {\n\t\tfmt.Fprintln(res, string(item.Value))\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/52_memcache/03_expiration/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/52_memcache/03_expiration/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n)\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\n\t//\titem1 := memcache.Item{\n\t//\t\tKey:   \"foo\",\n\t//\t\tValue: []byte(\"bar\"),\n\t//\t\tExpiration: 10 * time.Second,\n\t//\t}\n\t//\n\t//\tmemcache.Set(ctx, &item1)\n\n\titem, _ := memcache.Get(ctx, \"foo\")\n\tif item != nil {\n\t\tfmt.Fprintln(res, string(item.Value))\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/52_memcache/04_increment/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n  login: required\n"
  },
  {
    "path": "27_code-in-process/52_memcache/04_increment/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"google.golang.org/appengine/user\"\n)\n\nfunc index(res http.ResponseWriter, req *http.Request) {\n\t// gets rid of favicon.ico requests and any other requests\n\tif req.URL.Path != \"/\" {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\n\tglobalCount, _ := memcache.Increment(ctx, \"GLOBAL\", 1, 0)\n\tuserCount, _ := memcache.Increment(ctx, u.Email+\".COUNTER\", 1, 0)\n\n\tfmt.Fprintln(res, \"Global\", globalCount)\n\tfmt.Fprintln(res, \"User\", userCount)\n\n}\n\nfunc init() {\n\thttp.HandleFunc(\"/\", index)\n}\n"
  },
  {
    "path": "27_code-in-process/52_memcache/05_memcache-session/01i/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/52_memcache/05_memcache-session/01i/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tcookie, _ := req.Cookie(\"sessionid\")\n\tfmt.Fprintln(res, cookie)\n}\n"
  },
  {
    "path": "27_code-in-process/52_memcache/05_memcache-session/02i/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/52_memcache/05_memcache-session/02i/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"net/http\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tcookie, _ := req.Cookie(\"sessionid\")\n\tif cookie == nil {\n\t\tid, _ := uuid.NewV4()\n\t\tcookie = &http.Cookie{\n\t\t\tName:  \"sessionid\",\n\t\t\tValue: id.String(),\n\t\t}\n\t\thttp.SetCookie(res, cookie)\n\t}\n\n\tfmt.Fprintln(res, cookie)\n}\n"
  },
  {
    "path": "27_code-in-process/52_memcache/05_memcache-session/03i/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/52_memcache/05_memcache-session/03i/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"net/http\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tcookie, _ := req.Cookie(\"sessionid\")\n\tif cookie == nil {\n\t\tid, _ := uuid.NewV4()\n\t\tcookie = &http.Cookie{\n\t\t\tName:  \"sessionid\",\n\t\t\tValue: id.String(),\n\t\t}\n\t\thttp.SetCookie(res, cookie)\n\t}\n\n\tctx := appengine.NewContext(req)\n\titem, _ := memcache.Get(ctx, cookie.Value)\n\tif item == nil {\n\t\titem = &memcache.Item{\n\t\t\tKey:   cookie.Value,\n\t\t\tValue: []byte(\"???\"),\n\t\t}\n\t}\n\n\tfmt.Fprintln(res, item)\n}\n"
  },
  {
    "path": "27_code-in-process/52_memcache/05_memcache-session/04i/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/52_memcache/05_memcache-session/04i/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"net/http\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tcookie, _ := req.Cookie(\"sessionid\")\n\tif cookie == nil {\n\t\tid, _ := uuid.NewV4()\n\t\tcookie = &http.Cookie{\n\t\t\tName:  \"sessionid\",\n\t\t\tValue: id.String(),\n\t\t}\n\t\thttp.SetCookie(res, cookie)\n\t}\n\n\tctx := appengine.NewContext(req)\n\titem, _ := memcache.Get(ctx, cookie.Value)\n\tif item == nil {\n\t\tm := map[string]string{\n\t\t\t\"email\": \"test@example.com\",\n\t\t}\n\t\tbs, _ := json.Marshal(m)\n\n\t\titem = &memcache.Item{\n\t\t\tKey:   cookie.Value,\n\t\t\tValue: bs,\n\t\t}\n\t}\n\tfmt.Fprintln(res, string(item.Value))\n}\n"
  },
  {
    "path": "27_code-in-process/52_memcache/05_memcache-session/05i/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/52_memcache/05_memcache-session/05i/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"net/http\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tcookie, _ := req.Cookie(\"sessionid\")\n\tif cookie == nil {\n\t\tid, _ := uuid.NewV4()\n\t\tcookie = &http.Cookie{\n\t\t\tName:  \"sessionid\",\n\t\t\tValue: id.String(),\n\t\t}\n\t\thttp.SetCookie(res, cookie)\n\t}\n\n\tctx := appengine.NewContext(req)\n\titem, _ := memcache.Get(ctx, cookie.Value)\n\tif item == nil {\n\t\tm := map[string]string{\n\t\t\t\"email\": \"test@example.com\",\n\t\t}\n\t\tbs, _ := json.Marshal(m)\n\n\t\titem = &memcache.Item{\n\t\t\tKey:   cookie.Value,\n\t\t\tValue: bs,\n\t\t}\n\t\tmemcache.Set(ctx, item)\n\t}\n\n\tvar m map[string]string\n\tjson.Unmarshal(item.Value, &m)\n\n\tfmt.Fprintln(res, m)\n\n}\n"
  },
  {
    "path": "27_code-in-process/52_memcache/05_memcache-session/06_photo-blog_UNFINISHED/app.yaml",
    "content": "application: photoblog-1008\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app"
  },
  {
    "path": "27_code-in-process/52_memcache/05_memcache-session/06_photo-blog_UNFINISHED/assets/templates/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n</head>\n<body>\n<h1><a href=\"http://localhost:8080/logout\">LOG OUT</a></h1>\n<p><img src=\"/assets/imgs/01.jpg\"></p>\n<h1>ADD PHOTO</h1>\n<form method=\"POST\" action=\"http://localhost:8080/\" enctype=\"multipart/form-data\">\n    <input type=\"file\" name=\"data\" id=\"data\">\n    <input type=\"submit\">\n</form>\n<p>\n    {{range .}}\n    <img src=\"/assets/imgs/{{.}}\">\n    {{end}}\n</p>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/52_memcache/05_memcache-session/06_photo-blog_UNFINISHED/assets/templates/login.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n</head>\n<body>\n<h1>LOG IN</h1>\n<form method=\"post\" action=\"http://localhost:8080/login\">\n    <h3>User name</h3>\n    <input type=\"text\" name=\"userName\" id=\"userName\">\n    <h3>Password</h3>\n    <input type=\"text\" name=\"password\" id=\"password\">\n    <br>\n    <input type=\"submit\">\n    <input type=\"submit\" name=\"logout\" value=\"logout\">\n</form>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/52_memcache/05_memcache-session/06_photo-blog_UNFINISHED/main.go",
    "content": "package blog\n\nimport (\n\t\"crypto/sha1\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"html/template\"\n\t\"io\"\n\t\"mime/multipart\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\ntype Data struct {\n\temail string\n\tloggedin string\n\tpictures []string\n}\n\nvar tpl *template.Template\n\nfunc init() {\n\ttpl, _ = template.ParseGlob(\"assets/templates/*.html\")\n\tmux := http.DefaultServeMux\n\tmux.HandleFunc(\"/\", index)\n\tmux.HandleFunc(\"/login\", login)\n\tmux.HandleFunc(\"/logout\", logout)\n\tmux.Handle(\"/assets/imgs/\", http.StripPrefix(\"/assets/imgs\", http.FileServer(http.Dir(\"./assets/imgs\"))))\n\tmux.Handle(\"/favicon.ico\", http.NotFoundHandler())\n}\n\nfunc index(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\t// get cookie UUID, or set\n\tcookie, _ := req.Cookie(\"sessionid\")\n\tif cookie == nil {\n\t\tcookie = createCookie()\n\t\thttp.SetCookie(res, cookie)\n\t}\n\t// get memcache session data\n\titem, _ := memcache.Get(ctx, cookie.Value)\n\tif item == nil {\n\t\thttp.Redirect(res, req, \"/login\", 302)\n\t\treturn\n\t}\n\t// unmarshal\n\tvar m Data{}\n\tjson.Unmarshal(item.Value, &m)\n\t// authenticate\n\tif m[\"loggedin\"] == \"false\" || m[\"loggedin\"] == \"\" {\n\t\thttp.Redirect(res, req, \"/login\", 302)\n\t\treturn\n\t}\n\t// upload photo\n\tif req.Method == \"POST\" {\n\t\tsrc, hdr, err := req.FormFile(\"data\")\n\t\tif err == nil {\n\t\t\tm = uploadPhoto(m, src, hdr)\n\t\t}\n\t}\n\t// save session\n\tbs, _ := json.Marshal(m)\n\titem.Value = bs\n\tmemcache.Set(ctx, item)\n\t// get photos\n\tdata := getPhotos(m)\n\t// execute template\n\ttpl.ExecuteTemplate(res, \"index.html\", data)\n}\n\nfunc createCookie() *http.Cookie {\n\tid, _ := uuid.NewV4()\n\treturn &http.Cookie{\n\t\tName:  \"sessionid\",\n\t\tValue: id.String(),\n\t}\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request) {\n\t// get cookie UUID, or set\n\tcookie, _ := req.Cookie(\"sessionid\")\n\tif cookie == nil {\n\t\thttp.Redirect(res, req, \"/login\", 302)\n\t}\n\tcookie.MaxAge = -1\n\thttp.SetCookie(res, cookie)\n\thttp.Redirect(res, req, \"/login\", 302)\n}\n\nfunc login(res http.ResponseWriter, req *http.Request) {\n\tif req.Method == \"POST\" && req.FormValue(\"password\") == \"secret\" {\n\t\tsetMemcache(res, req)\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t\treturn\n\t}\n\t// execute template\n\ttpl.ExecuteTemplate(res, \"login.html\", nil)\n}\n\nfunc setMemcache(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\t// get cookie UUID, or set\n\tcookie, _ := req.Cookie(\"sessionid\")\n\tif cookie == nil {\n\t\tcookie = createCookie()\n\t\thttp.SetCookie(res, cookie)\n\t}\n\tm := map[string]string{\n\t\t\"username\": req.FormValue(\"userName\"),\n\t\t\"loggedin\": \"true\",\n\t\t\"photos\":   []string{},\n\t}\n\tbs, _ := json.Marshal(m)\n\titem := &memcache.Item{\n\t\tKey:   cookie.Value,\n\t\tValue: bs,\n\t}\n\tmemcache.Set(ctx, item)\n}\n\nfunc uploadPhoto(m map[string]string, src multipart.File, hdr *multipart.FileHeader) map[string]string {\n\tdefer src.Close()\n\tfName := getSha(src) + \".jpg\"\n\twd, _ := os.Getwd()\n\tpath := filepath.Join(wd, \"assets\", \"imgs\", fName)\n\tdst, _ := os.Create(path)\n\tdefer dst.Close()\n\tsrc.Seek(0, 0)\n\tio.Copy(dst, src)\n\taddPhoto(m, fName)\n\treturn m\n}\n\nfunc getSha(src multipart.File) string {\n\th := sha1.New()\n\tio.Copy(h, src)\n\treturn fmt.Sprintf(\"%x\", h.Sum(nil))\n}\n\nfunc addPhoto(m map[string]string, fName string) {\n\tdata := getPhotos(m)\n\tdata = append(data, fName)\n\tfmt.Println(\"addPhoto data: \", data) // DEBUGGING\n\tbs, _ := json.Marshal(data)\n\tfmt.Println(\"addPhoto bs: \", bs) // DEBUGGING\n\tm[\"data\"] = string(bs)\n}\n\nfunc getPhotos(m map[string]string) []string {\n\tvar data []string\n\tjsonData := m[\"data\"]\n\tfmt.Println(\"getPhotos jsonData: \", jsonData) // DEBUGGING\n\tif jsonData != nil {\n\t\tjson.Unmarshal([]byte(jsonData.(string)), &data)\n\t}\n\tfmt.Println(\"getPhotos data: \", data) // DEBUGGING\n\treturn data\n}\n"
  },
  {
    "path": "27_code-in-process/53_datastore/00_appengine-documentation-example/01_with-modifications/app.yaml",
    "content": "application: photoblog-1008\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/53_datastore/00_appengine-documentation-example/01_with-modifications/main.go",
    "content": "package example\n\nimport (\n\t\"fmt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"net/http\"\n)\n\ntype Entity struct {\n\tValue string\n}\n\nfunc init() {\n\thttp.HandleFunc(\"/\", home)\n}\n\nfunc home(w http.ResponseWriter, r *http.Request) {\n\tc := appengine.NewContext(r)\n\te := new(Entity)\n\te.Value = \"Todd\"\n\tk := datastore.NewKey(c, \"Entity\", \"todd.mcleod@fresnocitycollege.edu\", 0, nil)\n\n\tif _, err := datastore.Put(c, k, e); err != nil {\n\t\thttp.Error(w, err.Error(), 500)\n\t\treturn\n\t}\n\n\tw.Header().Set(\"Content-Type\", \"text/plain; charset=utf-8\")\n\tfmt.Fprintf(w, \"new=%q\\n\", e.Value)\n}\n"
  },
  {
    "path": "27_code-in-process/53_datastore/00_appengine-documentation-example/02_as-in-documentation/app.yaml",
    "content": "application: photoblog-1008\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/53_datastore/00_appengine-documentation-example/02_as-in-documentation/main.go",
    "content": "package example\n\nimport (\n\t\"fmt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"net/http\"\n)\n\ntype Entity struct {\n\tValue string\n}\n\nfunc init() {\n\thttp.HandleFunc(\"/\", home)\n}\n\nfunc home(w http.ResponseWriter, r *http.Request) {\n\tc := appengine.NewContext(r)\n\n\tk := datastore.NewKey(c, \"Entity\", \"todd.mcleod@fresnocitycollege.edu\", 0, nil)\n\te := new(Entity)\n\tif err := datastore.Get(c, k, e); err != nil {\n\t\thttp.Error(w, err.Error(), 500)\n\t\treturn\n\t}\n\n\told := e.Value\n\te.Value = r.URL.Path\n\n\tif _, err := datastore.Put(c, k, e); err != nil {\n\t\thttp.Error(w, err.Error(), 500)\n\t\treturn\n\t}\n\n\tw.Header().Set(\"Content-Type\", \"text/plain; charset=utf-8\")\n\tfmt.Fprintf(w, \"old=%q\\nnew=%q\\n\", old, e.Value)\n}\n"
  },
  {
    "path": "27_code-in-process/53_datastore/00_appengine-documentation-example/03_no-favicon/app.yaml",
    "content": "application: photoblog-1008\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/53_datastore/00_appengine-documentation-example/03_no-favicon/main.go",
    "content": "package example\n\nimport (\n\t\"fmt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"net/http\"\n)\n\ntype Entity struct {\n\tValue string\n}\n\nfunc init() {\n\thttp.HandleFunc(\"/\", home)\n}\n\nfunc home(w http.ResponseWriter, r *http.Request) {\n\tif r.URL.Path == \"/favicon.ico\" {\n\t\thttp.NotFound(w, r)\n\t\treturn\n\t}\n\n\tc := appengine.NewContext(r)\n\n\tk := datastore.NewKey(c, \"Entity\", \"todd.mcleod@fresnocitycollege.edu\", 0, nil)\n\te := new(Entity)\n\tif err := datastore.Get(c, k, e); err != nil {\n\t\thttp.Error(w, err.Error(), 500)\n\t\treturn\n\t}\n\n\told := e.Value\n\te.Value = r.URL.Path\n\n\tif _, err := datastore.Put(c, k, e); err != nil {\n\t\thttp.Error(w, err.Error(), 500)\n\t\treturn\n\t}\n\n\tw.Header().Set(\"Content-Type\", \"text/plain; charset=utf-8\")\n\tfmt.Fprintf(w, \"old=%q\\nnew=%q\\n\", old, e.Value)\n}\n"
  },
  {
    "path": "27_code-in-process/53_datastore/00_appengine-documentation-example/04_no-favicon/app.yaml",
    "content": "application: photoblog-1008\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/53_datastore/00_appengine-documentation-example/04_no-favicon/main.go",
    "content": "package example\n\nimport (\n\t\"fmt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"net/http\"\n)\n\ntype Entity struct {\n\tValue string\n}\n\nfunc init() {\n\thttp.HandleFunc(\"/\", home)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n}\n\nfunc home(w http.ResponseWriter, r *http.Request) {\n\n\tc := appengine.NewContext(r)\n\n\tk := datastore.NewKey(c, \"Entity\", \"todd.mcleod@fresnocitycollege.edu\", 0, nil)\n\te := new(Entity)\n\tif err := datastore.Get(c, k, e); err != nil {\n\t\thttp.Error(w, err.Error(), 500)\n\t\treturn\n\t}\n\n\told := e.Value\n\te.Value = r.URL.Path\n\n\tif _, err := datastore.Put(c, k, e); err != nil {\n\t\thttp.Error(w, err.Error(), 500)\n\t\treturn\n\t}\n\n\tw.Header().Set(\"Content-Type\", \"text/plain; charset=utf-8\")\n\tfmt.Fprintf(w, \"old=%q\\nnew=%q\\n\", old, e.Value)\n}\n"
  },
  {
    "path": "27_code-in-process/53_datastore/01_partial-example_does-not-run/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/user\"\n)\n\ntype Employee struct {\n\tName     string\n\tRole     string\n\tHireDate time.Time\n\tAccount  string\n}\n\nfunc handle(w http.ResponseWriter, r *http.Request) {\n\tc := appengine.NewContext(r)\n\n\te1 := Employee{\n\t\tName:     \"Joe Citizen\",\n\t\tRole:     \"Manager\",\n\t\tHireDate: time.Now(),\n\t\tAccount:  user.Current(c).String(),\n\t}\n\n\tkey, err := datastore.Put(c, datastore.NewIncompleteKey(c, \"employee\", nil), &e1)\n\tif err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tvar e2 Employee\n\tif err = datastore.Get(c, key, &e2); err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tfmt.Fprintf(w, \"Stored and retrieved the Employee named %q\", e2.Name)\n}\n"
  },
  {
    "path": "27_code-in-process/53_datastore/02/01_put/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/53_datastore/02/01_put/words.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n}\n\ntype Word struct {\n\tTerm       string\n\tDefinition string\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tif req.Method == \"POST\" {\n\t\tterm := req.FormValue(\"term\")\n\t\tdefinition := req.FormValue(\"definition\")\n\n\t\tctx := appengine.NewContext(req)\n\t\tkey := datastore.NewIncompleteKey(ctx, \"Word\", nil)\n\n\t\tentity := Word{\n\t\t\tTerm:       term,\n\t\t\tDefinition: definition,\n\t\t}\n\n\t\t_, err := datastore.Put(ctx, key, &entity)\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t}\n\tres.Header().Set(\"Content-Type\", \"text/html\")\n\tfmt.Fprintln(res, `\n\t\t\t<form method=\"POST\" action=\"/words/\">\n\t\t\t\t<input type=\"text\" name=\"term\">\n\t\t\t\t<textarea name=\"definition\"></textarea>\n\t\t\t\t<input type=\"submit\">\n\t\t\t</form>`)\n}\n"
  },
  {
    "path": "27_code-in-process/53_datastore/02/02/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/53_datastore/02/02/words.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n}\n\ntype Word struct {\n\tTerm       string\n\tDefinition string\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tif req.Method == \"POST\" {\n\t\tterm := req.FormValue(\"term\")\n\t\tdefinition := req.FormValue(\"definition\")\n\n\t\tctx := appengine.NewContext(req)\n\t\tkey := datastore.NewKey(ctx, \"Word\", term, 0, nil)\n\n\t\tentity := &Word{\n\t\t\tTerm:       term,\n\t\t\tDefinition: definition,\n\t\t}\n\n\t\t_, err := datastore.Put(ctx, key, entity)\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t}\n\tres.Header().Set(\"Content-Type\", \"text/html\")\n\tfmt.Fprintln(res, `\n\t\t\t<form method=\"POST\" action=\"/words/\">\n\t\t\t\t<input type=\"text\" name=\"term\">\n\t\t\t\t<textarea name=\"definition\"></textarea>\n\t\t\t\t<input type=\"submit\">\n\t\t\t</form>`)\n}\n"
  },
  {
    "path": "27_code-in-process/53_datastore/02/03_get/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/53_datastore/02/03_get/words.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleWords)\n}\n\ntype Word struct {\n\tTerm       string\n\tDefinition string\n}\n\nfunc handleWords(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path != \"/\" {\n\t\tterm := strings.Split(req.URL.Path, \"/\")[1]\n\t\tshowWord(res, req, term)\n\t\treturn\n\t}\n\n\tif req.Method == \"POST\" {\n\t\tsaveWord(res, req)\n\t\treturn\n\t}\n\n\tlistWords(res, req)\n}\n\nfunc listWords(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tq := datastore.NewQuery(\"Word\").Order(\"Term\")\n\n\thtml := \"\"\n\n\titerator := q.Run(ctx)\n\tfor {\n\t\tvar entity Word\n\t\t_, err := iterator.Next(&entity)\n\t\tif err == datastore.Done {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\thtml += `\n\t\t\t<dt>` + entity.Term + `</dt>\n\t\t\t<dd>` + entity.Definition + `</dd>\n\t\t`\n\t}\n\n\tres.Header().Set(\"Content-Type\", \"text/html\")\n\tfmt.Fprintln(res, `\n\t\t\t<dl>\n\t\t\t\t`+html+`\n\t\t\t</dl>\n\t\t\t<form method=\"POST\">\n\t\t\t\t<input type=\"text\" name=\"term\">\n\t\t\t\t<textarea name=\"definition\"></textarea>\n\t\t\t\t<input type=\"submit\">\n\t\t\t</form>\n\t\t\t`)\n}\n\nfunc showWord(res http.ResponseWriter, req *http.Request, term string) {\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Word\", term, 0, nil)\n\tvar entity Word\n\terr := datastore.Get(ctx, key, &entity)\n\tif err == datastore.ErrNoSuchEntity {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t} else if err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tres.Header().Set(\"Content-Type\", \"text/html\")\n\tfmt.Fprintln(res, `\n\t\t<dl>\n\t\t\t<dt>`+entity.Term+`</dt>\n\t\t\t<dd>`+entity.Definition+`</dd>\n\t\t</dl>\n\t`)\n}\n\nfunc saveWord(res http.ResponseWriter, req *http.Request) {\n\tterm := req.FormValue(\"term\")\n\tdefinition := req.FormValue(\"definition\")\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Word\", term, 0, nil)\n\tentity := Word{\n\t\tTerm:       term,\n\t\tDefinition: definition,\n\t}\n\n\t_, err := datastore.Put(ctx, key, &entity)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\thttp.Redirect(res, req, \"/\", 302)\n}\n"
  },
  {
    "path": "27_code-in-process/53_datastore/02/04_query-filter/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/53_datastore/02/04_query-filter/words.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleWords)\n}\n\ntype Word struct {\n\tTerm       string\n\tDefinition string\n}\n\nfunc handleWords(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path != \"/\" {\n\t\tterm := strings.Split(req.URL.Path, \"/\")[1]\n\t\tshowWord(res, req, term)\n\t\treturn\n\t}\n\n\tif req.Method == \"POST\" {\n\t\tsaveWord(res, req)\n\t\treturn\n\t}\n\n\tlistWords(res, req)\n}\n\nfunc listWords(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tq := datastore.NewQuery(\"Word\").\n\t\tFilter(\"Term >=\", \"c\").\n\t\tFilter(\"Term <\", \"e\").\n\t\tOrder(\"Term\")\n\n\thtml := \"\"\n\n\titerator := q.Run(ctx)\n\tfor {\n\t\tvar entity Word\n\t\t_, err := iterator.Next(&entity)\n\t\tif err == datastore.Done {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\thtml += `\n\t\t\t<dt>` + entity.Term + `</dt>\n\t\t\t<dd>` + entity.Definition + `</dd>\n\t\t`\n\t}\n\n\tres.Header().Set(\"Content-Type\", \"text/html\")\n\tfmt.Fprintln(res, `\n\t\t\t<dl>\n\t\t\t\t`+html+`\n\t\t\t</dl>\n\t\t\t<form method=\"POST\">\n\t\t\t\t<input type=\"text\" name=\"term\">\n\t\t\t\t<textarea name=\"definition\"></textarea>\n\t\t\t\t<input type=\"submit\">\n\t\t\t</form>\n\t\t\t`)\n}\n\nfunc showWord(res http.ResponseWriter, req *http.Request, term string) {\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Word\", term, 0, nil)\n\tvar entity Word\n\terr := datastore.Get(ctx, key, &entity)\n\tif err == datastore.ErrNoSuchEntity {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t} else if err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tres.Header().Set(\"Content-Type\", \"text/html\")\n\tfmt.Fprintln(res, `\n\t\t<dl>\n\t\t\t<dt>`+entity.Term+`</dt>\n\t\t\t<dd>`+entity.Definition+`</dd>\n\t\t</dl>\n\t`)\n}\n\nfunc saveWord(res http.ResponseWriter, req *http.Request) {\n\tterm := req.FormValue(\"term\")\n\tdefinition := req.FormValue(\"definition\")\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Word\", term, 0, nil)\n\tentity := &Word{\n\t\tTerm:       term,\n\t\tDefinition: definition,\n\t}\n\n\t_, err := datastore.Put(ctx, key, entity)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\thttp.Redirect(res, req, \"/\", 302)\n}\n"
  },
  {
    "path": "27_code-in-process/53_datastore/02/05_query-ancestor/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/53_datastore/02/05_query-ancestor/words.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"log\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleAnimals)\n\thttp.HandleFunc(\"/ateprocess\", ateProcess)\n}\n\ntype Animal struct {\n\tSpecies     string\n\tDescription string\n}\n\ntype Ate struct {\n\tFoodItem string\n}\n\nfunc handleAnimals(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path != \"/\" {\n\t\tterm := strings.Split(req.URL.Path, \"/\")[1]\n\t\tshowAnimal(res, req, term)\n\t\treturn\n\t}\n\tif req.Method == \"POST\" {\n\t\tsaveAnimal(res, req)\n\t\treturn\n\t}\n\tlistAnimals(res, req)\n}\n\nfunc listAnimals(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tq := datastore.NewQuery(\"Animal\").Order(\"Species\")\n\n\thtml := \"\"\n\n\titerator := q.Run(ctx)\n\tfor {\n\t\tvar entity Animal\n\t\t_, err := iterator.Next(&entity)\n\t\tif err == datastore.Done {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\thtml += `\n\t\t\t<dt>` + entity.Species + `</dt>\n\t\t\t<dd>` + entity.Description + `</dd>\n\t\t`\n\t}\n\n\tres.Header().Set(\"Content-Type\", \"text/html\")\n\tfmt.Fprintln(res, `\n\t\t\t<dl>\n\t\t\t\t`+html+`\n\t\t\t</dl>\n\t\t\t<form method=\"POST\">\n\t\t\t\t<input type=\"text\" name=\"term\">\n\t\t\t\t<textarea name=\"definition\"></textarea>\n\t\t\t\t<input type=\"submit\">\n\t\t\t</form>\n\t\t\t`)\n}\n\nfunc showAnimal(res http.ResponseWriter, req *http.Request, term string) {\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Animal\", term, 0, nil)\n\tvar entity Animal\n\terr := datastore.Get(ctx, key, &entity)\n\tif err == datastore.ErrNoSuchEntity {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t} else if err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// have they eaten something?\n\tq := datastore.NewQuery(\"Ate\").Ancestor(key)\n\thtml := \"\"\n\titerator := q.Run(ctx)\n\tfor {\n\t\tvar entity Ate\n\t\t_, err := iterator.Next(&entity)\n\t\tif err == datastore.Done {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\thtml += `\n\t\t\t<li>` + entity.FoodItem + `</li>\n\t\t`\n\t}\n\n\tres.Header().Set(\"Content-Type\", \"text/html\")\n\tfmt.Fprintln(res, `\n\t\t<dl>\n\t\t\t<dt>`+entity.Species+`</dt>\n\t\t\t<dd>`+entity.Description+`</dd>\n\t\t</dl>\n\t\t<h1>This Animal Just Ate:</h1>\n\t\t<form method=\"POST\" action=\"ateprocess\">\n\t\t\t<textarea name=\"fooditem\"></textarea>\n\t\t\t<input type=\"hidden\" name=\"eater\" value=\"`+term+`\">\n\t\t\t<input type=\"submit\">\n\t\t</form>\n\t\t<h1>This Animal Has Already Eaten:</h1>\n\t\t<ol>`+html+`</ol>\n\t`)\n}\n\nfunc saveAnimal(res http.ResponseWriter, req *http.Request) {\n\tterm := req.FormValue(\"term\")\n\tdefinition := req.FormValue(\"definition\")\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Animal\", term, 0, nil)\n\tentity := Animal{\n\t\tSpecies:     term,\n\t\tDescription: definition,\n\t}\n\n\t_, err := datastore.Put(ctx, key, &entity)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc ateProcess(res http.ResponseWriter, req *http.Request) {\n\tfooditem := req.FormValue(\"fooditem\")\n\teater := req.FormValue(\"eater\")\n\tctx := appengine.NewContext(req)\n\teaterKey := datastore.NewKey(ctx, \"Animal\", eater, 0, nil)\n\tkey := datastore.NewIncompleteKey(ctx, \"Ate\", eaterKey)\n\tentity := Ate{\n\t\tFoodItem: fooditem,\n\t}\n\tlog.Println(fooditem)\n\tlog.Println(entity)\n\tlog.Println(&entity)\n\t_, err := datastore.Put(ctx, key, &entity)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\thttp.Redirect(res, req, \"/\", 302)\n}\n"
  },
  {
    "path": "27_code-in-process/53_datastore/03_users_datastore_exercise/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n  login: required\n"
  },
  {
    "path": "27_code-in-process/53_datastore/03_users_datastore_exercise/main.go",
    "content": "package main\n\nimport (\n\t\"html/template\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/user\"\n)\n\ntype Profile struct {\n\tEmail     string\n\tFirstName string\n\tLastName  string\n\tAge       int\n}\n\nfunc init() {\n\trouter := httprouter.New()\n\trouter.GET(\"/\", showIndex)\n\trouter.GET(\"/profile\", showProfile)\n\trouter.POST(\"/profile\", updateProfile)\n\thttp.Handle(\"/\", router)\n}\n\nfunc showIndex(res http.ResponseWriter, req *http.Request, params httprouter.Params) {\n\thttp.Redirect(res, req, \"/profile\", 302)\n}\n\nfunc showProfile(res http.ResponseWriter, req *http.Request, params httprouter.Params) {\n\ttpl, err := template.ParseFiles(\"templates/templates.gohtml\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\tkey := datastore.NewKey(ctx, \"Profile\", u.Email, 0, nil)\n\tvar profile Profile\n\terr = datastore.Get(ctx, key, &profile)\n\tif err != nil {\n\t\tprofile.Email = u.Email\n\t}\n\n\terr = tpl.ExecuteTemplate(res, \"edit-form\", profile)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t}\n}\n\nfunc updateProfile(res http.ResponseWriter, req *http.Request, params httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\tkey := datastore.NewKey(ctx, \"Profile\", u.Email, 0, nil)\n\tage, _ := strconv.Atoi(req.FormValue(\"age\"))\n\tprofile := Profile{\n\t\tEmail:     u.Email,\n\t\tFirstName: req.FormValue(\"firstname\"),\n\t\tLastName:  req.FormValue(\"lastname\"),\n\t\tAge:       age,\n\t}\n\t_, err := datastore.Put(ctx, key, &profile)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t}\n\thttp.Redirect(res, req, \"/profile\", 302)\n}\n"
  },
  {
    "path": "27_code-in-process/53_datastore/03_users_datastore_exercise/templates/templates.gohtml",
    "content": "{{define \"edit-form\"}}<!DOCTYPE html>\n<html>\n  <head>\n    <title>User Profile</title>\n    <style>\n      html, body {\n        padding: 0;\n        margin: 0;\n        font-size: 18px;\n      }\n      body {\n        background-color: #EAEAEA;\n      }\n      * {\n        box-sizing: border-box;\n      }\n      form {\n        border-radius: 8px;\n        padding: 16px;\n        border: 2px solid #AAA;\n        background: white;\n        width: 400px;\n        margin: 32px auto;\n\n      }\n    </style>\n  </head>\n  <body>\n    <form method=\"POST\">\n      <table>\n        <tr>\n          <td><label for=\"email\">Email</label></td>\n          <td><input type=\"email\"\n                     readonly=\"readonly\"\n                     id=\"email\"\n                     name=\"email\"\n                     value=\"{{.Email}}\"></td>\n        </tr>\n        <tr>\n          <td><label for=\"firstname\">First Name</label></td>\n          <td><input type=\"text\"\n                     name=\"firstname\"\n                     id=\"firstname\"\n                     value=\"{{.FirstName}}\"></td>\n        </tr>\n        <tr>\n          <td><label for=\"lastname\">Last Name</label></td>\n          <td><input type=\"text\"\n                     name=\"lastname\"\n                     id=\"lastname\"\n                     value=\"{{.LastName}}\"></td>\n        </tr>\n        <tr>\n          <td><label for=\"age\">Age</label></td>\n          <td><input type=\"text\"\n                     name=\"age\"\n                     id=\"age\"\n                     value=\"{{.Age}}\"></td>\n        </tr>\n        <tr>\n          <td colspan=\"2\">\n            <input type=\"submit\" value=\"Update\">\n          </td>\n        </tr>\n      </table>\n    </form>\n  </body>\n</html>\n{{end}}\n"
  },
  {
    "path": "27_code-in-process/53_datastore/04_julien-schmidt-router/01/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {\n\tfmt.Fprint(w, \"Welcome!\\n\")\n}\n\nfunc Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {\n\tfmt.Fprintf(w, \"hello, %s!\\n\", ps.ByName(\"name\"))\n}\n\nfunc main() {\n\trouter := httprouter.New()\n\trouter.GET(\"/\", Index)\n\trouter.GET(\"/hello/:name\", Hello)\n\n\tlog.Fatal(http.ListenAndServe(\":8080\", router))\n}\n"
  },
  {
    "path": "27_code-in-process/53_datastore/04_julien-schmidt-router/02-with-appengine/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n  login: required\n"
  },
  {
    "path": "27_code-in-process/53_datastore/04_julien-schmidt-router/02-with-appengine/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"net/http\"\n)\n\nfunc Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {\n\tfmt.Fprint(w, \"Welcome!\\n\")\n}\n\nfunc Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {\n\tfmt.Fprintf(w, \"hello, %s!\\n\", ps.ByName(\"name\"))\n}\n\nfunc init() {\n\trouter := httprouter.New()\n\trouter.GET(\"/\", Index)\n\trouter.GET(\"/hello/:name\", Hello)\n\thttp.Handle(\"/\", router)\n}\n"
  },
  {
    "path": "27_code-in-process/54_AJAX/01/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n</head>\n<body>\n\n<span id=\"ajaxButton\" style=\"cursor: pointer; text-decoration: underline\">\n  Make a request\n</span>\n\n<script>\n    document.querySelector('#ajaxButton').onclick = function () {\n        makeRequest('test.html');\n    };\n\n    var httpRequest = new XMLHttpRequest();\n\n    function makeRequest(url) {\n        // make the request\n        httpRequest.open('GET', url);\n        httpRequest.send();\n        // listen for the response\n        // call alertContents function after we receive server response\n        httpRequest.onreadystatechange = alertContents;\n    }\n    \n    function alertContents() {\n        if (httpRequest.readyState === 4) {\n            if (httpRequest.status === 200) {\n                alert(httpRequest.responseText);\n            } else {\n                alert('There was a problem with the request.');\n            }\n        }\n    }\n</script>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/54_AJAX/01/test.html",
    "content": "I'm a test."
  },
  {
    "path": "27_code-in-process/54_AJAX/02_users_datastore_exercise_AJAX/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n  login: required\n"
  },
  {
    "path": "27_code-in-process/54_AJAX/02_users_datastore_exercise_AJAX/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"html/template\"\n\t\"net/http\"\n\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/user\"\n)\n\ntype Profile struct {\n\tEmail     string\n\tFirstName string\n\tLastName  string\n\tAge       int\n}\n\nfunc init() {\n\trouter := httprouter.New()\n\trouter.GET(\"/\", showIndex)\n\trouter.GET(\"/profile\", showProfile)\n\trouter.GET(\"/api/profile\", getAPIProfile)\n\trouter.POST(\"/api/profile\", updateAPIProfile)\n\thttp.Handle(\"/\", router)\n}\n\nfunc getAPIProfile(res http.ResponseWriter, req *http.Request, params httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\tkey := datastore.NewKey(ctx, \"Profile\", u.Email, 0, nil)\n\tvar profile Profile\n\terr := datastore.Get(ctx, key, &profile)\n\tif err != nil {\n\t\tprofile.Email = u.Email\n\t}\n\tjson.NewEncoder(res).Encode(profile)\n}\n\nfunc updateAPIProfile(res http.ResponseWriter, req *http.Request, params httprouter.Params) {\n\tvar profile Profile\n\tjson.NewDecoder(req.Body).Decode(&profile)\n\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\tkey := datastore.NewKey(ctx, \"Profile\", u.Email, 0, nil)\n\t_, err := datastore.Put(ctx, key, &profile)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t}\n}\n\nfunc showIndex(res http.ResponseWriter, req *http.Request, params httprouter.Params) {\n\thttp.Redirect(res, req, \"/profile\", 302)\n}\n\nfunc showProfile(res http.ResponseWriter, req *http.Request, params httprouter.Params) {\n\ttpl, err := template.ParseFiles(\"templates/templates.gohtml\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\terr = tpl.ExecuteTemplate(res, \"templates.gohtml\", nil)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/54_AJAX/02_users_datastore_exercise_AJAX/templates/templates.gohtml",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <title>User Profile</title>\n\n    <style>\n        html, body {\n            padding: 0;\n            margin: 0;\n            font-size: 18px;\n        }\n\n        body {\n            background-color: #EAEAEA;\n        }\n\n        * {\n            box-sizing: border-box;\n        }\n\n        form {\n            border-radius: 8px;\n            padding: 16px;\n            border: 2px solid #AAA;\n            background: white;\n            width: 400px;\n            margin: 32px auto;\n\n        }\n    </style>\n</head>\n<body>\n<form method=\"POST\" id=\"profile-form\">\n    <table>\n        <tr>\n            <td><label for=\"email\">Email</label></td>\n            <td><input type=\"email\"\n                       readonly=\"readonly\"\n                       id=\"email\"\n                       name=\"email\"></td>\n        </tr>\n        <tr>\n            <td><label for=\"firstname\">First Name</label></td>\n            <td><input type=\"text\"\n                       name=\"firstname\"\n                       id=\"firstname\"></td>\n        </tr>\n        <tr>\n            <td><label for=\"lastname\">Last Name</label></td>\n            <td><input type=\"text\"\n                       name=\"lastname\"\n                       id=\"lastname\"></td>\n        </tr>\n        <tr>\n            <td><label for=\"age\">Age</label></td>\n            <td><input type=\"text\"\n                       name=\"age\"\n                       id=\"age\"></td>\n        </tr>\n        <tr>\n            <td colspan=\"2\">\n                <input type=\"submit\" value=\"Update\">\n            </td>\n        </tr>\n    </table>\n</form>\n\n<script>\n\n    function getProfile() {\n        var xhr = new XMLHttpRequest();\n        xhr.open(\"GET\", \"/api/profile\");\n        xhr.send(null);\n        xhr.onreadystatechange = function () {\n            if (xhr.readyState === 4) {\n                var result = JSON.parse(xhr.responseText);\n                document.querySelector(\"#email\").value = result.Email;\n                document.querySelector(\"#lastname\").value = result.LastName;\n                document.querySelector(\"#firstname\").value = result.FirstName;\n                document.querySelector(\"#age\").value = result.Age;\n            }\n        };\n    }\n\n\n    var profileForm = document.querySelector(\"#profile-form\");\n    profileForm.onsubmit = function (evt) {\n        evt.preventDefault();\n\n        var lastName = document.querySelector(\"#lastname\").value;\n        var firstName = document.querySelector(\"#firstname\").value;\n        var email = document.querySelector(\"#email\").value;\n        var age = parseInt(document.querySelector(\"#age\").value);\n\n        var xhr = new XMLHttpRequest();\n        xhr.open(\"POST\", \"/api/profile\");\n        xhr.send(JSON.stringify({\n            LastName: lastName,\n            FirstName: firstName,\n            Email: email,\n            Age: age\n        }));\n\n        getProfile();\n    };\n\n\n    getProfile();\n\n</script>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/55_todo-list/01v_content-editable/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n  login: required\n"
  },
  {
    "path": "27_code-in-process/55_todo-list/01v_content-editable/assets/templates/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n    <link rel=\"stylesheet\" href=\"../css/reset.css\">\n    <link rel='stylesheet'\n          href='http://fonts.googleapis.com/css?family=Open+Sans|Merienda:700'>\n    <link rel=\"stylesheet\"\n          href=\"http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <style>\n\n        * {\n            box-sizing: border-box;\n        }\n\n        main {\n            display: flex;\n            flex-direction: row;\n            justify-content: center;\n            align-items: center;\n            /*border: 1px solid black;*/\n            margin: 10px;\n        }\n\n        article {\n            display: flex;\n            flex-direction: column;\n            justify-content: center;\n            align-items: center;\n            /*border: 1px solid black;*/\n            min-width: 600px;\n        }\n\n        section {\n            display: flex;\n            flex-direction: row;\n            justify-content: space-between;\n            align-items: center;\n            border: 1px solid #2ec371;\n            width: 100%;\n            padding: 7px 12px 7px 10px;\n            margin: 5px;\n            border-radius: 10px;\n        }\n\n        h1 {\n            font-family: 'Merienda', cursive;\n            font-size: 53px;\n            color: #2ec371;\n            margin: 10px;\n        }\n\n        h2 {\n            font-family: 'Open Sans', sans-serif;\n            font-size: 16px;\n            max-width: 500px;\n        }\n\n        #new-item {\n            color: gray;\n        }\n\n        .fa-minus-circle {\n            color: red;\n        }\n\n        .fa-plus-circle {\n            color: green;\n        }\n\n    </style>\n</head>\n<body>\n\n<main>\n    <article>\n        <h1>TO-DO</h1>\n        <div id=\"items\"></div>\n        <section>\n            <h2 id=\"new-item\" contenteditable=\"true\">add item</h2>\n            <a href=\"#\"><i class=\"fa fa-plus-circle fa-2x\" id=\"new\"></i></a>\n            <!--<i class=\"fa fa-minus-circle fa-2x\"></i>-->\n        </section>\n    </article>\n</main>\n\n<script>\n    // items: [{ Text: \"blah\", ID: 123456 }]\n    var CurrentItems = [];\n    var items = document.querySelector(\"#items\");\n    var newItem = document.querySelector('#new-item');\n    var article = document.querySelector('article');\n\n    // get items from server, then render them\n    function getItems() {\n        var xhr = new XMLHttpRequest();\n        xhr.open(\"GET\", \"/todo\");\n        xhr.send(null);\n        xhr.onreadystatechange = function () {\n            if (xhr.readyState === 4) {\n                CurrentItems = JSON.parse(xhr.responseText);\n                renderItems();\n            }\n        }\n    }\n    getItems();\n\n    function renderItems() {\n        // clear the html\n        items.innerHTML = \"\";\n        // create HTML structure for each item in <div id=\"items\">\n        //     <section>\n        //         <h2>\n        //         <a href=\"#\">\n        //             <i>\n        for (var i = 0; i < CurrentItems.length; i++) {\n            var section = document.createElement(\"section\");\n            var h2 = document.createElement(\"h2\");\n            var a = document.createElement(\"a\");\n            var icon = document.createElement(\"i\");\n            h2.textContent = CurrentItems[i].Text;\n            a.setAttribute(\"href\", \"#\");\n            icon.setAttribute(\"class\", \"fa fa-minus-circle fa-2x\");\n            icon.setAttribute(\"id\", CurrentItems[i].ID);\n            section.appendChild(h2);\n            a.appendChild(icon);\n            section.appendChild(a);\n            items.appendChild(section);\n        }\n    }\n\n    // clear placeholder text for new item\n    newItem.addEventListener('focus', function (e) {\n        window.setTimeout(function () {\n            e.target.textContent = '';\n        }, 100);\n    }, false);\n    //    this doesn't work - clears text but doesn't set cursor:\n    //     newItem.addEventListener('focus', function(){\n    //        newItem.textContent = '';\n    //     }, false);\n\n    // add new item\n    article.addEventListener('click', function (e) {\n        var text = newItem.textContent;\n        if ((e.target.id === 'new') && (text === 'add item')) {\n            alert('Please enter a todo item');\n        }\n        if ((e.target.id === 'new') && (text !== 'add item')) {\n            var xhr = new XMLHttpRequest();\n            xhr.open(\"POST\", \"/todo\");\n            var json = JSON.stringify({\n                Text: text\n            });\n            xhr.send(json);\n            xhr.onreadystatechange = function () {\n                if (xhr.readyState === 4) {\n                    var item = JSON.parse(xhr.responseText);\n                    CurrentItems.push(item);\n                    renderItems();\n                }\n            };\n        }\n    }, false);\n\n    // delete item from items\n    (function () {\n        items.addEventListener(\"click\", function (evt) {\n            var id = evt.target.id;\n            var xhr = new XMLHttpRequest();\n            xhr.open(\"DELETE\", \"/todo?id=\" + id);\n            xhr.send(null);\n            xhr.onreadystatechange = function () {\n                if (xhr.readyState === 4) {\n                    setTimeout(getItems, 100);\n                }\n            };\n        }, false);\n    })();\n\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/55_todo-list/01v_content-editable/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/user\"\n)\n\ntype ToDo struct {\n\tID    int64 `datastore:\"-\"`\n\tEmail string\n\tText  string\n}\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n\thttp.HandleFunc(\"/todo\", handleTodos)\n\thttp.Handle(\"/assets/\", http.StripPrefix(\"/assets\", http.FileServer(http.Dir(\"assets/\"))))\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path != \"/\" {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\thttp.ServeFile(res, req, \"assets/templates/index.html\")\n}\n\nfunc handleTodos(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\n\ttodos := make([]ToDo, 0)\n\n\tswitch req.Method {\n\tcase \"GET\":\n\t\tq := datastore.NewQuery(\"ToDo\").Filter(\"Email =\", u.Email)\n\t\titerator := q.Run(ctx)\n\t\tfor {\n\t\t\tvar todo ToDo\n\t\t\tkey, err := iterator.Next(&todo)\n\t\t\tif err == datastore.Done {\n\t\t\t\tbreak\n\t\t\t} else if err != nil {\n\t\t\t\tlog.Errorf(ctx, \"error retrieving todos: %v\", err)\n\t\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttodo.ID = key.IntID()\n\t\t\ttodos = append(todos, todo)\n\t\t}\n\t\terr := json.NewEncoder(res).Encode(todos)\n\t\tif err != nil {\n\t\t\tlog.Errorf(ctx, \"error marshalling todos: %v\", err)\n\t\t\treturn\n\t\t}\n\tcase \"POST\":\n\t\t// the user is posting a new item\n\t\tvar todo ToDo\n\t\terr := json.NewDecoder(req.Body).Decode(&todo)\n\t\tif err != nil {\n\t\t\tlog.Errorf(ctx, \"error unmarshalling todos: %v\", err)\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\ttodo.Email = u.Email\n\t\t// add to datastore\n\t\tkey := datastore.NewIncompleteKey(ctx, \"ToDo\", nil)\n\t\tkey, err = datastore.Put(ctx, key, &todo)\n\t\tif err != nil {\n\t\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\ttodo.ID = key.IntID()\n\t\t// send back to user\n\t\terr = json.NewEncoder(res).Encode(todo)\n\t\tif err != nil {\n\t\t\tlog.Errorf(ctx, \"error marshalling todo: %v\", err)\n\t\t\treturn\n\t\t}\n\tcase \"DELETE\":\n\t\tid, _ := strconv.ParseInt(req.FormValue(\"id\"), 10, 64)\n\t\tif id == 0 {\n\t\t\thttp.Error(res, \"not found\", 404)\n\t\t\treturn\n\t\t}\n\t\tkey := datastore.NewKey(ctx, \"ToDo\", \"\", id, nil)\n\t\tvar todo ToDo\n\t\terr := datastore.Get(ctx, key, &todo)\n\t\tif err != nil {\n\t\t\tlog.Errorf(ctx, \"error getting todo: %v\", err)\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\tif todo.Email != u.Email {\n\t\t\thttp.Error(res, \"access denied\", 401)\n\t\t\treturn\n\t\t}\n\t\terr = datastore.Delete(ctx, key)\n\t\tif err != nil {\n\t\t\tlog.Errorf(ctx, \"error deleting todo: %v\", err)\n\t\t\treturn\n\t\t}\n\tdefault:\n\t\thttp.Error(res, \"Method Not Allowed\", 405)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/55_todo-list/02v_input/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n  login: required\n"
  },
  {
    "path": "27_code-in-process/55_todo-list/02v_input/assets/templates/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n    <link rel=\"stylesheet\" href=\"../css/reset.css\">\n    <link rel='stylesheet'\n          href='http://fonts.googleapis.com/css?family=Open+Sans|Merienda:700'>\n    <link rel=\"stylesheet\"\n          href=\"http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <style>\n\n        * {\n            box-sizing: border-box;\n        }\n\n        main {\n            display: flex;\n            flex-direction: row;\n            justify-content: center;\n            align-items: center;\n            /*border: 1px solid black;*/\n            margin: 10px;\n        }\n\n        article {\n            display: flex;\n            flex-direction: column;\n            justify-content: center;\n            align-items: center;\n            /*border: 1px solid black;*/\n            min-width: 600px;\n        }\n\n        section {\n            display: flex;\n            flex-direction: row;\n            justify-content: space-between;\n            align-items: center;\n            border: 1px solid #2ec371;\n            width: 100%;\n            padding: 7px 12px 7px 10px;\n            margin: 5px;\n            border-radius: 10px;\n        }\n\n        h1 {\n            font-family: 'Merienda', cursive;\n            font-size: 53px;\n            color: #2ec371;\n            margin: 10px;\n        }\n\n        h2 {\n            font-family: 'Open Sans', sans-serif;\n            font-size: 16px;\n            max-width: 500px;\n        }\n\n        #new-item {\n            color: gray;\n            width: 100%;\n            height: 100%;\n            border: none;\n            font-family: 'Open Sans', sans-serif;\n            font-size: 16px;\n        }\n\n        .fa-minus-circle {\n            color: red;\n        }\n\n        .fa-plus-circle {\n            color: green;\n        }\n\n    </style>\n</head>\n<body>\n\n<main>\n    <article>\n        <h1>TO-DO</h1>\n        <div id=\"items\"></div>\n        <section>\n            <input type=\"text\" id=\"new-item\" placeholder=\"add item\">\n            <a href=\"#\"><i class=\"fa fa-plus-circle fa-2x\" id=\"new\"></i></a>\n            <!--<i class=\"fa fa-minus-circle fa-2x\"></i>-->\n        </section>\n    </article>\n</main>\n\n<script>\n    // items: [{ Text: \"blah\", ID: 123456 }]\n    var CurrentItems = [];\n    var items = document.querySelector(\"#items\");\n    var newItem = document.querySelector('#new-item');\n    var article = document.querySelector('article');\n\n    // get items from server, then render them\n    function getItems() {\n        var xhr = new XMLHttpRequest();\n        xhr.open(\"GET\", \"/todo\");\n        xhr.send(null);\n        xhr.onreadystatechange = function () {\n            if (xhr.readyState === 4) {\n                CurrentItems = JSON.parse(xhr.responseText);\n                renderItems();\n            }\n        }\n    }\n    getItems();\n\n    function renderItems() {\n        // clear the html\n        items.innerHTML = \"\";\n        // create HTML structure for each item in <div id=\"items\">\n        //     <section>\n        //         <h2>\n        //         <a href=\"#\">\n        //             <i>\n        for (var i = 0; i < CurrentItems.length; i++) {\n            var section = document.createElement(\"section\");\n            var h2 = document.createElement(\"h2\");\n            var a = document.createElement(\"a\");\n            var icon = document.createElement(\"i\");\n            h2.textContent = CurrentItems[i].Text;\n            a.setAttribute(\"href\", \"#\");\n            icon.setAttribute(\"class\", \"fa fa-minus-circle fa-2x\");\n            icon.setAttribute(\"id\", CurrentItems[i].ID);\n            section.appendChild(h2);\n            a.appendChild(icon);\n            section.appendChild(a);\n            items.appendChild(section);\n        }\n    }\n\n    // add new item\n    article.addEventListener('click', function (e) {\n        var text = newItem.value;\n        newItem.value = '';\n        if ((e.target.id === 'new') && (text === 'add item')) {\n            alert('Please enter a todo item');\n        }\n        if ((e.target.id === 'new') && (text !== 'add item')) {\n            var xhr = new XMLHttpRequest();\n            xhr.open(\"POST\", \"/todo\");\n            var json = JSON.stringify({\n                Text: text\n            });\n            xhr.send(json);\n            xhr.onreadystatechange = function () {\n                if (xhr.readyState === 4) {\n                    var item = JSON.parse(xhr.responseText);\n                    CurrentItems.push(item);\n                    renderItems();\n                }\n            };\n        }\n    }, false);\n\n    // delete item from items\n    (function () {\n        items.addEventListener(\"click\", function (evt) {\n            var id = evt.target.id;\n            var xhr = new XMLHttpRequest();\n            xhr.open(\"DELETE\", \"/todo?id=\" + id);\n            xhr.send(null);\n            xhr.onreadystatechange = function () {\n                if (xhr.readyState === 4) {\n                    setTimeout(getItems, 100);\n                }\n            };\n        }, false);\n    })();\n\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/55_todo-list/02v_input/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/user\"\n)\n\ntype ToDo struct {\n\tID    int64  `datastore:\"-\"`\n\tEmail string `json:\"-\"`\n\tText  string\n}\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n\thttp.HandleFunc(\"/todo\", handleTodos)\n\t//\thttp.Handle(\"/assets/\", http.StripPrefix(\"/assets\", http.FileServer(http.Dir(\"assets/\"))))\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path != \"/\" {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\thttp.ServeFile(res, req, \"assets/templates/index.html\")\n}\n\nfunc handleTodos(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\n\ttodos := make([]ToDo, 0)\n\n\tswitch req.Method {\n\tcase \"GET\":\n\t\tq := datastore.NewQuery(\"ToDo\").Filter(\"Email =\", u.Email)\n\t\titerator := q.Run(ctx)\n\t\tfor {\n\t\t\tvar todo ToDo\n\t\t\tkey, err := iterator.Next(&todo)\n\t\t\tif err == datastore.Done {\n\t\t\t\tbreak\n\t\t\t} else if err != nil {\n\t\t\t\tlog.Errorf(ctx, \"error retrieving todos: %v\", err)\n\t\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttodo.ID = key.IntID()\n\t\t\ttodos = append(todos, todo)\n\t\t}\n\t\terr := json.NewEncoder(res).Encode(todos)\n\t\tif err != nil {\n\t\t\tlog.Errorf(ctx, \"error marshalling todos: %v\", err)\n\t\t\treturn\n\t\t}\n\tcase \"POST\":\n\t\t// the user is posting a new item\n\t\tvar todo ToDo\n\t\terr := json.NewDecoder(req.Body).Decode(&todo)\n\t\tif err != nil {\n\t\t\tlog.Errorf(ctx, \"error unmarshalling todos: %v\", err)\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\ttodo.Email = u.Email\n\t\t// add to datastore\n\t\tkey := datastore.NewIncompleteKey(ctx, \"ToDo\", nil)\n\t\tkey, err = datastore.Put(ctx, key, &todo)\n\t\tif err != nil {\n\t\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\ttodo.ID = key.IntID()\n\t\t// send back to user\n\t\terr = json.NewEncoder(res).Encode(todo)\n\t\tif err != nil {\n\t\t\tlog.Errorf(ctx, \"error marshalling todo: %v\", err)\n\t\t\treturn\n\t\t}\n\tcase \"DELETE\":\n\t\tid, _ := strconv.ParseInt(req.FormValue(\"id\"), 10, 64)\n\t\tif id == 0 {\n\t\t\thttp.Error(res, \"not found\", 404)\n\t\t\treturn\n\t\t}\n\t\tkey := datastore.NewKey(ctx, \"ToDo\", \"\", id, nil)\n\t\tvar todo ToDo\n\t\terr := datastore.Get(ctx, key, &todo)\n\t\tif err != nil {\n\t\t\tlog.Errorf(ctx, \"error getting todo: %v\", err)\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\tif todo.Email != u.Email {\n\t\t\thttp.Error(res, \"access denied\", 401)\n\t\t\treturn\n\t\t}\n\t\terr = datastore.Delete(ctx, key)\n\t\tif err != nil {\n\t\t\tlog.Errorf(ctx, \"error deleting todo: %v\", err)\n\t\t\treturn\n\t\t}\n\tdefault:\n\t\thttp.Error(res, \"Method Not Allowed\", 405)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/01_ux_design/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/01_ux_design/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/01_ux_design/templates/html/home.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"../../public/css/reset.css\">\n    <link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"../../public/css/styles.css\">\n</head>\n<body>\n\n<div id=\"top\">\n    <header>\n        <i class=\"fa fa-heart-o fa-3x\"></i>\n        <nav>\n            <a href=\"/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n\n</div>\n\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/56_twitter/02_ListenAndServe/main.go",
    "content": "package main\n\nimport (\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc main() {\n\ttpl, _ = template.ParseGlob(\"templates/html/*.html\")\n\thttp.HandleFunc(\"/\", home)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\thttp.ListenAndServe(\":8080\", nil)\n}\n\nfunc home(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path != \"/\" {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\ttpl.ExecuteTemplate(res, \"home.html\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/02_ListenAndServe/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/02_ListenAndServe/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/02_ListenAndServe/templates/html/home.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"public/css/reset.css\">\n    <link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"public/css/styles.css\">\n</head>\n<body>\n\n<div id=\"top\">\n    <header>\n        <i class=\"fa fa-heart-o fa-3x\"></i>\n        <nav>\n            <a href=\"/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n\n</div>\n\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/56_twitter/03_error-handling/main.go",
    "content": "package main\n\nimport (\n\t\"html/template\"\n\t\"log\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc main() {\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n\thttp.HandleFunc(\"/\", home)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\tlog.Fatal(http.ListenAndServe(\":8080\", nil))\n}\n\nfunc home(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path != \"/\" {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\ttpl.ExecuteTemplate(res, \"home.html\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/03_error-handling/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/03_error-handling/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/03_error-handling/templates/html/home.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"public/css/reset.css\">\n    <link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"public/css/styles.css\">\n</head>\n<body>\n\n<div id=\"top\">\n    <header>\n        <i class=\"fa fa-heart-o fa-3x\"></i>\n        <nav>\n            <a href=\"/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n\n</div>\n\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/56_twitter/04_template_abstraction/main.go",
    "content": "package main\n\nimport (\n\t\"html/template\"\n\t\"log\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc main() {\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n\thttp.HandleFunc(\"/\", home)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\tlog.Fatal(http.ListenAndServe(\":8080\", nil))\n}\n\nfunc home(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path != \"/\" {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\ttpl.ExecuteTemplate(res, \"home.html\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/04_template_abstraction/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/04_template_abstraction/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/04_template_abstraction/templates/html/footer.html",
    "content": "{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/04_template_abstraction/templates/html/header.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"public/css/reset.css\">\n    <link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"public/css/styles.css\">\n</head>\n<body>\n{{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/04_template_abstraction/templates/html/home.html",
    "content": "{{template \"header\"}}\n<div id=\"top\">\n    <header>\n        <i class=\"fa fa-heart-o fa-3x\"></i>\n        <nav>\n            <a href=\"/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n\n</div>\n\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/05_document/main.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n\nimport (\n\t\"html/template\"\n\t\"log\"\n\t\"net/http\"\n)\n\n// tpl holds all of our templates.\nvar tpl *template.Template\n\n// main is the entry point for our web app. main parses our templates.\n// main handles our routing and defines our end-points. Doc comments work\n// best as complete sentences, which allow a wide variety of automated\n// presentations. The first sentence should be a one-sentence summary\n// that starts with the name being declared.\nfunc main() {\n\tGodocExperiment()\n\tgodocUnexported()\n\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n\thttp.HandleFunc(\"/\", home)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\tlog.Fatal(http.ListenAndServe(\":8080\", nil))\n}\n\n// home handles everything coming into the root of our web app.\nfunc home(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path != \"/\" {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\ttpl.ExecuteTemplate(res, \"home.html\", nil)\n}\n\n// GodocExperiment tests whether or not exported functions appear in\n// documentation when godoc is run.\nfunc GodocExperiment() {\n\tlog.Println(\"This is a godoc EXPORTED experiment\")\n}\n\n// godocUnexported tests whether or not exported functions appear in\n// documentation when godoc is run.\nfunc godocUnexported() {\n\tlog.Println(\"This is a godoc UNEXPORTED experiment\")\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/05_document/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/05_document/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/05_document/templates/html/footer.html",
    "content": "{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/05_document/templates/html/header.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"public/css/reset.css\">\n    <link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"public/css/styles.css\">\n</head>\n<body>\n{{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/05_document/templates/html/home.html",
    "content": "{{template \"header\"}}\n<div id=\"top\">\n    <header>\n        <i class=\"fa fa-heart-o fa-3x\"></i>\n        <nav>\n            <a href=\"/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n\n</div>\n\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/06_document/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/06_document/main.go",
    "content": "package main\n\nimport (\n\t\"html/template\"\n\t\"log\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc main() {\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n\thttp.HandleFunc(\"/\", home)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\tlog.Fatal(http.ListenAndServe(\":8080\", nil))\n}\n\nfunc home(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path != \"/\" {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\ttpl.ExecuteTemplate(res, \"home.html\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/06_document/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/06_document/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/06_document/templates/html/footer.html",
    "content": "{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/06_document/templates/html/header.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"public/css/reset.css\">\n    <link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"public/css/styles.css\">\n</head>\n<body>\n{{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/06_document/templates/html/home.html",
    "content": "{{template \"header\"}}\n<div id=\"top\">\n    <header>\n        <i class=\"fa fa-heart-o fa-3x\"></i>\n        <nav>\n            <a href=\"/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n\n</div>\n\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/07_app-engine/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n\n"
  },
  {
    "path": "27_code-in-process/56_twitter/07_app-engine/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/07_app-engine/main.go",
    "content": "package main\n\nimport (\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n\thttp.HandleFunc(\"/\", home)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\t// We do not need ListenAndServe on app engine\n\t// log.Fatal(http.ListenAndServe(\":8080\", nil))\n}\n\nfunc home(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path != \"/\" {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\ttpl.ExecuteTemplate(res, \"home.html\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/07_app-engine/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/07_app-engine/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/07_app-engine/templates/html/footer.html",
    "content": "{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/07_app-engine/templates/html/header.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"public/css/reset.css\">\n    <link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"public/css/styles.css\">\n</head>\n<body>\n{{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/07_app-engine/templates/html/home.html",
    "content": "{{template \"header\"}}\n<div id=\"top\">\n    <header>\n        <i class=\"fa fa-heart-o fa-3x\"></i>\n        <nav>\n            <a href=\"/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n\n</div>\n\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/08_julien-schmidt/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n\n"
  },
  {
    "path": "27_code-in-process/56_twitter/08_julien-schmidt/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/08_julien-schmidt/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/julienschmidt/httprouter\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tif req.URL.Path != \"/\" {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\ttpl.ExecuteTemplate(res, \"home.html\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/08_julien-schmidt/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/08_julien-schmidt/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/08_julien-schmidt/templates/html/footer.html",
    "content": "{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/08_julien-schmidt/templates/html/header.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"public/css/reset.css\">\n    <link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"public/css/styles.css\">\n</head>\n<body>\n{{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/08_julien-schmidt/templates/html/home.html",
    "content": "{{template \"header\"}}\n<div id=\"top\">\n    <header>\n        <i class=\"fa fa-heart-o fa-3x\"></i>\n        <nav>\n            <a href=\"/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n\n</div>\n\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/09_login-form/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n\n"
  },
  {
    "path": "27_code-in-process/56_twitter/09_login-form/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/09_login-form/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/julienschmidt/httprouter\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/login\", Login)\n\tr.GET(\"/signup\", Signup)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tif req.URL.Path != \"/\" {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\ttpl.ExecuteTemplate(res, \"home.html\", nil)\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\ttpl.ExecuteTemplate(res, \"login.html\", nil)\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\ttpl.ExecuteTemplate(res, \"signup.html\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/09_login-form/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/09_login-form/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/09_login-form/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/09_login-form/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/09_login-form/temp/tempLogin.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"../public/css/reset.css\">\n    <link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"../public/css/styles.css\">\n    <style>\n        form {\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n            justify-content: center;\n            border: 1px solid #2ec371;\n            border-radius: 4px;\n            padding: 20px;\n            background-color: #f3f3f3;\n            box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n            margin-top: 40px;\n        }\n\n        .fa-5x {\n            color: #2ec371;\n            border: 1px solid #2ec371;\n            border-radius: 100%;\n            padding: 15px;\n            margin-bottom: 10px;;\n        }\n\n        input, button {\n            height: 40px;\n            width: 250px;\n            font-size: 16px;\n            margin: 4px 0;\n            padding: 10px;\n        }\n\n        button {\n            background-color: #2ec371;\n            border: 0px;\n            border-radius: 3px;\n            font-size: 14px;\n            color: #fff;\n        }\n\n        #create-account {\n            color: #2ec371;\n            display: flex;\n            justify-content: center;\n            margin-top: 10px;\n            text-decoration: none;\n        }\n\n    </style>\n</head>\n<body>\n<form method=\"POST\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"user\" type=\"email\" placeholder=\"Enter your email\">\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n    <button>Submit</button>\n</form>\n<a href=\"signup\" id=\"create-account\">Create account</a>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/56_twitter/09_login-form/templates/html/footer.html",
    "content": "{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/09_login-form/templates/html/header.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"public/css/reset.css\">\n    <link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"public/css/styles.css\">\n{{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/09_login-form/templates/html/header2.html",
    "content": "{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            <a href=\"/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>{{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/09_login-form/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"header2\"}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/09_login-form/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"public/css/login.css\">\n{{template \"header2\"}}\n    <form method=\"POST\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"email\" name=\"user\" type=\"email\" placeholder=\"Enter your email\">\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <button>Submit</button>\n    </form>\n    <a href=\"/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/09_login-form/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"public/css/signup.css\">\n{{template \"header2\"}}\n    <form method=\"POST\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"email\" name=\"user\" type=\"email\" placeholder=\"Enter your email\">\n        <input id=\"name\" name=\"name\" placeholder=\"Enter your full name\">\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n        <button>Create Account</button>\n    </form>\n<!-- TODO add javascript event listener to validate form -->\n<!-- TODO AJAX to check if username is taken -->\n<!-- TODO email is valid -->\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/01v_form-validation/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n\n"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/01v_form-validation/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/01v_form-validation/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"html/template\"\n\t\"io/ioutil\"\n\t\"log\"\n\tstdlog \"log\"\n\t\"net/http\"\n)\n\ntype User struct {\n\tEmail    string\n\tUserName string\n\tPassword string\n}\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/login\", Login)\n\tr.GET(\"/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tif req.URL.Path != \"/\" {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\ttpl.ExecuteTemplate(res, \"home.html\", nil)\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\ttpl.ExecuteTemplate(res, \"login.html\", nil)\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\ttpl.ExecuteTemplate(res, \"signup.html\", nil)\n}\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tstdlog.Println(\"REQUEST BODY: \", sbs)\n\tq, err := datastore.NewQuery(\"Users\").Filter(\"UserName=\", sbs).Count(ctx)\n\tstdlog.Println(\"ERR: \", err)\n\tstdlog.Println(\"QUANTITY: \", q)\n\tif err != nil {\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t}\n\tif q >= 1 {\n\t\tfmt.Fprint(res, \"true\")\n\t} else {\n\t\tfmt.Fprint(res, \"false\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tNewUser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: req.FormValue(\"password\"),\n\t}\n\tlog.Println(NewUser)\n\tfmt.Fprintln(res, NewUser.Email, NewUser.Password, NewUser.UserName)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/01v_form-validation/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/01v_form-validation/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/01v_form-validation/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/01v_form-validation/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/01v_form-validation/temp/tempLogin.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"../public/css/reset.css\">\n    <link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"../public/css/styles.css\">\n    <style>\n        form {\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n            justify-content: center;\n            border: 1px solid #2ec371;\n            border-radius: 4px;\n            padding: 20px;\n            background-color: #f3f3f3;\n            box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n            margin-top: 40px;\n        }\n\n        .fa-5x {\n            color: #2ec371;\n            border: 1px solid #2ec371;\n            border-radius: 100%;\n            padding: 15px;\n            margin-bottom: 10px;;\n        }\n\n        input, button {\n            height: 40px;\n            width: 250px;\n            font-size: 16px;\n            margin: 4px 0;\n            padding: 10px;\n        }\n\n        button {\n            background-color: #2ec371;\n            border: 0px;\n            border-radius: 3px;\n            font-size: 14px;\n            color: #fff;\n        }\n\n        .form-field-err {\n            width: 250px;\n            text-align: left;\n            padding: 0 0 0 5px;\n            color: red;\n            font-size: 14px;\n        }\n\n        #create-account {\n            color: #2ec371;\n            display: flex;\n            justify-content: center;\n            margin-top: 10px;\n            text-decoration: none;\n        }\n\n    </style>\n</head>\n<body>\n<form method=\"POST\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"user\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\">something</p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n    <p class=\"form-field-err\"></p>\n    <button>Submit</button>\n</form>\n<a href=\"signup\" id=\"create-account\">Create account</a>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/01v_form-validation/temp/tempSignup.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"../public/css/reset.css\">\n    <link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"../public/css/styles.css\">\n    <style>\n        form {\n            display: flex;\n            flex-wrap: wrap;\n            flex-direction: column;\n            align-items: center;\n            justify-content: center;\n            border: 1px solid #2ec371;\n            border-radius: 4px;\n            padding: 20px;\n            background-color: #f3f3f3;\n            box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n            margin-top: 40px;\n        }\n\n        .fa-5x {\n            color: #2ec371;\n            border: 1px solid #2ec371;\n            border-radius: 100%;\n            padding: 15px;\n            margin-bottom: 10px;;\n        }\n\n        input, button {\n            height: 40px;\n            width: 250px;\n            font-size: 16px;\n            margin: 4px 0;\n            padding: 10px;\n        }\n\n        button {\n            background-color: #2ec371;\n            border: 0px;\n            border-radius: 3px;\n            font-size: 14px;\n            color: #fff;\n        }\n\n        .form-field-err {\n            width: 250px;\n            text-align: left;\n            padding: 0 0 0 5px;\n            color: red;\n            font-size: 14px;\n        }\n\n    </style>\n</head>\n<body>\n<form method=\"POST\" action=\"/api/createuser\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('keyup', function(){\n        var json = JSON.stringify(userName.value);\n        console.log(json);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(json);\n        xhr.addEventListener('readystatechange', function(){\n            var item = xhr.responseText;\n            if (item == 'true') {\n                nameErr.textContent = 'Username taken - Try another name!';\n            } else {\n                nameErr.textContent = '';\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    btnSubmit.addEventListener('click', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value == '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value != p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/01v_form-validation/temp/test-js.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n</head>\n<body>\n\n<form action=\"#\">\n    <label for=\"exampleInput\">Enter five digits:</label>\n    <input id=\"exampleInput\">\n</form>\n\n<script>\n    var exampleNode = document.querySelector('#exampleInput');\n    exampleNode.addEventListener('blur', function (e) {\n        var re5digit = /^\\d{5}$/;\n        e.preventDefault();\n        if (exampleNode.value.search(re5digit) === -1) {\n            alert(\"Enter a 5 digit number inside form\");\n        } else {\n            exampleNode.submit();\n        }\n    })\n</script>\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/01v_form-validation/templates/html/footer.html",
    "content": "{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/01v_form-validation/templates/html/header.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"public/css/reset.css\">\n    <link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"public/css/styles.css\">\n{{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/01v_form-validation/templates/html/header2.html",
    "content": "{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            <a href=\"/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>{{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/01v_form-validation/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"header2\"}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/01v_form-validation/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"public/css/login.css\">\n{{template \"header2\"}}\n    <form method=\"POST\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"email\" name=\"user\" type=\"email\" placeholder=\"Enter your email\">\n        <p class=\"form-field-err\">something</p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\">something</p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/01v_form-validation/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"public/css/signup.css\">\n{{template \"header2\"}}\n<form method=\"POST\" action=\"/api/createuser\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('keyup', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            var item = xhr.responseText;\n            if (item == 'true') {\n                nameErr.textContent = 'Username taken - Try another name!';\n            } else {\n                nameErr.textContent = '';\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    btnSubmit.addEventListener('click', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value == '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value != p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/02v_datastore-put/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n\n"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/02v_datastore-put/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/02v_datastore-put/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"html/template\"\n\t\"io/ioutil\"\n\tstdlog \"log\"\n\t\"net/http\"\n)\n\ntype User struct {\n\tEmail    string\n\tUserName string\n\tPassword string\n}\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/login\", Login)\n\tr.GET(\"/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tif req.URL.Path != \"/\" {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\ttpl.ExecuteTemplate(res, \"home.html\", nil)\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\ttpl.ExecuteTemplate(res, \"login.html\", nil)\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\ttpl.ExecuteTemplate(res, \"signup.html\", nil)\n}\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tstdlog.Println(\"REQUEST BODY: \", sbs)\n\tq, err := datastore.NewQuery(\"Users\").Filter(\"UserName=\", sbs).Count(ctx)\n\tstdlog.Println(\"ERR: \", err)\n\tstdlog.Println(\"QUANTITY: \", q)\n\tif err != nil {\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t}\n\tif q >= 1 {\n\t\tfmt.Fprint(res, \"true\")\n\t} else {\n\t\tfmt.Fprint(res, \"false\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tNewUser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: req.FormValue(\"password\"),\n\t}\n\tkey := datastore.NewIncompleteKey(ctx, \"Users\", nil)\n\tkey, _ = datastore.Put(ctx, key, &NewUser)\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\n/*\nFYI - watch out for this error:\n\nOn your imports ... you don't want this:\n\n\"google.golang.org/appengine\"\n\"google.golang.org/cloud/datastore\"\n\nYou want this:\n\n\"google.golang.org/appengine\"\n\"google.golang.org/appengine/datastore\"\n\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/02v_datastore-put/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/02v_datastore-put/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/02v_datastore-put/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/02v_datastore-put/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/02v_datastore-put/temp/tempLogin.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"../public/css/reset.css\">\n    <link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"../public/css/styles.css\">\n    <style>\n        form {\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n            justify-content: center;\n            border: 1px solid #2ec371;\n            border-radius: 4px;\n            padding: 20px;\n            background-color: #f3f3f3;\n            box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n            margin-top: 40px;\n        }\n\n        .fa-5x {\n            color: #2ec371;\n            border: 1px solid #2ec371;\n            border-radius: 100%;\n            padding: 15px;\n            margin-bottom: 10px;;\n        }\n\n        input, button {\n            height: 40px;\n            width: 250px;\n            font-size: 16px;\n            margin: 4px 0;\n            padding: 10px;\n        }\n\n        button {\n            background-color: #2ec371;\n            border: 0px;\n            border-radius: 3px;\n            font-size: 14px;\n            color: #fff;\n        }\n\n        .form-field-err {\n            width: 250px;\n            text-align: left;\n            padding: 0 0 0 5px;\n            color: red;\n            font-size: 14px;\n        }\n\n        #create-account {\n            color: #2ec371;\n            display: flex;\n            justify-content: center;\n            margin-top: 10px;\n            text-decoration: none;\n        }\n\n    </style>\n</head>\n<body>\n<form method=\"POST\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"user\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\">something</p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n    <p class=\"form-field-err\"></p>\n    <button>Submit</button>\n</form>\n<a href=\"signup\" id=\"create-account\">Create account</a>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/02v_datastore-put/temp/tempSignup.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"../public/css/reset.css\">\n    <link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"../public/css/styles.css\">\n    <style>\n        form {\n            display: flex;\n            flex-wrap: wrap;\n            flex-direction: column;\n            align-items: center;\n            justify-content: center;\n            border: 1px solid #2ec371;\n            border-radius: 4px;\n            padding: 20px;\n            background-color: #f3f3f3;\n            box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n            margin-top: 40px;\n        }\n\n        .fa-5x {\n            color: #2ec371;\n            border: 1px solid #2ec371;\n            border-radius: 100%;\n            padding: 15px;\n            margin-bottom: 10px;;\n        }\n\n        input, button {\n            height: 40px;\n            width: 250px;\n            font-size: 16px;\n            margin: 4px 0;\n            padding: 10px;\n        }\n\n        button {\n            background-color: #2ec371;\n            border: 0px;\n            border-radius: 3px;\n            font-size: 14px;\n            color: #fff;\n        }\n\n        .form-field-err {\n            width: 250px;\n            text-align: left;\n            padding: 0 0 0 5px;\n            color: red;\n            font-size: 14px;\n        }\n\n    </style>\n</head>\n<body>\n<form method=\"POST\" action=\"/api/createuser\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('keyup', function(){\n        var json = JSON.stringify(userName.value);\n        console.log(json);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(json);\n        xhr.addEventListener('readystatechange', function(){\n            var item = xhr.responseText;\n            if (item == 'true') {\n                nameErr.textContent = 'Username taken - Try another name!';\n            } else {\n                nameErr.textContent = '';\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    btnSubmit.addEventListener('click', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value == '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value != p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/02v_datastore-put/temp/test-js.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n</head>\n<body>\n\n<form action=\"#\">\n    <label for=\"exampleInput\">Enter five digits:</label>\n    <input id=\"exampleInput\">\n</form>\n\n<script>\n    var exampleNode = document.querySelector('#exampleInput');\n    exampleNode.addEventListener('blur', function (e) {\n        var re5digit = /^\\d{5}$/;\n        e.preventDefault();\n        if (exampleNode.value.search(re5digit) === -1) {\n            alert(\"Enter a 5 digit number inside form\");\n        } else {\n            exampleNode.submit();\n        }\n    })\n</script>\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/02v_datastore-put/templates/html/footer.html",
    "content": "{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/02v_datastore-put/templates/html/header.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"public/css/reset.css\">\n    <link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"public/css/styles.css\">\n{{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/02v_datastore-put/templates/html/header2.html",
    "content": "{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            <a href=\"/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>{{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/02v_datastore-put/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"header2\"}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/02v_datastore-put/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"public/css/login.css\">\n{{template \"header2\"}}\n    <form method=\"POST\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"email\" name=\"user\" type=\"email\" placeholder=\"Enter your email\">\n        <p class=\"form-field-err\">something</p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\">something</p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/10_signup-form-validate/02v_datastore-put/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"public/css/signup.css\">\n{{template \"header2\"}}\n<form method=\"POST\" action=\"/api/createuser\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('keyup', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            var item = xhr.responseText;\n            if (item == 'true') {\n                nameErr.textContent = 'Username taken - Try another name!';\n            } else {\n                nameErr.textContent = '';\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    btnSubmit.addEventListener('click', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value == '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value != p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/11_HTTPS-TLS/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/11_HTTPS-TLS/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/11_HTTPS-TLS/err_main.tmp",
    "content": "package main\n\nimport (\n\t\"html/template\"\n\t\"net/http\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/cloud/datastore\"\n\t\"encoding/json\"\n\t\"google.golang.org/appengine/log\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/login\", Login)\n\tr.GET(\"/signup\", Signup)\n\tr.GET(\"/api/checkUserName\", checkUserName)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tif req.URL.Path != \"/\" {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\ttpl.ExecuteTemplate(res, \"home.html\", nil)\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\ttpl.ExecuteTemplate(res, \"login.html\", nil)\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\ttpl.ExecuteTemplate(res, \"signup.html\", nil)\n}\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tvar Possibility string\n\terr := json.NewDecoder(req.Body).Decode(&Possibility)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error decoding name possibility\", err)\n\t\treturn\n\t}\n\tq, err := datastore.NewQuery(\"Users\").Filter(\"Username =\", Possibility).Count(ctx)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error running query\", err, \" - \", Possibility)\n\t\treturn\n\t}\n\tif q == 1 {\n\t\terr := json.NewEncoder(res).Encode(\"true\")\n\t\tif err != nil {\n\t\t\tlog.Errorf(ctx, \"error encoding username possibility response - one match\", err, Possibility)\n\t\t}\n\t} else if q > 1 {\n\t\tlog.Errorf(ctx, \"hmm, we had more than one username\", Possibility)\n\t} else {\n\t\terr := json.NewEncoder(res).Encode(\"false\")\n\t\tif err != nil {\n\t\t\tlog.Errorf(ctx, \"error encoding username possibility response - no matches\", err, Possibility)\n\t\t}\n\t}\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/11_HTTPS-TLS/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"html/template\"\n\t\"io/ioutil\"\n\tstdlog \"log\"\n\t\"net/http\"\n)\n\ntype User struct {\n\tEmail    string\n\tUserName string\n\tPassword string\n}\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tif req.URL.Path != \"/\" {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\ttpl.ExecuteTemplate(res, \"home.html\", nil)\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\ttpl.ExecuteTemplate(res, \"login.html\", nil)\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\ttpl.ExecuteTemplate(res, \"signup.html\", nil)\n}\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tstdlog.Println(\"REQUEST BODY: \", sbs)\n\tq, err := datastore.NewQuery(\"Users\").Filter(\"UserName=\", sbs).Count(ctx)\n\tstdlog.Println(\"ERR: \", err)\n\tstdlog.Println(\"QUANTITY: \", q)\n\tif err != nil {\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t}\n\tif q >= 1 {\n\t\tfmt.Fprint(res, \"true\")\n\t} else {\n\t\tfmt.Fprint(res, \"false\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tNewUser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: req.FormValue(\"password\"),\n\t}\n\tkey := datastore.NewIncompleteKey(ctx, \"Users\", nil)\n\tkey, _ = datastore.Put(ctx, key, &NewUser)\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\n/*\nFYI - good to read:\n\nhttps://cloud.google.com/appengine/docs/go/config/appconfig\n\nhttps://cloud.google.com/appengine/docs/using-custom-domains-and-ssl\n\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/11_HTTPS-TLS/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/11_HTTPS-TLS/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/11_HTTPS-TLS/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/11_HTTPS-TLS/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/11_HTTPS-TLS/templates/html/footer.html",
    "content": "{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/11_HTTPS-TLS/templates/html/header.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/11_HTTPS-TLS/templates/html/header2.html",
    "content": "{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            <a href=\"/form/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>{{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/11_HTTPS-TLS/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"header2\"}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/11_HTTPS-TLS/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\"}}\n    <form method=\"POST\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"email\" name=\"user\" type=\"email\" placeholder=\"Enter your email\">\n        <p class=\"form-field-err\">something</p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\">something</p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/11_HTTPS-TLS/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\"}}\n<form method=\"POST\" action=\"/api/createuser\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('keyup', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            var item = xhr.responseText;\n            if (item == 'true') {\n                nameErr.textContent = 'Username taken - Try another name!';\n            } else {\n                nameErr.textContent = '';\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    btnSubmit.addEventListener('click', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value == '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value != p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/12_error-handling/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/12_error-handling/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/12_error-handling/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"html/template\"\n\t\"io/ioutil\"\n\tstdlog \"log\"\n\t\"net/http\"\n)\n\ntype User struct {\n\tEmail    string\n\tUserName string\n\tPassword string\n}\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tif req.URL.Path != \"/\" {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\ttpl.ExecuteTemplate(res, \"home.html\", nil)\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\ttpl.ExecuteTemplate(res, \"login.html\", nil)\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\ttpl.ExecuteTemplate(res, \"signup.html\", nil)\n}\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tstdlog.Println(\"REQUEST BODY: \", sbs)\n\tq, err := datastore.NewQuery(\"Users\").Filter(\"UserName=\", sbs).Count(ctx)\n\tstdlog.Println(\"ERR: \", err)\n\tstdlog.Println(\"QUANTITY: \", q)\n\tif err != nil {\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t}\n\tif q >= 1 {\n\t\tfmt.Fprint(res, \"true\")\n\t} else {\n\t\tfmt.Fprint(res, \"false\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tNewUser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: req.FormValue(\"password\"),\n\t}\n\tkey := datastore.NewIncompleteKey(ctx, \"Users\", nil)\n\tkey, err := datastore.Put(ctx, key, &NewUser)\n\t// this is the only error checking I added; any others on this page needed?\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\thttp.Redirect(res, req, \"/\", 302)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/12_error-handling/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/12_error-handling/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/12_error-handling/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/12_error-handling/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/12_error-handling/templates/html/footer.html",
    "content": "{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/12_error-handling/templates/html/header.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/12_error-handling/templates/html/header2.html",
    "content": "{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            <a href=\"/form/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>{{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/12_error-handling/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"header2\"}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/12_error-handling/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\"}}\n    <form method=\"POST\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"email\" name=\"user\" type=\"email\" placeholder=\"Enter your email\">\n        <p class=\"form-field-err\">something</p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\">something</p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/12_error-handling/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\"}}\n<form method=\"POST\" action=\"/api/createuser\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('keyup', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            var item = xhr.responseText;\n            if (item == 'true') {\n                nameErr.textContent = 'Username taken - Try another name!';\n            } else {\n                nameErr.textContent = '';\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    btnSubmit.addEventListener('click', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value == '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value != p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/13_login_unfinished/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/13_login_unfinished/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/13_login_unfinished/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"html/template\"\n\t\"io/ioutil\"\n\tstdlog \"log\"\n\t\"net/http\"\n)\n\ntype User struct {\n\tEmail    string\n\tUserName string\n\tPassword string\n}\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tif req.URL.Path != \"/\" {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\ttpl.ExecuteTemplate(res, \"home.html\", nil)\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\ttpl.ExecuteTemplate(res, \"login.html\", nil)\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\ttpl.ExecuteTemplate(res, \"signup.html\", nil)\n}\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tstdlog.Println(\"REQUEST BODY: \", sbs)\n\tq, err := datastore.NewQuery(\"Users\").Filter(\"UserName=\", sbs).Count(ctx)\n\tstdlog.Println(\"ERR: \", err)\n\tstdlog.Println(\"QUANTITY: \", q)\n\tif err != nil {\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t}\n\tif q >= 1 {\n\t\tfmt.Fprint(res, \"true\")\n\t} else {\n\t\tfmt.Fprint(res, \"false\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tNewUser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: req.FormValue(\"password\"),\n\t}\n\tkey := datastore.NewIncompleteKey(ctx, \"Users\", nil)\n\tkey, err := datastore.Put(ctx, key, &NewUser)\n\t// this is the only error checking I added; any others on this page needed?\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\thttp.Redirect(res, req, \"/\", 302)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/13_login_unfinished/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/13_login_unfinished/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/13_login_unfinished/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/13_login_unfinished/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/13_login_unfinished/templates/html/footer.html",
    "content": "{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/13_login_unfinished/templates/html/header.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/13_login_unfinished/templates/html/header2.html",
    "content": "{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            <a href=\"/form/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>{{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/13_login_unfinished/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"header2\"}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/13_login_unfinished/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\"}}\n    <form method=\"POST\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"email\" name=\"user\" type=\"email\" placeholder=\"Enter your email\">\n        <p class=\"form-field-err\">something</p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\">something</p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/13_login_unfinished/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\"}}\n<form method=\"POST\" action=\"/api/createuser\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('keyup', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            var item = xhr.responseText;\n            if (item == 'true') {\n                nameErr.textContent = 'Username taken - Try another name!';\n            } else {\n                nameErr.textContent = '';\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    btnSubmit.addEventListener('click', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value == '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value != p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/14_code-review/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/14_code-review/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/14_code-review/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"html/template\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t//\t\"io\"\n\t//\t\"bytes\"\n\t//\t\"google.golang.org/appengine/memcache\"\n)\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string\n}\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler()) // maybe not needed b/c of schmidt router\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\ttpl.ExecuteTemplate(res, \"home.html\", nil)\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\ttpl.ExecuteTemplate(res, \"login.html\", nil)\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\ttpl.ExecuteTemplate(res, \"signup.html\", nil)\n}\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tNewUser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: req.FormValue(\"password\"),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", NewUser.UserName, 0, nil)\n\tkey, err := datastore.Put(ctx, key, &NewUser)\n\t// this is the only error checking I added; any others on this page needed?\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\n/*\nTO DO:\nsession\n-memcache templates\n- uuid in a cookie\n--- https while logged in? - depends upon security required\n- encrypt password on datastore?\n--- never store an unencrypted password, so, resoundingly, YES\n--- sha-256 fast hash value\n- user memcache?\n- datastore / memcache\nsession interface change\n- change login button to logout when user logged in\npost tweets\nfollow people\nsee tweets for everyone\nsee tweets for individual user\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/14_code-review/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/14_code-review/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/14_code-review/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/14_code-review/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/14_code-review/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            <a href=\"/form/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>\n{{end}}\n\n{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/14_code-review/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"header2\"}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/14_code-review/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\"}}\n    <form method=\"POST\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"email\" name=\"user\" type=\"email\" placeholder=\"Enter your email\">\n        <p class=\"form-field-err\">something</p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\">something</p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/14_code-review/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\"}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/15_memcache-home/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/15_memcache-home/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/15_memcache-home/main.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"html/template\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"net/http\"\n)\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string\n}\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler()) // maybe not needed b/c of schmidt router\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\ti, err := memcache.Get(ctx, \"Homepage\")\n\tif err != nil {\n\t\tbuf := new(bytes.Buffer)\n\t\twrit := io.MultiWriter(res, buf)\n\t\ttpl.ExecuteTemplate(writ, \"home.html\", nil)\n\t\tmemcache.Set(ctx, &memcache.Item{\n\t\t\tValue: buf.Bytes(),\n\t\t\tKey:   \"Homepage\",\n\t\t})\n\t\treturn\n\t}\n\tio.WriteString(res, string(i.Value))\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\ttpl.ExecuteTemplate(res, \"login.html\", nil)\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\ttpl.ExecuteTemplate(res, \"signup.html\", nil)\n}\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tNewUser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: req.FormValue(\"password\"),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", NewUser.UserName, 0, nil)\n\tkey, err := datastore.Put(ctx, key, &NewUser)\n\t// this is the only error checking I added; any others on this page needed?\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\n/*\nTO DO:\nsession\n-memcache templates\n- uuid in a cookie\n--- https while logged in? - depends upon security required\n- encrypt password on datastore?\n--- never store an unencrypted password, so, resoundingly, YES\n--- sha-256 fast hash value\n- user memcache?\n- datastore / memcache\nsession interface change\n- change login button to logout when user logged in\npost tweets\nfollow people\nsee tweets for everyone\nsee tweets for individual user\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/15_memcache-home/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/15_memcache-home/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/15_memcache-home/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/15_memcache-home/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/15_memcache-home/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            <a href=\"/form/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>\n{{end}}\n\n{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/15_memcache-home/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"header2\"}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/15_memcache-home/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\"}}\n    <form method=\"POST\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"email\" name=\"user\" type=\"email\" placeholder=\"Enter your email\">\n        <p class=\"form-field-err\">something</p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\">something</p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/15_memcache-home/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\"}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/16_abstract-memcache-code/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/16_abstract-memcache-code/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/16_abstract-memcache-code/main.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"html/template\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"net/http\"\n)\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string\n}\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler()) // maybe not needed b/c of schmidt router\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tmemTemplate(res, req, \"Homepage\", \"home.html\")\n}\n\nfunc memTemplate(res http.ResponseWriter, req *http.Request, memKey, templateName string) {\n\tctx := appengine.NewContext(req)\n\ti, err := memcache.Get(ctx, memKey)\n\tif err != nil {\n\t\tbuf := new(bytes.Buffer)\n\t\twrit := io.MultiWriter(res, buf)\n\t\ttpl.ExecuteTemplate(writ, templateName, nil)\n\t\tmemcache.Set(ctx, &memcache.Item{\n\t\t\tValue: buf.Bytes(),\n\t\t\tKey:   memKey,\n\t\t})\n\t\treturn\n\t}\n\tio.WriteString(res, string(i.Value))\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\ttpl.ExecuteTemplate(res, \"login.html\", nil)\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\ttpl.ExecuteTemplate(res, \"signup.html\", nil)\n}\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tNewUser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: req.FormValue(\"password\"),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", NewUser.UserName, 0, nil)\n\tkey, err := datastore.Put(ctx, key, &NewUser)\n\t// this is the only error checking I added; any others on this page needed?\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\n/*\nTO DO:\nsession\n-memcache templates\n- uuid in a cookie\n--- https while logged in? - depends upon security required\n- encrypt password on datastore?\n--- never store an unencrypted password, so, resoundingly, YES\n--- sha-256 fast hash value\n- user memcache?\n- datastore / memcache\nsession interface change\n- change login button to logout when user logged in\npost tweets\nfollow people\nsee tweets for everyone\nsee tweets for individual user\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/16_abstract-memcache-code/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/16_abstract-memcache-code/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/16_abstract-memcache-code/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/16_abstract-memcache-code/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/16_abstract-memcache-code/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            <a href=\"/form/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>\n{{end}}\n\n{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/16_abstract-memcache-code/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"header2\"}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/16_abstract-memcache-code/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\"}}\n    <form method=\"POST\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"email\" name=\"user\" type=\"email\" placeholder=\"Enter your email\">\n        <p class=\"form-field-err\">something</p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\">something</p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/16_abstract-memcache-code/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\"}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/17_memcache-templates/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/17_memcache-templates/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/17_memcache-templates/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"html/template\"\n\t\"io/ioutil\"\n\t\"net/http\"\n)\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string\n}\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tmemTemplate(res, req, \"Homepage\", \"home.html\")\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tmemTemplate(res, req, \"Loginpage\", \"login.html\")\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tmemTemplate(res, req, \"Signuppage\", \"signup.html\")\n}\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tNewUser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: req.FormValue(\"password\"),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", NewUser.UserName, 0, nil)\n\tkey, err := datastore.Put(ctx, key, &NewUser)\n\t// this is the only error checking I added; any others on this page needed?\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\n/*\nTO DO:\nsession\n-memcache templates\n- uuid in a cookie\n--- https while logged in? - depends upon security required\n- encrypt password on datastore?\n--- never store an unencrypted password, so, resoundingly, YES\n--- sha-256 fast hash value\n- user memcache?\n- datastore / memcache\nsession interface change\n- change login button to logout when user logged in\npost tweets\nfollow people\nsee tweets for everyone\nsee tweets for individual user\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/17_memcache-templates/memcache.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc memTemplate(res http.ResponseWriter, req *http.Request, memKey, templateName string) {\n\tctx := appengine.NewContext(req)\n\ti, err := memcache.Get(ctx, memKey)\n\tif err != nil {\n\t\tbuf := new(bytes.Buffer)\n\t\twrit := io.MultiWriter(res, buf)\n\t\ttpl.ExecuteTemplate(writ, templateName, nil)\n\t\tmemcache.Set(ctx, &memcache.Item{\n\t\t\tValue: buf.Bytes(),\n\t\t\tKey:   memKey,\n\t\t})\n\t\treturn\n\t}\n\tio.WriteString(res, string(i.Value))\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/17_memcache-templates/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/17_memcache-templates/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/17_memcache-templates/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/17_memcache-templates/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/17_memcache-templates/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            <a href=\"/form/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>\n{{end}}\n\n{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/17_memcache-templates/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"header2\"}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/17_memcache-templates/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\"}}\n    <form method=\"POST\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"email\" name=\"user\" type=\"email\" placeholder=\"Enter your email\">\n        <p class=\"form-field-err\">something</p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\">something</p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/17_memcache-templates/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\"}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/18_abstract-API-Model/API/users.go",
    "content": "package API\n\nimport (\n\t\"Model\"\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"io/ioutil\"\n\t\"net/http\"\n)\n\nfunc CheckUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user Model.User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc CreateUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tNewUser := Model.User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: req.FormValue(\"password\"),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", NewUser.UserName, 0, nil)\n\tkey, err := datastore.Put(ctx, key, &NewUser)\n\t// this is the only error checking I added; any others on this page needed?\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\thttp.Redirect(res, req, \"/\", 302)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/18_abstract-API-Model/IMPORTANT-READ-ME.txt",
    "content": "Go applications are organized into packages that mirror the directory structure\nof your source files. When you use an import statement in App Engine source code,\nthe SDK tools interpret the relative paths in the import two ways:\n-- Relative to the directory that contains the module's app.yaml file\n-- Relative to the src subdirectory of all the directories in GOPATH\n---- (this is called a \"fully-qualifed\" import path)\n\nIf we had this:\n\nproject-dir\n  module1-dir\n    app.yaml\n    src1-1.go\n    src1-2.go\n\nAnd if GOPATH is defined this way:\n    export GOPATH=/home/fred/go\n\nAnd the file src1-1.go in the project directory example above contains this statement:\n\timport \"foo/bar\"\n\nApp Engine will look for the package \"foo/bar\" in these locations:\n\tproject-dir/module1/foo/bar\n\t/home/fred/go/src/foo/bar\n\nIf you include your package sources in GOPATH,\nyou must be careful not to place the source code\n*** at or below any directories in your App Engine project that contain app.yaml files. ***\nIf that happens, a package could be loaded twice,\nonce for the path relative to a module's directory,\nand once for the fully-qualified path.\n\n\nSOURCE:\nhttps://cloud.google.com/appengine/docs/go/#Go_Organizing_Go_apps\n\nThis all lead me to learning about MODULES:\nhttps://cloud.google.com/appengine/docs/go/modules/#Go_Configuration"
  },
  {
    "path": "27_code-in-process/56_twitter/18_abstract-API-Model/Memcache/templates.go",
    "content": "package Memcache\n\nimport (\n\t\"bytes\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"html/template\"\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc Template(res http.ResponseWriter, req *http.Request, memKey, templateName string, tpl *template.Template) {\n\tctx := appengine.NewContext(req)\n\ti, err := memcache.Get(ctx, memKey)\n\tif err != nil {\n\t\tbuf := new(bytes.Buffer)\n\t\twrit := io.MultiWriter(res, buf)\n\t\ttpl.ExecuteTemplate(writ, templateName, nil)\n\t\tmemcache.Set(ctx, &memcache.Item{\n\t\t\tValue: buf.Bytes(),\n\t\t\tKey:   memKey,\n\t\t})\n\t\treturn\n\t}\n\tio.WriteString(res, string(i.Value))\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/18_abstract-API-Model/Model/users.go",
    "content": "package Model\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/18_abstract-API-Model/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/18_abstract-API-Model/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/18_abstract-API-Model/main.go",
    "content": "package main\n\nimport (\n\t//\t\"API\"\n\t\"Memcache\"\n\t\"github.com/GoesToEleven/GolangTraining/56_twitter/18_abstract-API-Model/api\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", API.CheckUserName)\n\tr.POST(\"/api/createuser\", API.CreateUser)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tMemcache.Template(res, req, \"Homepage\", \"home.html\", tpl)\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tMemcache.Template(res, req, \"Loginpage\", \"login.html\", tpl)\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tMemcache.Template(res, req, \"Signuppage\", \"signup.html\", tpl)\n}\n\n/*\nTO DO:\nsession\n-memcache templates\n- uuid in a cookie\n--- https while logged in? - depends upon security required\n- encrypt password on datastore?\n--- never store an unencrypted password, so, resoundingly, YES\n--- sha-256 fast hash value\n- user memcache?\n- datastore / memcache\nsession interface change\n- change login button to logout when user logged in\npost tweets\nfollow people\nsee tweets for everyone\nsee tweets for individual user\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/18_abstract-API-Model/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/18_abstract-API-Model/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/18_abstract-API-Model/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/18_abstract-API-Model/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/18_abstract-API-Model/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            <a href=\"/form/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>\n{{end}}\n\n{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/18_abstract-API-Model/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"header2\"}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/18_abstract-API-Model/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\"}}\n    <form method=\"POST\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"email\" name=\"user\" type=\"email\" placeholder=\"Enter your email\">\n        <p class=\"form-field-err\">something</p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\">something</p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/18_abstract-API-Model/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\"}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/19_abstract-API-Model_AE-fix/API/users.go",
    "content": "package API\n\nimport (\n\t\"fmt\"\n\t\"github.com/GoesToEleven/GolangTraining/56_twitter/19_abstract-API-Model_AE-fix/Model\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"io/ioutil\"\n\t\"net/http\"\n)\n\nfunc CheckUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user Model.User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc CreateUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tNewUser := Model.User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: req.FormValue(\"password\"),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", NewUser.UserName, 0, nil)\n\tkey, err := datastore.Put(ctx, key, &NewUser)\n\t// this is the only error checking I added; any others on this page needed?\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\thttp.Redirect(res, req, \"/\", 302)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/19_abstract-API-Model_AE-fix/App/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/19_abstract-API-Model_AE-fix/App/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/19_abstract-API-Model_AE-fix/App/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/GoesToEleven/GolangTraining/56_twitter/19_abstract-API-Model_AE-fix/API\"\n\t\"github.com/GoesToEleven/GolangTraining/56_twitter/19_abstract-API-Model_AE-fix/Memcache\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", API.CheckUserName)\n\tr.POST(\"/api/createuser\", API.CreateUser)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tMemcache.Template(res, req, \"Homepage\", \"home.html\", tpl)\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tMemcache.Template(res, req, \"Loginpage\", \"login.html\", tpl)\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tMemcache.Template(res, req, \"Signuppage\", \"signup.html\", tpl)\n}\n\n/*\nTO DO:\nsession\n-memcache templates\n- uuid in a cookie\n--- https while logged in? - depends upon security required\n- encrypt password on datastore?\n--- never store an unencrypted password, so, resoundingly, YES\n--- sha-256 fast hash value\n- user memcache?\n- datastore / memcache\nsession interface change\n- change login button to logout when user logged in\npost tweets\nfollow people\nsee tweets for everyone\nsee tweets for individual user\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/19_abstract-API-Model_AE-fix/App/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/19_abstract-API-Model_AE-fix/App/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/19_abstract-API-Model_AE-fix/App/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/19_abstract-API-Model_AE-fix/App/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/19_abstract-API-Model_AE-fix/App/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            <a href=\"/form/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>\n{{end}}\n\n{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/19_abstract-API-Model_AE-fix/App/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"header2\"}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/19_abstract-API-Model_AE-fix/App/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\"}}\n    <form method=\"POST\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"email\" name=\"user\" type=\"email\" placeholder=\"Enter your email\">\n        <p class=\"form-field-err\">something</p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\">something</p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/19_abstract-API-Model_AE-fix/App/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\"}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/19_abstract-API-Model_AE-fix/Memcache/templates.go",
    "content": "package Memcache\n\nimport (\n\t\"bytes\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"html/template\"\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc Template(res http.ResponseWriter, req *http.Request, memKey, templateName string, tpl *template.Template) {\n\tctx := appengine.NewContext(req)\n\ti, err := memcache.Get(ctx, memKey)\n\tif err != nil {\n\t\tbuf := new(bytes.Buffer)\n\t\twrit := io.MultiWriter(res, buf)\n\t\ttpl.ExecuteTemplate(writ, templateName, nil)\n\t\tmemcache.Set(ctx, &memcache.Item{\n\t\t\tValue: buf.Bytes(),\n\t\t\tKey:   memKey,\n\t\t})\n\t\treturn\n\t}\n\tio.WriteString(res, string(i.Value))\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/19_abstract-API-Model_AE-fix/Model/users.go",
    "content": "package Model\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/20_reverting_to_only_package-main/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/20_reverting_to_only_package-main/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/20_reverting_to_only_package-main/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/julienschmidt/httprouter\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string\n}\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tmemTemplate(res, req, \"Homepage\", \"home.html\")\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tmemTemplate(res, req, \"Loginpage\", \"login.html\")\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tmemTemplate(res, req, \"Signuppage\", \"signup.html\")\n}\n\n/*\nTO DO:\nsession\n-memcache templates\n- uuid in a cookie\n--- https while logged in? - depends upon security required\n- encrypt password on datastore?\n--- never store an unencrypted password, so, resoundingly, YES\n--- sha-256 fast hash value\n- user memcache?\n- datastore / memcache\nsession interface change\n- change login button to logout when user logged in\npost tweets\nfollow people\nsee tweets for everyone\nsee tweets for individual user\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/20_reverting_to_only_package-main/memcache.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc memTemplate(res http.ResponseWriter, req *http.Request, memKey, templateName string) {\n\tctx := appengine.NewContext(req)\n\ti, err := memcache.Get(ctx, memKey)\n\tif err != nil {\n\t\tbuf := new(bytes.Buffer)\n\t\twrit := io.MultiWriter(res, buf)\n\t\ttpl.ExecuteTemplate(writ, templateName, nil)\n\t\tmemcache.Set(ctx, &memcache.Item{\n\t\t\tValue: buf.Bytes(),\n\t\t\tKey:   memKey,\n\t\t})\n\t\treturn\n\t}\n\tio.WriteString(res, string(i.Value))\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/20_reverting_to_only_package-main/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/20_reverting_to_only_package-main/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/20_reverting_to_only_package-main/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/20_reverting_to_only_package-main/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/20_reverting_to_only_package-main/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            <a href=\"/form/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>\n{{end}}\n\n{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/20_reverting_to_only_package-main/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"header2\"}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/20_reverting_to_only_package-main/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\"}}\n    <form method=\"POST\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"email\" name=\"user\" type=\"email\" placeholder=\"Enter your email\">\n        <p class=\"form-field-err\">something</p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\">something</p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/20_reverting_to_only_package-main/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\"}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/20_reverting_to_only_package-main/userCreation.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"io/ioutil\"\n\t\"net/http\"\n)\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tNewUser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: req.FormValue(\"password\"),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", NewUser.UserName, 0, nil)\n\tkey, err := datastore.Put(ctx, key, &NewUser)\n\t// this is the only error checking I added; any others on this page needed?\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\thttp.Redirect(res, req, \"/\", 302)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/21_set-cookie_no-PATH/IMPORTANT-TO-READ.txt",
    "content": "If set to '/', the cookie will be available within the entire domain.\n\nIf set to '/foo/', the cookie will only be available within the /foo/ directory\nand all sub-directories such as /foo/bar/ of domain\n\nCookies can be bound to a specific domain, subdomain, path, and protocol (http/https).\nYou need to specify the path when setting the cookie"
  },
  {
    "path": "27_code-in-process/56_twitter/21_set-cookie_no-PATH/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/21_set-cookie_no-PATH/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/21_set-cookie_no-PATH/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/julienschmidt/httprouter\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string `json:\"-\"`\n}\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:  \"my-cookie\",\n\t\tValue: \"some value\",\n\t})\n\tmemTemplate(res, req, \"Homepage\", \"home.html\")\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:  \"my-cookie-login\",\n\t\tValue: \"some value logg logg loggin\",\n\t})\n\tmemTemplate(res, req, \"Loginpage\", \"login.html\")\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tmemTemplate(res, req, \"Signuppage\", \"signup.html\")\n}\n\n/*\nTO DO:\nsession\n-memcache templates\n- uuid in a cookie\n--- https while logged in? - depends upon security required\n- encrypt password on datastore?\n--- never store an unencrypted password, so, resoundingly, YES\n--- sha-256 fast hash value\n- user memcache?\n- datastore / memcache\nsession interface change\n- change login button to logout when user logged in\npost tweets\nfollow people\nsee tweets for everyone\nsee tweets for individual user\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/21_set-cookie_no-PATH/memcache.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc memTemplate(res http.ResponseWriter, req *http.Request, memKey, templateName string) {\n\tctx := appengine.NewContext(req)\n\ti, err := memcache.Get(ctx, memKey)\n\tif err != nil {\n\t\tbuf := new(bytes.Buffer)\n\t\twrit := io.MultiWriter(res, buf)\n\t\ttpl.ExecuteTemplate(writ, templateName, nil)\n\t\tmemcache.Set(ctx, &memcache.Item{\n\t\t\tValue: buf.Bytes(),\n\t\t\tKey:   memKey,\n\t\t})\n\t\treturn\n\t}\n\tio.WriteString(res, string(i.Value))\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/21_set-cookie_no-PATH/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/21_set-cookie_no-PATH/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/21_set-cookie_no-PATH/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/21_set-cookie_no-PATH/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/21_set-cookie_no-PATH/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            <a href=\"/form/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>\n{{end}}\n\n{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/21_set-cookie_no-PATH/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"header2\"}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/21_set-cookie_no-PATH/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\"}}\n    <form method=\"POST\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"email\" name=\"user\" type=\"email\" placeholder=\"Enter your email\">\n        <p class=\"form-field-err\">something</p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\">something</p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/21_set-cookie_no-PATH/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\"}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/21_set-cookie_no-PATH/userCreation.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"io/ioutil\"\n\t\"net/http\"\n)\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tNewUser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: req.FormValue(\"password\"),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", NewUser.UserName, 0, nil)\n\tkey, err := datastore.Put(ctx, key, &NewUser)\n\t// this is the only error checking I added; any others on this page needed?\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\t// SET COOKIE\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:  \"my-cookies\",\n\t\tValue: \"some value user creation\",\n\t})\n\n\t// redirect\n\t//\thttp.Redirect(res, req, \"/\", 302)\n}\n\n/*\n1. Introduction\n\nSecuring cookies is an important subject.\nThink about an authentication cookie. When the attacker is able to grab this cookie,\nhe can impersonate the user. This article describes HttpOnly and secure flags that can\nenhance security of cookies.\n\n2. HTTP, HTTPS and secure Flag\n\nWhen HTTP protocol is used, the traffic is sent in plaintext.\nIt allows the attacker to see/modify the traffic (man-in-the-middle attack).\nHTTPS is a secure version of HTTP – it uses SSL/TLS to protect the data\nof the application layer. When HTTPS is used, the following properties are achieved:\nauthentication, data integrity, confidentiality. How are HTTP and HTTPS related to\na secure flag of the cookie?\n\nLet’s consider the case of an authentication cookie. As was previously said,\nstealing this cookie is equivalent to impersonating the user. When HTTP is used,\nthe cookie is sent in plaintext. This is fine for the attacker eavesdropping on the\ncommunication channel between the browser and the server – he can grab the cookie and\nimpersonate the user.\n\nNow let’s assume that HTTPS is used instead of HTTP.\nHTTPS provides confidentiality. That’s why the attacker can’t see the cookie.\nThe conclusion is to send the authentication cookie over a secure channel so that\nit can’t be eavesdropped. The question that might appear in this moment is:\nwhy do we need a secure flag if we can use HTTPS?\n\nLet’s consider the following scenario to answer this question.\nThe site is available over HTTP and HTTPS. Moreover, let’s assume that there is\nan attacker in the middle of the communication channel between the browser and the server.\nThe cookie sent over HTTPS can’t be eavesdropped. However, the attacker can take advantage of\nthe fact that the site is also available over HTTP. The attacker can send the link to\nthe HTTP version of the site to the user. The user clicks the link and the HTTP request\nis generated. Since HTTP traffic is sent in plaintext, the attacker eavesdrops on the\ncommunication channel and reads the authentication cookie of the user. Can we allow\nthis cookie to be sent only over HTTPS? If this was possible, we would prevent the attacker\nfrom reading the authentication cookie in our story. It turns out that it is possible,\nand a secure flag is used exactly for this purpose – the cookie with a secure flag will\nonly be sent over an HTTPS connection.\n\n3. HttpOnly Flag\n\nIn the previous section, it was presented how to protect the cookie from an attacker\neavesdropping on the communication channel between the browser and the server.\nHowever, eavesdropping is not the only attack vector to grab the cookie.\n\nLet’s continue the story with the authentication cookie and assume that XSS\n(cross-site scripting) vulnerability is present in the application. Then the\nattacker can take advantage of the XSS vulnerability to steal the authentication cookie.\nCan we somehow prevent this from happening? It turns out that an HttpOnly flag can be used\nto solve this problem. When an HttpOnly flag is used, JavaScript will not be able to read\nthis authentication cookie in case of XSS exploitation. It seems like we have achieved\nthe goal, but the problem might still be present when cross-site tracing (XST)\nvulnerability exists (this vulnerability will be explained in the next section of the article)\n – the attacker might take advantage of XSS and enabled TRACE method to read\n the authentication cookie even if HttpOnly flag is used. Let’s see how XST works.\n\nSOURCE:\nhttp://resources.infosecinstitute.com/securing-cookies-httponly-secure-flags/\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/22_set-cookie_PATH/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/22_set-cookie_PATH/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/22_set-cookie_PATH/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/julienschmidt/httprouter\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string `json:\"-\"`\n}\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tmemTemplate(res, req, \"Homepage\", \"home.html\")\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tmemTemplate(res, req, \"Loginpage\", \"login.html\")\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tmemTemplate(res, req, \"Signuppage\", \"signup.html\")\n}\n\n/*\nTO DO:\nsession\n-memcache templates\n- uuid in a cookie\n--- https while logged in? - depends upon security required\n- encrypt password on datastore?\n--- never store an unencrypted password, so, resoundingly, YES\n--- sha-256 fast hash value\n- user memcache?\n- datastore / memcache\nsession interface change\n- change login button to logout when user logged in\npost tweets\nfollow people\nsee tweets for everyone\nsee tweets for individual user\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/22_set-cookie_PATH/memcache.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc memTemplate(res http.ResponseWriter, req *http.Request, memKey, templateName string) {\n\tctx := appengine.NewContext(req)\n\ti, err := memcache.Get(ctx, memKey)\n\tif err != nil {\n\t\tbuf := new(bytes.Buffer)\n\t\twrit := io.MultiWriter(res, buf)\n\t\ttpl.ExecuteTemplate(writ, templateName, nil)\n\t\tmemcache.Set(ctx, &memcache.Item{\n\t\t\tValue: buf.Bytes(),\n\t\t\tKey:   memKey,\n\t\t})\n\t\treturn\n\t}\n\tio.WriteString(res, string(i.Value))\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/22_set-cookie_PATH/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/22_set-cookie_PATH/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/22_set-cookie_PATH/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/22_set-cookie_PATH/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/22_set-cookie_PATH/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            <a href=\"/form/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>\n{{end}}\n\n{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/22_set-cookie_PATH/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"header2\"}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/22_set-cookie_PATH/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\"}}\n    <form method=\"POST\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"email\" name=\"user\" type=\"email\" placeholder=\"Enter your email\">\n        <p class=\"form-field-err\">something</p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\">something</p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/22_set-cookie_PATH/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\"}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/22_set-cookie_PATH/userCreation.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"io/ioutil\"\n\t\"net/http\"\n)\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tNewUser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: req.FormValue(\"password\"),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", NewUser.UserName, 0, nil)\n\tkey, err := datastore.Put(ctx, key, &NewUser)\n\t// this is the only error checking I added; any others on this page needed?\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\t// SET COOKIE\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:  \"my-cookies\",\n\t\tValue: \"some value user creation WITH PATH / \",\n\t\tPath:  \"/\",\n\t})\n\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\n/*\n1. Introduction\n\nSecuring cookies is an important subject.\nThink about an authentication cookie. When the attacker is able to grab this cookie,\nhe can impersonate the user. This article describes HttpOnly and secure flags that can\nenhance security of cookies.\n\n2. HTTP, HTTPS and secure Flag\n\nWhen HTTP protocol is used, the traffic is sent in plaintext.\nIt allows the attacker to see/modify the traffic (man-in-the-middle attack).\nHTTPS is a secure version of HTTP – it uses SSL/TLS to protect the data\nof the application layer. When HTTPS is used, the following properties are achieved:\nauthentication, data integrity, confidentiality. How are HTTP and HTTPS related to\na secure flag of the cookie?\n\nLet’s consider the case of an authentication cookie. As was previously said,\nstealing this cookie is equivalent to impersonating the user. When HTTP is used,\nthe cookie is sent in plaintext. This is fine for the attacker eavesdropping on the\ncommunication channel between the browser and the server – he can grab the cookie and\nimpersonate the user.\n\nNow let’s assume that HTTPS is used instead of HTTP.\nHTTPS provides confidentiality. That’s why the attacker can’t see the cookie.\nThe conclusion is to send the authentication cookie over a secure channel so that\nit can’t be eavesdropped. The question that might appear in this moment is:\nwhy do we need a secure flag if we can use HTTPS?\n\nLet’s consider the following scenario to answer this question.\nThe site is available over HTTP and HTTPS. Moreover, let’s assume that there is\nan attacker in the middle of the communication channel between the browser and the server.\nThe cookie sent over HTTPS can’t be eavesdropped. However, the attacker can take advantage of\nthe fact that the site is also available over HTTP. The attacker can send the link to\nthe HTTP version of the site to the user. The user clicks the link and the HTTP request\nis generated. Since HTTP traffic is sent in plaintext, the attacker eavesdrops on the\ncommunication channel and reads the authentication cookie of the user. Can we allow\nthis cookie to be sent only over HTTPS? If this was possible, we would prevent the attacker\nfrom reading the authentication cookie in our story. It turns out that it is possible,\nand a secure flag is used exactly for this purpose – the cookie with a secure flag will\nonly be sent over an HTTPS connection.\n\n3. HttpOnly Flag\n\nIn the previous section, it was presented how to protect the cookie from an attacker\neavesdropping on the communication channel between the browser and the server.\nHowever, eavesdropping is not the only attack vector to grab the cookie.\n\nLet’s continue the story with the authentication cookie and assume that XSS\n(cross-site scripting) vulnerability is present in the application. Then the\nattacker can take advantage of the XSS vulnerability to steal the authentication cookie.\nCan we somehow prevent this from happening? It turns out that an HttpOnly flag can be used\nto solve this problem. When an HttpOnly flag is used, JavaScript will not be able to read\nthis authentication cookie in case of XSS exploitation. It seems like we have achieved\nthe goal, but the problem might still be present when cross-site tracing (XST)\nvulnerability exists (this vulnerability will be explained in the next section of the article)\n – the attacker might take advantage of XSS and enabled TRACE method to read\n the authentication cookie even if HttpOnly flag is used. Let’s see how XST works.\n\nSOURCE:\nhttp://resources.infosecinstitute.com/securing-cookies-httponly-secure-flags/\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/23_set-cookie-UUID/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/23_set-cookie-UUID/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/23_set-cookie-UUID/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/julienschmidt/httprouter\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string `json:\"-\"`\n}\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tmemTemplate(res, req, \"Homepage\", \"home.html\")\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tmemTemplate(res, req, \"Loginpage\", \"login.html\")\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tmemTemplate(res, req, \"Signuppage\", \"signup.html\")\n}\n\n/*\nTO DO:\nsession\n-memcache templates\n- uuid in a cookie\n--- https while logged in? - depends upon security required\n- encrypt password on datastore?\n--- never store an unencrypted password, so, resoundingly, YES\n--- sha-256 fast hash value\n- user memcache?\n- datastore / memcache\nsession interface change\n- change login button to logout when user logged in\npost tweets\nfollow people\nsee tweets for everyone\nsee tweets for individual user\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/23_set-cookie-UUID/memcache.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc memTemplate(res http.ResponseWriter, req *http.Request, memKey, templateName string) {\n\tctx := appengine.NewContext(req)\n\ti, err := memcache.Get(ctx, memKey)\n\tif err != nil {\n\t\tbuf := new(bytes.Buffer)\n\t\twrit := io.MultiWriter(res, buf)\n\t\ttpl.ExecuteTemplate(writ, templateName, nil)\n\t\tmemcache.Set(ctx, &memcache.Item{\n\t\t\tValue: buf.Bytes(),\n\t\t\tKey:   memKey,\n\t\t})\n\t\treturn\n\t}\n\tio.WriteString(res, string(i.Value))\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/23_set-cookie-UUID/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/23_set-cookie-UUID/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/23_set-cookie-UUID/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/23_set-cookie-UUID/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#login {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#login:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/23_set-cookie-UUID/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            <a href=\"/form/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>\n{{end}}\n\n{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/23_set-cookie-UUID/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"header2\"}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/23_set-cookie-UUID/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\"}}\n    <form method=\"POST\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"email\" name=\"user\" type=\"email\" placeholder=\"Enter your email\">\n        <p class=\"form-field-err\">something</p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\">something</p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/23_set-cookie-UUID/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\"}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/23_set-cookie-UUID/userCreation.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io/ioutil\"\n\t\"net/http\"\n)\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tNewUser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: req.FormValue(\"password\"),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", NewUser.UserName, 0, nil)\n\tkey, err := datastore.Put(ctx, key, &NewUser)\n\t// this is the only error checking I added; any others on this page needed?\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\t// SET COOKIE\n\tid, _ := uuid.NewV4()\n\tcookie := &http.Cookie{\n\t\tName:  \"session\",\n\t\tValue: id.String(),\n\t\tPath:  \"/\",\n\t\t//\t\tUNCOMMENT WHEN DEPLOYED:\n\t\t//\t\tSecure: true,\n\t\t//\t\tHttpOnly: true,\n\t}\n\thttp.SetCookie(res, cookie)\n\n\t// SET MEMCACHE session data (sd)\n\tjson, err := json.Marshal(NewUser)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error marshalling during user creation: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd := memcache.Item{\n\t\tKey:   id.String(),\n\t\tValue: json,\n\t}\n\tmemcache.Set(ctx, &sd)\n\n\t// TEST memcache\n\titem, _ := memcache.Get(ctx, cookie.Value)\n\tif item != nil {\n\t\tlog.Infof(ctx, \"%s\", string(item.Value))\n\t}\n\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\n/*\n1. Introduction\n\nSecuring cookies is an important subject.\nThink about an authentication cookie. When the attacker is able to grab this cookie,\nhe can impersonate the user. This article describes HttpOnly and secure flags that can\nenhance security of cookies.\n\n2. HTTP, HTTPS and secure Flag\n\nWhen HTTP protocol is used, the traffic is sent in plaintext.\nIt allows the attacker to see/modify the traffic (man-in-the-middle attack).\nHTTPS is a secure version of HTTP – it uses SSL/TLS to protect the data\nof the application layer. When HTTPS is used, the following properties are achieved:\nauthentication, data integrity, confidentiality. How are HTTP and HTTPS related to\na secure flag of the cookie?\n\nLet’s consider the case of an authentication cookie. As was previously said,\nstealing this cookie is equivalent to impersonating the user. When HTTP is used,\nthe cookie is sent in plaintext. This is fine for the attacker eavesdropping on the\ncommunication channel between the browser and the server – he can grab the cookie and\nimpersonate the user.\n\nNow let’s assume that HTTPS is used instead of HTTP.\nHTTPS provides confidentiality. That’s why the attacker can’t see the cookie.\nThe conclusion is to send the authentication cookie over a secure channel so that\nit can’t be eavesdropped. The question that might appear in this moment is:\nwhy do we need a secure flag if we can use HTTPS?\n\nLet’s consider the following scenario to answer this question.\nThe site is available over HTTP and HTTPS. Moreover, let’s assume that there is\nan attacker in the middle of the communication channel between the browser and the server.\nThe cookie sent over HTTPS can’t be eavesdropped. However, the attacker can take advantage of\nthe fact that the site is also available over HTTP. The attacker can send the link to\nthe HTTP version of the site to the user. The user clicks the link and the HTTP request\nis generated. Since HTTP traffic is sent in plaintext, the attacker eavesdrops on the\ncommunication channel and reads the authentication cookie of the user. Can we allow\nthis cookie to be sent only over HTTPS? If this was possible, we would prevent the attacker\nfrom reading the authentication cookie in our story. It turns out that it is possible,\nand a secure flag is used exactly for this purpose – the cookie with a secure flag will\nonly be sent over an HTTPS connection.\n\n3. HttpOnly Flag\n\nIn the previous section, it was presented how to protect the cookie from an attacker\neavesdropping on the communication channel between the browser and the server.\nHowever, eavesdropping is not the only attack vector to grab the cookie.\n\nLet’s continue the story with the authentication cookie and assume that XSS\n(cross-site scripting) vulnerability is present in the application. Then the\nattacker can take advantage of the XSS vulnerability to steal the authentication cookie.\nCan we somehow prevent this from happening? It turns out that an HttpOnly flag can be used\nto solve this problem. When an HttpOnly flag is used, JavaScript will not be able to read\nthis authentication cookie in case of XSS exploitation. It seems like we have achieved\nthe goal, but the problem might still be present when cross-site tracing (XST)\nvulnerability exists (this vulnerability will be explained in the next section of the article)\n – the attacker might take advantage of XSS and enabled TRACE method to read\n the authentication cookie even if HttpOnly flag is used. Let’s see how XST works.\n\nSOURCE:\nhttp://resources.infosecinstitute.com/securing-cookies-httponly-secure-flags/\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/24_session/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/24_session/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/24_session/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\titem := loggedIn(req)\n\tctx := appengine.NewContext(req)\n\tlog.Infof(ctx, \"%v\", item.Value)\n\tlog.Infof(ctx, \"%v\", len(item.Value))\n\tif len(item.Value) > 0 {\n\t\tvar td templateData\n\t\tjson.Unmarshal(item.Value, &td)\n\t\tlog.Infof(ctx, \"%v\", td)\n\t\tlog.Infof(ctx, \"%v\", td.Email)\n\t\tlog.Infof(ctx, \"%v\", td.LoggedIn)\n\t\ttd.LoggedIn = true\n\t\tlog.Infof(ctx, \"%v\", td.LoggedIn)\n\t\ttpl.ExecuteTemplate(res, \"home.html\", td)\n\t} else {\n\t\tmemTemplate(res, req, \"Homepage\", \"home.html\")\n\t}\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tmemTemplate(res, req, \"Loginpage\", \"login.html\")\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tmemTemplate(res, req, \"Signuppage\", \"signup.html\")\n}\n\n/*\nTO DO:\nsession\n-memcache templates\n- uuid in a cookie\n--- https while logged in? - depends upon security required\n- encrypt password on datastore?\n--- never store an unencrypted password, so, resoundingly, YES\n--- sha-256 fast hash value\n- user memcache?\n- datastore / memcache\nsession interface change\n- change login button to logout when user logged in\npost tweets\nfollow people\nsee tweets for everyone\nsee tweets for individual user\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/24_session/memcache.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc memTemplate(res http.ResponseWriter, req *http.Request, memKey, templateName string) {\n\tctx := appengine.NewContext(req)\n\ti, err := memcache.Get(ctx, memKey)\n\tif err != nil {\n\t\tbuf := new(bytes.Buffer)\n\t\twrit := io.MultiWriter(res, buf)\n\t\ttpl.ExecuteTemplate(writ, templateName, templateData{})\n\t\tmemcache.Set(ctx, &memcache.Item{\n\t\t\tValue: buf.Bytes(),\n\t\t\tKey:   memKey,\n\t\t})\n\t\treturn\n\t}\n\tio.WriteString(res, string(i.Value))\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/24_session/model.go",
    "content": "package main\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string `json:\"-\"`\n}\n\ntype templateData struct {\n\tUser\n\tLoggedIn bool\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/24_session/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/24_session/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/24_session/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/24_session/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#loginOut {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#loginOut:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/24_session/session.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"net/http\"\n)\n\nfunc loggedIn(req *http.Request) *memcache.Item {\n\tcookie, err := req.Cookie(\"session\")\n\tif err != nil {\n\t\treturn &memcache.Item{}\n\t}\n\n\tctx := appengine.NewContext(req)\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\treturn &memcache.Item{}\n\t}\n\tlog.Infof(ctx, \"%s\", string(item.Value))\n\treturn item\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/24_session/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            {{if .LoggedIn}}\n            <a href=\"/api/logout\"><p id=\"loginOut\">Log Out</p></a>\n            {{else}}\n            <a href=\"/form/login\"><p id=\"loginOut\">Log In</p></a>\n            {{end}}\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n    <p>{{.}}</p>\n    <p>{{.Email}}</p>\n    <p>{{.UserName}}</p>\n    <p>{{.LoggedIn}}</p>\n</div>\n{{end}}\n\n{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/24_session/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"header2\" .}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <p>{{.}}</p>\n    <p>{{.Email}}</p>\n    <p>{{.UserName}}</p>\n    <p>{{.LoggedIn}}</p>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/24_session/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\"}}\n    <form method=\"POST\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"email\" name=\"user\" type=\"email\" placeholder=\"Enter your email\">\n        <p class=\"form-field-err\">something</p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\">something</p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/24_session/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\"}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/24_session/userCreation.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tNewUser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: req.FormValue(\"password\"),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", NewUser.UserName, 0, nil)\n\tkey, err := datastore.Put(ctx, key, &NewUser)\n\t// this is the only error checking I added; any others on this page needed?\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\t// SET COOKIE\n\tid, _ := uuid.NewV4()\n\tcookie := &http.Cookie{\n\t\tName:  \"session\",\n\t\tValue: id.String(),\n\t\tPath:  \"/\",\n\t\t//\t\tUNCOMMENT WHEN DEPLOYED:\n\t\t//\t\tSecure: true,\n\t\t//\t\tHttpOnly: true,\n\t}\n\thttp.SetCookie(res, cookie)\n\n\t// SET MEMCACHE session data (sd)\n\tjson, err := json.Marshal(NewUser)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error marshalling during user creation: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd := memcache.Item{\n\t\tKey:   id.String(),\n\t\tValue: json,\n\t\t//\t\tExpiration: time.Duration(20*time.Minute),\n\t\tExpiration: time.Duration(20 * time.Second),\n\t}\n\tmemcache.Set(ctx, &sd)\n\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\n/*\n1. Introduction\n\nSecuring cookies is an important subject.\nThink about an authentication cookie. When the attacker is able to grab this cookie,\nhe can impersonate the user. This article describes HttpOnly and secure flags that can\nenhance security of cookies.\n\n2. HTTP, HTTPS and secure Flag\n\nWhen HTTP protocol is used, the traffic is sent in plaintext.\nIt allows the attacker to see/modify the traffic (man-in-the-middle attack).\nHTTPS is a secure version of HTTP – it uses SSL/TLS to protect the data\nof the application layer. When HTTPS is used, the following properties are achieved:\nauthentication, data integrity, confidentiality. How are HTTP and HTTPS related to\na secure flag of the cookie?\n\nLet’s consider the case of an authentication cookie. As was previously said,\nstealing this cookie is equivalent to impersonating the user. When HTTP is used,\nthe cookie is sent in plaintext. This is fine for the attacker eavesdropping on the\ncommunication channel between the browser and the server – he can grab the cookie and\nimpersonate the user.\n\nNow let’s assume that HTTPS is used instead of HTTP.\nHTTPS provides confidentiality. That’s why the attacker can’t see the cookie.\nThe conclusion is to send the authentication cookie over a secure channel so that\nit can’t be eavesdropped. The question that might appear in this moment is:\nwhy do we need a secure flag if we can use HTTPS?\n\nLet’s consider the following scenario to answer this question.\nThe site is available over HTTP and HTTPS. Moreover, let’s assume that there is\nan attacker in the middle of the communication channel between the browser and the server.\nThe cookie sent over HTTPS can’t be eavesdropped. However, the attacker can take advantage of\nthe fact that the site is also available over HTTP. The attacker can send the link to\nthe HTTP version of the site to the user. The user clicks the link and the HTTP request\nis generated. Since HTTP traffic is sent in plaintext, the attacker eavesdrops on the\ncommunication channel and reads the authentication cookie of the user. Can we allow\nthis cookie to be sent only over HTTPS? If this was possible, we would prevent the attacker\nfrom reading the authentication cookie in our story. It turns out that it is possible,\nand a secure flag is used exactly for this purpose – the cookie with a secure flag will\nonly be sent over an HTTPS connection.\n\n3. HttpOnly Flag\n\nIn the previous section, it was presented how to protect the cookie from an attacker\neavesdropping on the communication channel between the browser and the server.\nHowever, eavesdropping is not the only attack vector to grab the cookie.\n\nLet’s continue the story with the authentication cookie and assume that XSS\n(cross-site scripting) vulnerability is present in the application. Then the\nattacker can take advantage of the XSS vulnerability to steal the authentication cookie.\nCan we somehow prevent this from happening? It turns out that an HttpOnly flag can be used\nto solve this problem. When an HttpOnly flag is used, JavaScript will not be able to read\nthis authentication cookie in case of XSS exploitation. It seems like we have achieved\nthe goal, but the problem might still be present when cross-site tracing (XST)\nvulnerability exists (this vulnerability will be explained in the next section of the article)\n – the attacker might take advantage of XSS and enabled TRACE method to read\n the authentication cookie even if HttpOnly flag is used. Let’s see how XST works.\n\nSOURCE:\nhttp://resources.infosecinstitute.com/securing-cookies-httponly-secure-flags/\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/25_session-all-pages/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/25_session-all-pages/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/25_session-all-pages/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/julienschmidt/httprouter\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"Homepage\", \"home.html\")\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"Loginpage\", \"login.html\")\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"Signuppage\", \"signup.html\")\n}\n\n/*\nTO DO:\nsession\n-memcache templates\n- uuid in a cookie\n--- https while logged in? - depends upon security required\n- encrypt password on datastore?\n--- never store an unencrypted password, so, resoundingly, YES\n--- sha-256 fast hash value\n- user memcache?\n- datastore / memcache\nsession interface change\n- change login button to logout when user logged in\npost tweets\nfollow people\nsee tweets for everyone\nsee tweets for individual user\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/25_session-all-pages/model.go",
    "content": "package main\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string `json:\"-\"`\n}\n\ntype sessionData struct {\n\tUser\n\tLoggedIn bool\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/25_session-all-pages/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/25_session-all-pages/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/25_session-all-pages/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/25_session-all-pages/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#loginOut {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#loginOut:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/25_session-all-pages/session.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"net/http\"\n)\n\nfunc getSession(req *http.Request) *memcache.Item {\n\tcookie, err := req.Cookie(\"session\")\n\tif err != nil {\n\t\treturn &memcache.Item{}\n\t}\n\n\tctx := appengine.NewContext(req)\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\treturn &memcache.Item{}\n\t}\n\tlog.Infof(ctx, \"%s\", string(item.Value))\n\treturn item\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/25_session-all-pages/template.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc serveTemplate(res http.ResponseWriter, req *http.Request, pageKey, templateName string) {\n\tsession := getSession(req)\n\tif len(session.Value) > 0 {\n\t\tvar sd sessionData\n\t\tjson.Unmarshal(session.Value, &sd)\n\t\tsd.LoggedIn = true\n\t\ttpl.ExecuteTemplate(res, templateName, sd)\n\t} else {\n\t\tctx := appengine.NewContext(req)\n\t\ti, err := memcache.Get(ctx, pageKey)\n\t\tif err != nil {\n\t\t\tbuf := new(bytes.Buffer)\n\t\t\twrit := io.MultiWriter(res, buf)\n\t\t\ttpl.ExecuteTemplate(writ, templateName, sessionData{})\n\t\t\tmemcache.Set(ctx, &memcache.Item{\n\t\t\t\tValue: buf.Bytes(),\n\t\t\t\tKey:   pageKey,\n\t\t\t})\n\t\t\treturn\n\t\t}\n\t\tio.WriteString(res, string(i.Value)) // we're serving the page from memcache\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/25_session-all-pages/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            {{if .LoggedIn}}\n            <a href=\"/api/logout\"><p id=\"loginOut\">Log Out</p></a>\n            {{else}}\n            <a href=\"/form/login\"><p id=\"loginOut\">Log In</p></a>\n            {{end}}\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n    <p>{{.}}</p>\n    <p>{{.Email}}</p>\n    <p>{{.UserName}}</p>\n    <p>{{.LoggedIn}}</p>\n</div>\n{{end}}\n\n{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/25_session-all-pages/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"header2\" .}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <p>{{.}}</p>\n    <p>{{.Email}}</p>\n    <p>{{.UserName}}</p>\n    <p>{{.LoggedIn}}</p>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/25_session-all-pages/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\" .}}\n    <form method=\"POST\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"email\" name=\"user\" type=\"email\" placeholder=\"Enter your email\">\n        <p class=\"form-field-err\">something</p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\">something</p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/25_session-all-pages/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\" .}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/25_session-all-pages/userCreation.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tNewUser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: req.FormValue(\"password\"),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", NewUser.UserName, 0, nil)\n\tkey, err := datastore.Put(ctx, key, &NewUser)\n\t// this is the only error checking I added; any others on this page needed?\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\t// SET COOKIE\n\tid, _ := uuid.NewV4()\n\tcookie := &http.Cookie{\n\t\tName:  \"session\",\n\t\tValue: id.String(),\n\t\tPath:  \"/\",\n\t\t//\t\tUNCOMMENT WHEN DEPLOYED:\n\t\t//\t\tSecure: true,\n\t\t//\t\tHttpOnly: true,\n\t}\n\thttp.SetCookie(res, cookie)\n\n\t// SET MEMCACHE session data (sd)\n\tjson, err := json.Marshal(NewUser)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error marshalling during user creation: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd := memcache.Item{\n\t\tKey:   id.String(),\n\t\tValue: json,\n\t\t//\t\tExpiration: time.Duration(20*time.Minute),\n\t\tExpiration: time.Duration(20 * time.Second),\n\t}\n\tmemcache.Set(ctx, &sd)\n\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\n/*\n1. Introduction\n\nSecuring cookies is an important subject.\nThink about an authentication cookie. When the attacker is able to grab this cookie,\nhe can impersonate the user. This article describes HttpOnly and secure flags that can\nenhance security of cookies.\n\n2. HTTP, HTTPS and secure Flag\n\nWhen HTTP protocol is used, the traffic is sent in plaintext.\nIt allows the attacker to see/modify the traffic (man-in-the-middle attack).\nHTTPS is a secure version of HTTP – it uses SSL/TLS to protect the data\nof the application layer. When HTTPS is used, the following properties are achieved:\nauthentication, data integrity, confidentiality. How are HTTP and HTTPS related to\na secure flag of the cookie?\n\nLet’s consider the case of an authentication cookie. As was previously said,\nstealing this cookie is equivalent to impersonating the user. When HTTP is used,\nthe cookie is sent in plaintext. This is fine for the attacker eavesdropping on the\ncommunication channel between the browser and the server – he can grab the cookie and\nimpersonate the user.\n\nNow let’s assume that HTTPS is used instead of HTTP.\nHTTPS provides confidentiality. That’s why the attacker can’t see the cookie.\nThe conclusion is to send the authentication cookie over a secure channel so that\nit can’t be eavesdropped. The question that might appear in this moment is:\nwhy do we need a secure flag if we can use HTTPS?\n\nLet’s consider the following scenario to answer this question.\nThe site is available over HTTP and HTTPS. Moreover, let’s assume that there is\nan attacker in the middle of the communication channel between the browser and the server.\nThe cookie sent over HTTPS can’t be eavesdropped. However, the attacker can take advantage of\nthe fact that the site is also available over HTTP. The attacker can send the link to\nthe HTTP version of the site to the user. The user clicks the link and the HTTP request\nis generated. Since HTTP traffic is sent in plaintext, the attacker eavesdrops on the\ncommunication channel and reads the authentication cookie of the user. Can we allow\nthis cookie to be sent only over HTTPS? If this was possible, we would prevent the attacker\nfrom reading the authentication cookie in our story. It turns out that it is possible,\nand a secure flag is used exactly for this purpose – the cookie with a secure flag will\nonly be sent over an HTTPS connection.\n\n3. HttpOnly Flag\n\nIn the previous section, it was presented how to protect the cookie from an attacker\neavesdropping on the communication channel between the browser and the server.\nHowever, eavesdropping is not the only attack vector to grab the cookie.\n\nLet’s continue the story with the authentication cookie and assume that XSS\n(cross-site scripting) vulnerability is present in the application. Then the\nattacker can take advantage of the XSS vulnerability to steal the authentication cookie.\nCan we somehow prevent this from happening? It turns out that an HttpOnly flag can be used\nto solve this problem. When an HttpOnly flag is used, JavaScript will not be able to read\nthis authentication cookie in case of XSS exploitation. It seems like we have achieved\nthe goal, but the problem might still be present when cross-site tracing (XST)\nvulnerability exists (this vulnerability will be explained in the next section of the article)\n – the attacker might take advantage of XSS and enabled TRACE method to read\n the authentication cookie even if HttpOnly flag is used. Let’s see how XST works.\n\nSOURCE:\nhttp://resources.infosecinstitute.com/securing-cookies-httponly-secure-flags/\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/26_login/api.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tuser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: req.FormValue(\"password\"),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey, err := datastore.Put(ctx, key, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tcreateSession(res, req, user)\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Users\", req.FormValue(\"userName\"), 0, nil)\n\tvar user User\n\terr := datastore.Get(ctx, key, &user)\n\tif err != nil || req.FormValue(\"password\") != user.Password {\n\t\t// failure logging in\n\t\tvar sd sessionData\n\t\tsd.LoginFail = true\n\t\ttpl.ExecuteTemplate(res, \"login.html\", sd)\n\t\treturn\n\t} else {\n\t\tuser.UserName = req.FormValue(\"userName\")\n\t\t// success logging in\n\t\tcreateSession(res, req, user)\n\t\t// redirect\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t}\n}\n\nfunc createSession(res http.ResponseWriter, req *http.Request, user User) {\n\tctx := appengine.NewContext(req)\n\t// SET COOKIE\n\tid, _ := uuid.NewV4()\n\tcookie := &http.Cookie{\n\t\tName:  \"session\",\n\t\tValue: id.String(),\n\t\tPath:  \"/\",\n\t\t//\t\tUNCOMMENT WHEN DEPLOYED:\n\t\t//\t\tSecure: true,\n\t\t//\t\tHttpOnly: true,\n\t}\n\thttp.SetCookie(res, cookie)\n\n\t// SET MEMCACHE session data (sd)\n\tjson, err := json.Marshal(user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error marshalling during user creation: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd := memcache.Item{\n\t\tKey:   id.String(),\n\t\tValue: json,\n\t\t//\t\tExpiration: time.Duration(20*time.Minute),\n\t\tExpiration: time.Duration(20 * time.Second),\n\t}\n\tmemcache.Set(ctx, &sd)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/26_login/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/26_login/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/26_login/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/julienschmidt/httprouter\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\tr.POST(\"/api/login\", login)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"home.html\")\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"login.html\")\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"signup.html\")\n}\n\n/*\nTO DO:\nsession\n-memcache templates\n- uuid in a cookie\n--- https while logged in? - depends upon security required\n- encrypt password on datastore?\n--- never store an unencrypted password, so, resoundingly, YES\n--- sha-256 fast hash value\n- user memcache?\n- datastore / memcache\nsession interface change\n- change login button to logout when user logged in\npost tweets\nfollow people\nsee tweets for everyone\nsee tweets for individual user\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/26_login/model.go",
    "content": "package main\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string `json:\"-\"`\n}\n\ntype sessionData struct {\n\tUser\n\tLoggedIn  bool\n\tLoginFail bool\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/26_login/notes.txt",
    "content": "Sessions - Three Options:\n\nGOOGLE\nUse Google logins and their session\n\nGORILLA\nUse Gorilla sessions\nstore session data in cookie or memcache\n\nHMAC / NO-HMAC\ndo a regular cookie\nstore in that cookie a session ID\nstore session data in cookie or memcache\n"
  },
  {
    "path": "27_code-in-process/56_twitter/26_login/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/26_login/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/26_login/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/26_login/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#loginOut {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#loginOut:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/26_login/session.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"net/http\"\n)\n\nfunc getSession(req *http.Request) *memcache.Item {\n\tcookie, err := req.Cookie(\"session\")\n\tif err != nil {\n\t\treturn &memcache.Item{}\n\t}\n\n\tctx := appengine.NewContext(req)\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\treturn &memcache.Item{}\n\t}\n\tlog.Infof(ctx, \"%s\", string(item.Value))\n\treturn item\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/26_login/template.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc serveTemplate(res http.ResponseWriter, req *http.Request, templateName string) {\n\tsession := getSession(req)\n\tif len(session.Value) > 0 {\n\t\tvar sd sessionData\n\t\tjson.Unmarshal(session.Value, &sd)\n\t\tsd.LoggedIn = true\n\t\ttpl.ExecuteTemplate(res, templateName, sd)\n\t} else {\n\t\tctx := appengine.NewContext(req)\n\t\ti, err := memcache.Get(ctx, templateName)\n\t\tif err != nil {\n\t\t\tbuf := new(bytes.Buffer)\n\t\t\twrit := io.MultiWriter(res, buf)\n\t\t\ttpl.ExecuteTemplate(writ, templateName, sessionData{})\n\t\t\tmemcache.Set(ctx, &memcache.Item{\n\t\t\t\tValue: buf.Bytes(),\n\t\t\t\tKey:   templateName,\n\t\t\t})\n\t\t\treturn\n\t\t}\n\t\tio.WriteString(res, string(i.Value)) // we're serving the page from memcache\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/26_login/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            {{if .LoggedIn}}\n            <a href=\"/api/logout\"><p id=\"loginOut\">Log Out</p></a>\n            {{else}}\n            <a href=\"/form/login\"><p id=\"loginOut\">Log In</p></a>\n            {{end}}\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n    <p>{{.}}</p>\n    <p>{{.Email}}</p>\n    <p>{{.UserName}}</p>\n    <p>{{.LoggedIn}}</p>\n</div>\n{{end}}\n\n{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/26_login/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"header2\" .}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <p>{{.}}</p>\n    <p>{{.Email}}</p>\n    <p>{{.UserName}}</p>\n    <p>{{.LoggedIn}}</p>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/26_login/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\" .}}\n    <form method=\"POST\" action=\"/api/login\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"userName\" name=\"userName\" placeholder=\"Enter your user name\">\n        <p class=\"form-field-err\"></p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\"></p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/26_login/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\" .}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/27_logout/api.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tuser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: req.FormValue(\"password\"),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey, err := datastore.Put(ctx, key, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tcreateSession(res, req, user)\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Users\", req.FormValue(\"userName\"), 0, nil)\n\tvar user User\n\terr := datastore.Get(ctx, key, &user)\n\tif err != nil || req.FormValue(\"password\") != user.Password {\n\t\t// failure logging in\n\t\tvar sd sessionData\n\t\tsd.LoginFail = true\n\t\ttpl.ExecuteTemplate(res, \"login.html\", sd)\n\t\treturn\n\t} else {\n\t\tuser.UserName = req.FormValue(\"userName\")\n\t\t// success logging in\n\t\tcreateSession(res, req, user)\n\t\t// redirect\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t}\n}\n\nfunc createSession(res http.ResponseWriter, req *http.Request, user User) {\n\tctx := appengine.NewContext(req)\n\t// SET COOKIE\n\tid, _ := uuid.NewV4()\n\tcookie := &http.Cookie{\n\t\tName:  \"session\",\n\t\tValue: id.String(),\n\t\tPath:  \"/\",\n\t\t//\t\tUNCOMMENT WHEN DEPLOYED:\n\t\t//\t\tSecure: true,\n\t\t//\t\tHttpOnly: true,\n\t}\n\thttp.SetCookie(res, cookie)\n\n\t// SET MEMCACHE session data (sd)\n\tjson, err := json.Marshal(user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error marshalling during user creation: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd := memcache.Item{\n\t\tKey:   id.String(),\n\t\tValue: json,\n\t\t//\t\tExpiration: time.Duration(20*time.Minute),\n\t\tExpiration: time.Duration(20 * time.Second),\n\t}\n\tmemcache.Set(ctx, &sd)\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\t// cookie is not set\n\tif err != nil {\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t}\n\n\t// clear memcache\n\tsd := memcache.Item{\n\t\tKey:        cookie.Value,\n\t\tValue:      []byte(\"\"),\n\t\tExpiration: time.Duration(1 * time.Microsecond),\n\t}\n\tmemcache.Set(ctx, &sd)\n\n\t// clear the cookie\n\tcookie.MaxAge = -1\n\thttp.SetCookie(res, cookie)\n\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/27_logout/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/27_logout/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/27_logout/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/julienschmidt/httprouter\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\tr.POST(\"/api/login\", login)\n\tr.GET(\"/api/logout\", logout)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"home.html\")\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"login.html\")\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"signup.html\")\n}\n\n/*\nTO DO:\nsession\n-memcache templates\n- uuid in a cookie\n--- https while logged in? - depends upon security required\n- encrypt password on datastore?\n--- never store an unencrypted password, so, resoundingly, YES\n--- sha-256 fast hash value\n- user memcache?\n- datastore / memcache\nsession interface change\n- change login button to logout when user logged in\npost tweets\nfollow people\nsee tweets for everyone\nsee tweets for individual user\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/27_logout/model.go",
    "content": "package main\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string `json:\"-\"`\n}\n\ntype sessionData struct {\n\tUser\n\tLoggedIn  bool\n\tLoginFail bool\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/27_logout/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/27_logout/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/27_logout/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/27_logout/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#loginOut {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#loginOut:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/27_logout/session.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"net/http\"\n)\n\nfunc getSession(req *http.Request) *memcache.Item {\n\tcookie, err := req.Cookie(\"session\")\n\tif err != nil {\n\t\treturn &memcache.Item{}\n\t}\n\n\tctx := appengine.NewContext(req)\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\treturn &memcache.Item{}\n\t}\n\tlog.Infof(ctx, \"%s\", string(item.Value))\n\treturn item\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/27_logout/template.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc serveTemplate(res http.ResponseWriter, req *http.Request, templateName string) {\n\tsession := getSession(req)\n\tif len(session.Value) > 0 {\n\t\tvar sd sessionData\n\t\tjson.Unmarshal(session.Value, &sd)\n\t\tsd.LoggedIn = true\n\t\ttpl.ExecuteTemplate(res, templateName, sd)\n\t} else {\n\t\tctx := appengine.NewContext(req)\n\t\ti, err := memcache.Get(ctx, templateName)\n\t\tif err != nil {\n\t\t\tbuf := new(bytes.Buffer)\n\t\t\twrit := io.MultiWriter(res, buf)\n\t\t\ttpl.ExecuteTemplate(writ, templateName, sessionData{})\n\t\t\tmemcache.Set(ctx, &memcache.Item{\n\t\t\t\tValue: buf.Bytes(),\n\t\t\t\tKey:   templateName,\n\t\t\t})\n\t\t\treturn\n\t\t}\n\t\tio.WriteString(res, string(i.Value)) // we're serving the page from memcache\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/27_logout/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            {{if .LoggedIn}}\n            <a href=\"/api/logout\"><p id=\"loginOut\">Log Out</p></a>\n            {{else}}\n            <a href=\"/form/login\"><p id=\"loginOut\">Log In</p></a>\n            {{end}}\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n    <p>{{.}}</p>\n    <p>{{.Email}}</p>\n    <p>{{.UserName}}</p>\n    <p>{{.LoggedIn}}</p>\n</div>\n{{end}}\n\n{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/27_logout/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"header2\" .}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <p>{{.}}</p>\n    <p>{{.Email}}</p>\n    <p>{{.UserName}}</p>\n    <p>{{.LoggedIn}}</p>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/27_logout/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\" .}}\n    <form method=\"POST\" action=\"/api/login\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"userName\" name=\"userName\" placeholder=\"Enter your user name\">\n        <p class=\"form-field-err\"></p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\"></p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/27_logout/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\" .}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/28_code-review/api.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tuser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: req.FormValue(\"password\"),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey, err := datastore.Put(ctx, key, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tcreateSession(res, req, user)\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc loginProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Users\", req.FormValue(\"userName\"), 0, nil)\n\tvar user User\n\terr := datastore.Get(ctx, key, &user)\n\tif err != nil || req.FormValue(\"password\") != user.Password {\n\t\t// failure logging in\n\t\tvar sd SessionData\n\t\tsd.LoginFail = true\n\t\ttpl.ExecuteTemplate(res, \"login.html\", sd)\n\t\treturn\n\t} else {\n\t\tuser.UserName = req.FormValue(\"userName\")\n\t\t// success logging in\n\t\tcreateSession(res, req, user)\n\t\t// redirect\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t}\n}\n\nfunc createSession(res http.ResponseWriter, req *http.Request, user User) {\n\tctx := appengine.NewContext(req)\n\t// SET COOKIE\n\tid, _ := uuid.NewV4()\n\tcookie := &http.Cookie{\n\t\tName:  \"session\",\n\t\tValue: id.String(),\n\t\tPath:  \"/\",\n\t\t//\t\tUNCOMMENT WHEN DEPLOYED:\n\t\t//\t\tSecure: true,\n\t\t//\t\tHttpOnly: true,\n\t}\n\thttp.SetCookie(res, cookie)\n\n\t// SET MEMCACHE session data (sd)\n\tjson, err := json.Marshal(user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error marshalling during user creation: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd := memcache.Item{\n\t\tKey:   id.String(),\n\t\tValue: json,\n\t\t//\t\tExpiration: time.Duration(20*time.Minute),\n\t\tExpiration: time.Duration(20 * time.Second),\n\t}\n\tmemcache.Set(ctx, &sd)\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\t// cookie is not set\n\tif err != nil {\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t\treturn\n\t}\n\n\t// clear memcache\n\tsd := memcache.Item{\n\t\tKey:        cookie.Value,\n\t\tValue:      []byte(\"\"),\n\t\tExpiration: time.Duration(1 * time.Microsecond),\n\t}\n\tmemcache.Set(ctx, &sd)\n\n\t// clear the cookie\n\tcookie.MaxAge = -1\n\thttp.SetCookie(res, cookie)\n\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/28_code-review/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/28_code-review/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/28_code-review/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/julienschmidt/httprouter\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\tr.POST(\"/api/login\", loginProcess)\n\tr.GET(\"/api/logout\", logout)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"home.html\")\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"login.html\")\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"signup.html\")\n}\n\n/*\nTO DO:\nsession\n-memcache templates\n- uuid in a cookie\n--- https while logged in? - depends upon security required\n- encrypt password on datastore?\n--- never store an unencrypted password, so, resoundingly, YES\n--- sha-256 fast hash value\n- user memcache?\n- datastore / memcache\nsession interface change\n- change login button to logout when user logged in\npost tweets\nfollow people\nsee tweets for everyone\nsee tweets for individual user\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/28_code-review/model.go",
    "content": "package main\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string `json:\"-\"`\n}\n\ntype SessionData struct {\n\tUser\n\tLoggedIn  bool\n\tLoginFail bool\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/28_code-review/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/28_code-review/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/28_code-review/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/28_code-review/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#loginOut {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#loginOut:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/28_code-review/session.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"net/http\"\n)\n\nfunc getSession(req *http.Request) *memcache.Item {\n\tcookie, err := req.Cookie(\"session\")\n\tif err != nil {\n\t\treturn &memcache.Item{}\n\t}\n\n\tctx := appengine.NewContext(req)\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\treturn &memcache.Item{}\n\t}\n\treturn item\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/28_code-review/template.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc serveTemplate(res http.ResponseWriter, req *http.Request, templateName string) {\n\tmemItem := getSession(req)\n\tif len(memItem.Value) > 0 {\n\t\tvar sd SessionData\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t\ttpl.ExecuteTemplate(res, templateName, sd)\n\t} else {\n\t\tctx := appengine.NewContext(req)\n\t\ti, err := memcache.Get(ctx, templateName)\n\t\tif err != nil {\n\t\t\tbuf := new(bytes.Buffer)\n\t\t\twrit := io.MultiWriter(res, buf)\n\t\t\ttpl.ExecuteTemplate(writ, templateName, SessionData{})\n\t\t\tmemcache.Set(ctx, &memcache.Item{\n\t\t\t\tKey:   templateName,\n\t\t\t\tValue: buf.Bytes(),\n\t\t\t})\n\t\t\treturn\n\t\t}\n\t\tio.WriteString(res, string(i.Value)) // we're serving the page from memcache\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/28_code-review/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            {{if .LoggedIn}}\n            <a href=\"/api/logout\"><p id=\"loginOut\">Log Out</p></a>\n            {{else}}\n            <a href=\"/form/login\"><p id=\"loginOut\">Log In</p></a>\n            {{end}}\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n    <p>{{.}}</p>\n    <p>{{.Email}}</p>\n    <p>{{.UserName}}</p>\n    <p>{{.LoggedIn}}</p>\n</div>\n{{end}}\n\n{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/28_code-review/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"header2\" .}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <p>{{.}}</p>\n    <p>{{.Email}}</p>\n    <p>{{.UserName}}</p>\n    <p>{{.LoggedIn}}</p>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/28_code-review/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\" .}}\n    <form method=\"POST\" action=\"/api/login\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"userName\" name=\"userName\" placeholder=\"Enter your user name\">\n        <p class=\"form-field-err\"></p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\"></p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/28_code-review/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\" .}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/29_password-encryption/READ-ME.txt",
    "content": "ENCRYPT / HASH passwords\n- make your hash slow\n--- prevents brute force\n- salt your hash\n--- store your salt with your hash so you can use it\n--- each salt is unique to each password\n- Corey used bcrypt to do this:\ngolang.org/x/crypto/bcrypt\n- golang.org/x/ are maybe experimental projects made by google and not yet in standard library\n- you could also us a second salt, called a pepper sometimes\n-- this is a code unique to the whole website\n-- it's not stored with the passwords\nhttps://github.com/Saxleader/fall2015/tree/master/code-review_improvement\n\n/////////////////////////////\n\nhttps://github.com/FelixVicis/f15_advWeb_amills/tree/master/twitterclone\nfound error on line 63 of api.go, SessionData was misspelled\nStarted making global messages, Toots\n\ntype Toot struct {\n\tUserName string\n\tMessage  string\n}\n- also add in\n-- time of tweet\n-- make sure username unique\n\nRan into issue with serveTemplate, may need to extend functionality\numm. server 500 error. welp. something went wonky.\n\n\n/////////////////////////////\n\ntype Post struct {\n\tUsername string\n\tPost     string\n}\n\n\nposting user tweets\nusing jquery\nhttps://github.com/herrschwartz/AdvWeb\n\n\n//////////////////////////////\n\nprevent brute force\n- check IP address\n-- store in memcache\n- limited login attempts per account for certain time period\n\nhttps://godoc.org/net/http#Request\n// RemoteAddr allows HTTP servers and other software to record\n    // the network address that sent the request, usually for\n    // logging. This field is not filled in by ReadRequest and\n    // has no defined format. The HTTP server in this package\n    // sets RemoteAddr to an \"IP:port\" address before invoking a\n    // handler.\n    // This field is ignored by the HTTP client.\n    RemoteAddr string\n\n- package subtle\n\n/////////////\n\nauthenticate user when they create account\n- send email and have confirmation link to click\n\n//////////////\n\nxss\n\n\n"
  },
  {
    "path": "27_code-in-process/56_twitter/29_password-encryption/api.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"golang.org/x/crypto/bcrypt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\thashedPass, err := bcrypt.GenerateFromPassword([]byte(req.FormValue(\"password\")), bcrypt.DefaultCost)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error creating password: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tuser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: string(hashedPass),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey, err = datastore.Put(ctx, key, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tcreateSession(res, req, user)\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc loginProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Users\", req.FormValue(\"userName\"), 0, nil)\n\tvar user User\n\terr := datastore.Get(ctx, key, &user)\n\tif err != nil || bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.FormValue(\"password\"))) != nil {\n\t\t// failure logging in\n\t\tvar sd SessionData\n\t\tsd.LoginFail = true\n\t\ttpl.ExecuteTemplate(res, \"login.html\", sd)\n\t\treturn\n\t} else {\n\t\tuser.UserName = req.FormValue(\"userName\")\n\t\t// success logging in\n\t\tcreateSession(res, req, user)\n\t\t// redirect\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t}\n}\n\nfunc createSession(res http.ResponseWriter, req *http.Request, user User) {\n\tctx := appengine.NewContext(req)\n\t// SET COOKIE\n\tid, _ := uuid.NewV4()\n\tcookie := &http.Cookie{\n\t\tName:  \"session\",\n\t\tValue: id.String(),\n\t\tPath:  \"/\",\n\t\t//\t\tUNCOMMENT WHEN DEPLOYED:\n\t\t//\t\tSecure: true,\n\t\t//\t\tHttpOnly: true,\n\t}\n\thttp.SetCookie(res, cookie)\n\n\t// SET MEMCACHE session data (sd)\n\tjson, err := json.Marshal(user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error marshalling during user creation: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd := memcache.Item{\n\t\tKey:   id.String(),\n\t\tValue: json,\n\t\t//\t\tExpiration: time.Duration(20*time.Minute),\n\t\tExpiration: time.Duration(20 * time.Second),\n\t}\n\tmemcache.Set(ctx, &sd)\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\t// cookie is not set\n\tif err != nil {\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t\treturn\n\t}\n\n\t// clear memcache\n\tsd := memcache.Item{\n\t\tKey:        cookie.Value,\n\t\tValue:      []byte(\"\"),\n\t\tExpiration: time.Duration(1 * time.Microsecond),\n\t}\n\tmemcache.Set(ctx, &sd)\n\n\t// clear the cookie\n\tcookie.MaxAge = -1\n\thttp.SetCookie(res, cookie)\n\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/29_password-encryption/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/29_password-encryption/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/29_password-encryption/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/julienschmidt/httprouter\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\tr.POST(\"/api/login\", loginProcess)\n\tr.GET(\"/api/logout\", logout)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"home.html\")\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"login.html\")\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"signup.html\")\n}\n\n/*\nTO DO:\nsession\n-memcache templates\n- uuid in a cookie\n--- https while logged in? - depends upon security required\n- encrypt password on datastore?\n--- never store an unencrypted password, so, resoundingly, YES\n--- sha-256 fast hash value\n- user memcache?\n- datastore / memcache\nsession interface change\n- change login button to logout when user logged in\npost tweets\nfollow people\nsee tweets for everyone\nsee tweets for individual user\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/29_password-encryption/model.go",
    "content": "package main\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string `json:\"-\"`\n}\n\ntype SessionData struct {\n\tUser\n\tLoggedIn  bool\n\tLoginFail bool\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/29_password-encryption/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/29_password-encryption/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/29_password-encryption/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/29_password-encryption/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#loginOut {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#loginOut:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/29_password-encryption/session.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"net/http\"\n)\n\nfunc getSession(req *http.Request) *memcache.Item {\n\tcookie, err := req.Cookie(\"session\")\n\tif err != nil {\n\t\treturn &memcache.Item{}\n\t}\n\n\tctx := appengine.NewContext(req)\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\treturn &memcache.Item{}\n\t}\n\treturn item\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/29_password-encryption/template.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc serveTemplate(res http.ResponseWriter, req *http.Request, templateName string) {\n\tmemItem := getSession(req)\n\tif len(memItem.Value) > 0 {\n\t\tvar sd SessionData\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t\ttpl.ExecuteTemplate(res, templateName, sd)\n\t} else {\n\t\tctx := appengine.NewContext(req)\n\t\ti, err := memcache.Get(ctx, templateName)\n\t\tif err != nil {\n\t\t\tbuf := new(bytes.Buffer)\n\t\t\twrit := io.MultiWriter(res, buf)\n\t\t\ttpl.ExecuteTemplate(writ, templateName, SessionData{})\n\t\t\tmemcache.Set(ctx, &memcache.Item{\n\t\t\t\tKey:   templateName,\n\t\t\t\tValue: buf.Bytes(),\n\t\t\t})\n\t\t\treturn\n\t\t}\n\t\tio.WriteString(res, string(i.Value)) // we're serving the page from memcache\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/29_password-encryption/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            {{if .LoggedIn}}\n            <a href=\"/api/logout\"><p id=\"loginOut\">Log Out</p></a>\n            {{else}}\n            <a href=\"/form/login\"><p id=\"loginOut\">Log In</p></a>\n            {{end}}\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n    <p>{{.}}</p>\n    <p>{{.Email}}</p>\n    <p>{{.UserName}}</p>\n    <p>{{.LoggedIn}}</p>\n</div>\n{{end}}\n\n{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/29_password-encryption/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"header2\" .}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <p>{{.}}</p>\n    <p>{{.Email}}</p>\n    <p>{{.UserName}}</p>\n    <p>{{.LoggedIn}}</p>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/29_password-encryption/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\" .}}\n    <form method=\"POST\" action=\"/api/login\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"userName\" name=\"userName\" placeholder=\"Enter your user name\">\n        <p class=\"form-field-err\"></p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\"></p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/29_password-encryption/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\" .}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/30_turn-off-memcache/READ-ME.txt",
    "content": "ENCRYPT / HASH passwords\n- make your hash slow\n--- prevents brute force\n- salt your hash\n--- store your salt with your hash so you can use it\n--- each salt is unique to each password\n- Corey used bcrypt to do this:\ngolang.org/x/crypto/bcrypt\n- golang.org/x/ are maybe experimental projects made by google and not yet in standard library\n- you could also us a second salt, called a pepper sometimes\n-- this is a code unique to the whole website\n-- it's not stored with the passwords\nhttps://github.com/Saxleader/fall2015/tree/master/code-review_improvement\n\n/////////////////////////////\n\nhttps://github.com/FelixVicis/f15_advWeb_amills/tree/master/twitterclone\nfound error on line 63 of api.go, SessionData was misspelled\nStarted making global messages, Toots\n\ntype Toot struct {\n\tUserName string\n\tMessage  string\n}\n- also add in\n-- time of tweet\n-- make sure username unique\n\nRan into issue with serveTemplate, may need to extend functionality\numm. server 500 error. welp. something went wonky.\n\n\n/////////////////////////////\n\ntype Post struct {\n\tUsername string\n\tPost     string\n}\n\n\nposting user tweets\nusing jquery\nhttps://github.com/herrschwartz/AdvWeb\n\n\n//////////////////////////////\n\nprevent brute force\n- check IP address\n-- store in memcache\n- limited login attempts per account for certain time period\n\nhttps://godoc.org/net/http#Request\n// RemoteAddr allows HTTP servers and other software to record\n    // the network address that sent the request, usually for\n    // logging. This field is not filled in by ReadRequest and\n    // has no defined format. The HTTP server in this package\n    // sets RemoteAddr to an \"IP:port\" address before invoking a\n    // handler.\n    // This field is ignored by the HTTP client.\n    RemoteAddr string\n\n- package subtle\n\n/////////////\n\nauthenticate user when they create account\n- send email and have confirmation link to click\n\n//////////////\n\nxss\n\n\n"
  },
  {
    "path": "27_code-in-process/56_twitter/30_turn-off-memcache/api.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"golang.org/x/crypto/bcrypt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\thashedPass, err := bcrypt.GenerateFromPassword([]byte(req.FormValue(\"password\")), bcrypt.DefaultCost)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error creating password: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tuser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: string(hashedPass),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey, err = datastore.Put(ctx, key, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tcreateSession(res, req, user)\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc loginProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Users\", req.FormValue(\"userName\"), 0, nil)\n\tvar user User\n\terr := datastore.Get(ctx, key, &user)\n\tif err != nil || bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.FormValue(\"password\"))) != nil {\n\t\t// failure logging in\n\t\tvar sd SessionData\n\t\tsd.LoginFail = true\n\t\ttpl.ExecuteTemplate(res, \"login.html\", sd)\n\t\treturn\n\t} else {\n\t\tuser.UserName = req.FormValue(\"userName\")\n\t\t// success logging in\n\t\tcreateSession(res, req, user)\n\t\t// redirect\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t}\n}\n\nfunc createSession(res http.ResponseWriter, req *http.Request, user User) {\n\tctx := appengine.NewContext(req)\n\t// SET COOKIE\n\tid, _ := uuid.NewV4()\n\tcookie := &http.Cookie{\n\t\tName:  \"session\",\n\t\tValue: id.String(),\n\t\tPath:  \"/\",\n\t\t//\t\tUNCOMMENT WHEN DEPLOYED:\n\t\t//\t\tSecure: true,\n\t\t//\t\tHttpOnly: true,\n\t}\n\thttp.SetCookie(res, cookie)\n\n\t// SET MEMCACHE session data (sd)\n\tjson, err := json.Marshal(user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error marshalling during user creation: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd := memcache.Item{\n\t\tKey:   id.String(),\n\t\tValue: json,\n\t\t//\t\tExpiration: time.Duration(20*time.Minute),\n\t\tExpiration: time.Duration(20 * time.Second),\n\t}\n\tmemcache.Set(ctx, &sd)\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\t// cookie is not set\n\tif err != nil {\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t\treturn\n\t}\n\n\t// clear memcache\n\tsd := memcache.Item{\n\t\tKey:        cookie.Value,\n\t\tValue:      []byte(\"\"),\n\t\tExpiration: time.Duration(1 * time.Microsecond),\n\t}\n\tmemcache.Set(ctx, &sd)\n\n\t// clear the cookie\n\tcookie.MaxAge = -1\n\thttp.SetCookie(res, cookie)\n\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/30_turn-off-memcache/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/30_turn-off-memcache/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/30_turn-off-memcache/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/julienschmidt/httprouter\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\tr.POST(\"/api/login\", loginProcess)\n\tr.GET(\"/api/logout\", logout)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"home.html\")\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"login.html\")\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"signup.html\")\n}\n\n/*\nTO DO:\nsession\n-memcache templates\n- uuid in a cookie\n--- https while logged in? - depends upon security required\n- encrypt password on datastore?\n--- never store an unencrypted password, so, resoundingly, YES\n--- sha-256 fast hash value\n- user memcache?\n- datastore / memcache\nsession interface change\n- change login button to logout when user logged in\npost tweets\nfollow people\nsee tweets for everyone\nsee tweets for individual user\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/30_turn-off-memcache/model.go",
    "content": "package main\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string `json:\"-\"`\n}\n\ntype SessionData struct {\n\tUser\n\tLoggedIn  bool\n\tLoginFail bool\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/30_turn-off-memcache/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/30_turn-off-memcache/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/30_turn-off-memcache/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/30_turn-off-memcache/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\n#loginOut {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n#loginOut:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/30_turn-off-memcache/session.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"net/http\"\n)\n\nfunc getSession(req *http.Request) *memcache.Item {\n\tcookie, err := req.Cookie(\"session\")\n\tif err != nil {\n\t\treturn &memcache.Item{}\n\t}\n\n\tctx := appengine.NewContext(req)\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\treturn &memcache.Item{}\n\t}\n\treturn item\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/30_turn-off-memcache/template.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n)\n\nfunc serveTemplate(res http.ResponseWriter, req *http.Request, templateName string) {\n\tmemItem := getSession(req)\n\tif len(memItem.Value) > 0 {\n\t\t// logged in\n\t\tvar sd SessionData\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t\ttpl.ExecuteTemplate(res, templateName, sd)\n\t} else {\n\t\t// not logged in\n\t\ttpl.ExecuteTemplate(res, templateName, SessionData{})\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/30_turn-off-memcache/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            {{if .LoggedIn}}\n            <a href=\"/api/logout\"><p id=\"loginOut\">Log Out</p></a>\n            {{else}}\n            <a href=\"/form/login\"><p id=\"loginOut\">Log In</p></a>\n            {{end}}\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n    <p>{{.}}</p>\n    <p>{{.Email}}</p>\n    <p>{{.UserName}}</p>\n    <p>{{.LoggedIn}}</p>\n</div>\n{{end}}\n\n{{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/30_turn-off-memcache/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"header2\" .}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <p>{{.}}</p>\n    <p>{{.Email}}</p>\n    <p>{{.UserName}}</p>\n    <p>{{.LoggedIn}}</p>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/30_turn-off-memcache/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\" .}}\n    <form method=\"POST\" action=\"/api/login\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"userName\" name=\"userName\" placeholder=\"Enter your user name\">\n        <p class=\"form-field-err\"></p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\"></p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/30_turn-off-memcache/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\" .}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\">\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/31_modal-post-tweet/README.txt",
    "content": "ENCRYPT / HASH passwords\n- make your hash slow\n--- prevents brute force\n- salt your hash\n--- store your salt with your hash so you can use it\n--- each salt is unique to each password\n- Corey used bcrypt to do this:\ngolang.org/x/crypto/bcrypt\n- golang.org/x/ are maybe experimental projects made by google and not yet in standard library\n- you could also us a second salt, called a pepper sometimes\n-- this is a code unique to the whole website\n-- it's not stored with the passwords\nhttps://github.com/Saxleader/fall2015/tree/master/code-review_improvement\n\n/////////////////////////////\n\nhttps://github.com/FelixVicis/f15_advWeb_amills/tree/master/twitterclone\nfound error on line 63 of api.go, SessionData was misspelled\nStarted making global messages, Toots\n\ntype Toot struct {\n\tUserName string\n\tMessage  string\n}\n- also add in\n-- time of tweet\n-- make sure username unique\n\nRan into issue with serveTemplate, may need to extend functionality\numm. server 500 error. welp. something went wonky.\n\n\n/////////////////////////////\n\ntype Post struct {\n\tUsername string\n\tPost     string\n}\n\n\nposting user tweets\nusing jquery\nhttps://github.com/herrschwartz/AdvWeb\n\n\n//////////////////////////////\n\nprevent brute force\n- check IP address\n-- store in memcache\n- limited login attempts per account for certain time period\n\nhttps://godoc.org/net/http#Request\n// RemoteAddr allows HTTP servers and other software to record\n    // the network address that sent the request, usually for\n    // logging. This field is not filled in by ReadRequest and\n    // has no defined format. The HTTP server in this package\n    // sets RemoteAddr to an \"IP:port\" address before invoking a\n    // handler.\n    // This field is ignored by the HTTP client.\n    RemoteAddr string\n\n- package subtle\n\n/////////////\n\nauthenticate user when they create account\n- send email and have confirmation link to click\n\n//////////////\n\nxss\n\n\n"
  },
  {
    "path": "27_code-in-process/56_twitter/31_modal-post-tweet/api.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"golang.org/x/crypto/bcrypt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\thashedPass, err := bcrypt.GenerateFromPassword([]byte(req.FormValue(\"password\")), bcrypt.DefaultCost)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error creating password: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tuser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: string(hashedPass),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey, err = datastore.Put(ctx, key, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tcreateSession(res, req, user)\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc loginProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Users\", req.FormValue(\"userName\"), 0, nil)\n\tvar user User\n\terr := datastore.Get(ctx, key, &user)\n\tif err != nil || bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.FormValue(\"password\"))) != nil {\n\t\t// failure logging in\n\t\tvar sd SessionData\n\t\tsd.LoginFail = true\n\t\ttpl.ExecuteTemplate(res, \"login.html\", sd)\n\t\treturn\n\t} else {\n\t\tuser.UserName = req.FormValue(\"userName\")\n\t\t// success logging in\n\t\tcreateSession(res, req, user)\n\t\t// redirect\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t}\n}\n\nfunc createSession(res http.ResponseWriter, req *http.Request, user User) {\n\tctx := appengine.NewContext(req)\n\t// SET COOKIE\n\tid, _ := uuid.NewV4()\n\tcookie := &http.Cookie{\n\t\tName:  \"session\",\n\t\tValue: id.String(),\n\t\tPath:  \"/\",\n\t\t//\t\tUNCOMMENT WHEN DEPLOYED:\n\t\t//\t\tSecure: true,\n\t\t//\t\tHttpOnly: true,\n\t}\n\thttp.SetCookie(res, cookie)\n\n\t// SET MEMCACHE session data (sd)\n\tjson, err := json.Marshal(user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error marshalling during user creation: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd := memcache.Item{\n\t\tKey:   id.String(),\n\t\tValue: json,\n\t\t//\t\tExpiration: time.Duration(20*time.Minute),\n\t\tExpiration: time.Duration(20 * time.Second),\n\t}\n\tmemcache.Set(ctx, &sd)\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\t// cookie is not set\n\tif err != nil {\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t\treturn\n\t}\n\n\t// clear memcache\n\tsd := memcache.Item{\n\t\tKey:        cookie.Value,\n\t\tValue:      []byte(\"\"),\n\t\tExpiration: time.Duration(1 * time.Microsecond),\n\t}\n\tmemcache.Set(ctx, &sd)\n\n\t// clear the cookie\n\tcookie.MaxAge = -1\n\thttp.SetCookie(res, cookie)\n\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/31_modal-post-tweet/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/31_modal-post-tweet/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/31_modal-post-tweet/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/julienschmidt/httprouter\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\tr.POST(\"/api/login\", loginProcess)\n\tr.GET(\"/api/logout\", logout)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"home.html\")\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"login.html\")\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"signup.html\")\n}\n\n/*\nTO DO:\nsession\n-memcache templates\n- uuid in a cookie\n--- https while logged in? - depends upon security required\n- encrypt password on datastore?\n--- never store an unencrypted password, so, resoundingly, YES\n--- sha-256 fast hash value\n- user memcache?\n- datastore / memcache\nsession interface change\n- change login button to logout when user logged in\npost tweets\nfollow people\nsee tweets for everyone\nsee tweets for individual user\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/31_modal-post-tweet/model.go",
    "content": "package main\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string `json:\"-\"`\n}\n\ntype SessionData struct {\n\tUser\n\tLoggedIn  bool\n\tLoginFail bool\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/31_modal-post-tweet/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/31_modal-post-tweet/public/css/modal-tweet.css",
    "content": ".modalDialog {\n    position: fixed;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    background: rgba(255, 255, 255, 0.7);\n    z-index: 99999;\n    opacity:0;\n    -webkit-transition: opacity 400ms ease-in;\n    -moz-transition: opacity 400ms ease-in;\n    transition: opacity 400ms ease-in;\n    pointer-events: none;\n}\n.modalDialog:target {\n    opacity:1;\n    pointer-events: auto;\n}\n.modalDialog > div {\n    border: 4px solid #2ec371;\n    width: 70%;\n    position: relative;\n    margin: 10% auto;\n    padding: 5px 20px 13px 20px;\n    border-radius: 10px;\n    background: rgba(46, 195, 113, 0.6);\n}\n.modal-close {\n    border: 1px solid #2ec371;\n    background: #2ec371;\n    color: #FFFFFF;\n    line-height: 20px;\n    position: absolute;\n    right: 0px;\n    text-align: center;\n    top: 0px;\n    width: 24px;\n    text-decoration: none;\n    border-radius: 0px 6px 0px 4px;\n}\n.modal-close:hover {\n    background: #2ec371;\n}\n\n#modal-tweet {\n    width: 100%;\n    border-radius: 10px;\n    border: 1px solid #2ec371;\n    margin: 20px 0 0 0;\n    font-size: 40px;\n}\n\n#modal-submit {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n    margin: 15px 15px 0 0;\n    font-family: 'Lobster', cursive;\n    font-size: 25px;\n    background-color: #2ec371;\n}\n\n#modal-submit:hover {\n    background-color: #00acc1;\n}\n\n\n\n#modal-form {\n    display: flex;\n    flex-direction: column;\n    align-items: flex-end;\n}\n\n#opens-modal {\n    margin-right: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/31_modal-post-tweet/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/31_modal-post-tweet/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/31_modal-post-tweet/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\nheader nav {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n}\n\n.loginOut {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n.loginOut:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/31_modal-post-tweet/session.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"net/http\"\n)\n\nfunc getSession(req *http.Request) *memcache.Item {\n\tcookie, err := req.Cookie(\"session\")\n\tif err != nil {\n\t\treturn &memcache.Item{}\n\t}\n\n\tctx := appengine.NewContext(req)\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\treturn &memcache.Item{}\n\t}\n\treturn item\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/31_modal-post-tweet/template.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n)\n\nfunc serveTemplate(res http.ResponseWriter, req *http.Request, templateName string) {\n\tmemItem := getSession(req)\n\tif len(memItem.Value) > 0 {\n\t\t// logged in\n\t\tvar sd SessionData\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t\ttpl.ExecuteTemplate(res, templateName, sd)\n\t} else {\n\t\t// not logged in\n\t\ttpl.ExecuteTemplate(res, templateName, SessionData{})\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/31_modal-post-tweet/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            {{if .LoggedIn}}\n            {{template \"modal-tweet\"}}\n            <a href=\"/api/logout\"><p class=\"loginOut\">Log Out</p></a>\n            {{else}}\n            <a href=\"/form/login\"><p class=\"loginOut\">Log In</p></a>\n            {{end}}\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n    <p>{{.}}</p>\n    <p>{{.Email}}</p>\n    <p>{{.UserName}}</p>\n    <p>{{.LoggedIn}}</p>\n</div>\n{{end}}\n\n    {{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/31_modal-post-tweet/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <p>{{.}}</p>\n    <p>{{.Email}}</p>\n    <p>{{.UserName}}</p>\n    <p>{{.LoggedIn}}</p>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/31_modal-post-tweet/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\" .}}\n    <form method=\"POST\" action=\"/api/login\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"userName\" name=\"userName\" placeholder=\"Enter your user name\" autofocus>\n        <p class=\"form-field-err\"></p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\"></p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/31_modal-post-tweet/templates/html/modal-tweet.html",
    "content": "{{ define \"modal-tweet\"}}\n<a href=\"#openModal\" id=\"opens-modal\"><p class=\"loginOut\">Tweet</p></a>\n\n<div id=\"openModal\" class=\"modalDialog\">\n    <div>\t<a href=\"#close\" title=\"Close\" class=\"modal-close\">X</a>\n        <form method=\"post\" id=\"modal-form\">\n            <textarea name=\"tweet\" id=\"modal-tweet\" rows=\"4\" maxlength=\"140\"></textarea>\n            <a href=\"/tweet\"><p id=\"modal-submit\">Tweet</p></a>\n        </form>\n    </div>\n    {{end}}\n\n    {{ define \"modal-tweet-css\"}}\n    <link rel=\"stylesheet\" href=\"/public/css/modal-tweet.css\">\n    {{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/31_modal-post-tweet/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\" .}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\" autofocus>\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/32_tweets/READ-ME.txt",
    "content": "ENCRYPT / HASH passwords\n- make your hash slow\n--- prevents brute force\n- salt your hash\n--- store your salt with your hash so you can use it\n--- each salt is unique to each password\n- Corey used bcrypt to do this:\ngolang.org/x/crypto/bcrypt\n- golang.org/x/ are maybe experimental projects made by google and not yet in standard library\n- you could also us a second salt, called a pepper sometimes\n-- this is a code unique to the whole website\n-- it's not stored with the passwords\nhttps://github.com/Saxleader/fall2015/tree/master/code-review_improvement\n\n/////////////////////////////\n\nhttps://github.com/FelixVicis/f15_advWeb_amills/tree/master/twitterclone\nfound error on line 63 of api.go, SessionData was misspelled\nStarted making global messages, Toots\n\ntype Toot struct {\n\tUserName string\n\tMessage  string\n}\n- also add in\n-- time of tweet\n-- make sure username unique\n\nRan into issue with serveTemplate, may need to extend functionality\numm. server 500 error. welp. something went wonky.\n\n\n/////////////////////////////\n\ntype Post struct {\n\tUsername string\n\tPost     string\n}\n\n\nposting user tweets\nusing jquery\nhttps://github.com/herrschwartz/AdvWeb\n\n\n//////////////////////////////\n\nprevent brute force\n- check IP address\n-- store in memcache\n- limited login attempts per account for certain time period\n\nhttps://godoc.org/net/http#Request\n// RemoteAddr allows HTTP servers and other software to record\n    // the network address that sent the request, usually for\n    // logging. This field is not filled in by ReadRequest and\n    // has no defined format. The HTTP server in this package\n    // sets RemoteAddr to an \"IP:port\" address before invoking a\n    // handler.\n    // This field is ignored by the HTTP client.\n    RemoteAddr string\n\n- package subtle\n\n/////////////\n\nauthenticate user when they create account\n- send email and have confirmation link to click\n\n//////////////\n\nxss\n\n\n"
  },
  {
    "path": "27_code-in-process/56_twitter/32_tweets/api.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"golang.org/x/crypto/bcrypt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\thashedPass, err := bcrypt.GenerateFromPassword([]byte(req.FormValue(\"password\")), bcrypt.DefaultCost)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error creating password: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tuser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: string(hashedPass),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey, err = datastore.Put(ctx, key, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tcreateSession(res, req, user)\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc loginProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Users\", req.FormValue(\"userName\"), 0, nil)\n\tvar user User\n\terr := datastore.Get(ctx, key, &user)\n\tif err != nil || bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.FormValue(\"password\"))) != nil {\n\t\t// failure logging in\n\t\tvar sd SessionData\n\t\tsd.LoginFail = true\n\t\ttpl.ExecuteTemplate(res, \"login.html\", sd)\n\t\treturn\n\t} else {\n\t\tuser.UserName = req.FormValue(\"userName\")\n\t\t// success logging in\n\t\tcreateSession(res, req, user)\n\t\t// redirect\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t}\n}\n\nfunc createSession(res http.ResponseWriter, req *http.Request, user User) {\n\tctx := appengine.NewContext(req)\n\t// SET COOKIE\n\tid, _ := uuid.NewV4()\n\tcookie := &http.Cookie{\n\t\tName:  \"session\",\n\t\tValue: id.String(),\n\t\tPath:  \"/\",\n\t\t// twenty minute session:\n\t\tMaxAge: 60 * 20,\n\t\t//\t\tUNCOMMENT WHEN DEPLOYED:\n\t\t//\t\tSecure: true,\n\t\t//\t\tHttpOnly: true,\n\t}\n\thttp.SetCookie(res, cookie)\n\n\t// SET MEMCACHE session data (sd)\n\tjson, err := json.Marshal(user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error marshalling during user creation: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd := memcache.Item{\n\t\tKey:   id.String(),\n\t\tValue: json,\n\t}\n\tmemcache.Set(ctx, &sd)\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\t// cookie is not set\n\tif err != nil {\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t\treturn\n\t}\n\n\t// clear memcache\n\tsd := memcache.Item{\n\t\tKey:        cookie.Value,\n\t\tValue:      []byte(\"\"),\n\t\tExpiration: time.Duration(1 * time.Microsecond),\n\t}\n\tmemcache.Set(ctx, &sd)\n\n\t// clear the cookie\n\tcookie.MaxAge = -1\n\thttp.SetCookie(res, cookie)\n\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc tweetProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to post tweet from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// declare a variable of type tweet\n\t// initialize it with values\n\ttweet := Tweet{\n\t\tMsg:  req.FormValue(\"tweet\"),\n\t\tTime: time.Now(),\n\t}\n\tuserKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey := datastore.NewIncompleteKey(ctx, \"Tweets\", userKey)\n\t_, err = datastore.Put(ctx, key, &tweet)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/32_tweets/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/32_tweets/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/32_tweets/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/julienschmidt/httprouter\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\tr.POST(\"/api/login\", loginProcess)\n\tr.POST(\"/api/tweet\", tweetProcess)\n\tr.GET(\"/api/logout\", logout)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"home.html\")\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"login.html\")\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"signup.html\")\n}\n\n/*\nTO DO:\nsession\n-memcache templates\n- uuid in a cookie\n--- https while logged in? - depends upon security required\n- encrypt password on datastore?\n--- never store an unencrypted password, so, resoundingly, YES\n--- sha-256 fast hash value\n- user memcache?\n- datastore / memcache\nsession interface change\n- change login button to logout when user logged in\npost tweets\nfollow people\nsee tweets for everyone\nsee tweets for individual user\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/32_tweets/model.go",
    "content": "package main\n\nimport \"time\"\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string `json:\"-\"`\n}\n\ntype SessionData struct {\n\tUser\n\tLoggedIn  bool\n\tLoginFail bool\n}\n\ntype Tweet struct {\n\tMsg  string\n\tTime time.Time\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/32_tweets/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/32_tweets/public/css/modal-tweet.css",
    "content": ".modalDialog {\n    position: fixed;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    background: rgba(255, 255, 255, 0.7);\n    z-index: 99999;\n    opacity:0;\n    -webkit-transition: opacity 400ms ease-in;\n    -moz-transition: opacity 400ms ease-in;\n    transition: opacity 400ms ease-in;\n    pointer-events: none;\n}\n.modalDialog:target {\n    opacity:1;\n    pointer-events: auto;\n}\n.modalDialog > div {\n    border: 4px solid #2ec371;\n    width: 70%;\n    position: relative;\n    margin: 10% auto;\n    padding: 5px 20px 13px 20px;\n    border-radius: 10px;\n    background: rgba(46, 195, 113, 0.6);\n}\n.modal-close {\n    border: 1px solid #2ec371;\n    background: #2ec371;\n    color: #FFFFFF;\n    line-height: 20px;\n    position: absolute;\n    right: 0px;\n    text-align: center;\n    top: 0px;\n    width: 24px;\n    text-decoration: none;\n    border-radius: 0px 6px 0px 4px;\n}\n.modal-close:hover {\n    background: #2ec371;\n}\n\n#modal-tweet {\n    width: 100%;\n    border-radius: 10px;\n    border: 1px solid #2ec371;\n    margin: 20px 0 0 0;\n    font-size: 40px;\n}\n\n#modal-submit {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n    margin: 15px 15px 0 0;\n    font-family: 'Lobster', cursive;\n    font-size: 25px;\n    background-color: #2ec371;\n}\n\n#modal-submit:hover {\n    background-color: #00acc1;\n}\n\n\n\n#modal-form {\n    display: flex;\n    flex-direction: column;\n    align-items: flex-end;\n}\n\n#opens-modal {\n    margin-right: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/32_tweets/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/32_tweets/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/32_tweets/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\nheader nav {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n}\n\n.loginOut {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n.loginOut:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n#post {\n    padding: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/32_tweets/session.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"net/http\"\n)\n\nfunc getSession(req *http.Request) (*memcache.Item, error) {\n\tcookie, err := req.Cookie(\"session\")\n\tif err != nil {\n\t\treturn &memcache.Item{}, err\n\t}\n\n\tctx := appengine.NewContext(req)\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\treturn &memcache.Item{}, err\n\t}\n\treturn item, nil\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/32_tweets/template.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n)\n\nfunc serveTemplate(res http.ResponseWriter, req *http.Request, templateName string) {\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\t// not logged in\n\t\ttpl.ExecuteTemplate(res, templateName, SessionData{})\n\t} else {\n\t\t// logged in\n\t\tvar sd SessionData\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t\ttpl.ExecuteTemplate(res, templateName, sd)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/32_tweets/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            {{if .LoggedIn}}\n            {{template \"modal-tweet\"}}\n            <a href=\"/api/logout\"><p class=\"loginOut\">Log Out</p></a>\n            {{else}}\n            <a href=\"/form/login\"><p class=\"loginOut\">Log In</p></a>\n            {{end}}\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n    <p>{{.}}</p>\n    <p>{{.Email}}</p>\n    <p>{{.UserName}}</p>\n    <p>{{.LoggedIn}}</p>\n</div>\n{{end}}\n\n    {{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/32_tweets/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <p>{{.}}</p>\n    <p>{{.Email}}</p>\n    <p>{{.UserName}}</p>\n    <p>{{.LoggedIn}}</p>\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/32_tweets/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\" .}}\n    <form method=\"POST\" action=\"/api/login\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"userName\" name=\"userName\" placeholder=\"Enter your user name\" autofocus>\n        <p class=\"form-field-err\"></p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\"></p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/32_tweets/templates/html/modal-tweet.html",
    "content": "{{ define \"modal-tweet\"}}\n<a href=\"#openModal\" id=\"opens-modal\"><p class=\"loginOut\">Tweet</p></a>\n\n<div id=\"openModal\" class=\"modalDialog\">\n    <div>\t<a href=\"#close\" title=\"Close\" class=\"modal-close\">X</a>\n        <form method=\"POST\" id=\"modal-form\" action=\"/api/tweet\">\n            <textarea name=\"tweet\" id=\"modal-tweet\" rows=\"4\" maxlength=\"140\"></textarea>\n            <input type=\"submit\" id=\"modal-submit\" value=\"Tweet\">\n        </form>\n    </div>\n</div>\n    {{end}}\n\n    {{ define \"modal-tweet-css\"}}\n    <link rel=\"stylesheet\" href=\"/public/css/modal-tweet.css\">\n    {{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/32_tweets/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\" .}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\" autofocus>\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/33_display-all-tweets/READ-ME.txt",
    "content": "ENCRYPT / HASH passwords\n- make your hash slow\n--- prevents brute force\n- salt your hash\n--- store your salt with your hash so you can use it\n--- each salt is unique to each password\n- Corey used bcrypt to do this:\ngolang.org/x/crypto/bcrypt\n- golang.org/x/ are maybe experimental projects made by google and not yet in standard library\n- you could also us a second salt, called a pepper sometimes\n-- this is a code unique to the whole website\n-- it's not stored with the passwords\nhttps://github.com/Saxleader/fall2015/tree/master/code-review_improvement\n\n/////////////////////////////\n\nhttps://github.com/FelixVicis/f15_advWeb_amills/tree/master/twitterclone\nfound error on line 63 of api.go, SessionData was misspelled\nStarted making global messages, Toots\n\ntype Toot struct {\n\tUserName string\n\tMessage  string\n}\n- also add in\n-- time of tweet\n-- make sure username unique\n\nRan into issue with serveTemplate, may need to extend functionality\numm. server 500 error. welp. something went wonky.\n\n\n/////////////////////////////\n\ntype Post struct {\n\tUsername string\n\tPost     string\n}\n\n\nposting user tweets\nusing jquery\nhttps://github.com/herrschwartz/AdvWeb\n\n\n//////////////////////////////\n\nprevent brute force\n- check IP address\n-- store in memcache\n- limited login attempts per account for certain time period\n\nhttps://godoc.org/net/http#Request\n// RemoteAddr allows HTTP servers and other software to record\n    // the network address that sent the request, usually for\n    // logging. This field is not filled in by ReadRequest and\n    // has no defined format. The HTTP server in this package\n    // sets RemoteAddr to an \"IP:port\" address before invoking a\n    // handler.\n    // This field is ignored by the HTTP client.\n    RemoteAddr string\n\n- package subtle\n\n/////////////\n\nauthenticate user when they create account\n- send email and have confirmation link to click\n\n//////////////\n\nxss\n\n\n"
  },
  {
    "path": "27_code-in-process/56_twitter/33_display-all-tweets/api.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"golang.org/x/crypto/bcrypt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\thashedPass, err := bcrypt.GenerateFromPassword([]byte(req.FormValue(\"password\")), bcrypt.DefaultCost)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error creating password: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tuser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: string(hashedPass),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey, err = datastore.Put(ctx, key, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tcreateSession(res, req, user)\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc loginProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Users\", req.FormValue(\"userName\"), 0, nil)\n\tvar user User\n\terr := datastore.Get(ctx, key, &user)\n\tif err != nil || bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.FormValue(\"password\"))) != nil {\n\t\t// failure logging in\n\t\tvar sd SessionData\n\t\tsd.LoginFail = true\n\t\ttpl.ExecuteTemplate(res, \"login.html\", sd)\n\t\treturn\n\t} else {\n\t\tuser.UserName = req.FormValue(\"userName\")\n\t\t// success logging in\n\t\tcreateSession(res, req, user)\n\t\t// redirect\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t}\n}\n\nfunc createSession(res http.ResponseWriter, req *http.Request, user User) {\n\tctx := appengine.NewContext(req)\n\t// SET COOKIE\n\tid, _ := uuid.NewV4()\n\tcookie := &http.Cookie{\n\t\tName:  \"session\",\n\t\tValue: id.String(),\n\t\tPath:  \"/\",\n\t\t// twenty minute session:\n\t\tMaxAge: 60 * 20,\n\t\t//\t\tUNCOMMENT WHEN DEPLOYED:\n\t\t//\t\tSecure: true,\n\t\t//\t\tHttpOnly: true,\n\t}\n\thttp.SetCookie(res, cookie)\n\n\t// SET MEMCACHE session data (sd)\n\tjson, err := json.Marshal(user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error marshalling during user creation: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd := memcache.Item{\n\t\tKey:   id.String(),\n\t\tValue: json,\n\t}\n\tmemcache.Set(ctx, &sd)\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\t// cookie is not set\n\tif err != nil {\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t\treturn\n\t}\n\n\t// clear memcache\n\tsd := memcache.Item{\n\t\tKey:        cookie.Value,\n\t\tValue:      []byte(\"\"),\n\t\tExpiration: time.Duration(1 * time.Microsecond),\n\t}\n\tmemcache.Set(ctx, &sd)\n\n\t// clear the cookie\n\tcookie.MaxAge = -1\n\thttp.SetCookie(res, cookie)\n\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc tweetProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to post tweet from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// declare a variable of type tweet\n\t// initialize it with values\n\tlog.Infof(ctx, user.UserName)\n\ttweet := Tweet{\n\t\tMsg:      req.FormValue(\"tweet\"),\n\t\tTime:     time.Now(),\n\t\tUserName: user.UserName,\n\t}\n\t// put in datastore\n\terr = putTweet(req, &user, &tweet)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/33_display-all-tweets/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/33_display-all-tweets/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/33_display-all-tweets/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\tr.POST(\"/api/login\", loginProcess)\n\tr.POST(\"/api/tweet\", tweetProcess)\n\tr.GET(\"/api/logout\", logout)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\t//get tweets\n\ttweets, err := getTweets(req, nil)\n\tif err != nil {\n\t\t// lala\n\t}\n\tmemItem, err := getSession(req)\n\tvar sd SessionData\n\tif err != nil {\n\t\t// not logged in\n\t\tsd.Tweets = tweets\n\t} else {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t}\n\ttpl.ExecuteTemplate(res, \"home.html\", &sd)\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"login.html\")\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"signup.html\")\n}\n\n/*\nTO DO:\nsession\n-memcache templates\n- uuid in a cookie\n--- https while logged in? - depends upon security required\n- encrypt password on datastore?\n--- never store an unencrypted password, so, resoundingly, YES\n--- sha-256 fast hash value\n- user memcache?\n- datastore / memcache\nsession interface change\n- change login button to logout when user logged in\npost tweets\nfollow people\nsee tweets for everyone\nsee tweets for individual user\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/33_display-all-tweets/model.go",
    "content": "package main\n\nimport \"time\"\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string `json:\"-\"`\n}\n\ntype SessionData struct {\n\tUser\n\tLoggedIn  bool\n\tLoginFail bool\n\tTweets    []Tweet\n}\n\ntype Tweet struct {\n\tMsg      string\n\tTime     time.Time\n\tUserName string\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/33_display-all-tweets/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/33_display-all-tweets/public/css/modal-tweet.css",
    "content": ".modalDialog {\n    position: fixed;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    background: rgba(255, 255, 255, 0.7);\n    z-index: 99999;\n    opacity:0;\n    -webkit-transition: opacity 400ms ease-in;\n    -moz-transition: opacity 400ms ease-in;\n    transition: opacity 400ms ease-in;\n    pointer-events: none;\n}\n.modalDialog:target {\n    opacity:1;\n    pointer-events: auto;\n}\n.modalDialog > div {\n    border: 4px solid #2ec371;\n    width: 70%;\n    position: relative;\n    margin: 10% auto;\n    padding: 5px 20px 13px 20px;\n    border-radius: 10px;\n    background: rgba(46, 195, 113, 0.6);\n}\n.modal-close {\n    border: 1px solid #2ec371;\n    background: #2ec371;\n    color: #FFFFFF;\n    line-height: 20px;\n    position: absolute;\n    right: 0px;\n    text-align: center;\n    top: 0px;\n    width: 24px;\n    text-decoration: none;\n    border-radius: 0px 6px 0px 4px;\n}\n.modal-close:hover {\n    background: #2ec371;\n}\n\n#modal-tweet {\n    width: 100%;\n    border-radius: 10px;\n    border: 1px solid #2ec371;\n    margin: 20px 0 0 0;\n    font-size: 40px;\n}\n\n#modal-submit {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n    margin: 15px 15px 0 0;\n    font-family: 'Lobster', cursive;\n    font-size: 25px;\n    background-color: #2ec371;\n}\n\n#modal-submit:hover {\n    background-color: #00acc1;\n}\n\n\n\n#modal-form {\n    display: flex;\n    flex-direction: column;\n    align-items: flex-end;\n}\n\n#opens-modal {\n    margin-right: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/33_display-all-tweets/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/33_display-all-tweets/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/33_display-all-tweets/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\nheader nav {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n}\n\n.loginOut {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n.loginOut:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n.post {\n    padding: 10px 10px 0 10px;\n}\n\n.post-meta {\n    font-size: 12px;\n    padding: 0;\n    border: 0;\n    margin: 2px 0 0 20px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/33_display-all-tweets/session.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"net/http\"\n)\n\nfunc getSession(req *http.Request) (*memcache.Item, error) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\tif err != nil {\n\t\treturn &memcache.Item{}, err\n\t}\n\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\treturn &memcache.Item{}, err\n\t}\n\treturn item, nil\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/33_display-all-tweets/template.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n)\n\nfunc serveTemplate(res http.ResponseWriter, req *http.Request, templateName string) {\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\t// not logged in\n\t\ttpl.ExecuteTemplate(res, templateName, SessionData{})\n\t\treturn\n\t}\n\t// logged in\n\tvar sd SessionData\n\tjson.Unmarshal(memItem.Value, &sd)\n\tsd.LoggedIn = true\n\ttpl.ExecuteTemplate(res, templateName, &sd)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/33_display-all-tweets/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            {{if .LoggedIn}}\n            {{template \"modal-tweet\"}}\n            <a href=\"/api/logout\"><p class=\"loginOut\">Log Out</p></a>\n            {{else}}\n            <a href=\"/form/login\"><p class=\"loginOut\">Log In</p></a>\n            {{end}}\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>\n{{end}}\n\n    {{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/33_display-all-tweets/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Tweets}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post\">{{.Msg}}</p>\n            <p class=\"post-meta\">{{.UserName}}</p>\n            <p class=\"post-meta\">{{.Time}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/33_display-all-tweets/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\" .}}\n    <form method=\"POST\" action=\"/api/login\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"userName\" name=\"userName\" placeholder=\"Enter your user name\" autofocus>\n        <p class=\"form-field-err\"></p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\"></p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/33_display-all-tweets/templates/html/modal-tweet.html",
    "content": "{{ define \"modal-tweet\"}}\n<a href=\"#openModal\" id=\"opens-modal\"><p class=\"loginOut\">Tweet</p></a>\n\n<div id=\"openModal\" class=\"modalDialog\">\n    <div>\t<a href=\"#close\" title=\"Close\" class=\"modal-close\">X</a>\n        <form method=\"POST\" id=\"modal-form\" action=\"/api/tweet\">\n            <textarea name=\"tweet\" id=\"modal-tweet\" rows=\"4\" maxlength=\"140\"></textarea>\n            <input type=\"submit\" id=\"modal-submit\" value=\"Tweet\">\n        </form>\n    </div>\n</div>\n    {{end}}\n\n    {{ define \"modal-tweet-css\"}}\n    <link rel=\"stylesheet\" href=\"/public/css/modal-tweet.css\">\n    {{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/33_display-all-tweets/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\" .}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\" autofocus>\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/33_display-all-tweets/tweets.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"net/http\"\n)\n\nfunc putTweet(req *http.Request, user *User, tweet *Tweet) error {\n\tctx := appengine.NewContext(req)\n\tuserKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey := datastore.NewIncompleteKey(ctx, \"Tweets\", userKey)\n\t_, err := datastore.Put(ctx, key, tweet)\n\treturn err\n}\n\nfunc getTweets(req *http.Request, user *User) ([]Tweet, error) {\n\tctx := appengine.NewContext(req)\n\n\tvar tweets []Tweet\n\tq := datastore.NewQuery(\"Tweets\")\n\n\tif user != nil {\n\t\t// we're on the main page\n\t\tuserKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\t\tq = q.Ancestor(userKey)\n\t}\n\n\tq = q.Order(\"-Time\").Limit(20)\n\t_, err := q.GetAll(ctx, &tweets)\n\treturn tweets, err\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/34_humanize/READ-ME.txt",
    "content": "ENCRYPT / HASH passwords\n- make your hash slow\n--- prevents brute force\n- salt your hash\n--- store your salt with your hash so you can use it\n--- each salt is unique to each password\n- Corey used bcrypt to do this:\ngolang.org/x/crypto/bcrypt\n- golang.org/x/ are maybe experimental projects made by google and not yet in standard library\n- you could also us a second salt, called a pepper sometimes\n-- this is a code unique to the whole website\n-- it's not stored with the passwords\nhttps://github.com/Saxleader/fall2015/tree/master/code-review_improvement\n\n/////////////////////////////\n\nhttps://github.com/FelixVicis/f15_advWeb_amills/tree/master/twitterclone\nfound error on line 63 of api.go, SessionData was misspelled\nStarted making global messages, Toots\n\ntype Toot struct {\n\tUserName string\n\tMessage  string\n}\n- also add in\n-- time of tweet\n-- make sure username unique\n\nRan into issue with serveTemplate, may need to extend functionality\numm. server 500 error. welp. something went wonky.\n\n\n/////////////////////////////\n\ntype Post struct {\n\tUsername string\n\tPost     string\n}\n\n\nposting user tweets\nusing jquery\nhttps://github.com/herrschwartz/AdvWeb\n\n\n//////////////////////////////\n\nprevent brute force\n- check IP address\n-- store in memcache\n- limited login attempts per account for certain time period\n\nhttps://godoc.org/net/http#Request\n// RemoteAddr allows HTTP servers and other software to record\n    // the network address that sent the request, usually for\n    // logging. This field is not filled in by ReadRequest and\n    // has no defined format. The HTTP server in this package\n    // sets RemoteAddr to an \"IP:port\" address before invoking a\n    // handler.\n    // This field is ignored by the HTTP client.\n    RemoteAddr string\n\n- package subtle\n\n/////////////\n\nauthenticate user when they create account\n- send email and have confirmation link to click\n\n//////////////\n\nxss\n\n\n"
  },
  {
    "path": "27_code-in-process/56_twitter/34_humanize/api.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"golang.org/x/crypto/bcrypt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\thashedPass, err := bcrypt.GenerateFromPassword([]byte(req.FormValue(\"password\")), bcrypt.DefaultCost)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error creating password: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tuser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: string(hashedPass),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey, err = datastore.Put(ctx, key, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tcreateSession(res, req, user)\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc loginProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Users\", req.FormValue(\"userName\"), 0, nil)\n\tvar user User\n\terr := datastore.Get(ctx, key, &user)\n\tif err != nil || bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.FormValue(\"password\"))) != nil {\n\t\t// failure logging in\n\t\tvar sd SessionData\n\t\tsd.LoginFail = true\n\t\ttpl.ExecuteTemplate(res, \"login.html\", sd)\n\t\treturn\n\t} else {\n\t\tuser.UserName = req.FormValue(\"userName\")\n\t\t// success logging in\n\t\tcreateSession(res, req, user)\n\t\t// redirect\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t}\n}\n\nfunc createSession(res http.ResponseWriter, req *http.Request, user User) {\n\tctx := appengine.NewContext(req)\n\t// SET COOKIE\n\tid, _ := uuid.NewV4()\n\tcookie := &http.Cookie{\n\t\tName:  \"session\",\n\t\tValue: id.String(),\n\t\tPath:  \"/\",\n\t\t// twenty minute session:\n\t\tMaxAge: 60 * 20,\n\t\t//\t\tUNCOMMENT WHEN DEPLOYED:\n\t\t//\t\tSecure: true,\n\t\t//\t\tHttpOnly: true,\n\t}\n\thttp.SetCookie(res, cookie)\n\n\t// SET MEMCACHE session data (sd)\n\tjson, err := json.Marshal(user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error marshalling during user creation: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd := memcache.Item{\n\t\tKey:   id.String(),\n\t\tValue: json,\n\t}\n\tmemcache.Set(ctx, &sd)\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\t// cookie is not set\n\tif err != nil {\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t\treturn\n\t}\n\n\t// clear memcache\n\tsd := memcache.Item{\n\t\tKey:        cookie.Value,\n\t\tValue:      []byte(\"\"),\n\t\tExpiration: time.Duration(1 * time.Microsecond),\n\t}\n\tmemcache.Set(ctx, &sd)\n\n\t// clear the cookie\n\tcookie.MaxAge = -1\n\thttp.SetCookie(res, cookie)\n\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc tweetProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to post tweet from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// declare a variable of type tweet\n\t// initialize it with values\n\tlog.Infof(ctx, user.UserName)\n\ttweet := Tweet{\n\t\tMsg:      req.FormValue(\"tweet\"),\n\t\tTime:     time.Now(),\n\t\tUserName: user.UserName,\n\t}\n\t// put in datastore\n\terr = putTweet(req, &user, &tweet)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/34_humanize/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/34_humanize/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/34_humanize/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\tr.POST(\"/api/login\", loginProcess)\n\tr.POST(\"/api/tweet\", tweetProcess)\n\tr.GET(\"/api/logout\", logout)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\n\ttpl = template.New(\"roottemplate\")\n\ttpl = tpl.Funcs(template.FuncMap{\n\t\t\"humanize_time\": humanize.Time,\n\t})\n\n\ttpl = template.Must(tpl.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\t//get tweets\n\ttweets, err := getTweets(req, nil)\n\tif err != nil {\n\t\t// lala\n\t}\n\tmemItem, err := getSession(req)\n\tvar sd SessionData\n\tif err == nil {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t}\n\tsd.Tweets = tweets\n\ttpl.ExecuteTemplate(res, \"home.html\", &sd)\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"login.html\")\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"signup.html\")\n}\n\n/*\nTO DO:\nsession\n-memcache templates\n- uuid in a cookie\n--- https while logged in? - depends upon security required\n- encrypt password on datastore?\n--- never store an unencrypted password, so, resoundingly, YES\n--- sha-256 fast hash value\n- user memcache?\n- datastore / memcache\nsession interface change\n- change login button to logout when user logged in\npost tweets\nfollow people\nsee tweets for everyone\nsee tweets for individual user\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/34_humanize/model.go",
    "content": "package main\n\nimport \"time\"\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string `json:\"-\"`\n}\n\ntype SessionData struct {\n\tUser\n\tLoggedIn  bool\n\tLoginFail bool\n\tTweets    []Tweet\n}\n\ntype Tweet struct {\n\tMsg      string\n\tTime     time.Time\n\tUserName string\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/34_humanize/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/34_humanize/public/css/modal-tweet.css",
    "content": ".modalDialog {\n    position: fixed;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    background: rgba(255, 255, 255, 0.7);\n    z-index: 99999;\n    opacity:0;\n    -webkit-transition: opacity 400ms ease-in;\n    -moz-transition: opacity 400ms ease-in;\n    transition: opacity 400ms ease-in;\n    pointer-events: none;\n}\n.modalDialog:target {\n    opacity:1;\n    pointer-events: auto;\n}\n.modalDialog > div {\n    border: 4px solid #2ec371;\n    width: 70%;\n    position: relative;\n    margin: 10% auto;\n    padding: 5px 20px 13px 20px;\n    border-radius: 10px;\n    background: rgba(46, 195, 113, 0.6);\n}\n.modal-close {\n    border: 1px solid #2ec371;\n    background: #2ec371;\n    color: #FFFFFF;\n    line-height: 20px;\n    position: absolute;\n    right: 0px;\n    text-align: center;\n    top: 0px;\n    width: 24px;\n    text-decoration: none;\n    border-radius: 0px 6px 0px 4px;\n}\n.modal-close:hover {\n    background: #2ec371;\n}\n\n#modal-tweet {\n    width: 100%;\n    border-radius: 10px;\n    border: 1px solid #2ec371;\n    margin: 20px 0 0 0;\n    font-size: 40px;\n}\n\n#modal-submit {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n    margin: 15px 15px 0 0;\n    font-family: 'Lobster', cursive;\n    font-size: 25px;\n    background-color: #2ec371;\n}\n\n#modal-submit:hover {\n    background-color: #00acc1;\n}\n\n\n\n#modal-form {\n    display: flex;\n    flex-direction: column;\n    align-items: flex-end;\n}\n\n#opens-modal {\n    margin-right: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/34_humanize/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/34_humanize/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/34_humanize/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\nheader nav {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n}\n\n.loginOut {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n.loginOut:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n.post {\n    padding: 10px 10px 0 10px;\n}\n\n.post-meta {\n    font-size: 12px;\n    padding: 0;\n    border: 0;\n    margin: 2px 0 0 20px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/34_humanize/session.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"net/http\"\n)\n\nfunc getSession(req *http.Request) (*memcache.Item, error) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\tif err != nil {\n\t\treturn &memcache.Item{}, err\n\t}\n\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\treturn &memcache.Item{}, err\n\t}\n\treturn item, nil\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/34_humanize/template.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n)\n\nfunc serveTemplate(res http.ResponseWriter, req *http.Request, templateName string) {\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\t// not logged in\n\t\ttpl.ExecuteTemplate(res, templateName, SessionData{})\n\t\treturn\n\t}\n\t// logged in\n\tvar sd SessionData\n\tjson.Unmarshal(memItem.Value, &sd)\n\tsd.LoggedIn = true\n\ttpl.ExecuteTemplate(res, templateName, &sd)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/34_humanize/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            {{if .LoggedIn}}\n            {{template \"modal-tweet\"}}\n            <a href=\"/api/logout\"><p class=\"loginOut\">Log Out</p></a>\n            {{else}}\n            <a href=\"/form/login\"><p class=\"loginOut\">Log In</p></a>\n            {{end}}\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>\n{{end}}\n\n    {{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/34_humanize/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Tweets}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post\">{{.Msg}}</p>\n            <p class=\"post-meta\">{{.UserName}}</p>\n            <p class=\"post-meta\">{{humanize_time .Time}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/34_humanize/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\" .}}\n    <form method=\"POST\" action=\"/api/login\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"userName\" name=\"userName\" placeholder=\"Enter your user name\" autofocus>\n        <p class=\"form-field-err\"></p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\"></p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/34_humanize/templates/html/modal-tweet.html",
    "content": "{{ define \"modal-tweet\"}}\n<a href=\"#openModal\" id=\"opens-modal\"><p class=\"loginOut\">Tweet</p></a>\n\n<div id=\"openModal\" class=\"modalDialog\">\n    <div>\t<a href=\"#close\" title=\"Close\" class=\"modal-close\">X</a>\n        <form method=\"POST\" id=\"modal-form\" action=\"/api/tweet\">\n            <textarea name=\"tweet\" id=\"modal-tweet\" rows=\"4\" maxlength=\"140\"></textarea>\n            <input type=\"submit\" id=\"modal-submit\" value=\"Tweet\">\n        </form>\n    </div>\n</div>\n    {{end}}\n\n    {{ define \"modal-tweet-css\"}}\n    <link rel=\"stylesheet\" href=\"/public/css/modal-tweet.css\">\n    {{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/34_humanize/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\" .}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\" autofocus>\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/34_humanize/tweets.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"net/http\"\n)\n\nfunc putTweet(req *http.Request, user *User, tweet *Tweet) error {\n\tctx := appengine.NewContext(req)\n\tuserKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey := datastore.NewIncompleteKey(ctx, \"Tweets\", userKey)\n\t_, err := datastore.Put(ctx, key, tweet)\n\treturn err\n}\n\nfunc getTweets(req *http.Request, user *User) ([]Tweet, error) {\n\tctx := appengine.NewContext(req)\n\n\tvar tweets []Tweet\n\tq := datastore.NewQuery(\"Tweets\")\n\n\tif user != nil {\n\t\t// we're on the main page\n\t\tuserKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\t\tq = q.Ancestor(userKey)\n\t}\n\n\tq = q.Order(\"-Time\").Limit(20)\n\t_, err := q.GetAll(ctx, &tweets)\n\treturn tweets, err\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/35_schmidt-params/01/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {\n\tfmt.Fprint(w, \"Welcome!\\n\")\n}\n\nfunc Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {\n\tfmt.Fprintf(w, \"hello, %s!\\n\", ps.ByName(\"name\"))\n}\n\nfunc main() {\n\trouter := httprouter.New()\n\trouter.GET(\"/\", Index)\n\trouter.GET(\"/hello/:name\", Hello)\n\n\tlog.Fatal(http.ListenAndServe(\":8080\", router))\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/35_schmidt-params/02/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {\n\tfmt.Fprint(w, \"Welcome!\\n\")\n}\n\nfunc Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {\n\tfmt.Fprintf(w, \"hello, %s!\\n\", ps.ByName(\"name\"))\n}\n\nfunc main() {\n\trouter := httprouter.New()\n\trouter.GET(\"/\", Index)\n\trouter.GET(\"/:name\", Hello)\n\n\tlog.Fatal(http.ListenAndServe(\":8080\", router))\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/35_schmidt-params/03/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc Index(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {\n\tfmt.Printf(\"%T %v \\n\", ps, ps)\n\tfmt.Println(ps == nil)    // true\n\tfmt.Println(ps != nil)    // false\n\tfmt.Println(len(ps) == 0) // true\n\tfmt.Println(len(ps) != 0) // false\n\tfmt.Fprint(w, \"Welcome!\\n\")\n}\n\nfunc main() {\n\trouter := httprouter.New()\n\trouter.GET(\"/\", Index)\n\trouter.GET(\"/:name\", Index)\n\n\tlog.Fatal(http.ListenAndServe(\":8080\", router))\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/35_schmidt-params/04/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc Index(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {\n\tif len(ps) != 0 {\n\t\tfmt.Fprintf(w, \"hello, %s!\\n\", ps.ByName(\"name\"))\n\t\treturn\n\t}\n\n\tfmt.Fprint(w, \"Welcome!\\n\")\n}\n\nfunc main() {\n\trouter := httprouter.New()\n\trouter.GET(\"/\", Index)\n\trouter.GET(\"/:name\", Index)\n\n\tlog.Fatal(http.ListenAndServe(\":8080\", router))\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/35_schmidt-params/05/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc Index(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {\n\tif len(ps) != 0 {\n\t\tfmt.Fprintf(w, \"hello, %s!\\n\", ps.ByName(\"name\"))\n\t\treturn\n\t}\n\n\tfmt.Fprint(w, \"Welcome!\\n\")\n}\n\nfunc main() {\n\trouter := httprouter.New()\n\trouter.GET(\"/\", Index)\n\trouter.GET(\"/user/*name\", Index)\n\n\tlog.Fatal(http.ListenAndServe(\":8080\", router))\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/36_user-tweets/READ-ME.txt",
    "content": "ENCRYPT / HASH passwords\n- make your hash slow\n--- prevents brute force\n- salt your hash\n--- store your salt with your hash so you can use it\n--- each salt is unique to each password\n- Corey used bcrypt to do this:\ngolang.org/x/crypto/bcrypt\n- golang.org/x/ are maybe experimental projects made by google and not yet in standard library\n- you could also us a second salt, called a pepper sometimes\n-- this is a code unique to the whole website\n-- it's not stored with the passwords\nhttps://github.com/Saxleader/fall2015/tree/master/code-review_improvement\n\n/////////////////////////////\n\nhttps://github.com/FelixVicis/f15_advWeb_amills/tree/master/twitterclone\nfound error on line 63 of api.go, SessionData was misspelled\nStarted making global messages, Toots\n\ntype Toot struct {\n\tUserName string\n\tMessage  string\n}\n- also add in\n-- time of tweet\n-- make sure username unique\n\nRan into issue with serveTemplate, may need to extend functionality\numm. server 500 error. welp. something went wonky.\n\n\n/////////////////////////////\n\ntype Post struct {\n\tUsername string\n\tPost     string\n}\n\n\nposting user tweets\nusing jquery\nhttps://github.com/herrschwartz/AdvWeb\n\n\n//////////////////////////////\n\nprevent brute force\n- check IP address\n-- store in memcache\n- limited login attempts per account for certain time period\n\nhttps://godoc.org/net/http#Request\n// RemoteAddr allows HTTP servers and other software to record\n    // the network address that sent the request, usually for\n    // logging. This field is not filled in by ReadRequest and\n    // has no defined format. The HTTP server in this package\n    // sets RemoteAddr to an \"IP:port\" address before invoking a\n    // handler.\n    // This field is ignored by the HTTP client.\n    RemoteAddr string\n\n- package subtle\n\n/////////////\n\nauthenticate user when they create account\n- send email and have confirmation link to click\n\n//////////////\n\nxss\n\n\n"
  },
  {
    "path": "27_code-in-process/56_twitter/36_user-tweets/api.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"golang.org/x/crypto/bcrypt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\thashedPass, err := bcrypt.GenerateFromPassword([]byte(req.FormValue(\"password\")), bcrypt.DefaultCost)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error creating password: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tuser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: string(hashedPass),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey, err = datastore.Put(ctx, key, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tcreateSession(res, req, user)\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc loginProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Users\", req.FormValue(\"userName\"), 0, nil)\n\tvar user User\n\terr := datastore.Get(ctx, key, &user)\n\tif err != nil || bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.FormValue(\"password\"))) != nil {\n\t\t// failure logging in\n\t\tvar sd SessionData\n\t\tsd.LoginFail = true\n\t\ttpl.ExecuteTemplate(res, \"login.html\", sd)\n\t\treturn\n\t} else {\n\t\tuser.UserName = req.FormValue(\"userName\")\n\t\t// success logging in\n\t\tcreateSession(res, req, user)\n\t\t// redirect\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t}\n}\n\nfunc createSession(res http.ResponseWriter, req *http.Request, user User) {\n\tctx := appengine.NewContext(req)\n\t// SET COOKIE\n\tid, _ := uuid.NewV4()\n\tcookie := &http.Cookie{\n\t\tName:  \"session\",\n\t\tValue: id.String(),\n\t\tPath:  \"/\",\n\t\t// twenty minute session:\n\t\tMaxAge: 60 * 20,\n\t\t//\t\tUNCOMMENT WHEN DEPLOYED:\n\t\t//\t\tSecure: true,\n\t\t//\t\tHttpOnly: true,\n\t}\n\thttp.SetCookie(res, cookie)\n\n\t// SET MEMCACHE session data (sd)\n\tjson, err := json.Marshal(user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error marshalling during user creation: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd := memcache.Item{\n\t\tKey:   id.String(),\n\t\tValue: json,\n\t}\n\tmemcache.Set(ctx, &sd)\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\t// cookie is not set\n\tif err != nil {\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t\treturn\n\t}\n\n\t// clear memcache\n\tsd := memcache.Item{\n\t\tKey:        cookie.Value,\n\t\tValue:      []byte(\"\"),\n\t\tExpiration: time.Duration(1 * time.Microsecond),\n\t}\n\tmemcache.Set(ctx, &sd)\n\n\t// clear the cookie\n\tcookie.MaxAge = -1\n\thttp.SetCookie(res, cookie)\n\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc tweetProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to post tweet from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// declare a variable of type tweet\n\t// initialize it with values\n\tlog.Infof(ctx, user.UserName)\n\ttweet := Tweet{\n\t\tMsg:      req.FormValue(\"tweet\"),\n\t\tTime:     time.Now(),\n\t\tUserName: user.UserName,\n\t}\n\t// put in datastore\n\terr = putTweet(req, &user, &tweet)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// redirect\n\ttime.Sleep(time.Millisecond * 500) // This is not the best code, probably. Thoughts?\n\thttp.Redirect(res, req, \"/\", 302)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/36_user-tweets/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/36_user-tweets/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/36_user-tweets/index.yaml",
    "content": "indexes:\n\n# AUTOGENERATED\n\n# This index.yaml is automatically updated whenever the dev_appserver\n# detects that a new type of query is run.  If you want to manage the\n# index.yaml file manually, remove the above marker line (the line\n# saying \"# AUTOGENERATED\").  If you want to manage some indexes\n# manually, move them above the marker line.  The index.yaml file is\n# automatically uploaded to the admin console when you next deploy\n# your application using appcfg.py.\n\n- kind: Tweets\n  ancestor: yes\n  properties:\n  - name: Time\n    direction: desc\n"
  },
  {
    "path": "27_code-in-process/56_twitter/36_user-tweets/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", Home)\n\tr.GET(\"/user/:user\", Home)\n\tr.GET(\"/form/login\", Login)\n\tr.GET(\"/form/signup\", Signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\tr.POST(\"/api/login\", loginProcess)\n\tr.POST(\"/api/tweet\", tweetProcess)\n\tr.GET(\"/api/logout\", logout)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\n\ttpl = template.New(\"roottemplate\")\n\ttpl = tpl.Funcs(template.FuncMap{\n\t\t\"humanize_time\": humanize.Time,\n\t})\n\n\ttpl = template.Must(tpl.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc Home(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\t//get tweets\n\tvar err error\n\tvar tweets []Tweet\n\tif len(ps) != 0 {\n\t\tuser := User{UserName: ps.ByName(\"user\")}\n\t\ttweets, err = getTweets(req, &user)\n\t} else {\n\t\ttweets, err = getTweets(req, nil)\n\t}\n\tif err != nil {\n\t\t// lala\n\t}\n\tmemItem, err := getSession(req)\n\tvar sd SessionData\n\tif err == nil {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t}\n\tsd.Tweets = tweets\n\ttpl.ExecuteTemplate(res, \"home.html\", &sd)\n}\n\nfunc Login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"login.html\")\n}\n\nfunc Signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"signup.html\")\n}\n\n/*\nTO DO:\nsession\n-memcache templates\n- uuid in a cookie\n--- https while logged in? - depends upon security required\n- encrypt password on datastore?\n--- never store an unencrypted password, so, resoundingly, YES\n--- sha-256 fast hash value\n- user memcache?\n- datastore / memcache\nsession interface change\n- change login button to logout when user logged in\npost tweets\nfollow people\nsee tweets for everyone\nsee tweets for individual user\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/36_user-tweets/model.go",
    "content": "package main\n\nimport \"time\"\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string `json:\"-\"`\n}\n\ntype SessionData struct {\n\tUser\n\tLoggedIn  bool\n\tLoginFail bool\n\tTweets    []Tweet\n}\n\ntype Tweet struct {\n\tMsg      string\n\tTime     time.Time\n\tUserName string\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/36_user-tweets/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/36_user-tweets/public/css/modal-tweet.css",
    "content": ".modalDialog {\n    position: fixed;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    background: rgba(255, 255, 255, 0.7);\n    z-index: 99999;\n    opacity:0;\n    -webkit-transition: opacity 400ms ease-in;\n    -moz-transition: opacity 400ms ease-in;\n    transition: opacity 400ms ease-in;\n    pointer-events: none;\n}\n.modalDialog:target {\n    opacity:1;\n    pointer-events: auto;\n}\n.modalDialog > div {\n    border: 4px solid #2ec371;\n    width: 70%;\n    position: relative;\n    margin: 10% auto;\n    padding: 5px 20px 13px 20px;\n    border-radius: 10px;\n    background: rgba(46, 195, 113, 0.6);\n}\n.modal-close {\n    border: 1px solid #2ec371;\n    background: #2ec371;\n    color: #FFFFFF;\n    line-height: 20px;\n    position: absolute;\n    right: 0px;\n    text-align: center;\n    top: 0px;\n    width: 24px;\n    text-decoration: none;\n    border-radius: 0px 6px 0px 4px;\n}\n.modal-close:hover {\n    background: #2ec371;\n}\n\n#modal-tweet {\n    width: 100%;\n    border-radius: 10px;\n    border: 1px solid #2ec371;\n    margin: 20px 0 0 0;\n    font-size: 40px;\n}\n\n#modal-submit {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n    margin: 15px 15px 0 0;\n    font-family: 'Lobster', cursive;\n    font-size: 25px;\n    background-color: #2ec371;\n}\n\n#modal-submit:hover {\n    background-color: #00acc1;\n}\n\n\n\n#modal-form {\n    display: flex;\n    flex-direction: column;\n    align-items: flex-end;\n}\n\n#opens-modal {\n    margin-right: 10px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/36_user-tweets/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/36_user-tweets/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/36_user-tweets/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\nheader nav {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n}\n\n.loginOut {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n}\n\n.loginOut:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n.post {\n    padding: 10px 10px 0 10px;\n}\n\n.post-meta {\n    font-size: 12px;\n    padding: 0;\n    border: 0;\n    margin: 2px 0 0 20px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/36_user-tweets/session.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"net/http\"\n)\n\nfunc getSession(req *http.Request) (*memcache.Item, error) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\tif err != nil {\n\t\treturn &memcache.Item{}, err\n\t}\n\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\treturn &memcache.Item{}, err\n\t}\n\treturn item, nil\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/36_user-tweets/template.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n)\n\nfunc serveTemplate(res http.ResponseWriter, req *http.Request, templateName string) {\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\t// not logged in\n\t\ttpl.ExecuteTemplate(res, templateName, SessionData{})\n\t\treturn\n\t}\n\t// logged in\n\tvar sd SessionData\n\tjson.Unmarshal(memItem.Value, &sd)\n\tsd.LoggedIn = true\n\ttpl.ExecuteTemplate(res, templateName, &sd)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/36_user-tweets/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            {{if .LoggedIn}}\n            {{template \"modal-tweet\"}}\n            <a href=\"/api/logout\"><p class=\"loginOut\">Log Out</p></a>\n            {{else}}\n            <a href=\"/form/login\"><p class=\"loginOut\">Log In</p></a>\n            {{end}}\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>\n{{end}}\n\n    {{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/36_user-tweets/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Tweets}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post\">{{.Msg}}</p>\n            <p class=\"post-meta\">{{.UserName}}</p>\n            <p class=\"post-meta\">{{humanize_time .Time}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/36_user-tweets/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\" .}}\n    <form method=\"POST\" action=\"/api/login\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"userName\" name=\"userName\" placeholder=\"Enter your user name\" autofocus>\n        <p class=\"form-field-err\"></p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\"></p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/36_user-tweets/templates/html/modal-tweet.html",
    "content": "{{ define \"modal-tweet\"}}\n<a href=\"#openModal\" id=\"opens-modal\"><p class=\"loginOut\">Tweet</p></a>\n\n<div id=\"openModal\" class=\"modalDialog\">\n    <div>\t<a href=\"#close\" title=\"Close\" class=\"modal-close\">X</a>\n        <form method=\"POST\" id=\"modal-form\" action=\"/api/tweet\">\n            <textarea name=\"tweet\" id=\"modal-tweet\" rows=\"4\" maxlength=\"140\"></textarea>\n            <input type=\"submit\" id=\"modal-submit\" value=\"Tweet\">\n        </form>\n    </div>\n</div>\n    {{end}}\n\n    {{ define \"modal-tweet-css\"}}\n    <link rel=\"stylesheet\" href=\"/public/css/modal-tweet.css\">\n    {{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/36_user-tweets/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\" .}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\" autofocus>\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/36_user-tweets/tweets.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"net/http\"\n)\n\nfunc putTweet(req *http.Request, user *User, tweet *Tweet) error {\n\tctx := appengine.NewContext(req)\n\tuserKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey := datastore.NewIncompleteKey(ctx, \"Tweets\", userKey)\n\t_, err := datastore.Put(ctx, key, tweet)\n\treturn err\n}\n\nfunc getTweets(req *http.Request, user *User) ([]Tweet, error) {\n\tctx := appengine.NewContext(req)\n\n\tvar tweets []Tweet\n\tq := datastore.NewQuery(\"Tweets\")\n\n\tif user != nil {\n\t\t// show tweets of a specific user\n\t\tlog.Infof(ctx, \"HERE IS THE USER INFO: %v ---\", user.UserName)\n\t\tuserKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\t\tq = q.Ancestor(userKey)\n\t}\n\n\tq = q.Order(\"-Time\").Limit(20)\n\t_, err := q.GetAll(ctx, &tweets)\n\treturn tweets, err\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/01_daniel/app.yaml",
    "content": "application: twitter-1012\nversion: main\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /public\n  static_dir: public\n- url: /login\n  login: required\n  script: _go_app\n- url: /.*\n  script: _go_app\n\ninbound_services:\n- mail\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/01_daniel/data.go",
    "content": "package twitter\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/mail\"\n)\n\nfunc getProfileByEmail(ctx context.Context, email string) (*profile, error) {\n\tkey := datastore.NewKey(ctx, \"profile\", email, 0, nil)\n\tvar p profile\n\terr := datastore.Get(ctx, key, &p)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &p, nil\n}\n\nfunc getProfileByUsername(ctx context.Context, usr string) (*profile, error) {\n\tquery := datastore.NewQuery(\"profile\")\n\tp := []profile{}\n\t_, err := query.Filter(\"Username =\", usr).GetAll(ctx, &p)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(p) == 0 {\n\t\treturn nil, datastore.ErrNoSuchEntity\n\t} else if len(p) > 1 {\n\t\treturn nil, datastore.ErrInvalidKey\n\t}\n\treturn &p[0], nil\n}\n\nfunc itemIn(item string, list []string) bool {\n\tfor _, v := range list {\n\t\tif item == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc getMultiTweets(ctx context.Context, emails []string) ([]tweet, error) {\n\tquery := datastore.NewQuery(\"Tweets\")\n\tt := []tweet{}\n\tquery = query.Order(\"-SubmitTime\")\n\tit := query.Run(ctx)\n\tfor {\n\t\tvar i tweet\n\t\tkey, err := it.Next(&i)\n\t\tif err == datastore.Done {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tp, err := getProfileByEmail(ctx, key.Parent().StringID())\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif !itemIn(p.Username, emails) {\n\t\t\tcontinue\n\t\t}\n\t\ti.Username = p.Username\n\t\tt = append(t, i)\n\t}\n\treturn t, nil\n}\n\nfunc getTweets(ctx context.Context, email string) ([]tweet, error) {\n\tquery := datastore.NewQuery(\"Tweets\")\n\tt := []tweet{}\n\tquery = query.Order(\"-SubmitTime\")\n\tif email != \"\" {\n\t\tkey := datastore.NewKey(ctx, \"profile\", email, 0, nil)\n\t\tquery = query.Ancestor(key)\n\t}\n\tkeys, err := query.GetAll(ctx, &t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor i := range t {\n\t\tp, err := getProfileByEmail(ctx, keys[i].Parent().StringID())\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tt[i].Username = p.Username\n\t}\n\treturn t, nil\n}\n\nfunc createProfile(ctx context.Context, username, email string) error {\n\tkey := datastore.NewKey(ctx, \"profile\", email, 0, nil)\n\tp := profile{\n\t\tUsername: username,\n\t\tEmail:    email,\n\t}\n\t_, err := datastore.Put(ctx, key, &p)\n\treturn err\n}\n\nfunc emailUser(ctx context.Context, username string, t *tweet) error {\n\tto, err := getProfileByUsername(ctx, username)\n\tif err == datastore.ErrNoSuchEntity {\n\t\treturn nil\n\t} else if err != nil {\n\t\treturn err\n\t}\n\tmsg := &mail.Message{\n\t\tSender:  \"noreply@twitter-1012.appspotmail.com\",\n\t\tTo:      []string{fmt.Sprintf(\"%s <%s>\", to.Username, to.Email)},\n\t\tSubject: fmt.Sprintf(\"Mention from %s\", t.Username),\n\t\tBody:    fmt.Sprintf(\"%s has mentioned you in a tweet: %s\", t.Username, t.Message),\n\t}\n\terr = mail.Send(ctx, msg)\n\treturn err\n}\n\nfunc postTweet(ctx context.Context, t *tweet, email string) error {\n\twords := strings.Fields(t.Message)\n\tfor _, w := range words {\n\t\tif w[0] == '@' {\n\t\t\tif err := emailUser(ctx, w[1:], t); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\tprofileKey := datastore.NewKey(ctx, \"profile\", email, 0, nil)\n\tkey := datastore.NewIncompleteKey(ctx, \"Tweets\", profileKey)\n\t_, err := datastore.Put(ctx, key, t)\n\treturn err\n}\n\nfunc addFollower(ctx context.Context, currentUser *profile, newFollowed string) error {\n\tif itemIn(newFollowed, currentUser.Following) || newFollowed == currentUser.Username {\n\t\treturn nil\n\t}\n\tcurrentUser.Following = append(currentUser.Following, newFollowed)\n\tkey := datastore.NewKey(ctx, \"profile\", currentUser.Email, 0, nil)\n\t_, err := datastore.Put(ctx, key, currentUser)\n\treturn err\n}\n\nfunc removeFollower(ctx context.Context, currentUser *profile, oldFollowed string) error {\n\tneedsStore := false\n\tfor i, f := range currentUser.Following {\n\t\tif f == oldFollowed {\n\t\t\tcurrentUser.Following = append(currentUser.Following[:i], currentUser.Following[i+1:]...)\n\t\t\tneedsStore = true\n\t\t\tbreak\n\t\t}\n\t}\n\tif !needsStore {\n\t\treturn nil\n\t}\n\tkey := datastore.NewKey(ctx, \"profile\", currentUser.Email, 0, nil)\n\t_, err := datastore.Put(ctx, key, currentUser)\n\treturn err\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/01_daniel/email.go",
    "content": "package twitter\n\nimport (\n\t\"encoding/base64\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"mime\"\n\t\"mime/multipart\"\n\t\"strings\"\n\n\t\"golang.org/x/net/context\"\n)\n\nfunc parseFile(ctx context.Context, mme, enc string, reader io.Reader) (string, error) {\n\tmediatype, params, err := mime.ParseMediaType(mme)\n\tret := \"\"\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tswitch mediatype {\n\tcase \"multipart/alternative\":\n\t\trdr := multipart.NewReader(reader, params[\"boundary\"])\n\t\tfor {\n\t\t\tpart, err := rdr.NextPart()\n\t\t\tif err == io.EOF {\n\t\t\t\tbreak\n\t\t\t} else if err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t\tnewMime := part.Header.Get(\"Content-Type\")\n\t\t\tif !strings.HasPrefix(newMime, \"text/plain\") {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tencoding := part.Header.Get(\"Content-Transfer-Encoding\")\n\t\t\tret, err = parseFile(ctx, newMime, encoding, part)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t}\n\n\tcase \"text/plain\":\n\t\tif enc == \"base64\" {\n\t\t\tdcode := base64.NewDecoder(base64.StdEncoding, reader)\n\t\t\tbts, err := ioutil.ReadAll(dcode)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t\tret = string(bts)\n\t\t} else {\n\t\t\tbts, err := ioutil.ReadAll(reader)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t\tret = string(bts)\n\t\t}\n\t}\n\n\treturn ret, nil\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/01_daniel/index.yaml",
    "content": "indexes:\n\n# AUTOGENERATED\n\n# This index.yaml is automatically updated whenever the dev_appserver\n# detects that a new type of query is run.  If you want to manage the\n# index.yaml file manually, remove the above marker line (the line\n# saying \"# AUTOGENERATED\").  If you want to manage some indexes\n# manually, move them above the marker line.  The index.yaml file is\n# automatically uploaded to the admin console when you next deploy\n# your application using appcfg.py.\n\n- kind: Tweets\n  ancestor: yes\n  properties:\n  - name: SubmitTime\n    direction: desc\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/01_daniel/main.go",
    "content": "package twitter\n\nimport (\n\t\"html/template\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/mail\"\n\t\"time\"\n\n\t\"golang.org/x/net/context\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/user\"\n)\n\ntype profile struct {\n\tUsername  string\n\tEmail     string\n\tFollowing []string\n}\n\ntype tweet struct {\n\tUsername   string `datastore:\"-\"`\n\tMessage    string\n\tSubmitTime time.Time\n}\n\ntype mainpageData struct {\n\tTweets   []tweet\n\tLogged   bool\n\tUsername string\n}\n\ntype profileData struct {\n\tTweets      []tweet\n\tProfile     profile\n\tCurrentUser string\n\tFollowing   bool\n}\n\ntype loginData struct {\n\tErrorMessage string\n\tUsername     string\n}\n\nconst (\n\tminUsernameSize = 5\n\tmaxUsernameSize = 20\n\ttweetSize       = 140\n\tloginDuration   = 60 * 60 * 24 // 1 Day\n)\n\nvar tpl = template.New(\"templates\")\n\nfunc init() {\n\t_, err := tpl.ParseGlob(\"templates/*.gohtml\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\thttp.HandleFunc(\"/\", handle)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.HandleFunc(\"/CreateProfile\", handleCreateProfile)\n\thttp.HandleFunc(\"/login\", handleLogin)\n\thttp.HandleFunc(\"/logout\", handleLogout)\n\thttp.HandleFunc(\"/tweet.json\", handleTweet)\n\thttp.HandleFunc(\"/_ah/mail/\", incomingMail)\n}\n\nfunc getCurrentUser(req *http.Request) *profile {\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\tif u == nil {\n\t\treturn nil\n\t}\n\tc, err := req.Cookie(\"login\")\n\tif err != nil {\n\t\treturn nil\n\t}\n\tp, err := getProfileByUsername(ctx, c.Value)\n\tif err != nil {\n\t\treturn nil\n\t}\n\tif p.Email != u.Email {\n\t\treturn nil\n\t}\n\treturn p\n}\n\nfunc confirmCreateProfile(ctx context.Context, username string) bool {\n\t_, err := getProfileByUsername(ctx, username)\n\treturn len(username) >= minUsernameSize && len(username) <= maxUsernameSize &&\n\t\terr == datastore.ErrNoSuchEntity\n}\n\nfunc incomingMail(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tdefer req.Body.Close()\n\tmsg, err := mail.ReadMessage(req.Body)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"Email error: %s\\n\", err.Error())\n\t\treturn\n\t}\n\taddresses, err := msg.Header.AddressList(\"From\")\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"Email error: %s\\n\", err.Error())\n\t\treturn\n\t}\n\taddr := addresses[0]\n\tp, err := getProfileByEmail(ctx, addr.Address)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"Email error: %s\\n\", err.Error())\n\t\treturn\n\t}\n\n\tcontentType := msg.Header.Get(\"Content-Type\")\n\ttext, err := parseFile(ctx, contentType, \"\", msg.Body)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"Email error: %s\\n\", err.Error())\n\t\treturn\n\t}\n\tt := &tweet{\n\t\tMessage:    text,\n\t\tSubmitTime: time.Now(),\n\t\tUsername:   p.Username,\n\t}\n\terr = postTweet(ctx, t, addr.Address)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"Email error: %s\\n\", err.Error())\n\t\treturn\n\t}\n}\n\nfunc handleTweet(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tu := getCurrentUser(req)\n\tif u == nil {\n\t\thttp.Error(res, \"Incorrect login\", http.StatusUnauthorized)\n\t\tlog.Warningf(ctx, \"Incorrect login from: %s\\n\", req.RemoteAddr)\n\t\treturn\n\t}\n\tif req.Method != \"POST\" {\n\t\thttp.Error(res, \"Unknown method\", http.StatusMethodNotAllowed)\n\t\tlog.Warningf(ctx, \"Incorrect method on tweet.json from %s\", req.RemoteAddr)\n\t\treturn\n\t}\n\tbuffer := make([]byte, tweetSize)\n\tn, err := req.Body.Read(buffer)\n\tif err != nil && err != io.EOF {\n\t\thttp.Error(res, \"Bad Request\", http.StatusBadRequest)\n\t\tlog.Warningf(ctx, \"Bad request: %s\\n\", err.Error())\n\t\treturn\n\t}\n\tmsg := string(buffer[:n])\n\tt := tweet{\n\t\tUsername:   u.Username,\n\t\tMessage:    msg,\n\t\tSubmitTime: time.Now(),\n\t}\n\terr = postTweet(ctx, &t, u.Email)\n\tif err != nil {\n\t\thttp.Error(res, \"Server error!\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, \"Put Tweet Error: %s\\n\", err.Error())\n\t\treturn\n\t}\n}\n\nfunc handleLogin(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\n\tcookie, err := req.Cookie(\"login\")\n\tif err != http.ErrNoCookie {\n\t\thttp.Redirect(res, req, \"/\"+cookie.Value, http.StatusSeeOther)\n\t\treturn\n\t}\n\n\tcurrentProfile, err := getProfileByEmail(ctx, u.Email)\n\tif err == datastore.ErrNoSuchEntity {\n\t\thttp.Redirect(res, req, \"/CreateProfile\", http.StatusSeeOther)\n\t\treturn\n\t} else if err != nil {\n\t\thttp.Error(res, \"Server error!\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, \"Get profile error: %s\\n\", err.Error())\n\t\treturn\n\t}\n\n\tlogin := loginData{\n\t\tUsername: currentProfile.Username,\n\t}\n\tif req.Method == \"POST\" {\n\t\tusername := req.FormValue(\"username\")\n\t\tp, err := getProfileByUsername(ctx, username)\n\t\tif err != nil {\n\t\t\tlogin.ErrorMessage = \"No such username\"\n\t\t} else if p.Email != u.Email {\n\t\t\tlogin.ErrorMessage = \"Not your profile\"\n\t\t} else {\n\t\t\tc := http.Cookie{\n\t\t\t\tName:   \"login\",\n\t\t\t\tValue:  username,\n\t\t\t\tMaxAge: loginDuration,\n\t\t\t}\n\t\t\thttp.SetCookie(res, &c)\n\t\t\thttp.Redirect(res, req, \"/\"+username, http.StatusSeeOther)\n\t\t\treturn\n\t\t}\n\t}\n\terr = tpl.ExecuteTemplate(res, \"login.gohtml\", login)\n\tif err != nil {\n\t\thttp.Error(res, \"Server error!\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, \"Template Execute Error: %s\\n\", err.Error())\n\t\treturn\n\t}\n}\n\nfunc handleLogout(res http.ResponseWriter, req *http.Request) {\n\thttp.SetCookie(res, &http.Cookie{Name: \"login\", MaxAge: -1})\n\thttp.Redirect(res, req, \"/\", http.StatusSeeOther)\n}\n\nfunc handleCreateProfile(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\n\tif req.Method == \"POST\" {\n\t\tusername := req.FormValue(\"username\")\n\t\tif !confirmCreateProfile(ctx, username) {\n\t\t\thttp.Error(res, \"Invalid input!\", http.StatusBadRequest)\n\t\t\tlog.Warningf(ctx, \"Invalid profile information from %s\\n\", req.RemoteAddr)\n\t\t\treturn\n\t\t}\n\t\terr := createProfile(ctx, username, u.Email)\n\t\thttp.SetCookie(res, &http.Cookie{Name: \"login\", Value: username, MaxAge: loginDuration})\n\t\tif err != nil {\n\t\t\thttp.Error(res, \"Server error!\", http.StatusInternalServerError)\n\t\t\tlog.Errorf(ctx, \"Create profile Error: %s\\n\", err.Error())\n\t\t\treturn\n\t\t}\n\t}\n\n\t_, err := getProfileByEmail(ctx, u.Email)\n\tif err == nil {\n\t\thttp.Redirect(res, req, \"login\", http.StatusSeeOther)\n\t\treturn\n\t} else if err != datastore.ErrNoSuchEntity {\n\t\thttp.Error(res, \"Server error!\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, \"Get profile Error: %s\\n\", err.Error())\n\t\treturn\n\t}\n\n\terr = tpl.ExecuteTemplate(res, \"createProfile.gohtml\", nil)\n\tif err != nil {\n\t\thttp.Error(res, \"Server error!\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, \"Template Execute Error: %s\\n\", err.Error())\n\t\treturn\n\t}\n}\n\nfunc getProfile(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\n\tusername := req.URL.Path[1:]\n\n\tp, err := getProfileByUsername(ctx, username)\n\tif err == datastore.ErrNoSuchEntity {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t} else if err != nil {\n\t\thttp.Error(res, \"Server error!\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, \"Get Profile Error: %s\\n\", username)\n\t\treturn\n\t}\n\n\ttweets, err := getTweets(ctx, p.Email)\n\tif err != nil {\n\t\thttp.Error(res, \"Server error!\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, \"Query Error: %s\\n\", err.Error())\n\t\treturn\n\t}\n\n\tpd := profileData{\n\t\tTweets:  tweets,\n\t\tProfile: *p,\n\t}\n\tu := getCurrentUser(req)\n\tif u != nil {\n\t\tpd.CurrentUser = u.Username\n\t\tpd.Following = itemIn(username, u.Following)\n\t}\n\n\tisFollower := req.URL.Query().Get(\"f\")\n\tif isFollower == \"y\" {\n\t\terr := addFollower(ctx, u, username)\n\t\tif err != nil {\n\t\t\thttp.Error(res, \"Unable to remove follower\", http.StatusInternalServerError)\n\t\t\tlog.Errorf(ctx, \"Save add followed: %s\\n\", err.Error())\n\t\t\treturn\n\t\t}\n\t} else if isFollower == \"n\" {\n\t\terr := removeFollower(ctx, u, username)\n\t\tif err != nil {\n\t\t\thttp.Error(res, \"Unable to remove follower\", http.StatusInternalServerError)\n\t\t\tlog.Errorf(ctx, \"Save remove followed: %s\\n\", err.Error())\n\t\t\treturn\n\t\t}\n\t}\n\n\terr = tpl.ExecuteTemplate(res, \"profile.gohtml\", pd)\n\tif err != nil {\n\t\thttp.Error(res, \"Server error!\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, \"Template Execute Error: %s\\n\", err.Error())\n\t\treturn\n\t}\n}\n\nfunc handle(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path != \"/\" {\n\t\tgetProfile(res, req)\n\t\treturn\n\t}\n\n\tctx := appengine.NewContext(req)\n\tu := getCurrentUser(req)\n\n\tif u != nil {\n\t\t_, err := getProfileByEmail(ctx, u.Email)\n\t\tif err == datastore.ErrNoSuchEntity {\n\t\t\thttp.Redirect(res, req, \"/CreateProfile\", http.StatusSeeOther)\n\t\t\treturn\n\t\t} else if err != nil {\n\t\t\thttp.Error(res, \"Server error!\", http.StatusInternalServerError)\n\t\t\tlog.Errorf(ctx, \"Datastore get Error: %s\\n\", err.Error())\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Get recent tweets\n\tvar tweets []tweet\n\tvar err error\n\tif u == nil {\n\t\ttweets, err = getTweets(ctx, \"\")\n\t} else {\n\t\ttweets, err = getMultiTweets(ctx, u.Following)\n\t}\n\n\tif err != nil {\n\t\thttp.Error(res, \"Server error!\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, \"Query Error: %s\\n\", err.Error())\n\t\treturn\n\t}\n\n\t// Create template\n\tdata := mainpageData{\n\t\tTweets: tweets,\n\t}\n\n\tc, err := req.Cookie(\"login\")\n\tif err == nil {\n\t\tdata.Logged = true\n\t\tdata.Username = c.Value\n\t} else {\n\t\tdata.Logged = false\n\t}\n\n\terr = tpl.ExecuteTemplate(res, \"index.gohtml\", data)\n\tif err != nil {\n\t\thttp.Error(res, \"Server error!\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, \"Template Execute Error: %s\\n\", err.Error())\n\t\treturn\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/01_daniel/public/makeTweet.js",
    "content": "document.querySelector('#create').addEventListener('click', function() {\n  var form = document.createElement('form');\n  form.id = 'createTweet';\n  form.method = 'POST';\n\n  charactersLeft = document.createElement('p');\n  charactersLeft.textContent = '140 characters left';\n  charactersLeft.id = 'characters';\n  form.appendChild(charactersLeft);\n\n  textInput = document.createElement('input');\n  textInput.type = 'text';\n  textInput.name = 'message';\n  textInput.setAttribute('maxlength', 140);\n  textInput.placeholder = 'Message';\n  textInput.setAttribute('required', 'true');\n  textInput.addEventListener('input', function() {\n    document.querySelector('#characters').textContent = (140 - textInput.value.length) + ' characters left';\n  });\n  form.appendChild(textInput);\n\n  submitInput = document.createElement('input');\n  submitInput.type = 'submit';\n  submitInput.value = 'Tweet';\n  form.appendChild(submitInput);\n\n  form.addEventListener('submit', function(e) {\n    e.preventDefault();\n    xhr = new XMLHttpRequest();\n    xhr.open('POST', '/tweet.json');\n    xhr.send(textInput.value);\n    form.parentNode.removeChild(form);\n  });\n  document.body.appendChild(form);\n});\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/01_daniel/public/style.css",
    "content": "* {\n  box-sizing: border-box;\n}\n\nhtml {\n  background-color: #8a8;\n}\n\na {\n  color: blue;\n}\n\nh1 {\n  font-size: 50px;\n  margin: 8px 3px;\n  text-align: center;\n}\n\n.tweet {\n  margin: 5px;\n  border: 2px solid black;\n  background-color: #bbb;\n}\n\n.tweet a {\n  font-size: 20px;\n}\n\n.tweet p {\n  font-size: 18px;\n  margin: 10px 5px;\n}\n\n.tweet .submit-time {\n  color: #eee;\n  font-size: 12px;\n  margin: 3px;\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/01_daniel/templates/createProfile.gohtml",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Twitter Clone: Create Profile</title>\n  <link rel=\"stylesheet\" href=\"/public/style.css\">\n</head>\n<body>\n  <form method=\"POST\">\n    <input type=\"text\" name=\"username\" placeholder=\"Username\">\n    <input type=\"submit\" value=\"Create\">\n  </form>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/01_daniel/templates/index.gohtml",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Twitter Clone</title>\n  <link rel=\"stylesheet\" href=\"/public/style.css\">\n</head>\n<body>\n  {{if .Logged}}\n  <a href=\"/{{.Username}}\">Profile</a>\n  <a href=\"/logout\">Logout</a>\n  {{else}}\n  <a href=\"/login\">Log In</a>\n  {{end}}\n  {{range .Tweets}}\n  {{template \"tweet\" .}}\n  {{end}}\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/01_daniel/templates/login.gohtml",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Twitter Clone: Login</title>\n  <link rel=\"stylesheet\" href=\"/public/style.css\">\n</head>\n<body>\n  {{if .ErrorMessage}}\n    <p>{{.ErrorMessage}}</p>\n  {{end}}\n  <form method=\"POST\">\n    <input type=\"text\" name=\"username\" placeholder=\"Username\" value=\"{{.Username}}\" required>\n    <input type=\"submit\" value=\"Login\">\n  </form>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/01_daniel/templates/profile.gohtml",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Twitter Clone: {{.Profile.Username}}'s Profile</title>\n  <link rel=\"stylesheet\" href=\"/public/style.css\">\n</head>\n<body>\n  <a href=\"/\">Main Page</a>\n  {{if .CurrentUser}}\n    <a href=\"/{{.Profile.Username}}/followers\">Followers</a>\n    <a href=\"/{{.Profile.Username}}/following\">Following</a>\n  {{end}}\n  {{if eq .CurrentUser .Profile.Username}}\n  <button id=\"create\">Create Tweet</button>\n  {{else if .CurrentUser}}\n    {{if .Following}}\n      <a href=\"?f=n\">Unfollow</a>\n    {{else}}\n      <a href=\"?f=y\">Follow</a>\n    {{end}}\n  {{else}}\n  <a href=\"/login\">Login</a>\n  {{end}}\n  <h1>@{{.Profile.Username}}</h1>\n  {{range .Tweets}}\n  {{template \"tweet\" .}}\n  {{end}}\n  {{if eq .CurrentUser .Profile.Username}}\n  <script src=\"/public/makeTweet.js\"></script>\n  {{end}}\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/01_daniel/templates/tweet.gohtml",
    "content": "{{define \"tweet\"}}\n<div class=\"tweet\">\n  <a href=\"/{{.Username}}\">@{{.Username}}</a>\n  <p>{{.Message}}</p>\n  <p class=\"submit-time\">{{.SubmitTime}}</p>\n</div>\n{{end}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/02_tommy/README.md",
    "content": "## twitter-project aka Screamer\n\nCheck out the live site [here!](https://secret-spark-101320.appspot.com)\n\nThis was a project I did for the web development bootcamp at Fresno City College. It is meant to be a very simplistic clone of twitter. Users log in with their google account, and then they can post \"screams\". Everything is stored in the app-engine datastore.\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/02_tommy/app.yaml",
    "content": "application: secret-spark-101320\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /login\n  login: required\n  script: _go_app\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/02_tommy/assets/scripts/main.js",
    "content": "var scream = function() {\n  var screamButton = document.querySelector('#screamButton');\n  screamButton.addEventListener('click', function() {\n    var message = window.prompt(\"SCREAM HERE!\");\n    var xhr = new XMLHttpRequest();\n    xhr.open(\"POST\", \"/api/tweets\");\n    xhr.send(JSON.stringify({\n      Message: message\n    }));\n    xhr.onreadystatechange = function(evt) {\n      evt.preventDefault();\n      if (xhr.status === 200 && xhr.readyState === 4) {\n        //location.reload();\n      }\n    };\n  });\n};\n\nvar createTweets = function(tweetContent, user, time) {\n  var tweetList = document.querySelector('#list');\n  var tweets = document.createElement('li');\n  var userName = document.createElement('p');\n  tweets.setAttribute(\"class\", \"list-group-item\");\n  var output = '<strong>' + user + '</strong>';\n  output += '<em>' + time + '</em>';\n  output += '<p>' + tweetContent + '</p>';\n  tweets.innerHTML = output;\n  tweetList.appendChild(tweets);\n};\n\nvar loopJSON = function(json) {\n  for (var i = 0; i < json.length; i++) {\n    createTweets(json[i].Message, json[i].Username, json[i].Time);\n  }\n};\n//////////polling\nvar pollNewTweets = function() {\n  window.setInterval(function() {\n    var httpRequest = new XMLHttpRequest();\n    httpRequest.open('GET', '/api/tweets');\n    httpRequest.setRequestHeader(\"Content-Type\",\n      \"application/json;charset=UTF-8\");\n    httpRequest.send(null);\n    httpRequest.onreadystatechange = function(evt) {\n      evt.preventDefault();\n      if ((httpRequest.readyState === 4) && (httpRequest.status === 200)) {\n        var response = JSON.parse(httpRequest.responseText);\n        var poller = document.querySelector('#poller');\n        poller.textContent = response.length;\n      }\n    };\n  }, 10000);\n};\n\nvar getTweets = function() {\n  var username = location.pathname.split(\"/\").pop();\n  var httpRequest = new XMLHttpRequest();\n  httpRequest.open('GET', '/api/tweets' + (username ? (\"?username=\" +\n    username) : \"\"), true);\n  httpRequest.setRequestHeader(\"Content-Type\",\n    \"application/json;charset=UTF-8\");\n  httpRequest.send(null);\n  httpRequest.onreadystatechange = function(evt) {\n    evt.preventDefault();\n    if (httpRequest.readyState === 4) {\n      if (httpRequest.status === 200) {\n        var response = JSON.parse(httpRequest.responseText);\n        loopJSON(response);\n      } else {\n        console.log('There was a problem with the request.');\n      }\n    }\n  };\n};\n\nvar followFunction = function() {\n  var username = location.pathname.split(\"/\").pop();\n  var followButton = document.querySelector('#followButton');\n  followButton.addEventListener('click', function() {\n    var xhr = new XMLHttpRequest();\n    xhr.open('POST', '/api/follow');\n    xhr.send(JSON.stringify(username));\n    xhr.onreadystatechange = function(evt) {\n      console.log('follow');\n    };\n  });\n};\n\nscream();\ngetTweets();\nfollowFunction();\npollNewTweets();\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/02_tommy/data.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"golang.org/x/net/context\"\n\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/mail\"\n)\n\ntype Scream struct {\n\tID       int64\n\tUsername string\n\tEmail    string\n\tMessage  string\n\tTime     time.Time\n}\n\nfunc createScream(ctx context.Context, scream *Scream) error {\n\tkey := datastore.NewIncompleteKey(ctx, \"Scream\", nil)\n\t_, err := datastore.Put(ctx, key, scream)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif strings.Contains(scream.Message, \"@\") {\n\t\tgetUser := scanString(scream.Message)\n\t\tprofileMention, err := getProfileByUsername(ctx, getUser)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn sendMail(ctx, profileMention)\n\t}\n\treturn nil\n}\n\nfunc getScreams(ctx context.Context, username string) ([]*Scream, error) {\n\tscreams := make([]*Scream, 0)\n\tq := datastore.NewQuery(\"Scream\")\n\tif username != \"\" {\n\t\tq = q.Filter(\"Username=\", username)\n\t}\n\titerator := q.Run(ctx)\n\tfor {\n\t\tvar scream Scream\n\t\tkey, err := iterator.Next(&scream)\n\t\tif err == datastore.Done {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tscream.ID = key.IntID()\n\t\tscreams = append(screams, &scream)\n\t}\n\treturn screams, nil\n}\n\ntype Profile struct {\n\tUsername  string\n\tEmail     string\n\tFollowing []string\n}\n\nfunc getProfile(ctx context.Context, email string) (*Profile, error) {\n\tkey := datastore.NewKey(ctx, \"Profile\", email, 0, nil)\n\tvar profile Profile\n\treturn &profile, datastore.Get(ctx, key, &profile)\n}\n\nfunc getProfileByUsername(ctx context.Context, username string) (*Profile, error) {\n\tq := datastore.NewQuery(\"Profile\").Filter(\"Username =\", username).Limit(1)\n\tvar profiles []Profile\n\t_, err := q.GetAll(ctx, &profiles)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(profiles) == 0 {\n\t\treturn nil, fmt.Errorf(\"profile not found\")\n\t}\n\treturn &profiles[0], nil\n}\n\nfunc createProfile(ctx context.Context, profile *Profile) error {\n\tkey := datastore.NewKey(ctx, \"Profile\", profile.Email, 0, nil)\n\t_, err := datastore.Put(ctx, key, profile)\n\treturn err\n}\nfunc follow(ctx context.Context, email string, followee string) error {\n\tprofile, err := getProfile(ctx, email)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, f := range profile.Following {\n\t\tif f == followee {\n\t\t\treturn nil\n\t\t}\n\t\tif followee == \"\" {\n\t\t\treturn nil\n\t\t}\n\t}\n\tprofile.Following = append(profile.Following, followee)\n\treturn createProfile(ctx, profile)\n}\n\nfunc scanString(message string) string {\n\tuser := \"\"\n\twords := strings.Split(message, \" \")\n\tfor _, value := range words {\n\t\tif strings.HasPrefix(value, \"@\") {\n\t\t\tuser = value[1:len(value)]\n\t\t}\n\t}\n\treturn user\n}\nfunc sendMail(ctx context.Context, mentionProfile *Profile) error {\n\tmsg := &mail.Message{\n\t\tSender:  \"<admin@secret-spark-101320.appspotmail.com>\",\n\t\tTo:      []string{mentionProfile.Email},\n\t\tSubject: \"Someone mentioned you!\",\n\t\tBody:    fmt.Sprintf(\"Someone mentioned you!\"),\n\t}\n\treturn mail.Send(ctx, msg)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/02_tommy/handlers.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/user\"\n)\n\nfunc profileHandler(res http.ResponseWriter, req *http.Request) {\n\thttp.ServeFile(res, req, \"templates/profile.html\")\n}\nfunc homeHandler(res http.ResponseWriter, req *http.Request) {\n\tlog.Infof(appengine.NewContext(req), \"path: %v\", req.URL.Path)\n\tif req.URL.Path != \"/\" {\n\t\tprofileHandler(res, req)\n\t\treturn\n\t}\n\thttp.ServeFile(res, req, \"templates/home.html\")\n}\nfunc loginHandler(res http.ResponseWriter, req *http.Request) {\n\tres.Header().Set(\"Content-type\", \"text/html; charset=utf-8\")\n\tc := appengine.NewContext(req)\n\tu := user.Current(c)\n\n\tprofile, err := getProfile(c, u.Email)\n\tif err != nil || profile.Username == \"\" {\n\n\t\tif req.Method == \"POST\" {\n\t\t\terr = createProfile(c, &Profile{\n\t\t\t\tUsername: req.FormValue(\"username\"),\n\t\t\t\tEmail:    u.Email,\n\t\t\t})\n\t\t} else {\n\t\t\thttp.ServeFile(res, req, \"templates/login.html\")\n\t\t\treturn\n\t\t}\n\t}\n\thttp.SetCookie(res, &http.Cookie{Name: \"logged_in\", Value: \"true\"})\n\thttp.Redirect(res, req, \"/\"+profile.Username, 302)\n}\n\nfunc logoutHandler(res http.ResponseWriter, req *http.Request) {\n\thttp.SetCookie(res, &http.Cookie{Name: \"logged_in\", Value: \"\"})\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc tweetHandler(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\n\tswitch req.Method {\n\tcase \"GET\":\n\t\t// get a list of tweetss\n\t\tscreams, err := getScreams(ctx, req.FormValue(\"username\"))\n\t\tif err != nil {\n\t\t\tlog.Errorf(ctx, \"error getting screams: %v\", err)\n\t\t\treturn\n\t\t}\n\t\terr = json.NewEncoder(res).Encode(screams)\n\t\tif err != nil {\n\t\t\tlog.Errorf(ctx, \"error marshalling todos: %v\", err)\n\t\t\treturn\n\t\t}\n\n\tcase \"POST\":\n\t\tprofile, err := getProfile(ctx, u.Email)\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\t// create a tweet\n\t\tvar scream Scream\n\t\terr = json.NewDecoder(req.Body).Decode(&scream)\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\tscream.Time = time.Now()\n\t\tscream.Username = profile.Username\n\t\tscream.Email = u.Email\n\t\terr = createScream(ctx, &scream)\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\tjson.NewEncoder(res).Encode(&scream)\n\t\ttime.Sleep(time.Second * 3)\n\n\tcase \"DELETE\":\n\t\t// delete a tweet\n\tdefault:\n\t\thttp.Error(res, \"method not allowed\", 405)\n\t}\n}\nfunc followHandler(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\tswitch req.Method {\n\tcase \"POST\":\n\t\tvar userName string\n\t\terr := json.NewDecoder(req.Body).Decode(&userName)\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\terr = follow(ctx, u.Email, userName)\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\tjson.NewEncoder(res).Encode(true)\n\tcase \"GET\":\n\t\tprofile, err := getProfile(ctx, u.Email)\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\tjson.NewEncoder(res).Encode(profile.Following)\n\tcase \"DELETE\":\n\t\t// delete a follower\n\tdefault:\n\t\thttp.Error(res, \"method not allowed\", 405)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/02_tommy/main.go",
    "content": "package main\n\nimport \"net/http\"\n\nfunc init() {\n\thttp.Handle(\"/assets/\", http.StripPrefix(\"/assets\", http.FileServer(http.Dir(\"assets/\"))))\n\n\thttp.HandleFunc(\"/\", homeHandler)\n\thttp.HandleFunc(\"/api/tweets\", tweetHandler)\n\thttp.HandleFunc(\"/api/follow\", followHandler)\n\thttp.HandleFunc(\"/login\", loginHandler)\n\thttp.HandleFunc(\"/logout\", logoutHandler)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/02_tommy/render.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\t\"text/template\"\n)\n\nfunc renderHome(res http.ResponseWriter, req *http.Request) {\n\ttpl, err := template.ParseFiles(\"templates/home.gohtml\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\terr = tpl.ExecuteTemplate(res, \"screamer\", nil)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t}\n}\n\nfunc renderProfile(res http.ResponseWriter, req *http.Request) {\n\ttpl, err := template.ParseFiles(\"templates/profile.gohtml\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\terr = tpl.ExecuteTemplate(res, \"profile\", nil)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/02_tommy/templates/home.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Screamer</title>\n  <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css\">\n  <link rel=\"stylesheet\" href=\"//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n</head>\n<body>\n  <div class=\"container\">\n    <button id=\"loginButton\"><a href=\"/login\">Login</a></button>\n    <button id=\"logoutButton\"><a href=\"/logout\">Logout</a></button>\n    <button id=\"screamButton\">SCREAM</button>\n    <button id=\"followButton\">follow</button>\n      <div class=\"well\">\n        <h2 class=\"text-center\">screams go here</h2>\n        <p id=\"poller\"></p>\n      </div>\n    <div classs=\"col-lg-12\">\n      <ul class=\"list-group\" id=\"list\">\n      </ul>\n    </div>\n  </div>\n\n\n<script src=\"https://code.jquery.com/jquery-2.1.4.min.js\"></script>\n<script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js\"></script>\n<script type=\"text/javascript\" src=\"/assets/scripts/main.js\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/02_tommy/templates/login.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Document</title>\n</head>\n<body>\n  <form method=\"POST\" action=\"/login\">\n    <label>Username <input type=\"text\" name=\"username\"></label><br>\n    <input type=\"submit\">\n  </form>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/02_tommy/templates/profile.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Profile</title>\n  <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css\">\n  <link rel=\"stylesheet\" href=\"//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n</head>\n<body>\n  <div class=\"container\">\n    <button id=\"loginButton\"><a href=\"/login\">Login</a></button>\n    <button id=\"logoutButton\"><a href=\"/logout\">Logout</a></button>\n    <button id=\"screamButton\">SCREAM</button>\n    <button id=\"followButton\">follow</button>\n      <div class=\"well\">\n        <h3 class=\"text-center\">Profile</h3>\n      </div>\n    <div classs=\"col-lg-12\">\n      <ul class=\"list-group\" id=\"list\">\n      </ul>\n    </div>\n  </div>\n\n\n<script src=\"https://code.jquery.com/jquery-2.1.4.min.js\"></script>\n<script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js\"></script>\n<script type=\"text/javascript\" src=\"/assets/scripts/main.js\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/03_t/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /login\n  script: _go_app\n  login: required\n- url: /.*\n  script: _go_app\n\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/03_t/data.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/user\"\n\t\"net/http\"\n\t\"time\"\n)\n\ntype Profile struct {\n\tEmail    string\n\tUsername string\n}\n\ntype Tweet struct {\n\tMessage  string\n\tTime     time.Time\n\tUsername string\n}\n\n// get profile by username\nfunc getProfileByUsername(req *http.Request, username string) (*Profile, error) {\n\tctx := appengine.NewContext(req)\n\tq := datastore.NewQuery(\"Profile\").Filter(\"Username =\", username).Limit(1)\n\tvar profiles []Profile\n\t_, err := q.GetAll(ctx, &profiles)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(profiles) == 0 {\n\t\treturn nil, fmt.Errorf(\"profile not found\")\n\t}\n\treturn &profiles[0], nil\n}\n\n// get profile by email\nfunc getProfileByEmail(ctx context.Context, email string) (*Profile, error) {\n\tkey := datastore.NewKey(ctx, \"Profile\", email, 0, nil)\n\tvar profile Profile\n\terr := datastore.Get(ctx, key, &profile)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &profile, nil\n}\n\n// get profile\nfunc getProfile(ctx context.Context) (*Profile, error) {\n\tu := user.Current(ctx)\n\treturn getProfileByEmail(ctx, u.Email)\n}\n\n// create profile\nfunc createProfile(req *http.Request, profile *Profile) error {\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Profile\", profile.Email, 0, nil)\n\t_, err := datastore.Put(ctx, key, profile)\n\treturn err\n\t// you can use memcache also to improve your consistency\n}\n\n// for eventual consistency thing\n// assumption: user will show up in 10 seconds on datastore\nfunc waitForProfile(req *http.Request, username string) error {\n\tdeadline := time.Now().Add(time.Second * 10)\n\tfor time.Now().Before(deadline) {\n\t\t_, err := getProfileByUsername(req, username)\n\t\tif err == nil {\n\t\t\treturn nil\n\t\t}\n\t\ttime.Sleep(time.Second * 1)\n\t}\n\treturn nil\n}\n\n//// insert tweet\nfunc putTweet(ctx context.Context, tweet *Tweet, email string) error {\n\tuserKey := datastore.NewKey(ctx, \"Profile\", email, 0, nil)\n\ttweetKey := datastore.NewIncompleteKey(ctx, \"Tweet\", userKey)\n\t_, err := datastore.Put(ctx, tweetKey, tweet)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// get user tweets\nfunc userTweets(ctx context.Context, email string) ([]Tweet, error) {\n\tvar tweets []Tweet\n\tuserKey := datastore.NewKey(ctx, \"Profile\", email, 0, nil)\n\tq := datastore.NewQuery(\"Tweet\").Ancestor(userKey).Order(\"-Time\").Limit(20)\n\t_, err := q.GetAll(ctx, &tweets)\n\treturn tweets, err\n\n}\n\n// get recent tweets\nfunc recentTweets(ctx context.Context) ([]Tweet, error) {\n\tvar tweets []Tweet\n\tq := datastore.NewQuery(\"Tweet\").Order(\"-Time\").Limit(20)\n\t_, err := q.GetAll(ctx, &tweets)\n\treturn tweets, err\n\n}\n\n//// delete tweet\n//func delTweet(ctx context.Context, username string) (*Profile, error) {\n//\n//}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/03_t/index.yaml",
    "content": "indexes:\n\n# AUTOGENERATED\n\n# This index.yaml is automatically updated whenever the dev_appserver\n# detects that a new type of query is run.  If you want to manage the\n# index.yaml file manually, remove the above marker line (the line\n# saying \"# AUTOGENERATED\").  If you want to manage some indexes\n# manually, move them above the marker line.  The index.yaml file is\n# automatically uploaded to the admin console when you next deploy\n# your application using appcfg.py.\n\n- kind: Tweet\n  ancestor: yes\n  properties:\n  - name: Time\n    direction: desc\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/03_t/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}\ninput:focus,\nselect:focus,\ntextarea:focus,\nbutton:focus {\n    outline: none;\n}\n[contenteditable=\"true\"]:focus {\n    outline: none;\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/03_t/public/js/make-post.js",
    "content": "// sending data to server\nvar modal = document.querySelector('#openModal');\nmodal.addEventListener('click', function(e){\n    if ((e.target.id === 'modal-submit') && (e.target.textContent !== '')) {\n        var modalTweet = document.querySelector('#modal-tweet')\n        // make your ajax post\n        var msg = modalTweet.value;\n        var xhr = new XMLHttpRequest();\n        xhr.open(\"POST\", \"/tweet\");\n        var json = JSON.stringify({Message: msg});\n        xhr.send(json);\n        // clear entry\n        modalTweet.value = '';\n        // receive data back from the post\n        xhr.addEventListener('readystatechange', function () {\n            if ((xhr.status === 200) && (xhr.readyState === 4)) {\n                location.reload(false);\n            }\n        })\n        //\n    }\n}, false);\n\nvar opensModal = document.querySelector('#opens-modal');\nopensModal.addEventListener('click', function(e){\n    window.setTimeout(function(){\n        var tweet = document.querySelector('#modal-tweet');\n        tweet.value = '';\n        tweet.focus();\n    }, 100);\n}, false);\n\n/*\ncheckout for the future:\n http://caniuse.com/#search=xmlhttp\n\n stream and post blobs\n video, etc\n*/"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/03_t/routes.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/user\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", home)\n\thttp.HandleFunc(\"/login\", login)\n\thttp.HandleFunc(\"/tweet\", tweet)\n\thttp.HandleFunc(\"/logout\", logout)\n\thttp.HandleFunc(\"/profile\", profile)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n}\n\nfunc home(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path != \"/\" {\n\t\tprofile(res, req)\n\t\treturn\n\t}\n\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\tlog.Infof(ctx, \"user: \", u)\n\t// pointers can be NIL so don't use a Profile * Profile here:\n\tvar model struct {\n\t\tProfile Profile\n\t\tTweets  []Tweet\n\t}\n\n\tif u != nil {\n\t\tprofile, err := getProfileByEmail(ctx, u.Email)\n\t\tif err != nil {\n\t\t\thttp.Redirect(res, req, \"/login\", 302)\n\t\t\treturn\n\t\t}\n\t\tmodel.Profile = *profile\n\t}\n\n\t// TODO: get recent tweets\n\tvar tweets []Tweet\n\ttweets, err := recentTweets(ctx)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t}\n\tmodel.Tweets = tweets\n\n\trenderTemplate(res, \"home.html\", model)\n}\n\nfunc login(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\n\t// look for the user's profile\n\tprofile, err := getProfileByEmail(ctx, u.Email)\n\t// if it exists redirect\n\tif err == nil && profile.Username != \"\" {\n\t\thttp.Redirect(res, req, \"/\"+profile.Username, 302)\n\t\treturn\n\t}\n\n\tvar model struct {\n\t\tProfile *Profile\n\t\tError   string\n\t}\n\tmodel.Profile = &Profile{Email: u.Email}\n\n\t// create the profile\n\tusername := req.FormValue(\"username\")\n\tif username != \"\" {\n\t\t_, err = getProfileByUsername(req, username)\n\t\t// if the username is already taken\n\t\tif err == nil {\n\t\t\tmodel.Error = \"username is not available\"\n\t\t\tmodel.Profile.Username = username // caleb didn't have this line\n\t\t} else {\n\t\t\tmodel.Profile.Username = username\n\t\t\t// try to create the profile\n\t\t\terr = createProfile(req, model.Profile)\n\t\t\tif err != nil {\n\t\t\t\tmodel.Error = err.Error()\n\t\t\t} else {\n\t\t\t\t// on success redirect to the user's timeline\n\t\t\t\twaitForProfile(req, username)\n\t\t\t\thttp.SetCookie(res, &http.Cookie{Name: \"logged_in\", Value: \"true\"})\n\t\t\t\thttp.Redirect(res, req, \"/\"+username, 302)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\t// render the login template\n\trenderTemplate(res, \"login.html\", model)\n}\n\nfunc profile(res http.ResponseWriter, req *http.Request) {\n\t// get the username\n\tusername := strings.SplitN(req.URL.Path, \"/\", 2)[1]\n\t// get the profile\n\tprofile, err := getProfileByUsername(req, username)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 404)\n\t\treturn\n\t}\n\n\t// get user's tweets\n\tctx := appengine.NewContext(req)\n\tvar tweets []Tweet\n\ttweets, err = userTweets(ctx, profile.Email)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\t// Render the template\n\tvar model struct {\n\t\tProfile *Profile\n\t\tTweets  []Tweet\n\t}\n\n\tmodel.Profile = profile\n\tmodel.Tweets = tweets\n\n\trenderTemplate(res, \"profile.html\", model)\n\t/*\n\n\t\t// Render the template\n\t\ttype Model struct {\n\t\t\tProfile *Profile\n\t\t}\n\t\trenderTemplate(res, \"user-profile\", Model{\n\t\t\tProfile: profile,\n\t\t})\n\n\t*/\n}\n\nfunc tweet(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\tvar tweet *Tweet\n\ttweet = receiveTweet(ctx, res, req)\n\ttweet.Time = time.Now()\n\t// add in username\n\tvar profile *Profile\n\tprofile, err := getProfileByEmail(ctx, u.Email)\n\ttweet.Username = profile.Username\n\terr = putTweet(ctx, tweet, u.Email)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tjson.NewEncoder(res).Encode(true)\n}\n\nfunc receiveTweet(ctx context.Context, res http.ResponseWriter, req *http.Request) *Tweet {\n\tvar tweet Tweet\n\terr := json.NewDecoder(req.Body).Decode(&tweet)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error unmarshalling todos: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn nil\n\t}\n\treturn &tweet\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request) {\n\thttp.SetCookie(res, &http.Cookie{Name: \"logged_in\", Value: \"\"})\n\thttp.Redirect(res, req, \"/\", 302)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/03_t/templates/html/footer.html",
    "content": "{{ define \"footer\" }}\n<div id=\"openModal\" class=\"modalDialog\">\n    <div>\t<a href=\"#close\" title=\"Close\" class=\"modal-close\">X</a>\n        <form method=\"post\" id=\"modal-form\">\n            <textarea name=\"tweet\" id=\"modal-tweet\" rows=\"4\" maxlength=\"140\"></textarea>\n            <a href=\"#\"><p id=\"modal-submit\">Tweet</p></a>\n            <!--<a href=\"/tweet\"><p id=\"modal-submit\">Tweet</p></a>-->\n        </form>\n    </div>\n</div>\n<script src=\"/public/js/make-post.js\"></script>\n</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/03_t/templates/html/header.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link href='http://fonts.googleapis.com/css?family=Lobster|Open+Sans' rel='stylesheet' type='text/css'>\n    <link rel=\"stylesheet\" href=\"http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <style>\n\n        * {\n            box-sizing: border-box;\n            font-family: 'Open Sans', sans-serif;\n        }\n\n        body {\n            display: flex;\n            flex-direction: column;\n            justify-content: center;\n            align-items: center;\n            background-color: rgba(46, 195, 113, 0.11);\n        }\n\n        #top {\n            display: flex;\n            flex-direction: column;\n            justify-content: center;\n            align-items: center;\n            background-color: #2ec371;\n            padding: 0 0 35px 0;\n            width: 100%\n        }\n\n        header {\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n            padding: 25px 75px;\n            width: 100%;\n\n        }\n\n        #login {\n            border: 1px solid #fff;\n            border-radius: 5px;\n            padding: 14px 28px;\n            font-size: 18px;\n            color: #fff;\n            margin: 0 0 0 15px;\n        }\n\n        #login:hover {\n            background-color: #00acc1;\n        }\n\n        .fa-heart-o {\n            color: #fff;\n        }\n\n        .fa-heart-o:hover {\n            color: #f00;\n        }\n\n        #motto {\n            font-family: 'Lobster', cursive;\n            font-size: 40px;\n            color: #f5f5f5;\n            text-align: center;\n            line-height: 47px;\n        }\n\n        main {\n            display: flex;\n            flex-direction: column;\n            justify-content: center;\n            align-items: center;\n            padding: 4px 0 35px 0;\n            /*border: 1px solid black;*/\n            width: 100%;\n        }\n\n        section {\n            display: flex;\n            justify-content: flex-start;\n            align-items: center;\n            border: 1px solid rgba(0, 0, 0, 0.19);\n            width: 60%;\n            padding: 10px;\n            margin: 4px;\n            background-color: #f5f5f5;\n        }\n\n        #post {\n            padding: 10px;\n        }\n\n        a {\n            text-decoration: none;\n        }\n\n        form {\n            display: flex;\n            flex-direction: column;\n        }\n\n        nav {\n            display: flex;\n        }\n\n        /*\n        modal dialog box styling\n        */\n\n        .modalDialog {\n            position: fixed;\n            top: 0;\n            right: 0;\n            bottom: 0;\n            left: 0;\n            background: rgba(255, 255, 255, 0.7);\n            z-index: 99999;\n            opacity:0;\n            -webkit-transition: opacity 400ms ease-in;\n            -moz-transition: opacity 400ms ease-in;\n            transition: opacity 400ms ease-in;\n            pointer-events: none;\n        }\n        .modalDialog:target {\n            opacity:1;\n            pointer-events: auto;\n        }\n        .modalDialog > div {\n            border: 4px solid #2ec371;\n            width: 70%;\n            position: relative;\n            margin: 10% auto;\n            padding: 5px 20px 13px 20px;\n            border-radius: 10px;\n            background: rgba(46, 195, 113, 0.6);\n        }\n        .modal-close {\n            border: 1px solid #2ec371;\n            background: #2ec371;\n            color: #FFFFFF;\n            line-height: 20px;\n            position: absolute;\n            right: 0px;\n            text-align: center;\n            top: 0px;\n            width: 24px;\n            text-decoration: none;\n            border-radius: 0px 6px 0px 4px;\n        }\n        .modal-close:hover {\n            background: #2ec371;\n        }\n\n        #modal-tweet {\n            width: 100%;\n            border-radius: 10px;\n            border: 2px solid #2ec371;\n            margin: 20px 0 0 0;\n            font-size: 40px;\n            outline-width: 0;\n        }\n\n        #modal-submit {\n            border: 1px solid #fff;\n            border-radius: 5px;\n            padding: 14px 28px;\n            font-size: 18px;\n            color: #fff;\n            margin: 15px 15px 0 0;\n            font-family: 'Lobster', cursive;\n            font-size: 25px;\n            background-color: #2ec371;\n        }\n\n        #modal-submit:hover {\n            background-color: #00acc1;\n        }\n\n        #modal-form {\n            display: flex;\n            flex-direction: column;\n            align-items: flex-end;\n        }\n\n    </style>\n</head>\n<body>\n\n<div id=\"top\">\n    <header>\n        <a href=\"/\" id=\"opens-modal\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n\n        {{ if .Profile.Email }}\n        <nav>\n            <a href=\"#openModal\" id=\"opens-modal\"><p id=\"login\">Tweet</p></a>\n            <a href=\"/logout\"><p id=\"login\">Log Out</p></a>\n        </nav>\n        {{ else }}\n        <nav>\n            <a href=\"/login\"><p id=\"login\">Log In</p></a>\n        </nav>\n        {{ end }}\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n\n</div>\n{{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/03_t/templates/html/home.html",
    "content": "{{template \"header\" . }}\n\n<main>\n    {{ range .Tweets }}\n    <section>\n        <i class=\"fa fa-user fa-2x\"> @{{ .Username}}</i>\n        <p id=\"post\">{{ .Message }}</p>\n    </section>\n    {{ end }}\n</main>\n{{template \"footer\" . }}"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/03_t/templates/html/login.html",
    "content": "{{ template \"header\" . }}\n<main>\n    <section>\n        <form method=\"POST\">\n            <label for=\"user-name\">User Name: </label>\n            <input type=\"text\" id=\"user-name\" name=\"username\" value=\"{{.Profile.Username}}\">\n            <input type=\"submit\" value=\"submit\" name=\"submit\">\n        </form>\n        {{ if .Error }}\n        <div class=\"error\">{{.Error}}</div>\n        {{ end }}\n    </section>\n</main>\n{{ template \"footer\" . }}"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/03_t/templates/html/profile.html",
    "content": "{{template \"header\" . }}\n\n<main>\n    {{ range .Tweets }}\n    <section>\n        <i class=\"fa fa-user fa-2x\"> @{{ .Username }}</i>\n        <p id=\"post\">{{ .Message }}</p>\n    </section>\n    {{ end }}\n</main>\n\n{{template \"footer\" . }}"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/03_t/templates.go",
    "content": "package main\n\nimport (\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\ttpl = template.Must(template.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc renderTemplate(res http.ResponseWriter, name string, data interface{}) {\n\terr := tpl.ExecuteTemplate(res, name, data)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/03_t/temporary/modal-dialog.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n    <link rel=\"stylesheet\" href=\"../public/css/reset.css\">\n    <link href='http://fonts.googleapis.com/css?family=Lobster|Open+Sans' rel='stylesheet' type='text/css'>\n    <link rel=\"stylesheet\" href=\"http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <style>\n\n        * {\n            box-sizing: border-box;\n            font-family: 'Open Sans', sans-serif;\n        }\n\n        body {\n            display: flex;\n            flex-direction: column;\n            justify-content: center;\n            align-items: center;\n            rgba(46, 195, 113, 0.11);\n        }\n\n        #top {\n            display: flex;\n            flex-direction: column;\n            justify-content: center;\n            align-items: center;\n            background-color: #2ec371;\n            padding: 0 0 35px 0;\n            width: 100%\n        }\n\n        header {\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n            padding: 25px 75px;\n            width: 100%;\n\n        }\n\n        #login {\n            border: 1px solid #fff;\n            border-radius: 5px;\n            padding: 14px 28px;\n            font-size: 18px;\n            color: #fff;\n            margin: 0 0 0 15px;\n        }\n\n        #login:hover {\n            background-color: #00acc1;\n        }\n\n        .fa-heart-o {\n            color: #fff;\n        }\n\n        .fa-heart-o:hover {\n            color: #f00;\n        }\n\n        #motto {\n            font-family: 'Lobster', cursive;\n            font-size: 40px;\n            color: #f5f5f5;\n            text-align: center;\n            line-height: 47px;\n        }\n\n        main {\n            display: flex;\n            flex-direction: column;\n            justify-content: center;\n            align-items: center;\n            padding: 4px 0 35px 0;\n            /*border: 1px solid black;*/\n            width: 100%;\n        }\n\n        section {\n            display: flex;\n            justify-content: flex-start;\n            align-items: center;\n            border: 1px solid rgba(0, 0, 0, 0.19);\n            width: 60%;\n            padding: 10px;\n            margin: 4px;\n            background-color: #f5f5f5;\n        }\n\n        #post {\n            padding: 10px;\n        }\n\n        a {\n            text-decoration: none;\n        }\n\n        form {\n            display: flex;\n            flex-direction: column;\n        }\n\n        nav {\n            display: flex;\n        }\n\n        /* MODAL CSS */\n\n        .modalDialog {\n            position: fixed;\n            top: 0;\n            right: 0;\n            bottom: 0;\n            left: 0;\n            background: rgba(255, 255, 255, 0.7);\n            z-index: 99999;\n            opacity:0;\n            -webkit-transition: opacity 400ms ease-in;\n            -moz-transition: opacity 400ms ease-in;\n            transition: opacity 400ms ease-in;\n            pointer-events: none;\n        }\n        .modalDialog:target {\n            opacity:1;\n            pointer-events: auto;\n        }\n        .modalDialog > div {\n            border: 4px solid #2ec371;\n            width: 70%;\n            position: relative;\n            margin: 10% auto;\n            padding: 5px 20px 13px 20px;\n            border-radius: 10px;\n            background: rgba(46, 195, 113, 0.6);\n        }\n        .modal-close {\n            border: 1px solid #2ec371;\n            background: #2ec371;\n            color: #FFFFFF;\n            line-height: 20px;\n            position: absolute;\n            right: 0px;\n            text-align: center;\n            top: 0px;\n            width: 24px;\n            text-decoration: none;\n            border-radius: 0px 6px 0px 4px;\n        }\n        .modal-close:hover {\n            background: #2ec371;\n        }\n\n        #modal-tweet {\n            width: 100%;\n            border-radius: 10px;\n            border: 1px solid #2ec371;\n            margin: 20px 0 0 0;\n            font-size: 40px;\n        }\n\n        #modal-submit {\n            border: 1px solid #fff;\n            border-radius: 5px;\n            padding: 14px 28px;\n            font-size: 18px;\n            color: #fff;\n            margin: 15px 15px 0 0;\n            font-family: 'Lobster', cursive;\n            font-size: 25px;\n            background-color: #2ec371;\n        }\n\n        #modal-submit:hover {\n            background-color: #00acc1;\n        }\n\n\n\n        #modal-form {\n            display: flex;\n            flex-direction: column;\n            align-items: flex-end;\n        }\n\n    </style>\n</head>\n<body>\n<a href=\"#openModal\">Open Modal</a>\n\n<div id=\"openModal\" class=\"modalDialog\">\n    <div>\t<a href=\"#close\" title=\"Close\" class=\"modal-close\">X</a>\n        <form method=\"post\" id=\"modal-form\">\n            <textarea name=\"tweet\" id=\"modal-tweet\" rows=\"4\" maxlength=\"140\"></textarea>\n            <a href=\"/tweet\"><p id=\"modal-submit\">Tweet</p></a>\n        </form>\n    </div>\n</div>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/03_t/temporary/temp_home.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n    <link rel=\"stylesheet\" href=\"../public/css/reset.css\">\n    <link href='http://fonts.googleapis.com/css?family=Lobster|Open+Sans' rel='stylesheet' type='text/css'>\n    <link rel=\"stylesheet\" href=\"http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <style>\n\n        * {\n            box-sizing: border-box;\n            font-family: 'Open Sans', sans-serif;\n        }\n\n        body {\n            display: flex;\n            flex-direction: column;\n            justify-content: center;\n            align-items: center;\n            background-color: rgba(46, 195, 113, 0.11); /*1*/\n        }\n\n        #top {\n            display: flex;\n            flex-direction: column;\n            justify-content: center;\n            align-items: center;\n            background-color: #2ec371;\n            padding: 0 0 35px 0;\n            width: 100%\n        }\n\n        header {\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n            padding: 25px 75px;\n            width: 100%;\n\n        }\n\n        #login {\n            border: 1px solid #fff;\n            border-radius: 5px;\n            padding: 14px 28px;\n            font-size: 18px;\n            color: #fff;\n            margin: 0 0 0 15px;\n        }\n\n        #login:hover {\n            background-color: #00acc1;\n        }\n\n        .fa-heart-o {\n            color: #fff;\n        }\n\n        .fa-heart-o:hover {\n            color: #f00;\n        }\n\n        #motto {\n            font-family: 'Lobster', cursive;\n            font-size: 40px;\n            color: #f5f5f5;\n            text-align: center;\n            line-height: 47px;\n        }\n\n        main {\n            display: flex;\n            flex-direction: column;\n            justify-content: center;\n            align-items: center;\n            padding: 4px 0 35px 0;\n            /*border: 1px solid black;*/\n            width: 70%;\n        }\n\n        section {\n            display: flex;\n            justify-content: flex-start;\n            align-items: center;\n            border: 1px solid rgba(0, 0, 0, 0.19);\n            width: 80%;\n            padding: 10px;\n            margin: 4px;\n            background-color: #f5f5f5; /*2 from main to here */\n        }\n\n        #post {\n            padding: 10px;\n        }\n\n        nav {\n            display: flex;\n        }\n\n    </style>\n</head>\n<body>\n\n<div id=\"top\">\n    <header>\n        <i class=\"fa fa-heart-o fa-3x\"></i>\n\n        <nav>\n            <p id=\"login\">Tweet</p>\n            <p id=\"login\">Log In</p>\n        </nav>\n    </header>\n    <p id=\"motto\">Come here, Judge People, Be Judged<br>One convenient location</p>\n\n</div>\n\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/03_t/temporary/temp_login.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n    <link rel=\"stylesheet\" href=\"../public/css/reset.css\">\n    <link href='http://fonts.googleapis.com/css?family=Lobster|Open+Sans' rel='stylesheet' type='text/css'>\n    <link rel=\"stylesheet\" href=\"http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <style>\n\n        * {\n            box-sizing: border-box;\n            font-family: 'Open Sans', sans-serif;\n        }\n\n        body {\n            display: flex;\n            flex-direction: column;\n            justify-content: center;\n            align-items: center;\n        }\n\n        #top {\n            display: flex;\n            flex-direction: column;\n            justify-content: center;\n            align-items: center;\n            background-color: #2ec371;\n            padding: 0 0 35px 0;\n            width: 100%\n        }\n\n        header {\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n            padding: 25px 75px;\n            width: 100%;\n\n        }\n\n        #login {\n            border: 1px solid #fff;\n            border-radius: 5px;\n            padding: 14px 28px;\n            font-size: 18px;\n            color: #fff;\n        }\n\n        #login:hover {\n            border: 1px solid #fff;\n            border-radius: 5px;\n            padding: 14px 28px;\n            font-size: 18px;\n            color: #fff;\n            background-color: #00acc1;\n        }\n\n        .fa-heart-o {\n            color: #fff;\n        }\n\n        .fa-heart-o:hover {\n            color: #f00;\n        }\n\n        #motto {\n            font-family: 'Lobster', cursive;\n            font-size: 40px;\n            color: #f5f5f5;\n            text-align: center;\n            line-height: 47px;\n        }\n\n        main {\n            display: flex;\n            flex-direction: column;\n            justify-content: center;\n            align-items: center;\n            background-color: #f5f5f5;\n            padding: 4px 0 35px 0;\n            /*border: 1px solid black;*/\n            width: 100%;\n        }\n\n        section {\n            display: flex;\n            justify-content: flex-start;\n            align-items: center;\n            border: 1px solid rgba(0, 0, 0, 0.19);\n            width: 60%;\n            padding: 10px;\n            margin: 4px;\n        }\n\n        #post {\n            padding: 10px;\n        }\n\n        a {\n            text-decoration: none;\n        }\n\n    </style>\n</head>\n<body>\n\n<div id=\"top\">\n    <header>\n        <i class=\"fa fa-heart-o fa-3x\"></i>\n\n        <nav>\n            <a href=\"#\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Come here, Judge People, Be Judged<br>One convenient location</p>\n\n</div>\n\n<main>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <p id=\"post\">post</p>\n    </section>\n</main>\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/56_twitter/37_other-implementations/03_t/temporary/temp_profile.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n    <link rel=\"stylesheet\" href=\"../public/css/reset.css\">\n    <link href='http://fonts.googleapis.com/css?family=Lobster|Open+Sans' rel='stylesheet' type='text/css'>\n    <link rel=\"stylesheet\" href=\"http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <style>\n\n        * {\n            box-sizing: border-box;\n            font-family: 'Open Sans', sans-serif;\n        }\n\n        body {\n            display: flex;\n            flex-direction: column;\n            justify-content: center;\n            align-items: center;\n        }\n\n        #top {\n            display: flex;\n            flex-direction: column;\n            justify-content: center;\n            align-items: center;\n            background-color: #2ec371;\n            padding: 0 0 35px 0;\n            width: 100%\n        }\n\n        header {\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n            padding: 25px 75px;\n            width: 100%;\n\n        }\n\n        #login {\n            border: 1px solid #fff;\n            border-radius: 5px;\n            padding: 14px 28px;\n            font-size: 18px;\n            color: #fff;\n        }\n\n        #login:hover {\n            border: 1px solid #fff;\n            border-radius: 5px;\n            padding: 14px 28px;\n            font-size: 18px;\n            color: #fff;\n            background-color: #00acc1;\n        }\n\n        .fa-heart-o {\n            color: #fff;\n        }\n\n        .fa-heart-o:hover {\n            color: #f00;\n        }\n\n        #motto {\n            font-family: 'Lobster', cursive;\n            font-size: 40px;\n            color: #f5f5f5;\n            text-align: center;\n            line-height: 47px;\n        }\n\n        main {\n            display: flex;\n            flex-direction: column;\n            justify-content: center;\n            align-items: center;\n            background-color: #f5f5f5;\n            padding: 4px 0 35px 0;\n            /*border: 1px solid black;*/\n            width: 100%;\n        }\n\n        section {\n            display: flex;\n            justify-content: flex-start;\n            align-items: center;\n            border: 1px solid rgba(0, 0, 0, 0.19);\n            width: 60%;\n            padding: 10px;\n            margin: 4px;\n        }\n\n        #post {\n            padding: 10px;\n        }\n\n        a {\n            text-decoration: none;\n        }\n\n        form {\n            display: flex;\n            flex-direction: column;\n        }\n\n    </style>\n</head>\n<body>\n\n<div id=\"top\">\n    <header>\n        <i class=\"fa fa-heart-o fa-3x\"></i>\n\n        <nav>\n            <a href=\"#\"><p id=\"login\">Log In</p></a>\n        </nav>\n    </header>\n    <p id=\"motto\">Come here, Judge People, Be Judged<br>One convenient location</p>\n\n</div>\n\n<main>\n    <section>\n        <form method=\"POST\">\n            <label for=\"user-name\">User Name: </label>\n            <input type=\"text\" id=\"user-name\" name=\"user-name\">\n            <input type=\"submit\" value=\"submit\" name=\"submit\">\n        </form>\n    </section>\n</main>\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/56_twitter/38_follow/api.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"golang.org/x/crypto/bcrypt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\thashedPass, err := bcrypt.GenerateFromPassword([]byte(req.FormValue(\"password\")), bcrypt.DefaultCost)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error creating password: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tuser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: string(hashedPass),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey, err = datastore.Put(ctx, key, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tcreateSession(res, req, user)\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc loginProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Users\", req.FormValue(\"userName\"), 0, nil)\n\tvar user User\n\terr := datastore.Get(ctx, key, &user)\n\tif err != nil || bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.FormValue(\"password\"))) != nil {\n\t\t// failure logging in\n\t\tvar sd SessionData\n\t\tsd.LoginFail = true\n\t\ttpl.ExecuteTemplate(res, \"login.html\", sd)\n\t\treturn\n\t} else {\n\t\tuser.UserName = req.FormValue(\"userName\")\n\t\t// success logging in\n\t\tcreateSession(res, req, user)\n\t\t// redirect\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t}\n}\n\nfunc createSession(res http.ResponseWriter, req *http.Request, user User) {\n\tctx := appengine.NewContext(req)\n\t// SET COOKIE\n\tid, _ := uuid.NewV4()\n\tcookie := &http.Cookie{\n\t\tName:  \"session\",\n\t\tValue: id.String(),\n\t\tPath:  \"/\",\n\t\t// twenty minute session:\n\t\tMaxAge: 60 * 20,\n\t\t//\t\tUNCOMMENT WHEN DEPLOYED:\n\t\t//\t\tSecure: true,\n\t\t//\t\tHttpOnly: true,\n\t}\n\thttp.SetCookie(res, cookie)\n\n\t// SET MEMCACHE session data (sd)\n\tjson, err := json.Marshal(user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error marshalling during user creation: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd := memcache.Item{\n\t\tKey:   id.String(),\n\t\tValue: json,\n\t}\n\tmemcache.Set(ctx, &sd)\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\t// cookie is not set\n\tif err != nil {\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t\treturn\n\t}\n\n\t// clear memcache\n\tsd := memcache.Item{\n\t\tKey:        cookie.Value,\n\t\tValue:      []byte(\"\"),\n\t\tExpiration: time.Duration(1 * time.Microsecond),\n\t}\n\tmemcache.Set(ctx, &sd)\n\n\t// clear the cookie\n\tcookie.MaxAge = -1\n\thttp.SetCookie(res, cookie)\n\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc tweetProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to post tweet from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// declare a variable of type tweet\n\t// initialize it with values\n\tlog.Infof(ctx, user.UserName)\n\ttweet := Tweet{\n\t\tMsg:      req.FormValue(\"tweet\"),\n\t\tTime:     time.Now(),\n\t\tUserName: user.UserName,\n\t}\n\t// put in datastore\n\terr = putTweet(req, &user, &tweet)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// redirect\n\ttime.Sleep(time.Millisecond * 500) // This is not the best code, probably. Thoughts?\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc follow(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t// get session\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to follow from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// get the datastore key for the follower\n\tfollowerKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\t// get a datastore key for the followee\n\tfolloweeKey := datastore.NewKey(ctx, \"Follows\", ps.ByName(\"user\"), 0, followerKey)\n\t// the follower is following the followee\n\t// put this into the datastore\n\ttype F struct {\n\t\tFollowing string\n\t}\n\t//\n\t_, err = datastore.Put(ctx, followeeKey, &F{ps.ByName(\"user\")})\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding followee: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\thttp.Redirect(res, req, \"/user/\"+ps.ByName(\"user\"), 302)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/38_follow/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/38_follow/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/38_follow/following.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"net/http\"\n)\n\nfunc following(follower, followee string, req *http.Request) (bool, error) {\n\tctx := appengine.NewContext(req)\n\tuserKey := datastore.NewKey(ctx, \"Users\", follower, 0, nil)\n\tx, err := datastore.NewQuery(\"Follows\").Ancestor(userKey).Filter(\"Following =\", followee).Count(ctx)\n\treturn x > 0, err\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/38_follow/index.yaml",
    "content": "indexes:\n\n# AUTOGENERATED\n\n# This index.yaml is automatically updated whenever the dev_appserver\n# detects that a new type of query is run.  If you want to manage the\n# index.yaml file manually, remove the above marker line (the line\n# saying \"# AUTOGENERATED\").  If you want to manage some indexes\n# manually, move them above the marker line.  The index.yaml file is\n# automatically uploaded to the admin console when you next deploy\n# your application using appcfg.py.\n\n- kind: Tweets\n  ancestor: yes\n  properties:\n  - name: Time\n    direction: desc\n"
  },
  {
    "path": "27_code-in-process/56_twitter/38_follow/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", home)\n\tr.GET(\"/user/:user\", user)\n\tr.GET(\"/form/login\", login)\n\tr.GET(\"/form/signup\", signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\tr.POST(\"/api/login\", loginProcess)\n\tr.POST(\"/api/tweet\", tweetProcess)\n\tr.GET(\"/api/logout\", logout)\n\tr.GET(\"/api/follow/:user\", follow)\n\t//\tr.GET(\"/api/unfollow/:user\", unfollow)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\n\ttpl = template.New(\"roottemplate\")\n\ttpl = tpl.Funcs(template.FuncMap{\n\t\t\"humanize_time\": humanize.Time,\n\t})\n\n\ttpl = template.Must(tpl.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc home(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t//get tweets\n\ttweets, err := getTweets(req, nil)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting tweets: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// get session\n\tmemItem, err := getSession(req)\n\tvar sd SessionData\n\tif err == nil {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t}\n\tsd.Tweets = tweets\n\ttpl.ExecuteTemplate(res, \"home.html\", &sd)\n}\n\nfunc user(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tuser := User{UserName: ps.ByName(\"user\")}\n\t//get tweets\n\ttweets, err := getTweets(req, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting tweets: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// get session\n\tmemItem, err := getSession(req)\n\tvar sd SessionData\n\tif err == nil {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t\tsd.ViewingUser = user.UserName\n\t\tsd.FollowingUser, err = following(sd.UserName, user.UserName, req)\n\t\tif err != nil {\n\t\t\tlog.Errorf(ctx, \"error running following query: %v\", err)\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t}\n\tsd.Tweets = tweets\n\ttpl.ExecuteTemplate(res, \"user.html\", &sd)\n}\n\nfunc login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"login.html\")\n}\n\nfunc signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"signup.html\")\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/38_follow/model.go",
    "content": "package main\n\nimport \"time\"\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string `json:\"-\"`\n}\n\ntype SessionData struct {\n\tUser\n\tLoggedIn      bool\n\tLoginFail     bool\n\tTweets        []Tweet\n\tViewingUser   string\n\tFollowingUser bool\n}\n\ntype Tweet struct {\n\tMsg      string\n\tTime     time.Time\n\tUserName string\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/38_follow/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/38_follow/public/css/modal-tweet.css",
    "content": ".modalDialog {\n    position: fixed;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    background: rgba(255, 255, 255, 0.7);\n    z-index: 99999;\n    opacity:0;\n    -webkit-transition: opacity 400ms ease-in;\n    -moz-transition: opacity 400ms ease-in;\n    transition: opacity 400ms ease-in;\n    pointer-events: none;\n}\n.modalDialog:target {\n    opacity:1;\n    pointer-events: auto;\n}\n.modalDialog > div {\n    border: 4px solid #2ec371;\n    width: 70%;\n    position: relative;\n    margin: 10% auto;\n    padding: 5px 20px 13px 20px;\n    border-radius: 10px;\n    background: rgba(46, 195, 113, 0.6);\n}\n.modal-close {\n    border: 1px solid #2ec371;\n    background: #2ec371;\n    color: #FFFFFF;\n    line-height: 20px;\n    position: absolute;\n    right: 0px;\n    text-align: center;\n    top: 0px;\n    width: 24px;\n    text-decoration: none;\n    border-radius: 0px 6px 0px 4px;\n}\n.modal-close:hover {\n    background: #2ec371;\n}\n\n#modal-tweet {\n    width: 100%;\n    border-radius: 10px;\n    border: 1px solid #2ec371;\n    margin: 20px 0 0 0;\n    font-size: 40px;\n}\n\n#modal-submit {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n    margin: 15px 15px 0 0;\n    font-family: 'Lobster', cursive;\n    font-size: 25px;\n    background-color: #2ec371;\n}\n\n#modal-submit:hover {\n    background-color: #00acc1;\n}\n\n\n\n#modal-form {\n    display: flex;\n    flex-direction: column;\n    align-items: flex-end;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/38_follow/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/38_follow/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/38_follow/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\nheader nav {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n}\n\n.loginOut {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n    margin-left: 10px;\n}\n\n.loginOut:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n.post {\n    padding: 10px 10px 0 10px;\n}\n\n.post-meta {\n    font-size: 12px;\n    padding: 0;\n    border: 0;\n    margin: 2px 0 0 20px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/38_follow/session.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"net/http\"\n)\n\nfunc getSession(req *http.Request) (*memcache.Item, error) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\tif err != nil {\n\t\treturn &memcache.Item{}, err\n\t}\n\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\treturn &memcache.Item{}, err\n\t}\n\treturn item, nil\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/38_follow/template.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n)\n\nfunc serveTemplate(res http.ResponseWriter, req *http.Request, templateName string) {\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\t// not logged in\n\t\ttpl.ExecuteTemplate(res, templateName, SessionData{})\n\t\treturn\n\t}\n\t// logged in\n\tvar sd SessionData\n\tjson.Unmarshal(memItem.Value, &sd)\n\tsd.LoggedIn = true\n\ttpl.ExecuteTemplate(res, templateName, &sd)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/38_follow/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            {{if .LoggedIn}}\n            {{template \"modal-tweet\"}}\n                {{if .ViewingUser}}\n                    {{if .FollowingUser}}\n                    <a href=\"/api/unfollow/{{.ViewingUser}}\"><p class=\"loginOut\">Unfollow</p></a>\n                    {{else}}\n                    <a href=\"/api/follow/{{.ViewingUser}}\"><p class=\"loginOut\">Follow</p></a>\n                    {{end}}\n                {{end}}\n            <a href=\"/api/logout\"><p class=\"loginOut\">Log Out</p></a>\n            {{else}}\n            <a href=\"/form/login\"><p class=\"loginOut\">Log In</p></a>\n            {{end}}\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>\n{{end}}\n\n    {{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/38_follow/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Tweets}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post\">{{.Msg}}</p>\n            <p class=\"post-meta\">{{.UserName}}</p>\n            <p class=\"post-meta\">{{humanize_time .Time}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/38_follow/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\" .}}\n    <form method=\"POST\" action=\"/api/login\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"userName\" name=\"userName\" placeholder=\"Enter your user name\" autofocus>\n        <p class=\"form-field-err\"></p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\"></p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/38_follow/templates/html/modal-tweet.html",
    "content": "{{ define \"modal-tweet\"}}\n<a href=\"#openModal\" id=\"opens-modal\"><p class=\"loginOut\">Tweet</p></a>\n\n<div id=\"openModal\" class=\"modalDialog\">\n    <div>\t<a href=\"#close\" title=\"Close\" class=\"modal-close\">X</a>\n        <form method=\"POST\" id=\"modal-form\" action=\"/api/tweet\">\n            <textarea name=\"tweet\" id=\"modal-tweet\" rows=\"4\" maxlength=\"140\"></textarea>\n            <input type=\"submit\" id=\"modal-submit\" value=\"Tweet\">\n        </form>\n    </div>\n</div>\n    {{end}}\n\n    {{ define \"modal-tweet-css\"}}\n    <link rel=\"stylesheet\" href=\"/public/css/modal-tweet.css\">\n    {{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/38_follow/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\" .}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\" autofocus>\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/38_follow/templates/html/user.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Tweets}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post\">{{.Msg}}</p>\n            <p class=\"post-meta\">{{.UserName}}</p>\n            <p class=\"post-meta\">{{humanize_time .Time}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/38_follow/tweets.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"net/http\"\n)\n\nfunc putTweet(req *http.Request, user *User, tweet *Tweet) error {\n\tctx := appengine.NewContext(req)\n\tuserKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey := datastore.NewIncompleteKey(ctx, \"Tweets\", userKey)\n\t_, err := datastore.Put(ctx, key, tweet)\n\treturn err\n}\n\nfunc getTweets(req *http.Request, user *User) ([]Tweet, error) {\n\tctx := appengine.NewContext(req)\n\n\tvar tweets []Tweet\n\tq := datastore.NewQuery(\"Tweets\")\n\n\tif user != nil {\n\t\t// show tweets of a specific user\n\t\tuserKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\t\tq = q.Ancestor(userKey)\n\t}\n\n\tq = q.Order(\"-Time\").Limit(20)\n\t_, err := q.GetAll(ctx, &tweets)\n\treturn tweets, err\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/39_unfollow/api.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"golang.org/x/crypto/bcrypt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\thashedPass, err := bcrypt.GenerateFromPassword([]byte(req.FormValue(\"password\")), bcrypt.DefaultCost)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error creating password: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tuser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: string(hashedPass),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey, err = datastore.Put(ctx, key, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tcreateSession(res, req, user)\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc loginProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Users\", req.FormValue(\"userName\"), 0, nil)\n\tvar user User\n\terr := datastore.Get(ctx, key, &user)\n\tif err != nil || bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.FormValue(\"password\"))) != nil {\n\t\t// failure logging in\n\t\tvar sd SessionData\n\t\tsd.LoginFail = true\n\t\ttpl.ExecuteTemplate(res, \"login.html\", sd)\n\t\treturn\n\t} else {\n\t\tuser.UserName = req.FormValue(\"userName\")\n\t\t// success logging in\n\t\tcreateSession(res, req, user)\n\t\t// redirect\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t}\n}\n\nfunc createSession(res http.ResponseWriter, req *http.Request, user User) {\n\tctx := appengine.NewContext(req)\n\t// SET COOKIE\n\tid, _ := uuid.NewV4()\n\tcookie := &http.Cookie{\n\t\tName:  \"session\",\n\t\tValue: id.String(),\n\t\tPath:  \"/\",\n\t\t// twenty minute session:\n\t\tMaxAge: 60 * 20,\n\t\t//\t\tUNCOMMENT WHEN DEPLOYED:\n\t\t//\t\tSecure: true,\n\t\t//\t\tHttpOnly: true,\n\t}\n\thttp.SetCookie(res, cookie)\n\n\t// SET MEMCACHE session data (sd)\n\tjson, err := json.Marshal(user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error marshalling during user creation: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd := memcache.Item{\n\t\tKey:   id.String(),\n\t\tValue: json,\n\t}\n\tmemcache.Set(ctx, &sd)\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\t// cookie is not set\n\tif err != nil {\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t\treturn\n\t}\n\n\t// clear memcache\n\tsd := memcache.Item{\n\t\tKey:        cookie.Value,\n\t\tValue:      []byte(\"\"),\n\t\tExpiration: time.Duration(1 * time.Microsecond),\n\t}\n\tmemcache.Set(ctx, &sd)\n\n\t// clear the cookie\n\tcookie.MaxAge = -1\n\thttp.SetCookie(res, cookie)\n\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc tweetProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to post tweet from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// declare a variable of type tweet\n\t// initialize it with values\n\tlog.Infof(ctx, user.UserName)\n\ttweet := Tweet{\n\t\tMsg:      req.FormValue(\"tweet\"),\n\t\tTime:     time.Now(),\n\t\tUserName: user.UserName,\n\t}\n\t// put in datastore\n\terr = putTweet(req, &user, &tweet)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// redirect\n\ttime.Sleep(time.Millisecond * 500) // This is not the best code, probably. Thoughts?\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc follow(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t// get session\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to follow from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// get the datastore key for the follower\n\tfollowerKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\t// get a datastore key for the followee\n\tfolloweeKey := datastore.NewKey(ctx, \"Follows\", ps.ByName(\"user\"), 0, followerKey)\n\t// the follower is following the followee\n\t// put this into the datastore\n\ttype F struct {\n\t\tFollowing string\n\t}\n\t//\n\t_, err = datastore.Put(ctx, followeeKey, &F{ps.ByName(\"user\")})\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding followee: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\thttp.Redirect(res, req, \"/user/\"+ps.ByName(\"user\"), 302)\n}\n\nfunc unfollow(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t// get session\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to unfollow from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// get the datastore key for the follower\n\tfollowerKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\t// get a datastore key for the followee\n\tfolloweeKey := datastore.NewKey(ctx, \"Follows\", ps.ByName(\"user\"), 0, followerKey)\n\t// delete entry in datastore\n\terr = datastore.Delete(ctx, followeeKey)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error deleting followee: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\thttp.Redirect(res, req, \"/user/\"+ps.ByName(\"user\"), 302)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/39_unfollow/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/39_unfollow/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/39_unfollow/following.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"net/http\"\n)\n\nfunc following(follower, followee string, req *http.Request) (bool, error) {\n\tctx := appengine.NewContext(req)\n\tuserKey := datastore.NewKey(ctx, \"Users\", follower, 0, nil)\n\tx, err := datastore.NewQuery(\"Follows\").Ancestor(userKey).Filter(\"Following =\", followee).Count(ctx)\n\treturn x > 0, err\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/39_unfollow/index.yaml",
    "content": "indexes:\n\n# AUTOGENERATED\n\n# This index.yaml is automatically updated whenever the dev_appserver\n# detects that a new type of query is run.  If you want to manage the\n# index.yaml file manually, remove the above marker line (the line\n# saying \"# AUTOGENERATED\").  If you want to manage some indexes\n# manually, move them above the marker line.  The index.yaml file is\n# automatically uploaded to the admin console when you next deploy\n# your application using appcfg.py.\n\n- kind: Tweets\n  ancestor: yes\n  properties:\n  - name: Time\n    direction: desc\n"
  },
  {
    "path": "27_code-in-process/56_twitter/39_unfollow/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", home)\n\tr.GET(\"/user/:user\", user)\n\tr.GET(\"/form/login\", login)\n\tr.GET(\"/form/signup\", signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\tr.POST(\"/api/login\", loginProcess)\n\tr.POST(\"/api/tweet\", tweetProcess)\n\tr.GET(\"/api/logout\", logout)\n\tr.GET(\"/api/follow/:user\", follow)\n\tr.GET(\"/api/unfollow/:user\", unfollow)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\n\ttpl = template.New(\"roottemplate\")\n\ttpl = tpl.Funcs(template.FuncMap{\n\t\t\"humanize_time\": humanize.Time,\n\t})\n\n\ttpl = template.Must(tpl.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc home(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t//get tweets\n\ttweets, err := getTweets(req, nil)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting tweets: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// get session\n\tmemItem, err := getSession(req)\n\tvar sd SessionData\n\tif err == nil {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t}\n\tsd.Tweets = tweets\n\ttpl.ExecuteTemplate(res, \"home.html\", &sd)\n}\n\nfunc user(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tuser := User{UserName: ps.ByName(\"user\")}\n\t//get tweets\n\ttweets, err := getTweets(req, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting tweets: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// get session\n\tmemItem, err := getSession(req)\n\tvar sd SessionData\n\tif err == nil {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t\tsd.ViewingUser = user.UserName\n\t\tsd.FollowingUser, err = following(sd.UserName, user.UserName, req)\n\t\tif err != nil {\n\t\t\tlog.Errorf(ctx, \"error running following query: %v\", err)\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t}\n\tsd.Tweets = tweets\n\ttpl.ExecuteTemplate(res, \"user.html\", &sd)\n}\n\nfunc login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"login.html\")\n}\n\nfunc signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"signup.html\")\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/39_unfollow/model.go",
    "content": "package main\n\nimport \"time\"\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string `json:\"-\"`\n}\n\ntype SessionData struct {\n\tUser\n\tLoggedIn      bool\n\tLoginFail     bool\n\tTweets        []Tweet\n\tViewingUser   string\n\tFollowingUser bool\n}\n\ntype Tweet struct {\n\tMsg      string\n\tTime     time.Time\n\tUserName string\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/39_unfollow/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/39_unfollow/public/css/modal-tweet.css",
    "content": ".modalDialog {\n    position: fixed;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    background: rgba(255, 255, 255, 0.7);\n    z-index: 99999;\n    opacity:0;\n    -webkit-transition: opacity 400ms ease-in;\n    -moz-transition: opacity 400ms ease-in;\n    transition: opacity 400ms ease-in;\n    pointer-events: none;\n}\n.modalDialog:target {\n    opacity:1;\n    pointer-events: auto;\n}\n.modalDialog > div {\n    border: 4px solid #2ec371;\n    width: 70%;\n    position: relative;\n    margin: 10% auto;\n    padding: 5px 20px 13px 20px;\n    border-radius: 10px;\n    background: rgba(46, 195, 113, 0.6);\n}\n.modal-close {\n    border: 1px solid #2ec371;\n    background: #2ec371;\n    color: #FFFFFF;\n    line-height: 20px;\n    position: absolute;\n    right: 0px;\n    text-align: center;\n    top: 0px;\n    width: 24px;\n    text-decoration: none;\n    border-radius: 0px 6px 0px 4px;\n}\n.modal-close:hover {\n    background: #2ec371;\n}\n\n#modal-tweet {\n    width: 100%;\n    border-radius: 10px;\n    border: 1px solid #2ec371;\n    margin: 20px 0 0 0;\n    font-size: 40px;\n}\n\n#modal-submit {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n    margin: 15px 15px 0 0;\n    font-family: 'Lobster', cursive;\n    font-size: 25px;\n    background-color: #2ec371;\n}\n\n#modal-submit:hover {\n    background-color: #00acc1;\n}\n\n\n\n#modal-form {\n    display: flex;\n    flex-direction: column;\n    align-items: flex-end;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/39_unfollow/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/39_unfollow/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/39_unfollow/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\nheader nav {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n}\n\n.loginOut {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n    margin-left: 10px;\n}\n\n.loginOut:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n.post {\n    padding: 10px 10px 0 10px;\n}\n\n.post-meta {\n    font-size: 12px;\n    padding: 0;\n    border: 0;\n    margin: 2px 0 0 20px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/39_unfollow/session.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"net/http\"\n)\n\nfunc getSession(req *http.Request) (*memcache.Item, error) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\tif err != nil {\n\t\treturn &memcache.Item{}, err\n\t}\n\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\treturn &memcache.Item{}, err\n\t}\n\treturn item, nil\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/39_unfollow/template.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n)\n\nfunc serveTemplate(res http.ResponseWriter, req *http.Request, templateName string) {\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\t// not logged in\n\t\ttpl.ExecuteTemplate(res, templateName, SessionData{})\n\t\treturn\n\t}\n\t// logged in\n\tvar sd SessionData\n\tjson.Unmarshal(memItem.Value, &sd)\n\tsd.LoggedIn = true\n\ttpl.ExecuteTemplate(res, templateName, &sd)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/39_unfollow/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            {{if .LoggedIn}}\n            {{template \"modal-tweet\"}}\n                {{if .ViewingUser}}\n                    {{if .FollowingUser}}\n                    <a href=\"/api/unfollow/{{.ViewingUser}}\"><p class=\"loginOut\">Unfollow</p></a>\n                    {{else}}\n                    <a href=\"/api/follow/{{.ViewingUser}}\"><p class=\"loginOut\">Follow</p></a>\n                    {{end}}\n                {{end}}\n            <a href=\"/api/logout\"><p class=\"loginOut\">Log Out</p></a>\n            {{else}}\n            <a href=\"/form/login\"><p class=\"loginOut\">Log In</p></a>\n            {{end}}\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>\n{{end}}\n\n    {{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/39_unfollow/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Tweets}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post\">{{.Msg}}</p>\n            <p class=\"post-meta\">{{.UserName}}</p>\n            <p class=\"post-meta\">{{humanize_time .Time}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/39_unfollow/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\" .}}\n    <form method=\"POST\" action=\"/api/login\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"userName\" name=\"userName\" placeholder=\"Enter your user name\" autofocus>\n        <p class=\"form-field-err\"></p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\"></p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/39_unfollow/templates/html/modal-tweet.html",
    "content": "{{ define \"modal-tweet\"}}\n<a href=\"#openModal\" id=\"opens-modal\"><p class=\"loginOut\">Tweet</p></a>\n\n<div id=\"openModal\" class=\"modalDialog\">\n    <div>\t<a href=\"#close\" title=\"Close\" class=\"modal-close\">X</a>\n        <form method=\"POST\" id=\"modal-form\" action=\"/api/tweet\">\n            <textarea name=\"tweet\" id=\"modal-tweet\" rows=\"4\" maxlength=\"140\"></textarea>\n            <input type=\"submit\" id=\"modal-submit\" value=\"Tweet\">\n        </form>\n    </div>\n</div>\n    {{end}}\n\n    {{ define \"modal-tweet-css\"}}\n    <link rel=\"stylesheet\" href=\"/public/css/modal-tweet.css\">\n    {{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/39_unfollow/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\" .}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\" autofocus>\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/39_unfollow/templates/html/user.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Tweets}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post\">{{.Msg}}</p>\n            <p class=\"post-meta\">{{.UserName}}</p>\n            <p class=\"post-meta\">{{humanize_time .Time}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/39_unfollow/tweets.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"net/http\"\n)\n\nfunc putTweet(req *http.Request, user *User, tweet *Tweet) error {\n\tctx := appengine.NewContext(req)\n\tuserKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey := datastore.NewIncompleteKey(ctx, \"Tweets\", userKey)\n\t_, err := datastore.Put(ctx, key, tweet)\n\treturn err\n}\n\nfunc getTweets(req *http.Request, user *User) ([]Tweet, error) {\n\tctx := appengine.NewContext(req)\n\n\tvar tweets []Tweet\n\tq := datastore.NewQuery(\"Tweets\")\n\n\tif user != nil {\n\t\t// show tweets of a specific user\n\t\tuserKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\t\tq = q.Ancestor(userKey)\n\t}\n\n\tq = q.Order(\"-Time\").Limit(20)\n\t_, err := q.GetAll(ctx, &tweets)\n\treturn tweets, err\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/40_send-email/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n  login: required\n"
  },
  {
    "path": "27_code-in-process/56_twitter/40_send-email/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/mail\"\n\t\"google.golang.org/appengine/user\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/sendmail\", handleIndex)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\n\tmsg := &mail.Message{\n\t\tSender:  u.Email,\n\t\tTo:      []string{\"Todd McLeod <todd.mcleod@fresnocitycollege.edu>\"},\n\t\tSubject: \"See you tonight\",\n\t\tBody:    \"Don't forget our plans. Hark, 'til later.\",\n\t}\n\tif err := mail.Send(ctx, msg); err != nil {\n\t\tlog.Errorf(ctx, \"Alas, my user, the email failed to sendeth: %v\", err)\n\t}\n}\n\n/*\n\ngoapp deploy\n\nappcfg.py --oauth2 update .\n\nhttp://twitmock-1012.appspot.com/\n\n*/\n"
  },
  {
    "path": "27_code-in-process/56_twitter/41_twitter-send-email/api.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"golang.org/x/crypto/bcrypt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\thashedPass, err := bcrypt.GenerateFromPassword([]byte(req.FormValue(\"password\")), bcrypt.DefaultCost)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error creating password: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tuser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: string(hashedPass),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey, err = datastore.Put(ctx, key, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tcreateSession(res, req, user)\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc loginProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Users\", req.FormValue(\"userName\"), 0, nil)\n\tvar user User\n\terr := datastore.Get(ctx, key, &user)\n\tif err != nil || bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.FormValue(\"password\"))) != nil {\n\t\t// failure logging in\n\t\tvar sd SessionData\n\t\tsd.LoginFail = true\n\t\ttpl.ExecuteTemplate(res, \"login.html\", sd)\n\t\treturn\n\t} else {\n\t\tuser.UserName = req.FormValue(\"userName\")\n\t\t// success logging in\n\t\tcreateSession(res, req, user)\n\t\t// redirect\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t}\n}\n\nfunc createSession(res http.ResponseWriter, req *http.Request, user User) {\n\tctx := appengine.NewContext(req)\n\t// SET COOKIE\n\tid, _ := uuid.NewV4()\n\tcookie := &http.Cookie{\n\t\tName:  \"session\",\n\t\tValue: id.String(),\n\t\tPath:  \"/\",\n\t\t// twenty minute session:\n\t\tMaxAge: 60 * 20,\n\t\t//\t\tUNCOMMENT WHEN DEPLOYED:\n\t\t//\t\tSecure: true,\n\t\t//\t\tHttpOnly: true,\n\t}\n\thttp.SetCookie(res, cookie)\n\n\t// SET MEMCACHE session data (sd)\n\tjson, err := json.Marshal(user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error marshalling during user creation: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd := memcache.Item{\n\t\tKey:   id.String(),\n\t\tValue: json,\n\t}\n\tmemcache.Set(ctx, &sd)\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\t// cookie is not set\n\tif err != nil {\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t\treturn\n\t}\n\n\t// clear memcache\n\tsd := memcache.Item{\n\t\tKey:        cookie.Value,\n\t\tValue:      []byte(\"\"),\n\t\tExpiration: time.Duration(1 * time.Microsecond),\n\t}\n\tmemcache.Set(ctx, &sd)\n\n\t// clear the cookie\n\tcookie.MaxAge = -1\n\thttp.SetCookie(res, cookie)\n\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc tweetProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to post tweet from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// declare a variable of type tweet\n\t// initialize it with values\n\tlog.Infof(ctx, user.UserName)\n\ttweet := Tweet{\n\t\tMsg:      req.FormValue(\"tweet\"),\n\t\tTime:     time.Now(),\n\t\tUserName: user.UserName,\n\t}\n\t// put in datastore\n\terr = putTweet(req, &user, &tweet)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// redirect\n\ttime.Sleep(time.Millisecond * 500) // This is not the best code, probably. Thoughts?\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc follow(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t// get session\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to follow from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// get the datastore key for the follower\n\tfollowerKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\t// get a datastore key for the followee\n\tfolloweeKey := datastore.NewKey(ctx, \"Follows\", ps.ByName(\"user\"), 0, followerKey)\n\t// the follower is following the followee\n\t// put this into the datastore\n\ttype F struct {\n\t\tFollowing string\n\t}\n\t// put in datastore\n\t_, err = datastore.Put(ctx, followeeKey, &F{ps.ByName(\"user\")})\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding followee: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// send the \"you are being followed\" email\n\temailKey := datastore.NewKey(ctx, \"Users\", ps.ByName(\"user\"), 0, nil)\n\tvar u User\n\terr = datastore.Get(ctx, emailKey, &u)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting followee's email user data: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tfollowedEmail(res, req, u.Email)\n\t// return to user account\n\thttp.Redirect(res, req, \"/user/\"+ps.ByName(\"user\"), 302)\n}\n\nfunc unfollow(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t// get session\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to unfollow from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// get the datastore key for the follower\n\tfollowerKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\t// get a datastore key for the followee\n\tfolloweeKey := datastore.NewKey(ctx, \"Follows\", ps.ByName(\"user\"), 0, followerKey)\n\t// delete entry in datastore\n\terr = datastore.Delete(ctx, followeeKey)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error deleting followee: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\thttp.Redirect(res, req, \"/user/\"+ps.ByName(\"user\"), 302)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/41_twitter-send-email/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/41_twitter-send-email/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/41_twitter-send-email/email.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/mail\"\n\t\"net/http\"\n)\n\nfunc followedEmail(w http.ResponseWriter, r *http.Request, recip string) {\n\tctx := appengine.NewContext(r)\n\tmsg := &mail.Message{\n\t\tSender:  \"TwitClone Support <support@example.com>\",\n\t\tTo:      []string{recip},\n\t\tSubject: \"You are being followed\",\n\t\tBody:    fmt.Sprintf(confirmMessage),\n\t}\n\tif err := mail.Send(ctx, msg); err != nil {\n\t\tlog.Errorf(ctx, \"Couldn't send email: %v\", err)\n\t}\n}\n\nconst confirmMessage = `\nSomeone is now following you. Don't say you didn't ask for it.\n`\n"
  },
  {
    "path": "27_code-in-process/56_twitter/41_twitter-send-email/following.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"net/http\"\n)\n\nfunc following(follower, followee string, req *http.Request) (bool, error) {\n\tctx := appengine.NewContext(req)\n\tuserKey := datastore.NewKey(ctx, \"Users\", follower, 0, nil)\n\tx, err := datastore.NewQuery(\"Follows\").Ancestor(userKey).Filter(\"Following =\", followee).Count(ctx)\n\treturn x > 0, err\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/41_twitter-send-email/index.yaml",
    "content": "indexes:\n\n# AUTOGENERATED\n\n# This index.yaml is automatically updated whenever the dev_appserver\n# detects that a new type of query is run.  If you want to manage the\n# index.yaml file manually, remove the above marker line (the line\n# saying \"# AUTOGENERATED\").  If you want to manage some indexes\n# manually, move them above the marker line.  The index.yaml file is\n# automatically uploaded to the admin console when you next deploy\n# your application using appcfg.py.\n\n- kind: Tweets\n  ancestor: yes\n  properties:\n  - name: Time\n    direction: desc\n"
  },
  {
    "path": "27_code-in-process/56_twitter/41_twitter-send-email/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", home)\n\tr.GET(\"/user/:user\", user)\n\tr.GET(\"/form/login\", login)\n\tr.GET(\"/form/signup\", signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\tr.POST(\"/api/login\", loginProcess)\n\tr.POST(\"/api/tweet\", tweetProcess)\n\tr.GET(\"/api/logout\", logout)\n\tr.GET(\"/api/follow/:user\", follow)\n\tr.GET(\"/api/unfollow/:user\", unfollow)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\n\ttpl = template.New(\"roottemplate\")\n\ttpl = tpl.Funcs(template.FuncMap{\n\t\t\"humanize_time\": humanize.Time,\n\t})\n\n\ttpl = template.Must(tpl.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc home(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t//get tweets\n\ttweets, err := getTweets(req, nil)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting tweets: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// get session\n\tmemItem, err := getSession(req)\n\tvar sd SessionData\n\tif err == nil {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t}\n\tsd.Tweets = tweets\n\ttpl.ExecuteTemplate(res, \"home.html\", &sd)\n}\n\nfunc user(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tuser := User{UserName: ps.ByName(\"user\")}\n\t//get tweets\n\ttweets, err := getTweets(req, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting tweets: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// get session\n\tmemItem, err := getSession(req)\n\tvar sd SessionData\n\tif err == nil {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t\tsd.ViewingUser = user.UserName\n\t\tsd.FollowingUser, err = following(sd.UserName, user.UserName, req)\n\t\tif err != nil {\n\t\t\tlog.Errorf(ctx, \"error running following query: %v\", err)\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t}\n\tsd.Tweets = tweets\n\ttpl.ExecuteTemplate(res, \"user.html\", &sd)\n}\n\nfunc login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"login.html\")\n}\n\nfunc signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"signup.html\")\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/41_twitter-send-email/model.go",
    "content": "package main\n\nimport \"time\"\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string `json:\"-\"`\n}\n\ntype SessionData struct {\n\tUser\n\tLoggedIn      bool\n\tLoginFail     bool\n\tTweets        []Tweet\n\tViewingUser   string\n\tFollowingUser bool\n}\n\ntype Tweet struct {\n\tMsg      string\n\tTime     time.Time\n\tUserName string\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/41_twitter-send-email/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/41_twitter-send-email/public/css/modal-tweet.css",
    "content": ".modalDialog {\n    position: fixed;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    background: rgba(255, 255, 255, 0.7);\n    z-index: 99999;\n    opacity:0;\n    -webkit-transition: opacity 400ms ease-in;\n    -moz-transition: opacity 400ms ease-in;\n    transition: opacity 400ms ease-in;\n    pointer-events: none;\n}\n.modalDialog:target {\n    opacity:1;\n    pointer-events: auto;\n}\n.modalDialog > div {\n    border: 4px solid #2ec371;\n    width: 70%;\n    position: relative;\n    margin: 10% auto;\n    padding: 5px 20px 13px 20px;\n    border-radius: 10px;\n    background: rgba(46, 195, 113, 0.6);\n}\n.modal-close {\n    border: 1px solid #2ec371;\n    background: #2ec371;\n    color: #FFFFFF;\n    line-height: 20px;\n    position: absolute;\n    right: 0px;\n    text-align: center;\n    top: 0px;\n    width: 24px;\n    text-decoration: none;\n    border-radius: 0px 6px 0px 4px;\n}\n.modal-close:hover {\n    background: #2ec371;\n}\n\n#modal-tweet {\n    width: 100%;\n    border-radius: 10px;\n    border: 1px solid #2ec371;\n    margin: 20px 0 0 0;\n    font-size: 40px;\n}\n\n#modal-submit {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n    margin: 15px 15px 0 0;\n    font-family: 'Lobster', cursive;\n    font-size: 25px;\n    background-color: #2ec371;\n}\n\n#modal-submit:hover {\n    background-color: #00acc1;\n}\n\n\n\n#modal-form {\n    display: flex;\n    flex-direction: column;\n    align-items: flex-end;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/41_twitter-send-email/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/41_twitter-send-email/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/41_twitter-send-email/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\nheader nav {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n}\n\n.loginOut {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n    margin-left: 10px;\n}\n\n.loginOut:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n.post {\n    padding: 10px 10px 0 10px;\n}\n\n.post-meta {\n    font-size: 12px;\n    padding: 0;\n    border: 0;\n    margin: 2px 0 0 20px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/41_twitter-send-email/session.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"net/http\"\n)\n\nfunc getSession(req *http.Request) (*memcache.Item, error) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\tif err != nil {\n\t\treturn &memcache.Item{}, err\n\t}\n\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\treturn &memcache.Item{}, err\n\t}\n\treturn item, nil\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/41_twitter-send-email/template.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n)\n\nfunc serveTemplate(res http.ResponseWriter, req *http.Request, templateName string) {\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\t// not logged in\n\t\ttpl.ExecuteTemplate(res, templateName, SessionData{})\n\t\treturn\n\t}\n\t// logged in\n\tvar sd SessionData\n\tjson.Unmarshal(memItem.Value, &sd)\n\tsd.LoggedIn = true\n\ttpl.ExecuteTemplate(res, templateName, &sd)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/41_twitter-send-email/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            {{if .LoggedIn}}\n            {{template \"modal-tweet\"}}\n                {{if .ViewingUser}}\n                    {{if .FollowingUser}}\n                    <a href=\"/api/unfollow/{{.ViewingUser}}\"><p class=\"loginOut\">Unfollow</p></a>\n                    {{else}}\n                    <a href=\"/api/follow/{{.ViewingUser}}\"><p class=\"loginOut\">Follow</p></a>\n                    {{end}}\n                {{end}}\n            <a href=\"/api/logout\"><p class=\"loginOut\">Log Out</p></a>\n            {{else}}\n            <a href=\"/form/login\"><p class=\"loginOut\">Log In</p></a>\n            {{end}}\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>\n{{end}}\n\n    {{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/41_twitter-send-email/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Tweets}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post\">{{.Msg}}</p>\n            <p class=\"post-meta\">{{.UserName}}</p>\n            <p class=\"post-meta\">{{humanize_time .Time}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/41_twitter-send-email/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\" .}}\n    <form method=\"POST\" action=\"/api/login\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"userName\" name=\"userName\" placeholder=\"Enter your user name\" autofocus>\n        <p class=\"form-field-err\"></p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\"></p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/41_twitter-send-email/templates/html/modal-tweet.html",
    "content": "{{ define \"modal-tweet\"}}\n<a href=\"#openModal\" id=\"opens-modal\"><p class=\"loginOut\">Tweet</p></a>\n\n<div id=\"openModal\" class=\"modalDialog\">\n    <div>\t<a href=\"#close\" title=\"Close\" class=\"modal-close\">X</a>\n        <form method=\"POST\" id=\"modal-form\" action=\"/api/tweet\">\n            <textarea name=\"tweet\" id=\"modal-tweet\" rows=\"4\" maxlength=\"140\"></textarea>\n            <input type=\"submit\" id=\"modal-submit\" value=\"Tweet\">\n        </form>\n    </div>\n</div>\n    {{end}}\n\n    {{ define \"modal-tweet-css\"}}\n    <link rel=\"stylesheet\" href=\"/public/css/modal-tweet.css\">\n    {{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/41_twitter-send-email/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\" .}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\" autofocus>\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/41_twitter-send-email/templates/html/user.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Tweets}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post\">{{.Msg}}</p>\n            <p class=\"post-meta\">{{.UserName}}</p>\n            <p class=\"post-meta\">{{humanize_time .Time}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/41_twitter-send-email/tweets.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"net/http\"\n)\n\nfunc putTweet(req *http.Request, user *User, tweet *Tweet) error {\n\tctx := appengine.NewContext(req)\n\tuserKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey := datastore.NewIncompleteKey(ctx, \"Tweets\", userKey)\n\t_, err := datastore.Put(ctx, key, tweet)\n\treturn err\n}\n\nfunc getTweets(req *http.Request, user *User) ([]Tweet, error) {\n\tctx := appengine.NewContext(req)\n\n\tvar tweets []Tweet\n\tq := datastore.NewQuery(\"Tweets\")\n\n\tif user != nil {\n\t\t// show tweets of a specific user\n\t\tuserKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\t\tq = q.Ancestor(userKey)\n\t}\n\n\tq = q.Order(\"-Time\").Limit(20)\n\t_, err := q.GetAll(ctx, &tweets)\n\treturn tweets, err\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/42_following/api.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"golang.org/x/crypto/bcrypt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\thashedPass, err := bcrypt.GenerateFromPassword([]byte(req.FormValue(\"password\")), bcrypt.DefaultCost)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error creating password: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tuser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: string(hashedPass),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey, err = datastore.Put(ctx, key, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tcreateSession(res, req, user)\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc loginProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Users\", req.FormValue(\"userName\"), 0, nil)\n\tvar user User\n\terr := datastore.Get(ctx, key, &user)\n\tif err != nil || bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.FormValue(\"password\"))) != nil {\n\t\t// failure logging in\n\t\tvar sd SessionData\n\t\tsd.LoginFail = true\n\t\ttpl.ExecuteTemplate(res, \"login.html\", sd)\n\t\treturn\n\t} else {\n\t\tuser.UserName = req.FormValue(\"userName\")\n\t\t// success logging in\n\t\tcreateSession(res, req, user)\n\t\t// redirect\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t}\n}\n\nfunc createSession(res http.ResponseWriter, req *http.Request, user User) {\n\tctx := appengine.NewContext(req)\n\t// SET COOKIE\n\tid, _ := uuid.NewV4()\n\tcookie := &http.Cookie{\n\t\tName:  \"session\",\n\t\tValue: id.String(),\n\t\tPath:  \"/\",\n\t\t// twenty minute session:\n\t\tMaxAge: 60 * 20,\n\t\t//\t\tUNCOMMENT WHEN DEPLOYED:\n\t\t//\t\tSecure: true,\n\t\t//\t\tHttpOnly: true,\n\t}\n\thttp.SetCookie(res, cookie)\n\n\t// SET MEMCACHE session data (sd)\n\tjson, err := json.Marshal(user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error marshalling during user creation: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd := memcache.Item{\n\t\tKey:   id.String(),\n\t\tValue: json,\n\t}\n\tmemcache.Set(ctx, &sd)\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\t// cookie is not set\n\tif err != nil {\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t\treturn\n\t}\n\n\t// clear memcache\n\tsd := memcache.Item{\n\t\tKey:        cookie.Value,\n\t\tValue:      []byte(\"\"),\n\t\tExpiration: time.Duration(1 * time.Microsecond),\n\t}\n\tmemcache.Set(ctx, &sd)\n\n\t// clear the cookie\n\tcookie.MaxAge = -1\n\thttp.SetCookie(res, cookie)\n\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc tweetProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to post tweet from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// declare a variable of type tweet\n\t// initialize it with values\n\tlog.Infof(ctx, user.UserName)\n\ttweet := Tweet{\n\t\tMsg:      req.FormValue(\"tweet\"),\n\t\tTime:     time.Now(),\n\t\tUserName: user.UserName,\n\t}\n\t// put in datastore\n\terr = putTweet(req, &user, &tweet)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// redirect\n\ttime.Sleep(time.Millisecond * 500) // This is not the best code, probably. Thoughts?\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc follow(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t// get session\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to follow from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// get the datastore key for the follower\n\tfollowerKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\t// get a datastore key for the followee\n\tfolloweeKey := datastore.NewKey(ctx, \"Follows\", ps.ByName(\"user\"), 0, followerKey)\n\t// the follower is following the followee\n\t// put this into the datastore\n\t_, err = datastore.Put(ctx, followeeKey, &F{ps.ByName(\"user\")})\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding followee: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// send the \"you are being followed\" email\n\temailKey := datastore.NewKey(ctx, \"Users\", ps.ByName(\"user\"), 0, nil)\n\tvar u User\n\terr = datastore.Get(ctx, emailKey, &u)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting followee's email user data: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tfollowedEmail(res, req, u.Email)\n\t// return to user account\n\thttp.Redirect(res, req, \"/user/\"+ps.ByName(\"user\"), 302)\n}\n\nfunc unfollow(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t// get session\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to unfollow from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// get the datastore key for the follower\n\tfollowerKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\t// get a datastore key for the followee\n\tfolloweeKey := datastore.NewKey(ctx, \"Follows\", ps.ByName(\"user\"), 0, followerKey)\n\t// delete entry in datastore\n\terr = datastore.Delete(ctx, followeeKey)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error deleting followee: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\thttp.Redirect(res, req, \"/user/\"+ps.ByName(\"user\"), 302)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/42_following/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/42_following/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/42_following/email.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/mail\"\n\t\"net/http\"\n)\n\nfunc followedEmail(w http.ResponseWriter, r *http.Request, recip string) {\n\tctx := appengine.NewContext(r)\n\tmsg := &mail.Message{\n\t\tSender:  \"TwitClone Support <support@example.com>\",\n\t\tTo:      []string{recip},\n\t\tSubject: \"You are being followed\",\n\t\tBody:    fmt.Sprintf(confirmMessage),\n\t}\n\tif err := mail.Send(ctx, msg); err != nil {\n\t\tlog.Errorf(ctx, \"Couldn't send email: %v\", err)\n\t}\n}\n\nconst confirmMessage = `\nSomeone is now following you. Don't say you didn't ask for it.\n`\n"
  },
  {
    "path": "27_code-in-process/56_twitter/42_following/following.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"net/http\"\n)\n\nfunc following(follower, followee string, req *http.Request) (bool, error) {\n\tctx := appengine.NewContext(req)\n\tuserKey := datastore.NewKey(ctx, \"Users\", follower, 0, nil)\n\tx, err := datastore.NewQuery(\"Follows\").Ancestor(userKey).Filter(\"Following =\", followee).Count(ctx)\n\treturn x > 0, err\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/42_following/index.yaml",
    "content": "indexes:\n\n# AUTOGENERATED\n\n# This index.yaml is automatically updated whenever the dev_appserver\n# detects that a new type of query is run.  If you want to manage the\n# index.yaml file manually, remove the above marker line (the line\n# saying \"# AUTOGENERATED\").  If you want to manage some indexes\n# manually, move them above the marker line.  The index.yaml file is\n# automatically uploaded to the admin console when you next deploy\n# your application using appcfg.py.\n\n- kind: Follows\n  ancestor: yes\n  properties:\n  - name: Following\n\n- kind: Tweets\n  ancestor: yes\n  properties:\n  - name: Time\n    direction: desc\n"
  },
  {
    "path": "27_code-in-process/56_twitter/42_following/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", home)\n\tr.GET(\"/following\", fing)\n\tr.GET(\"/user/:user\", user)\n\tr.GET(\"/form/login\", login)\n\tr.GET(\"/form/signup\", signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\tr.POST(\"/api/login\", loginProcess)\n\tr.POST(\"/api/tweet\", tweetProcess)\n\tr.GET(\"/api/logout\", logout)\n\tr.GET(\"/api/follow/:user\", follow)\n\tr.GET(\"/api/unfollow/:user\", unfollow)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\n\ttpl = template.New(\"roottemplate\")\n\ttpl = tpl.Funcs(template.FuncMap{\n\t\t\"humanize_time\": humanize.Time,\n\t})\n\n\ttpl = template.Must(tpl.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc home(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t//get tweets\n\ttweets, err := getTweets(req, nil)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting tweets: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// get session\n\tmemItem, err := getSession(req)\n\tvar sd SessionData\n\tif err == nil {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t}\n\tsd.Tweets = tweets\n\ttpl.ExecuteTemplate(res, \"home.html\", &sd)\n}\n\nfunc user(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tuser := User{UserName: ps.ByName(\"user\")}\n\t//get tweets\n\ttweets, err := getTweets(req, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting tweets: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// get session\n\tmemItem, err := getSession(req)\n\tvar sd SessionData\n\tif err == nil {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t\tsd.ViewingUser = user.UserName\n\t\tsd.FollowingUser, err = following(sd.UserName, user.UserName, req)\n\t\tif err != nil {\n\t\t\tlog.Errorf(ctx, \"error running following query: %v\", err)\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t}\n\tsd.Tweets = tweets\n\ttpl.ExecuteTemplate(res, \"user.html\", &sd)\n}\n\nfunc fing(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t// get session\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to see following from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\tvar sd SessionData\n\tif err == nil {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// Get followees\n\t// get the datastore key for the follower\n\tfollowerKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tvar XF []F\n\t_, err = datastore.NewQuery(\"Follows\").Ancestor(followerKey).Project(\"Following\").GetAll(ctx, &XF)\n\tlog.Errorf(ctx, \"here is type %T \\n and value %v\", XF, XF)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting followees: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd.Following = XF\n\ttpl.ExecuteTemplate(res, \"follow.html\", &sd)\n}\n\nfunc login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"login.html\")\n}\n\nfunc signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"signup.html\")\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/42_following/model.go",
    "content": "package main\n\nimport \"time\"\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string `json:\"-\"`\n}\n\ntype SessionData struct {\n\tUser\n\tLoggedIn      bool\n\tLoginFail     bool\n\tTweets        []Tweet\n\tViewingUser   string\n\tFollowingUser bool\n\tFollowing     []F\n}\n\ntype Tweet struct {\n\tMsg      string\n\tTime     time.Time\n\tUserName string\n}\n\ntype F struct {\n\tFollowing string\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/42_following/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/42_following/public/css/modal-tweet.css",
    "content": ".modalDialog {\n    position: fixed;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    background: rgba(255, 255, 255, 0.7);\n    z-index: 99999;\n    opacity:0;\n    -webkit-transition: opacity 400ms ease-in;\n    -moz-transition: opacity 400ms ease-in;\n    transition: opacity 400ms ease-in;\n    pointer-events: none;\n}\n.modalDialog:target {\n    opacity:1;\n    pointer-events: auto;\n}\n.modalDialog > div {\n    border: 4px solid #2ec371;\n    width: 70%;\n    position: relative;\n    margin: 10% auto;\n    padding: 5px 20px 13px 20px;\n    border-radius: 10px;\n    background: rgba(46, 195, 113, 0.6);\n}\n.modal-close {\n    border: 1px solid #2ec371;\n    background: #2ec371;\n    color: #FFFFFF;\n    line-height: 20px;\n    position: absolute;\n    right: 0px;\n    text-align: center;\n    top: 0px;\n    width: 24px;\n    text-decoration: none;\n    border-radius: 0px 6px 0px 4px;\n}\n.modal-close:hover {\n    background: #2ec371;\n}\n\n#modal-tweet {\n    width: 100%;\n    border-radius: 10px;\n    border: 1px solid #2ec371;\n    margin: 20px 0 0 0;\n    font-size: 40px;\n}\n\n#modal-submit {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n    margin: 15px 15px 0 0;\n    font-family: 'Lobster', cursive;\n    font-size: 25px;\n    background-color: #2ec371;\n}\n\n#modal-submit:hover {\n    background-color: #00acc1;\n}\n\n\n\n#modal-form {\n    display: flex;\n    flex-direction: column;\n    align-items: flex-end;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/42_following/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/42_following/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/42_following/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\nheader nav {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n}\n\n.loginOut {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n    margin-left: 10px;\n}\n\n.loginOut:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n.post {\n    padding: 10px 10px 0 10px;\n}\n\n.post-meta {\n    font-size: 12px;\n    padding: 0;\n    border: 0;\n    margin: 2px 0 0 20px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/42_following/session.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"net/http\"\n)\n\nfunc getSession(req *http.Request) (*memcache.Item, error) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\tif err != nil {\n\t\treturn &memcache.Item{}, err\n\t}\n\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\treturn &memcache.Item{}, err\n\t}\n\treturn item, nil\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/42_following/template.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n)\n\nfunc serveTemplate(res http.ResponseWriter, req *http.Request, templateName string) {\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\t// not logged in\n\t\ttpl.ExecuteTemplate(res, templateName, SessionData{})\n\t\treturn\n\t}\n\t// logged in\n\tvar sd SessionData\n\tjson.Unmarshal(memItem.Value, &sd)\n\tsd.LoggedIn = true\n\ttpl.ExecuteTemplate(res, templateName, &sd)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/42_following/templates/html/follow.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Following}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post-meta\">{{.Following}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/42_following/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            {{if .LoggedIn}}\n            {{template \"modal-tweet\"}}\n                {{if .ViewingUser}}\n                    {{if .FollowingUser}}\n                    <a href=\"/api/unfollow/{{.ViewingUser}}\"><p class=\"loginOut\">Unfollow</p></a>\n                    {{else}}\n                    <a href=\"/api/follow/{{.ViewingUser}}\"><p class=\"loginOut\">Follow</p></a>\n                    {{end}}\n                {{end}}\n            <a href=\"/api/logout\"><p class=\"loginOut\">Log Out</p></a>\n            {{else}}\n            <a href=\"/form/login\"><p class=\"loginOut\">Log In</p></a>\n            {{end}}\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>\n{{end}}\n\n    {{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/42_following/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Tweets}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post\">{{.Msg}}</p>\n            <p class=\"post-meta\">{{.UserName}}</p>\n            <p class=\"post-meta\">{{humanize_time .Time}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/42_following/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\" .}}\n    <form method=\"POST\" action=\"/api/login\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"userName\" name=\"userName\" placeholder=\"Enter your user name\" autofocus>\n        <p class=\"form-field-err\"></p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\"></p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/42_following/templates/html/modal-tweet.html",
    "content": "{{ define \"modal-tweet\"}}\n<a href=\"#openModal\" id=\"opens-modal\"><p class=\"loginOut\">Tweet</p></a>\n\n<div id=\"openModal\" class=\"modalDialog\">\n    <div>\t<a href=\"#close\" title=\"Close\" class=\"modal-close\">X</a>\n        <form method=\"POST\" id=\"modal-form\" action=\"/api/tweet\">\n            <textarea name=\"tweet\" id=\"modal-tweet\" rows=\"4\" maxlength=\"140\"></textarea>\n            <input type=\"submit\" id=\"modal-submit\" value=\"Tweet\">\n        </form>\n    </div>\n</div>\n    {{end}}\n\n    {{ define \"modal-tweet-css\"}}\n    <link rel=\"stylesheet\" href=\"/public/css/modal-tweet.css\">\n    {{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/42_following/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\" .}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\" autofocus>\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/42_following/templates/html/user.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Tweets}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post\">{{.Msg}}</p>\n            <p class=\"post-meta\">{{.UserName}}</p>\n            <p class=\"post-meta\">{{humanize_time .Time}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/42_following/tweets.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"net/http\"\n)\n\nfunc putTweet(req *http.Request, user *User, tweet *Tweet) error {\n\tctx := appengine.NewContext(req)\n\tuserKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey := datastore.NewIncompleteKey(ctx, \"Tweets\", userKey)\n\t_, err := datastore.Put(ctx, key, tweet)\n\treturn err\n}\n\nfunc getTweets(req *http.Request, user *User) ([]Tweet, error) {\n\tctx := appengine.NewContext(req)\n\n\tvar tweets []Tweet\n\tq := datastore.NewQuery(\"Tweets\")\n\n\tif user != nil {\n\t\t// show tweets of a specific user\n\t\tuserKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\t\tq = q.Ancestor(userKey)\n\t}\n\n\tq = q.Order(\"-Time\").Limit(20)\n\t_, err := q.GetAll(ctx, &tweets)\n\treturn tweets, err\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/api.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"golang.org/x/crypto/bcrypt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\thashedPass, err := bcrypt.GenerateFromPassword([]byte(req.FormValue(\"password\")), bcrypt.DefaultCost)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error creating password: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tuser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: string(hashedPass),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey, err = datastore.Put(ctx, key, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tcreateSession(res, req, user)\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc loginProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Users\", req.FormValue(\"userName\"), 0, nil)\n\tvar user User\n\terr := datastore.Get(ctx, key, &user)\n\tif err != nil || bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.FormValue(\"password\"))) != nil {\n\t\t// failure logging in\n\t\tvar sd SessionData\n\t\tsd.LoginFail = true\n\t\ttpl.ExecuteTemplate(res, \"login.html\", sd)\n\t\treturn\n\t} else {\n\t\tuser.UserName = req.FormValue(\"userName\")\n\t\t// success logging in\n\t\tcreateSession(res, req, user)\n\t\t// redirect\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t}\n}\n\nfunc createSession(res http.ResponseWriter, req *http.Request, user User) {\n\tctx := appengine.NewContext(req)\n\t// SET COOKIE\n\tid, _ := uuid.NewV4()\n\tcookie := &http.Cookie{\n\t\tName:  \"session\",\n\t\tValue: id.String(),\n\t\tPath:  \"/\",\n\t\t// twenty minute session:\n\t\tMaxAge: 60 * 20,\n\t\t//\t\tUNCOMMENT WHEN DEPLOYED:\n\t\t//\t\tSecure: true,\n\t\t//\t\tHttpOnly: true,\n\t}\n\thttp.SetCookie(res, cookie)\n\n\t// SET MEMCACHE session data (sd)\n\tjson, err := json.Marshal(user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error marshalling during user creation: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd := memcache.Item{\n\t\tKey:   id.String(),\n\t\tValue: json,\n\t}\n\tmemcache.Set(ctx, &sd)\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\t// cookie is not set\n\tif err != nil {\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t\treturn\n\t}\n\n\t// clear memcache\n\tsd := memcache.Item{\n\t\tKey:        cookie.Value,\n\t\tValue:      []byte(\"\"),\n\t\tExpiration: time.Duration(1 * time.Microsecond),\n\t}\n\tmemcache.Set(ctx, &sd)\n\n\t// clear the cookie\n\tcookie.MaxAge = -1\n\thttp.SetCookie(res, cookie)\n\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc tweetProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to post tweet from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// declare a variable of type tweet\n\t// initialize it with values\n\tlog.Infof(ctx, user.UserName)\n\ttweet := Tweet{\n\t\tMsg:      req.FormValue(\"tweet\"),\n\t\tTime:     time.Now(),\n\t\tUserName: user.UserName,\n\t}\n\t// put in datastore\n\terr = putTweet(req, &user, &tweet)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// redirect\n\ttime.Sleep(time.Millisecond * 500) // This is not the best code, probably. Thoughts?\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc follow(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t// get session\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to follow from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// get the datastore key for the follower\n\tfollowerKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\t// get a datastore key for the followee\n\tfolloweeKey := datastore.NewKey(ctx, \"Follows\", ps.ByName(\"user\"), 0, followerKey)\n\t// the follower is following the followee\n\t// put this into the datastore\n\t_, err = datastore.Put(ctx, followeeKey, &F{ps.ByName(\"user\"), user.UserName})\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding followee: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// send the \"you are being followed\" email\n\temailKey := datastore.NewKey(ctx, \"Users\", ps.ByName(\"user\"), 0, nil)\n\tvar u User\n\terr = datastore.Get(ctx, emailKey, &u)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting followee's email user data: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tfollowedEmail(res, req, u.Email)\n\t// return to user account\n\thttp.Redirect(res, req, \"/user/\"+ps.ByName(\"user\"), 302)\n}\n\nfunc unfollow(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t// get session\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to unfollow from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// get the datastore key for the follower\n\tfollowerKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\t// get a datastore key for the followee\n\tfolloweeKey := datastore.NewKey(ctx, \"Follows\", ps.ByName(\"user\"), 0, followerKey)\n\t// delete entry in datastore\n\terr = datastore.Delete(ctx, followeeKey)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error deleting followee: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\thttp.Redirect(res, req, \"/user/\"+ps.ByName(\"user\"), 302)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/email.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/mail\"\n\t\"net/http\"\n)\n\nfunc followedEmail(w http.ResponseWriter, r *http.Request, recip string) {\n\tctx := appengine.NewContext(r)\n\tmsg := &mail.Message{\n\t\tSender:  \"TwitClone Support <support@example.com>\",\n\t\tTo:      []string{recip},\n\t\tSubject: \"You are being followed\",\n\t\tBody:    fmt.Sprintf(confirmMessage),\n\t}\n\tif err := mail.Send(ctx, msg); err != nil {\n\t\tlog.Errorf(ctx, \"Couldn't send email: %v\", err)\n\t}\n}\n\nconst confirmMessage = `\nSomeone is now following you. Don't say you didn't ask for it.\n`\n"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/following.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"net/http\"\n)\n\nfunc following(follower, followee string, req *http.Request) (bool, error) {\n\tctx := appengine.NewContext(req)\n\tuserKey := datastore.NewKey(ctx, \"Users\", follower, 0, nil)\n\tx, err := datastore.NewQuery(\"Follows\").Ancestor(userKey).Filter(\"Following =\", followee).Count(ctx)\n\treturn x > 0, err\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/index.yaml",
    "content": "indexes:\n\n# AUTOGENERATED\n\n# This index.yaml is automatically updated whenever the dev_appserver\n# detects that a new type of query is run.  If you want to manage the\n# index.yaml file manually, remove the above marker line (the line\n# saying \"# AUTOGENERATED\").  If you want to manage some indexes\n# manually, move them above the marker line.  The index.yaml file is\n# automatically uploaded to the admin console when you next deploy\n# your application using appcfg.py.\n\n- kind: Follows\n  ancestor: yes\n  properties:\n  - name: Follower\n\n- kind: Follows\n  ancestor: yes\n  properties:\n  - name: Following\n\n- kind: Tweets\n  ancestor: yes\n  properties:\n  - name: Time\n    direction: desc\n"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", home)\n\tr.GET(\"/following\", fing)\n\tr.GET(\"/followingme\", fingme)\n\tr.GET(\"/user/:user\", user)\n\tr.GET(\"/form/login\", login)\n\tr.GET(\"/form/signup\", signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\tr.POST(\"/api/login\", loginProcess)\n\tr.POST(\"/api/tweet\", tweetProcess)\n\tr.GET(\"/api/logout\", logout)\n\tr.GET(\"/api/follow/:user\", follow)\n\tr.GET(\"/api/unfollow/:user\", unfollow)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\n\ttpl = template.New(\"roottemplate\")\n\ttpl = tpl.Funcs(template.FuncMap{\n\t\t\"humanize_time\": humanize.Time,\n\t})\n\n\ttpl = template.Must(tpl.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc home(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t//get tweets\n\ttweets, err := getTweets(req, nil)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting tweets: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// get session\n\tmemItem, err := getSession(req)\n\tvar sd SessionData\n\tif err == nil {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t}\n\tsd.Tweets = tweets\n\ttpl.ExecuteTemplate(res, \"home.html\", &sd)\n}\n\nfunc user(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tuser := User{UserName: ps.ByName(\"user\")}\n\t//get tweets\n\ttweets, err := getTweets(req, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting tweets: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// get session\n\tmemItem, err := getSession(req)\n\tvar sd SessionData\n\tif err == nil {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t\tsd.ViewingUser = user.UserName\n\t\tsd.FollowingUser, err = following(sd.UserName, user.UserName, req)\n\t\tif err != nil {\n\t\t\tlog.Errorf(ctx, \"error running following query: %v\", err)\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t}\n\tsd.Tweets = tweets\n\ttpl.ExecuteTemplate(res, \"user.html\", &sd)\n}\n\nfunc fing(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t// get session\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to see following from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\tvar sd SessionData\n\tif err == nil {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// Get followees\n\t// get the datastore key for the follower\n\tfollowerKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tvar XF []F\n\t_, err = datastore.NewQuery(\"Follows\").Ancestor(followerKey).Project(\"Following\").GetAll(ctx, &XF)\n\tlog.Errorf(ctx, \"here is type %T \\n and value %v\", XF, XF)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting followees: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd.Following = XF\n\ttpl.ExecuteTemplate(res, \"follow.html\", &sd)\n}\n\nfunc fingme(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t// get session\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to see followingme from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\tvar sd SessionData\n\tif err == nil {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// get those who are following this user\n\tvar XF []F\n\t_, err = datastore.NewQuery(\"Follows\").Filter(\"Following =\", user.UserName).GetAll(ctx, &XF)\n\tlog.Errorf(ctx, \"here is type %T \\n and value %v\", XF, XF)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting followees: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd.Following = XF\n\ttpl.ExecuteTemplate(res, \"followingme.html\", &sd)\n}\n\nfunc login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"login.html\")\n}\n\nfunc signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"signup.html\")\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/model.go",
    "content": "package main\n\nimport \"time\"\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string `json:\"-\"`\n}\n\ntype SessionData struct {\n\tUser\n\tLoggedIn      bool\n\tLoginFail     bool\n\tTweets        []Tweet\n\tViewingUser   string\n\tFollowingUser bool\n\tFollowing     []F\n}\n\ntype Tweet struct {\n\tMsg      string\n\tTime     time.Time\n\tUserName string\n}\n\ntype F struct {\n\tFollowing string\n\tFollower  string\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/public/css/modal-tweet.css",
    "content": ".modalDialog {\n    position: fixed;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    background: rgba(255, 255, 255, 0.7);\n    z-index: 99999;\n    opacity:0;\n    -webkit-transition: opacity 400ms ease-in;\n    -moz-transition: opacity 400ms ease-in;\n    transition: opacity 400ms ease-in;\n    pointer-events: none;\n}\n.modalDialog:target {\n    opacity:1;\n    pointer-events: auto;\n}\n.modalDialog > div {\n    border: 4px solid #2ec371;\n    width: 70%;\n    position: relative;\n    margin: 10% auto;\n    padding: 5px 20px 13px 20px;\n    border-radius: 10px;\n    background: rgba(46, 195, 113, 0.6);\n}\n.modal-close {\n    border: 1px solid #2ec371;\n    background: #2ec371;\n    color: #FFFFFF;\n    line-height: 20px;\n    position: absolute;\n    right: 0px;\n    text-align: center;\n    top: 0px;\n    width: 24px;\n    text-decoration: none;\n    border-radius: 0px 6px 0px 4px;\n}\n.modal-close:hover {\n    background: #2ec371;\n}\n\n#modal-tweet {\n    width: 100%;\n    border-radius: 10px;\n    border: 1px solid #2ec371;\n    margin: 20px 0 0 0;\n    font-size: 40px;\n}\n\n#modal-submit {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n    margin: 15px 15px 0 0;\n    font-family: 'Lobster', cursive;\n    font-size: 25px;\n    background-color: #2ec371;\n}\n\n#modal-submit:hover {\n    background-color: #00acc1;\n}\n\n\n\n#modal-form {\n    display: flex;\n    flex-direction: column;\n    align-items: flex-end;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\nheader nav {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n}\n\n.loginOut {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n    margin-left: 10px;\n}\n\n.loginOut:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n.post {\n    padding: 10px 10px 0 10px;\n}\n\n.post-meta {\n    font-size: 12px;\n    padding: 0;\n    border: 0;\n    margin: 2px 0 0 20px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/session.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"net/http\"\n)\n\nfunc getSession(req *http.Request) (*memcache.Item, error) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\tif err != nil {\n\t\treturn &memcache.Item{}, err\n\t}\n\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\treturn &memcache.Item{}, err\n\t}\n\treturn item, nil\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/template.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n)\n\nfunc serveTemplate(res http.ResponseWriter, req *http.Request, templateName string) {\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\t// not logged in\n\t\ttpl.ExecuteTemplate(res, templateName, SessionData{})\n\t\treturn\n\t}\n\t// logged in\n\tvar sd SessionData\n\tjson.Unmarshal(memItem.Value, &sd)\n\tsd.LoggedIn = true\n\ttpl.ExecuteTemplate(res, templateName, &sd)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/templates/html/follow.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Following}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post-meta\">{{.Following}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/templates/html/followingme.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Following}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post-meta\">{{.Follower}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            {{if .LoggedIn}}\n            {{template \"modal-tweet\"}}\n                {{if .ViewingUser}}\n                    {{if .FollowingUser}}\n                    <a href=\"/api/unfollow/{{.ViewingUser}}\"><p class=\"loginOut\">Unfollow</p></a>\n                    {{else}}\n                    <a href=\"/api/follow/{{.ViewingUser}}\"><p class=\"loginOut\">Follow</p></a>\n                    {{end}}\n                {{end}}\n            <a href=\"/api/logout\"><p class=\"loginOut\">Log Out</p></a>\n            {{else}}\n            <a href=\"/form/login\"><p class=\"loginOut\">Log In</p></a>\n            {{end}}\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>\n{{end}}\n\n    {{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Tweets}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post\">{{.Msg}}</p>\n            <p class=\"post-meta\">{{.UserName}}</p>\n            <p class=\"post-meta\">{{humanize_time .Time}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\" .}}\n    <form method=\"POST\" action=\"/api/login\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"userName\" name=\"userName\" placeholder=\"Enter your user name\" autofocus>\n        <p class=\"form-field-err\"></p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\"></p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/templates/html/modal-tweet.html",
    "content": "{{ define \"modal-tweet\"}}\n<a href=\"#openModal\" id=\"opens-modal\"><p class=\"loginOut\">Tweet</p></a>\n\n<div id=\"openModal\" class=\"modalDialog\">\n    <div>\t<a href=\"#close\" title=\"Close\" class=\"modal-close\">X</a>\n        <form method=\"POST\" id=\"modal-form\" action=\"/api/tweet\">\n            <textarea name=\"tweet\" id=\"modal-tweet\" rows=\"4\" maxlength=\"140\"></textarea>\n            <input type=\"submit\" id=\"modal-submit\" value=\"Tweet\">\n        </form>\n    </div>\n</div>\n    {{end}}\n\n    {{ define \"modal-tweet-css\"}}\n    <link rel=\"stylesheet\" href=\"/public/css/modal-tweet.css\">\n    {{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\" .}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\" autofocus>\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/templates/html/user.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Tweets}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post\">{{.Msg}}</p>\n            <p class=\"post-meta\">{{.UserName}}</p>\n            <p class=\"post-meta\">{{humanize_time .Time}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/43_following-me/tweets.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"net/http\"\n)\n\nfunc putTweet(req *http.Request, user *User, tweet *Tweet) error {\n\tctx := appengine.NewContext(req)\n\tuserKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey := datastore.NewIncompleteKey(ctx, \"Tweets\", userKey)\n\t_, err := datastore.Put(ctx, key, tweet)\n\treturn err\n}\n\nfunc getTweets(req *http.Request, user *User) ([]Tweet, error) {\n\tctx := appengine.NewContext(req)\n\n\tvar tweets []Tweet\n\tq := datastore.NewQuery(\"Tweets\")\n\n\tif user != nil {\n\t\t// show tweets of a specific user\n\t\tuserKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\t\tq = q.Ancestor(userKey)\n\t}\n\n\tq = q.Order(\"-Time\").Limit(20)\n\t_, err := q.GetAll(ctx, &tweets)\n\treturn tweets, err\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/api.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"golang.org/x/crypto/bcrypt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\thashedPass, err := bcrypt.GenerateFromPassword([]byte(req.FormValue(\"password\")), bcrypt.DefaultCost)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error creating password: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tuser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: string(hashedPass),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey, err = datastore.Put(ctx, key, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tcreateSession(res, req, user)\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc loginProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Users\", req.FormValue(\"userName\"), 0, nil)\n\tvar user User\n\terr := datastore.Get(ctx, key, &user)\n\tif err != nil || bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.FormValue(\"password\"))) != nil {\n\t\t// failure logging in\n\t\tvar sd SessionData\n\t\tsd.LoginFail = true\n\t\ttpl.ExecuteTemplate(res, \"login.html\", sd)\n\t\treturn\n\t} else {\n\t\tuser.UserName = req.FormValue(\"userName\")\n\t\t// success logging in\n\t\tcreateSession(res, req, user)\n\t\t// redirect\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t}\n}\n\nfunc createSession(res http.ResponseWriter, req *http.Request, user User) {\n\tctx := appengine.NewContext(req)\n\t// SET COOKIE\n\tid, _ := uuid.NewV4()\n\tcookie := &http.Cookie{\n\t\tName:  \"session\",\n\t\tValue: id.String(),\n\t\tPath:  \"/\",\n\t\t// twenty minute session:\n\t\tMaxAge: 60 * 20,\n\t\t//\t\tUNCOMMENT WHEN DEPLOYED:\n\t\t//\t\tSecure: true,\n\t\t//\t\tHttpOnly: true,\n\t}\n\thttp.SetCookie(res, cookie)\n\n\t// SET MEMCACHE session data (sd)\n\tjson, err := json.Marshal(user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error marshalling during user creation: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd := memcache.Item{\n\t\tKey:   id.String(),\n\t\tValue: json,\n\t}\n\tmemcache.Set(ctx, &sd)\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\t// cookie is not set\n\tif err != nil {\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t\treturn\n\t}\n\n\t// clear memcache\n\tsd := memcache.Item{\n\t\tKey:        cookie.Value,\n\t\tValue:      []byte(\"\"),\n\t\tExpiration: time.Duration(1 * time.Microsecond),\n\t}\n\tmemcache.Set(ctx, &sd)\n\n\t// clear the cookie\n\tcookie.MaxAge = -1\n\thttp.SetCookie(res, cookie)\n\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc tweetProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to post tweet from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// declare a variable of type tweet\n\t// initialize it with values\n\tlog.Infof(ctx, user.UserName)\n\ttweet := Tweet{\n\t\tMsg:      req.FormValue(\"tweet\"),\n\t\tTime:     time.Now(),\n\t\tUserName: user.UserName,\n\t}\n\t// put in datastore\n\terr = putTweet(req, &user, &tweet)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// redirect\n\ttime.Sleep(time.Millisecond * 500) // This is not the best code, probably. Thoughts?\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc follow(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t// get session\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to follow from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// get the datastore key for the follower\n\tfollowerKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\t// get a datastore key for the followee\n\tfolloweeKey := datastore.NewKey(ctx, \"Follows\", ps.ByName(\"user\"), 0, followerKey)\n\t// the follower is following the followee\n\t// put this into the datastore\n\t_, err = datastore.Put(ctx, followeeKey, &F{ps.ByName(\"user\"), user.UserName})\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding followee: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// send the \"you are being followed\" email\n\temailKey := datastore.NewKey(ctx, \"Users\", ps.ByName(\"user\"), 0, nil)\n\tvar u User\n\terr = datastore.Get(ctx, emailKey, &u)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting followee's email user data: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tfollowedEmail(res, req, u.Email)\n\t// return to user account\n\thttp.Redirect(res, req, \"/user/\"+ps.ByName(\"user\"), 302)\n}\n\nfunc unfollow(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t// get session\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to unfollow from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// get the datastore key for the follower\n\tfollowerKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\t// get a datastore key for the followee\n\tfolloweeKey := datastore.NewKey(ctx, \"Follows\", ps.ByName(\"user\"), 0, followerKey)\n\t// delete entry in datastore\n\terr = datastore.Delete(ctx, followeeKey)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error deleting followee: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\thttp.Redirect(res, req, \"/user/\"+ps.ByName(\"user\"), 302)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/email.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/mail\"\n\t\"net/http\"\n)\n\nfunc followedEmail(w http.ResponseWriter, r *http.Request, email string) {\n\tctx := appengine.NewContext(r)\n\tmsg := &mail.Message{\n\t\tSender:  \"TwitClone Support <support@example.com>\",\n\t\tTo:      []string{email},\n\t\tSubject: \"You are being followed\",\n\t\tBody:    fmt.Sprintf(confirmMessage),\n\t}\n\tif err := mail.Send(ctx, msg); err != nil {\n\t\tlog.Errorf(ctx, \"Couldn't send email: %v\", err)\n\t}\n}\n\nconst confirmMessage = `\nSomeone is now following you. Don't say you didn't ask for it.\n`\n"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/following.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"net/http\"\n)\n\nfunc following(follower, followee string, req *http.Request) (bool, error) {\n\tctx := appengine.NewContext(req)\n\tuserKey := datastore.NewKey(ctx, \"Users\", follower, 0, nil)\n\tx, err := datastore.NewQuery(\"Follows\").Ancestor(userKey).Filter(\"Following =\", followee).Count(ctx)\n\treturn x > 0, err\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/index.yaml",
    "content": "indexes:\n\n# AUTOGENERATED\n\n# This index.yaml is automatically updated whenever the dev_appserver\n# detects that a new type of query is run.  If you want to manage the\n# index.yaml file manually, remove the above marker line (the line\n# saying \"# AUTOGENERATED\").  If you want to manage some indexes\n# manually, move them above the marker line.  The index.yaml file is\n# automatically uploaded to the admin console when you next deploy\n# your application using appcfg.py.\n\n- kind: Follows\n  ancestor: yes\n  properties:\n  - name: Follower\n\n- kind: Follows\n  ancestor: yes\n  properties:\n  - name: Following\n\n- kind: Tweets\n  ancestor: yes\n  properties:\n  - name: Time\n    direction: desc\n"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", home)\n\tr.GET(\"/following\", fing)\n\tr.GET(\"/followingme\", fingme)\n\tr.GET(\"/user/:user\", user)\n\tr.GET(\"/form/login\", login)\n\tr.GET(\"/form/signup\", signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\tr.POST(\"/api/login\", loginProcess)\n\tr.POST(\"/api/tweet\", tweetProcess)\n\tr.GET(\"/api/logout\", logout)\n\tr.GET(\"/api/follow/:user\", follow)\n\tr.GET(\"/api/unfollow/:user\", unfollow)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\n\ttpl = template.New(\"roottemplate\")\n\ttpl = tpl.Funcs(template.FuncMap{\n\t\t\"humanize_time\": humanize.Time,\n\t})\n\n\ttpl = template.Must(tpl.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc home(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t//get tweets\n\ttweets, err := getTweets(req, nil)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting tweets: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// get session\n\tmemItem, err := getSession(req)\n\tvar sd SessionData\n\tif err == nil {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t}\n\tsd.Tweets = tweets\n\ttpl.ExecuteTemplate(res, \"home.html\", &sd)\n}\n\nfunc user(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tuser := User{UserName: ps.ByName(\"user\")}\n\t//get tweets\n\ttweets, err := getTweets(req, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting tweets: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// get session\n\tmemItem, err := getSession(req)\n\tvar sd SessionData\n\tif err == nil {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t\tsd.ViewingUser = user.UserName\n\t\tsd.FollowingUser, err = following(sd.UserName, user.UserName, req)\n\t\tif err != nil {\n\t\t\tlog.Errorf(ctx, \"error running following query: %v\", err)\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t}\n\tsd.Tweets = tweets\n\ttpl.ExecuteTemplate(res, \"user.html\", &sd)\n}\n\nfunc fing(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t// get session\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to see following from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\tvar sd SessionData\n\tif err == nil {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t}\n\t// Get followees\n\t// get the datastore key for the follower\n\tfollowerKey := datastore.NewKey(ctx, \"Users\", sd.UserName, 0, nil)\n\tvar XF []F\n\t_, err = datastore.NewQuery(\"Follows\").Ancestor(followerKey).Project(\"Following\").GetAll(ctx, &XF)\n\tlog.Infof(ctx, \"here is type %T \\n and value %v\", XF, XF)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting followees: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd.Following = XF\n\ttpl.ExecuteTemplate(res, \"follow.html\", &sd)\n}\n\nfunc fingme(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t// get session\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to see followingme from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\tvar sd SessionData\n\tif err == nil {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t}\n\t// get those who are following this user\n\tvar XF []F\n\t_, err = datastore.NewQuery(\"Follows\").Filter(\"Following =\", sd.UserName).GetAll(ctx, &XF)\n\tlog.Errorf(ctx, \"here is type %T \\n and value %v\", XF, XF)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting followees: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd.Following = XF\n\ttpl.ExecuteTemplate(res, \"followingme.html\", &sd)\n}\n\nfunc login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"login.html\")\n}\n\nfunc signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"signup.html\")\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/model.go",
    "content": "package main\n\nimport \"time\"\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string `json:\"-\"`\n}\n\ntype SessionData struct {\n\tUser\n\tLoggedIn      bool\n\tLoginFail     bool\n\tTweets        []Tweet\n\tViewingUser   string\n\tFollowingUser bool\n\tFollowing     []F\n}\n\ntype Tweet struct {\n\tMsg      string\n\tTime     time.Time\n\tUserName string\n}\n\ntype F struct {\n\tFollowing string\n\tFollower  string\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/public/css/modal-tweet.css",
    "content": ".modalDialog {\n    position: fixed;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    background: rgba(255, 255, 255, 0.7);\n    z-index: 99999;\n    opacity:0;\n    -webkit-transition: opacity 400ms ease-in;\n    -moz-transition: opacity 400ms ease-in;\n    transition: opacity 400ms ease-in;\n    pointer-events: none;\n}\n.modalDialog:target {\n    opacity:1;\n    pointer-events: auto;\n}\n.modalDialog > div {\n    border: 4px solid #2ec371;\n    width: 70%;\n    position: relative;\n    margin: 10% auto;\n    padding: 5px 20px 13px 20px;\n    border-radius: 10px;\n    background: rgba(46, 195, 113, 0.6);\n}\n.modal-close {\n    border: 1px solid #2ec371;\n    background: #2ec371;\n    color: #FFFFFF;\n    line-height: 20px;\n    position: absolute;\n    right: 0px;\n    text-align: center;\n    top: 0px;\n    width: 24px;\n    text-decoration: none;\n    border-radius: 0px 6px 0px 4px;\n}\n.modal-close:hover {\n    background: #2ec371;\n}\n\n#modal-tweet {\n    width: 100%;\n    border-radius: 10px;\n    border: 1px solid #2ec371;\n    margin: 20px 0 0 0;\n    font-size: 40px;\n}\n\n#modal-submit {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n    margin: 15px 15px 0 0;\n    font-family: 'Lobster', cursive;\n    font-size: 25px;\n    background-color: #2ec371;\n}\n\n#modal-submit:hover {\n    background-color: #00acc1;\n}\n\n\n\n#modal-form {\n    display: flex;\n    flex-direction: column;\n    align-items: flex-end;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\nheader nav {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n}\n\n.loginOut {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n    margin-left: 10px;\n}\n\n.loginOut:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n.post {\n    padding: 10px 10px 0 10px;\n}\n\n.post-meta {\n    font-size: 12px;\n    padding: 0;\n    border: 0;\n    margin: 2px 0 0 20px;\n}"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/session.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"net/http\"\n)\n\nfunc getSession(req *http.Request) (*memcache.Item, error) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\tif err != nil {\n\t\treturn &memcache.Item{}, err\n\t}\n\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\treturn &memcache.Item{}, err\n\t}\n\treturn item, nil\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/template.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n)\n\nfunc serveTemplate(res http.ResponseWriter, req *http.Request, templateName string) {\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\t// not logged in\n\t\ttpl.ExecuteTemplate(res, templateName, SessionData{})\n\t\treturn\n\t}\n\t// logged in\n\tvar sd SessionData\n\tjson.Unmarshal(memItem.Value, &sd)\n\tsd.LoggedIn = true\n\ttpl.ExecuteTemplate(res, templateName, &sd)\n}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/templates/html/follow.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Following}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post-meta\">{{.Following}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/templates/html/followingme.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Following}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post-meta\">{{.Follower}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            {{if .LoggedIn}}\n            {{template \"modal-tweet\"}}\n                {{if .ViewingUser}}\n                    {{if .FollowingUser}}\n                    <a href=\"/api/unfollow/{{.ViewingUser}}\"><p class=\"loginOut\">Unfollow</p></a>\n                    {{else}}\n                    <a href=\"/api/follow/{{.ViewingUser}}\"><p class=\"loginOut\">Follow</p></a>\n                    {{end}}\n                {{end}}\n            <a href=\"/api/logout\"><p class=\"loginOut\">Log Out</p></a>\n            {{else}}\n            <a href=\"/form/login\"><p class=\"loginOut\">Log In</p></a>\n            {{end}}\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>\n{{end}}\n\n    {{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Tweets}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post\">{{.Msg}}</p>\n            <p class=\"post-meta\">{{.UserName}}</p>\n            <p class=\"post-meta\">{{humanize_time .Time}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\" .}}\n    <form method=\"POST\" action=\"/api/login\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"userName\" name=\"userName\" placeholder=\"Enter your user name\" autofocus>\n        <p class=\"form-field-err\"></p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\"></p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/templates/html/modal-tweet.html",
    "content": "{{ define \"modal-tweet\"}}\n<a href=\"#openModal\" id=\"opens-modal\"><p class=\"loginOut\">Tweet</p></a>\n\n<div id=\"openModal\" class=\"modalDialog\">\n    <div>\t<a href=\"#close\" title=\"Close\" class=\"modal-close\">X</a>\n        <form method=\"POST\" id=\"modal-form\" action=\"/api/tweet\">\n            <textarea name=\"tweet\" id=\"modal-tweet\" rows=\"4\" maxlength=\"140\"></textarea>\n            <input type=\"submit\" id=\"modal-submit\" value=\"Tweet\">\n        </form>\n    </div>\n</div>\n    {{end}}\n\n    {{ define \"modal-tweet-css\"}}\n    <link rel=\"stylesheet\" href=\"/public/css/modal-tweet.css\">\n    {{end}}"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\" .}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\" autofocus>\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/templates/html/user.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Tweets}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post\">{{.Msg}}</p>\n            <p class=\"post-meta\">{{.UserName}}</p>\n            <p class=\"post-meta\">{{humanize_time .Time}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/56_twitter/44_code-review/tweets.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"net/http\"\n)\n\nfunc putTweet(req *http.Request, user *User, tweet *Tweet) error {\n\tctx := appengine.NewContext(req)\n\tuserKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey := datastore.NewIncompleteKey(ctx, \"Tweets\", userKey)\n\t_, err := datastore.Put(ctx, key, tweet)\n\treturn err\n}\n\nfunc getTweets(req *http.Request, user *User) ([]Tweet, error) {\n\tctx := appengine.NewContext(req)\n\n\tvar tweets []Tweet\n\tq := datastore.NewQuery(\"Tweets\")\n\n\tif user != nil {\n\t\t// show tweets of a specific user\n\t\tuserKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\t\tq = q.Ancestor(userKey)\n\t}\n\n\tq = q.Order(\"-Time\").Limit(20)\n\t_, err := q.GetAll(ctx, &tweets)\n\treturn tweets, err\n}\n"
  },
  {
    "path": "27_code-in-process/57_appengine-channel/01_basic/app.yaml",
    "content": "application: photoblog-1008\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/57_appengine-channel/01_basic/channel.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/channel\"\n)\n\nfunc init() {\n\t// build routing table\n\thttp.HandleFunc(\"/create_channel\", handleCreateChannel)\n\thttp.HandleFunc(\"/listen\", handleListen)\n\thttp.HandleFunc(\"/send\", handleSend)\n}\n\nfunc handleSend(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tmessage := req.FormValue(\"message\")\n\terr := channel.SendJSON(ctx, \"example\", message)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t}\n\tio.WriteString(res, \"Sent!\")\n}\n\nfunc handleCreateChannel(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\ttok, err := channel.Create(ctx, \"example\")\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tio.WriteString(res, tok)\n}\n\nfunc handleListen(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <head>\n  <script type=\"text/javascript\" src=\"/_ah/channel/jsapi\"></script>\n  </head>\n  <body>\n<script>\n// I want to listen on the channel\nvar token = prompt(\"Enter Your Token\");\n// listen\nvar channel = new goog.appengine.Channel(token);\n\n// this:\n var socket = channel.open();\n socket.onopen = function(evt) {\n\tconsole.log(\"OPEN\", arguments);\n };\n socket.onmessage = function(msg) {\n\tvar data = JSON.parse(msg.data);\n    alert(\"Message Received: \" + data);\n };\n socket.onerror = function(evt) {\n\tconsole.log(\"ERROR\", arguments);\n };\n socket.onclose = function(evt) {\n\tconsole.log(\"CLOSE\", arguments);\n };\n\n// or this:\nvar socket = channel.open({\n  onopen: function() {\n    console.log(\"OPEN\", arguments);\n  },\n  onmessage: function(msg) {\n    var data = JSON.parse(msg.data);\n    alert(\"Message Received: \" + data);\n  },\n  onerror: function() {\n    console.log(\"ERROR\", arguments);\n  },\n  onclose: function() {\n    console.log(\"CLOSE\", arguments);\n  }\n});\n</script>\n  </body>\n</html>`)\n}\n"
  },
  {
    "path": "27_code-in-process/57_appengine-channel/02_chat-room/app.yaml",
    "content": "application: photoblog-1008\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n  login: required\n"
  },
  {
    "path": "27_code-in-process/57_appengine-channel/02_chat-room/handlers.go",
    "content": "package chat\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"fmt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/channel\"\n\t\"google.golang.org/appengine/user\"\n)\n\n// API handles api calls\ntype API struct {\n\troot string\n}\n\n// NewAPI creates a new API, root should be set to the root url for the API\nfunc NewAPI(root string) *API {\n\tapi := &API{\n\t\troot: root,\n\t}\n\treturn api\n}\n\nfunc (api *API) ServeHTTP(res http.ResponseWriter, req *http.Request) {\n\tendpoint := req.URL.Path[len(api.root):]\n\tmethod := req.Method\n\n\tvar err error\n\tswitch endpoint {\n\tcase \"channels\":\n\t\tswitch method {\n\t\tcase \"POST\":\n\t\t\terr = api.handlePostChannel(res, req)\n\t\tdefault:\n\t\t\thttp.Error(res, \"Method Not Allowed\", http.StatusMethodNotAllowed)\n\t\t\treturn\n\t\t}\n\tcase \"messages\":\n\t\tswitch method {\n\t\tcase \"POST\":\n\t\t\terr = api.handlePostMessage(res, req)\n\t\tdefault:\n\t\t\thttp.Error(res, \"Method Not Allowed\", http.StatusMethodNotAllowed)\n\t\t\treturn\n\t\t}\n\tdefault:\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\n\tif err != nil {\n\t\tres.WriteHeader(http.StatusInternalServerError)\n\t\tjson.NewEncoder(res).Encode(err.Error())\n\t}\n}\n\n// create the channel\nfunc (api *API) handlePostChannel(res http.ResponseWriter, req *http.Request) error {\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\ttok, err := channel.Create(ctx, u.Email)\n\tif err != nil {\n\t\treturn err\n\t}\n\troom, err := getRoom(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\troom.Emails = append(room.Emails, u.Email)\n\terr = putRoom(ctx, room)\n\tif err != nil {\n\t\treturn err\n\t}\n\tjson.NewEncoder(res).Encode(tok)\n\treturn nil\n}\n\nfunc (api *API) handlePostMessage(res http.ResponseWriter, req *http.Request) error {\n\tctx := appengine.NewContext(req)\n\ttype Message struct {\n\t\tText string\n\t}\n\tvar message Message\n\terr := json.NewDecoder(req.Body).Decode(&message)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfmt.Println(\"***********IS THE MESSAGE HERE: \", message)\n\t// u.Email == \"test@example.com\"\n\troom, err := getRoom(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, email := range room.Emails {\n\t\terr = channel.SendJSON(ctx, email, message)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tjson.NewEncoder(res).Encode(true)\n\treturn nil\n}\n"
  },
  {
    "path": "27_code-in-process/57_appengine-channel/02_chat-room/public/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Chat Example</title>\n  </head>\n  <body>\n    <div class=\"chat-window\">\n      <div id=\"messages\"></div>\n      <form id=\"controls\">\n        <input type=\"text\" id=\"text-input\">\n        <input type=\"submit\">\n      </form>\n    </div>\n    <script type=\"text/javascript\" src=\"/_ah/channel/jsapi\"></script>\n    <script src=\"/main.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/57_appengine-channel/02_chat-room/public/main.css",
    "content": ""
  },
  {
    "path": "27_code-in-process/57_appengine-channel/02_chat-room/public/main.js",
    "content": "// make an api request\nfunction apiRequest(method, endpoint, data, callback) {\n  var xhr = new XMLHttpRequest();\n  xhr.open(method, \"/api/\" + endpoint);\n  xhr.send(JSON.stringify(data));\n  xhr.onreadystatechange = function(evt) {\n    if (xhr.readyState === 4) {\n      if (Math.floor(xhr.status/100) === 2) {\n        if (callback) {\n          callback(JSON.parse(xhr.responseText), null);\n        }\n          // any status other than 2XX, else ...\n      } else {\n        var msg;\n        try {\n          msg = JSON.parse(xhr.responseText);\n        } catch(e) {\n          msg = xhr.responseText;\n        }\n        if (callback) {\n          callback(null, msg);\n        }\n      }\n    }\n  };\n}\n\n// send a message\nfunction sendMessage(text, callback) {\n  apiRequest(\"POST\", \"messages\", {\n    \"Text\": text\n  }, callback);\n}\n\n// when a message is received\nfunction onMessage(message) {\n    console.log(\"DID I GET THE MESSAGE \" + message);\n  var el = document.getElementById(\"messages\");\n  var p = document.createElement(\"p\");\n  p.textContent = message;\n  el.appendChild(p);\n}\n\n(function() {\n\n// hook up text input\nvar controls = document.getElementById(\"controls\");\ncontrols.addEventListener(\"submit\", function(evt) {\n  evt.preventDefault();\n  var textInput = document.getElementById(\"text-input\");\n  var text = textInput.value;\n  sendMessage(text, function(res, err) {\n    if (err) {\n      alert(err);\n    }\n  });\n  textInput.value = \"\";\n}, false);\n\n\napiRequest(\"POST\", \"channels\", null, function(res, err) {\n  if (err) {\n    alert(err);\n    return;\n  }\n  var token = res;\n  var channel = new goog.appengine.Channel(token);\n  var socket = channel.open({\n    onopen: function() {\n      console.log(\"OPEN\", arguments);\n    },\n    onmessage: function(msg) {\n      var data = JSON.parse(msg.data);\n      onMessage(data.Text);\n        console.log(data);\n    },\n    onerror: function() {\n      console.log(\"ERROR\", arguments);\n    },\n    onclose: function() {\n      console.log(\"CLOSE\", arguments);\n    }\n  });\n});\n})();\n"
  },
  {
    "path": "27_code-in-process/57_appengine-channel/02_chat-room/room.go",
    "content": "package chat\n\nimport (\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine/datastore\"\n)\n\ntype Room struct {\n\tEmails []string\n}\n\nfunc getRoom(ctx context.Context) (*Room, error) {\n\tkey := datastore.NewKey(ctx, \"Room\", \"GLOBAL\", 0, nil)\n\tvar room Room\n\tdatastore.Get(ctx, key, &room)\n\treturn &room, nil\n}\n\nfunc putRoom(ctx context.Context, room *Room) error {\n\tkey := datastore.NewKey(ctx, \"Room\", \"GLOBAL\", 0, nil)\n\t_, err := datastore.Put(ctx, key, room)\n\treturn err\n}\n"
  },
  {
    "path": "27_code-in-process/57_appengine-channel/02_chat-room/routes.go",
    "content": "package chat\n\nimport \"net/http\"\n\nfunc init() {\n\thttp.Handle(\"/\", http.FileServer(http.Dir(\"public/\")))\n\thttp.Handle(\"/api/\", NewAPI(\"/api/\"))\n}\n"
  },
  {
    "path": "27_code-in-process/58_appengine-search/app.yaml",
    "content": "application: photoblog-1008\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/58_appengine-search/search.go",
    "content": "package search\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/search\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/put\", handlePut)\n\thttp.HandleFunc(\"/get\", handleGet)\n\thttp.HandleFunc(\"/search\", handleSearch)\n}\n\ntype Document struct {\n\tName string\n\tText string\n}\n\nfunc handleSearch(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tindex, err := search.Open(\"example\")\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\titerator := index.Search(ctx, \"the\", nil)\n\tfor {\n\t\tvar document Document\n\t\tid, err := iterator.Next(&document)\n\t\tif err == search.Done {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\tfmt.Fprintf(res, \"ID: %v, DOCUMENT: %v \\n\\n\", id, document)\n\t}\n}\n\nfunc handleGet(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tindex, err := search.Open(\"example\")\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tvar document Document\n\terr = index.Get(ctx, \"23687ac5-5417-4b13-b9f7-4e674fa5c227\", &document)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tfmt.Fprintf(res, \"%v\", document.Text)\n}\n\nfunc handlePut(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\n\tindex, err := search.Open(\"example\")\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tvar document = &Document{\n\t\tName: \"example\",\n\t\tText: `It is a truth universally acknowledged, that a single man in possession of a good fortune, must be in want of a wife.\nHowever little known the feelings or views of such a man may be on his first entering a neighbourhood, this truth is so well fixed in the minds of the surrounding families, that he is considered the rightful property of some one or other of their daughters.\n\"My dear Mr. Bennet,\" said his lady to him one day, \"have you heard that Netherfield Park is let at last?\"\nMr. Bennet replied that he had not.\n\"But it is,\" returned she; \"for Mrs. Long has just been here, and she told me all about it.\"\nMr. Bennet made no answer.\n\"Do you not want to know who has taken it?\" cried his wife impatiently.\n\"You want to tell me, and I have no objection to hearing it.\"\nThis was invitation enough.\n\"Why, my dear, you must know, Mrs. Long says that Netherfield is taken by a young man of large fortune from the north of England; that he came down on Monday in a chaise and four to see the place, and was so much delighted with it, that he agreed with Mr. Morris immediately; that he is to take possession before Michaelmas, and some of his servants are to be in the house by the end of next week.\"\n\"What is his name?\"\n\"Bingley.\"\n\"Is he married or single?\"\n\"Oh! Single, my dear, to be sure! A single man of large fortune; four or five thousand a year. What a fine thing for our girls!\"\n\"How so? How can it affect them?\"\n\"My dear Mr. Bennet,\" replied his wife, \"how can you be so tiresome! You must know that I am thinking of his marrying one of them.\"\n\"Is that his design in settling here?\"\n\"Design! Nonsense, how can you talk so! But it is very likely that he may fall in love with one of them, and therefore you must visit him as soon as he comes.\"\n\"I see no occasion for that. You and the girls may go, or you may send them by themselves, which perhaps will be still better, for as you are as handsome as any of them, Mr. Bingley may like you the best of the party.\"\n\"My dear, you flatter me. I certainly have had my share of beauty, but I do not pretend to be anything extraordinary now. When a woman has five grown-up daughters, she ought to give over thinking of her own beauty.\"\n\"In such cases, a woman has not often much beauty to think of.\"\n\"But, my dear, you must indeed go and see Mr. Bingley when he comes into the neighbourhood.\"\n\"It is more than I engage for, I assure you.\"\n\"But consider your daughters. Only think what an establishment it would be for one of them. Sir William and Lady Lucas are determined to go, merely on that account, for in general, you know, they visit no newcomers. Indeed you must go, for it will be impossible for us to visit him if you do not.\"\n\"You are over-scrupulous, surely. I dare say Mr. Bingley will be very glad to see you; and I will send a few lines by you to assure him of my hearty consent to his marrying whichever he chooses of the girls; though I must throw in a good word for my little Lizzy.\"\n\"I desire you will do no such thing. Lizzy is not a bit better than the others; and I am sure she is not half so handsome as Jane, nor half so good-humoured as Lydia. But you are always giving her the preference.\"`,\n\t}\n\n\t//\tvar document = &Document{\n\t//\t\tName: \"StephenKing\",\n\t//\t\tText: `Jacobs's electrical workshop was in West Tulsa. I don't know what that part of town is like now, but in 1992 it was a forlorn industrial zone where a lot of the industries seemed to be dead or dying. He pulled into the parking lot of an all-but-destitute strip mall on Olympia Avenue and parked in front of Wilson Auto Body. \"It was standing empty for a long time, that's what the Realtor told me,\" Jacobs said. He was dressed in faded jeans and a blue golf shirt, his hair washed and combed, his eyes sparkling with excitement. Just looking at him made me nervous. \"I had to take a year's lease, but it was still dirt cheap. Come on in.\" \"You ought to take down the sign and put up your own,\" I said. I framed it with hands that were only shaking a little. \"'Portraits in Lightning, C. D. Jacobs, Proprietor.' It would look good.\" \"I won't be in Tulsa that long,\" he said, \"and the portraits are really just a way of supporting myself while I conduct my experiments. I've come a long way since my pastoral days, but I've still got a long way to go. You have no idea. Come in, Jamie. Come in.\" He unlocked a door and led me through an office that was empty of furniture, although I could still see square clean patches on the grimy linoleum, where the legs of a desk had once stood. On the wall was a curling calendar with April 1989 showing. The garage had a corrugated metal roof and I expected it to be baking under the September sun, but it was wonderfully cool. I could hear the whisper of air conditioners. When he flicked a bank of switches—recently modified, judging from the makeshift way the wires stuck out of the uncovered holes where the plates had been—a dozen brilliant lights came on. If not for the oil-darkened concrete and the rectangular caverns where two lifts had once been, you would have thought it was an operating theater. \"It must cost a fortune to air-condition this place,\" I said. \"Especially when you've got all those lights blazing.\" \"Dirt cheap. The air conditioners are my own design. They draw very little power, and most of that I generate myself. I could gener- ate all of it, but I wouldn't want Tulsa Power and Light down here, snooping around to fifind out if I was volt-jacking, somehow. As for the lights . . . you could wrap a hand around one of the bulbs with- out burning yourself. Or even heating your skin, for that matter.\" Our footfalls echoed in all that empty space. So did our voices. It was like being in the company of phantoms. It just feels that way because I'm strung out, I told myself. \"Listen, Charlie — you're not messing with anything radioactive, are you?\" He grimaced and shook his head. \"Nuclear's the last thing I'm interested in. It's energy for idiots. A dead end.\" \"So how do you generate the juice?\" \"Electricity breeds electricity, if you know what you're doing. Leave it at that. Step over here, Jamie.\" There were three or four long tables at the end of the room with electrical stuff on them. I recognized an oscilloscope, a spectrom- eter, and a couple of things that looked like Marshall amps but could have been batteries of some kind. There was a control board that looked mostly torn apart, and several stacked consoles with darkened dials. Thick electrical cords snaked every whichway. Some disappeared into closed metal containers that could have been Craftsman tool chests; others just looped back to the dark equip- ment. This could all be a fantasy, I thought. Equipment that only comes alive in his imagination. But the Portraits in Lightning weren't make- believe. I had no idea how he was making those, his explanation had been vague at best, but he was making them. And although I was standing directly beneath one of those brilliant lights, it really did not seem to be throwing any heat. \"There doesn't seem to be much here,\" I said doubtfully. \"I expected more.\" \"Flashing lights! Chrome-plated knife-switches sticking out of science fiction control panels! Star Trek telescreens! Possibly a tele- portation chamber, or a hologram of Noah's Ark in a cloud cham- ber!\" He laughed cheerily. \"Nothing like that,\" I said, although he had pretty much hit the nail on the head. \"It just seems kind of . . . sparse.\" \"It is. I've gone about as far as I can for the time being. I've sold some of my equipment. Other stuff—more controversial stuff— I've dismantled and put in storage. I've done good work in Tulsa, especially considering how little spare time I have. Keeping body and soul together is an annoying business, as I suppose you know.\" I certainly did. \"But yes, I made some progress toward my ultimate goal. Now I need to think, and I don't believe I can do that when I'm turning half a dozen tips a night.\" \"Your ultimate goal being what?\" He ignored the question this time, too. \"Step over here, Jamie. Would you like a small pick-me-up before we begin?\" I wasn't sure I wanted to begin, but I wanted a pick-me-up, all right. Not for the first time, I considered just snatching the little brown bottle and running. Only he'd probably catch me and wrest it away. I was younger, and almost over the flu, but he was still in better shape. He hadn't suffered a shattered hip and leg in a motor- cycle accident, for one thing. He grabbed a paint-spattered wooden chair and set it in front of one of the black boxes that looked like a Marshall amp. \"Sit here.\" But I didn't, not right away. There was a picture on one of the tables, the kind with a little wedge on the back to prop it up. He saw me reach for it and made a move as if to stop me. Then he just stood there. A song on the radio can bring back the past with fierce (if mercifully transitory) immediacy: a first kiss, a good time with your buddies, or an unhappy life-passage. I can never hear Fleetwood Mac's \"Go Your Own Way\" without thinking of my mother's last painful weeks; that spring it seemed to be on the radio every time I turned it on. A picture can have the same effect. I looked at this one and all at once I was eight again. My sister was helping Morrie set up dominos in Toy Corner while Patsy Jacobs played \"Bringing in the Sheaves,\" swaying on the piano bench, her smooth blond hair shifting from side to side. It was a studio portrait. Patsy was wearing the sort of billowy, shin-length dress that went out of fashion years ago, but it looked good on her. The kid was on her lap, wearing short pants and a sweater vest. A cowlick I remembered well stuck up at the back of his head. Read more: http://www.rollingstone.com/culture/features/stephen-king-exclusive-read-an-excerpt-from-new-book-revival-20141027#ixzz3rGP0EkMZ Follow us: @rollingstone on Twitter | RollingStone on Facebook`,\n\t//\t}\n\n\tid, err := index.Put(ctx, \"\", document)\n\n\tfmt.Fprintf(res, \"ID: %v, ERROR: %v\", id, err)\n}\n"
  },
  {
    "path": "27_code-in-process/59_appengine-GCS-storage/00_GCS-setup/00_GCS-setup.txt",
    "content": "THIS PRESENTATION IS HELPFUL:\nhttps://docs.google.com/presentation/d/14NA_G-Wv5aTrRYqti5HIt3oie-wXLBSkkAt3ljEO2y0/edit?usp=sharing\n\n\n- activate GCS API\n\n- create a bucket\n-- the bucket must have a globally unique name, so maybe prefix with your app engine project ID\n\n- create a service account\n-- API's & AUTH\n---- Credentials\n------- generate service account\n-------- create new client ID\n-------- service account\n-------- GENERATE NEW P12 KEY\n\nThis is the private key's password. It will not be shown again. You must present this password to use the private key.\nnotasecret\n\nwe can use this private key to connect to google cloud storage\nbut it's in the wrong format....\n\napp engine expects a PEM and we have a p12\nwe have to convert .....\n\nhttps://cloud.google.com/storage/docs/authentication#converting-the-private-key\n\n# Convert the key from pkcs12 to pkcs1 (PEM).\n$ cat /path/to/xxxx-privatekey.p12 | openssl pkcs12 -nodes -nocerts -passin pass:notasecret | openssl rsa > /path/to/secret.pem\n\nfor example:\ncat ~/Downloads/downloaded_file.p12 | openssl pkcs12 -nodes -nocerts -passin pass:notasecret | openssl rsa > ~/Downloads/secret.pem\n\n\nnow we can look at this file\ncat ~/Downloads/secret.pem\n\n-these credentials let your local machine connect to your bucket\n-appengine doesn't need these credentials\n-we create/use them so that we can develop/test on our local machine / localhost\n\nFROM HERE:\nhttps://cloud.google.com/appengine/docs/go/googlecloudstorageclient/getstarted\nFOLLOW THIS STEP:\n- Make note of the Service Account Email Address for your project which will be in the form of <your_app_email_address>@developer.gserviceaccount.com.\n\nyou will need to get your email address key from the\n-- API's & AUTH\n---- Credentials\n\nAT TERMINAL:\n/path/to/AppEngSDK/dev_appserver.py . --appidentity_email_address <your_app_email_address>@developer.gserviceaccount.com --appidentity_private_key_path pem_file.pem\n\n/usr/local/go_appengine/dev_appserver.py . --appidentity_email_address account-1@learning-1130.iam.gserviceaccount.com --appidentity_private_key_path ~/Downloads/secret.pem\n"
  },
  {
    "path": "27_code-in-process/59_appengine-GCS-storage/01_NewWriter_PEM-auth/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/59_appengine-GCS-storage/01_NewWriter_PEM-auth/storage.go",
    "content": "package storage\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\n\t\"golang.org/x/oauth2\"\n\t\"golang.org/x/oauth2/google\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/urlfetch\"\n\t\"google.golang.org/cloud\"\n\t\"google.golang.org/cloud/storage\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/put\", handlePut)\n\n}\n\nfunc handlePut(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tbucket := \"learning-1130-bucket-01\"\n\n\thc := &http.Client{\n\t\tTransport: &oauth2.Transport{\n\t\t\tSource: google.AppEngineTokenSource(ctx, storage.ScopeFullControl),\n\t\t\tBase:   &urlfetch.Transport{Context: ctx},\n\t\t},\n\t}\n\n\tcctx := cloud.NewContext(appengine.AppID(ctx), hc)\n\n\twriter := storage.NewWriter(cctx, bucket, \"example.txt\")\n\tio.WriteString(writer, \"Hello World!!!!!\")\n\terr := writer.Close()\n\tif err != nil {\n\t\thttp.Error(res, \"ERROR WRITING TO BUCKET: \"+err.Error(), 500)\n\t\treturn\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/59_appengine-GCS-storage/02_NewWriter_JSON-auth/README.txt",
    "content": "Go to\nconsole.developers.google.com/apis/credentials\n\nClick on\nAdd Credentials / Service Account\n\nCreate a\nJSON Key\n\nThen\nPut that JSON key into the root of your app\n\nAnd\nChange the code to access **YOUR** JSON key\n\nAnd also\nChange the app.YAML"
  },
  {
    "path": "27_code-in-process/59_appengine-GCS-storage/02_NewWriter_JSON-auth/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/59_appengine-GCS-storage/02_NewWriter_JSON-auth/storage.go",
    "content": "package storage\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/cloud/storage\"\n\t\"io\"\n\t\"net/http\"\n)\n\nconst gcsBucket = \"learning-1130-bucket-01\"\n\nfunc init() {\n\thttp.HandleFunc(\"/put\", handlePut)\n}\n\nfunc handlePut(res http.ResponseWriter, req *http.Request) {\n\n\tctx := appengine.NewContext(req)\n\tclient, err := storage.NewClient(ctx)\n\tif err != nil {\n\t\thttp.Error(res, \"ERROR CREATING NEW CLIENT: \"+err.Error(), 500)\n\t\treturn\n\t}\n\twriter := client.Bucket(gcsBucket).Object(\"myOffice.txt\").NewWriter(ctx)\n\twriter.ContentType = \"text/plain\"\n\tio.WriteString(writer, \"in my office\")\n\terr = writer.Close()\n\tif err != nil {\n\t\thttp.Error(res, \"ERROR WRITING TO BUCKET: \"+err.Error(), 500)\n\t\treturn\n\t}\n\tclient.Close()\n}\n"
  },
  {
    "path": "27_code-in-process/59_appengine-GCS-storage/03_put-get-list_JSON-auth/README.txt",
    "content": "Go to\nconsole.developers.google.com/apis/credentials\n\nClick on\nAdd Credentials / Service Account\n\nCreate a\nJSON Key\n\nThen\nPut that JSON key into the root of your app\n\nAnd\nChange the code to access **YOUR** JSON key\n\nAnd also\nChange the app.YAML"
  },
  {
    "path": "27_code-in-process/59_appengine-GCS-storage/03_put-get-list_JSON-auth/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/59_appengine-GCS-storage/03_put-get-list_JSON-auth/storage.go",
    "content": "package storage\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"golang.org/x/net/context\"\n\t\"golang.org/x/oauth2/google\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/cloud\"\n\t\"google.golang.org/cloud/storage\"\n\t\"io/ioutil\"\n)\n\nconst gcsBucket = \"learning-1130-bucket-01\"\nconst aeId = \"learning-1130\"\n\nfunc init() {\n\thttp.HandleFunc(\"/put\", handlePut)\n\thttp.HandleFunc(\"/get\", handleGet)\n\thttp.HandleFunc(\"/list\", handleList)\n}\n\nfunc getCloudContext(req *http.Request) (context.Context, error) {\n\tjsonKey, err := ioutil.ReadFile(\"gcs.xxjson\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tconf, err := google.JWTConfigFromJSON(\n\t\tjsonKey,\n\t\tstorage.ScopeFullControl,\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tctx := appengine.NewContext(req)\n\thc := conf.Client(ctx)\n\treturn cloud.NewContext(aeId, hc), nil\n}\n\nfunc handlePut(res http.ResponseWriter, req *http.Request) {\n\tcctx, err := getCloudContext(req)\n\tif err != nil {\n\t\thttp.Error(res, \"ERROR GETTING CCTX: \"+err.Error(), 500)\n\t\treturn\n\t}\n\n\twriter := storage.NewWriter(cctx, gcsBucket, \"example999.txt\")\n\tio.WriteString(writer, \"showing the put get list\")\n\terr = writer.Close()\n\tif err != nil {\n\t\thttp.Error(res, \"ERROR WRITING TO BUCKET: \"+err.Error(), 500)\n\t\treturn\n\t}\n}\n\nfunc handleGet(res http.ResponseWriter, req *http.Request) {\n\tcctx, err := getCloudContext(req)\n\tif err != nil {\n\t\thttp.Error(res, \"ERROR GETTING CCTX: \"+err.Error(), 500)\n\t\treturn\n\t}\n\n\trdr, err := storage.NewReader(cctx, gcsBucket, \"example999.txt\")\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tdefer rdr.Close()\n\n\tio.Copy(res, rdr)\n}\n\nfunc handleList(res http.ResponseWriter, req *http.Request) {\n\tcctx, err := getCloudContext(req)\n\tif err != nil {\n\t\thttp.Error(res, \"ERROR GETTING CCTX: \"+err.Error(), 500)\n\t\treturn\n\t}\n\n\tvar query *storage.Query\n\tobjs, err := storage.ListObjects(cctx, gcsBucket, query)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tfor _, obj := range objs.Results {\n\t\tfmt.Fprintln(res, obj.Name)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/01_search/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/01_search/index.go",
    "content": "package movieinfo\n\nimport \"net/http\"\n\ntype indexModel struct {\n}\n\nvar fileServer = http.FileServer(http.Dir(\"public/\"))\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path != \"/\" {\n\t\tfileServer.ServeHTTP(res, req)\n\t\treturn\n\t}\n\tmodel := &indexModel{}\n\terr := tpl.ExecuteTemplate(res, \"index\", model)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/01_search/newmovie.go",
    "content": "package movieinfo\n\nimport (\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/search\"\n)\n\ntype newMovieModel struct {\n\tCreatedID string\n}\n\nfunc handleNewMovie(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tmodel := &newMovieModel{}\n\n\tif req.Method == \"POST\" {\n\t\ttitle := req.FormValue(\"title\")\n\t\tsummary := req.FormValue(\"summary\")\n\n\t\tindex, err := search.Open(\"movies\")\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\n\t\tmovie := &Movie{\n\t\t\tTitle:   title,\n\t\t\tSummary: summary,\n\t\t}\n\n\t\tid, err := index.Put(ctx, \"\", movie)\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\tmodel.CreatedID = id\n\t}\n\n\terr := tpl.ExecuteTemplate(res, \"new-movie\", model)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/01_search/public/main.css",
    "content": "* {\n  box-sizing: border-box;\n}\n\nhtml, body {\n  padding: 0;\n  margin: 0;\n  height: 100%;\n}\n\nbody {\n  background: #333;\n  color: #EEE;\n  height: 100%;\n  font-size: 18px;\n  font-family: Oswald;\n  line-height: 2em;\n}\n\n.outer-container {\n  max-width: 740px;\n  margin: auto;\n  min-height: 100%;\n\n  border: 3px solid #AAA;\n  border-top: none;\n  border-bottom: none;\n  background: black;\n\n}\n\nh1 {\n  margin: 0;\n}\na, a:visited, a:active, a:hover {\n  color: white;\n  text-decoration: none;\n}\na:hover {\n  text-decoration: underline;\n}\nheader {\n  border-bottom: 3px solid #AAA;\n  line-height: 50px;\n  height: 50px;\n  padding-right: 18px;\n  padding-left: 18px;\n}\nheader ul {\n  margin: 0;\n  padding: 0;\n  float: right;\n}\nheader li {\n  float: left;\n  list-style: none;\n  margin-left: 9px;\n}\n.body {\n    padding: 18px;\n}\n\ninput[type=text], textarea, button, input[type=submit] {\n  color: white;\n  background: #111;\n  border: 1px solid #CCC;\n}\n\ntextarea {\n  height: 200px;\n  width: 100%;\n}\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/01_search/public/opensearch.xml",
    "content": "<OpenSearchDescription xmlns=\"http://a9.com/-/spec/opensearch/1.1/\" xmlns:moz=\"http://www.mozilla.org/2006/browser/search/\">\n  <ShortName>Movie Info</ShortName>\n  <Description>\n    Search for Movies\n  </Description>\n  <InputEncoding>UTF-8</InputEncoding>\n  <Url type=\"text/html\" method=\"get\" template=\"http://localhost:8080/search?q={searchTerms}\"/>\n</OpenSearchDescription>\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/01_search/routes.go",
    "content": "package movieinfo\n\nimport \"net/http\"\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n\thttp.HandleFunc(\"/search\", handleSearch)\n\thttp.HandleFunc(\"/new-movie\", handleNewMovie)\n}\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/01_search/search.go",
    "content": "package movieinfo\n\nimport (\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/search\"\n)\n\ntype searchModel struct {\n\tQuery  string\n\tMovies []Movie\n}\n\nfunc handleSearch(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tquery := req.FormValue(\"q\")\n\tmodel := &searchModel{\n\t\tQuery: query,\n\t}\n\n\tindex, err := search.Open(\"movies\")\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\titerator := index.Search(ctx, query, nil)\n\tfor {\n\t\tvar movie Movie\n\t\t_, err := iterator.Next(&movie)\n\t\tif err == search.Done {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\tmodel.Movies = append(model.Movies, movie)\n\t}\n\n\terr = tpl.ExecuteTemplate(res, \"search\", model)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/01_search/templates/index.gohtml",
    "content": "{{define \"index\"}}\n{{template \"header\"}}\n<h2>Movie Information</h2>\n<a href=\"/search\">Search</a>\n<a href=\"/new-movie\">New Movie</a>\n{{template \"footer\"}}\n{{end}}\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/01_search/templates/layout.gohtml",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html>\n  <head>\n    <title>Movie Information</title>\n    <link rel=\"search\" type=\"application/opensearchdescription+xml\" title=\"Movie Information\" href=\"/opensearch.xml\">\n    <link href=\"//cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.min.css\" rel=\"stylesheet\" type=\"text/css\">\n    <link href='http://fonts.googleapis.com/css?family=Oswald' rel='stylesheet' type='text/css'>\n    <link href=\"/main.css\" rel=\"stylesheet\" type=\"text/css\">\n  </head>\n  <body>\n    <div class=\"outer-container\">\n      <header>\n        <nav>\n          <ul>\n            <li><a href=\"/\">Home</a></li>\n            <li><a href=\"/search\">Search</a></li>\n            <li><a href=\"/new-movie\">New Movie</a></li>\n          </ul>\n        </nav>\n        <h1>Movie Information</h1>\n      </header>\n      <div class=\"body\">\n{{end}}\n\n{{define \"footer\"}}\n      </div>\n    </div>\n  </body>\n</html>\n{{end}}\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/01_search/templates/new-movie.gohtml",
    "content": "{{define \"new-movie\"}}\n{{template \"header\"}}\n<h2>New Movie</h2>\n{{if .CreatedID}}\n<strong>Created {{.CreatedID}}</strong>\n{{end}}\n<form action=\"/new-movie\" method=\"POST\">\n  <label>Title:<br>\n    <input type=\"text\" name=\"title\" placeholder=\"Title\">\n  </label><br>\n  <label>Summary:<br>\n    <textarea name=\"summary\"\n              placeholder=\"Summary\"></textarea>\n  </label><br>\n  <input type=\"submit\">\n</form>\n{{template \"footer\"}}\n{{end}}\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/01_search/templates/search.gohtml",
    "content": "{{define \"search\"}}\n\n{{template \"header\"}}\n\n<h2>Search</h2>\n<form action=\"/search\" method=\"GET\">\n  <label>Query:<br>\n    <input type=\"text\" name=\"q\" placeholder=\"Query\">\n  </label><br>\n  <input type=\"submit\">\n</form>\n\n<table>\n  <thead>\n    <tr>\n      <th>Title</th>\n      <th>Summary</th>\n    </tr>\n  </thead>\n  <tbody>\n{{range .Movies}}\n    <tr>\n      <td>{{.Title}}</td>\n      <td>{{.Summary}}</td>\n    </tr>\n{{end}}\n  </tbody>\n</table>\n\n{{template \"footer\"}}\n\n{{end}}\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/01_search/templates.go",
    "content": "package movieinfo\n\nimport \"github.com/alecthomas/template\"\n\nvar tpl = template.Must(\n\ttemplate.New(\"\").\n\t\tFuncs(template.FuncMap{}).\n\t\tParseGlob(\"templates/*.gohtml\"),\n)\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/01_search/types.go",
    "content": "package movieinfo\n\ntype Movie struct {\n\tTitle   string\n\tSummary string\n}\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/02_image-upload-GCS/README.txt",
    "content": "Go to\nconsole.developers.google.com/apis/credentials\n\nClick on\nAdd Credentials / Service Account\n\nCreate a\nJSON Key\n\nThen\nPut that JSON key into the root of your app\n\nAnd\nChange the code to access **YOUR** JSON key\n\nAnd also\nChange the app.YAML"
  },
  {
    "path": "27_code-in-process/60_movie-website/02_image-upload-GCS/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/02_image-upload-GCS/index.go",
    "content": "package movieinfo\n\nimport \"net/http\"\n\ntype indexModel struct {\n}\n\nvar fileServer = http.FileServer(http.Dir(\"public/\"))\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path != \"/\" {\n\t\tfileServer.ServeHTTP(res, req)\n\t\treturn\n\t}\n\tmodel := &indexModel{}\n\terr := tpl.ExecuteTemplate(res, \"index\", model)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/02_image-upload-GCS/newmovie.go",
    "content": "package movieinfo\n\nimport (\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/nu7hatch/gouuid\"\n\n\t\"golang.org/x/net/context\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/search\"\n\t\"google.golang.org/appengine/urlfetch\"\n)\n\nconst githubAPIUrl = \"https://api.github.com\"\n\nfunc renderMarkdown(ctx context.Context, text string) (string, error) {\n\tclient := urlfetch.Client(ctx)\n\tresponse, err := client.Post(\n\t\tgithubAPIUrl+\"/markdown/raw\",\n\t\t\"text/x-markdown\",\n\t\tstrings.NewReader(text),\n\t)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer response.Body.Close()\n\n\tbs, _ := ioutil.ReadAll(response.Body)\n\treturn string(bs), nil\n}\n\ntype newMovieModel struct {\n\tCreatedID string\n}\n\nfunc handleNewMovie(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tmodel := &newMovieModel{}\n\n\tif req.Method == \"POST\" {\n\t\ttitle := req.FormValue(\"title\")\n\t\tsummary := req.FormValue(\"summary\")\n\t\tposter, _, _ := req.FormFile(\"poster\")\n\n\t\tvar posterID string\n\t\tif poster != nil {\n\t\t\tdefer poster.Close()\n\t\t\tpID, _ := uuid.NewV4()\n\t\t\tposterID = pID.String()\n\t\t\terr := putFile(ctx, posterID, poster)\n\t\t\tif err != nil {\n\t\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tsummary, err := renderMarkdown(ctx, summary)\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\n\t\tindex, err := search.Open(\"movies\")\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\n\t\tmovie := &Movie{\n\t\t\tTitle:    title,\n\t\t\tSummary:  search.HTML(summary),\n\t\t\tPosterID: posterID,\n\t\t}\n\n\t\tid, err := index.Put(ctx, \"\", movie)\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\tmodel.CreatedID = id\n\t}\n\n\terr := tpl.ExecuteTemplate(res, \"new-movie\", model)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n}\n\n/*\n// with no checking to see if a poster was uploaded:\n\nposter, _, err := req.FormFile(\"poster\")\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\tdefer poster.Close()\n\n\t\tposterID, _ := uuid.NewV4()\n\n\t\terr = putFile(ctx, posterID.String(), poster)\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n*/\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/02_image-upload-GCS/public/main.css",
    "content": "* {\n  box-sizing: border-box;\n}\n\nhtml, body {\n  padding: 0;\n  margin: 0;\n  height: 100%;\n}\n\nbody {\n  background: #333;\n  color: #EEE;\n  height: 100%;\n  font-size: 18px;\n  line-height: 2em;\n}\n\n.outer-container {\n  max-width: 740px;\n  margin: auto;\n  min-height: 100%;\n\n  border: 3px solid #AAA;\n  border-top: none;\n  border-bottom: none;\n  background: black;\n\n}\n\nh1 {\n  margin: 0;\n}\na, a:visited, a:active, a:hover {\n  color: white;\n  text-decoration: none;\n}\na:hover {\n  text-decoration: underline;\n}\nheader {\n  border-bottom: 3px solid #AAA;\n  line-height: 50px;\n  height: 50px;\n  padding-right: 18px;\n  padding-left: 18px;\n}\nheader ul {\n  margin: 0;\n  padding: 0;\n  float: right;\n}\nheader li {\n  float: left;\n  list-style: none;\n  margin-left: 9px;\n}\n.body {\n    padding: 18px;\n}\n\ninput[type=text], textarea, button, input[type=submit] {\n  color: white;\n  background: #111;\n  border: 1px solid #CCC;\n}\n\ntextarea {\n  height: 200px;\n  width: 100%;\n}\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/02_image-upload-GCS/public/opensearch.xml",
    "content": "<OpenSearchDescription xmlns=\"http://a9.com/-/spec/opensearch/1.1/\" xmlns:moz=\"http://www.mozilla.org/2006/browser/search/\">\n  <ShortName>Movie Info</ShortName>\n  <Description>\n    Search for Movies\n  </Description>\n  <InputEncoding>UTF-8</InputEncoding>\n  <Url type=\"text/html\" method=\"get\" template=\"http://localhost:8080/search?q={searchTerms}\"/>\n</OpenSearchDescription>\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/02_image-upload-GCS/routes.go",
    "content": "package movieinfo\n\nimport (\n\t\"net/http\"\n\t\"strings\"\n\n\t\"google.golang.org/appengine\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n\thttp.HandleFunc(\"/search\", handleSearch)\n\thttp.HandleFunc(\"/new-movie\", handleNewMovie)\n\thttp.HandleFunc(\"/posters/\", handlePosters)\n}\n\nfunc handlePosters(res http.ResponseWriter, req *http.Request) {\n\tposterID := strings.SplitN(req.URL.Path, \"/\", 3)[2]\n\tctx := appengine.NewContext(req)\n\t// rc, err := getFile(ctx, posterID)\n\t// if err != nil {\n\t// \thttp.NotFound(res, req)\n\t// \treturn\n\t// }\n\t// defer rc.Close()\n\t//\n\t// io.Copy(res, rc)\n\tmediaLink, err := getFileLink(ctx, posterID)\n\tif err != nil {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\thttp.Redirect(res, req, mediaLink, 302)\n}\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/02_image-upload-GCS/search.go",
    "content": "package movieinfo\n\nimport (\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/search\"\n)\n\ntype searchModel struct {\n\tQuery  string\n\tMovies []Movie\n}\n\nfunc handleSearch(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tquery := req.FormValue(\"q\")\n\tmodel := &searchModel{\n\t\tQuery: query,\n\t}\n\n\tindex, err := search.Open(\"movies\")\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\titerator := index.Search(ctx, query, nil)\n\tfor {\n\t\tvar movie Movie\n\t\t_, err := iterator.Next(&movie)\n\t\tif err == search.Done {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\tmodel.Movies = append(model.Movies, movie)\n\t}\n\n\terr = tpl.ExecuteTemplate(res, \"search\", model)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/02_image-upload-GCS/storage.go",
    "content": "package movieinfo\n\nimport (\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/cloud/storage\"\n\t\"io\"\n)\n\nconst gcsBucket = \"learning-1130-bucket-01\"\n\nfunc putFile(ctx context.Context, name string, rdr io.Reader) error {\n\tclient, err := storage.NewClient(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer client.Close()\n\twriter := client.Bucket(gcsBucket).Object(name).NewWriter(ctx)\n\twriter.ACL = []storage.ACLRule{\n\t\t{storage.AllUsers, storage.RoleReader},\n\t}\n\tio.Copy(writer, rdr)\n\treturn writer.Close()\n}\n\nfunc getFile(ctx context.Context, name string) (io.ReadCloser, error) {\n\tclient, err := storage.NewClient(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer client.Close()\n\n\treturn client.Bucket(gcsBucket).Object(name).NewReader(ctx)\n}\n\nfunc getFileLink(ctx context.Context, name string) (string, error) {\n\tclient, err := storage.NewClient(ctx)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer client.Close()\n\n\tattrs, err := client.Bucket(gcsBucket).Object(name).Attrs(ctx)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn attrs.MediaLink, nil\n}\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/02_image-upload-GCS/templates/index.gohtml",
    "content": "{{define \"index\"}}\n{{template \"header\"}}\n<h2>Movie Information</h2>\n<a href=\"/search\">Search</a>\n<a href=\"/new-movie\">New Movie</a>\n{{template \"footer\"}}\n{{end}}\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/02_image-upload-GCS/templates/layout.gohtml",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html>\n  <head>\n    <title>Movie Information</title>\n    <link rel=\"search\" type=\"application/opensearchdescription+xml\" title=\"Movie Information\" href=\"/opensearch.xml\">\n    <link href=\"//cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.min.css\" rel=\"stylesheet\" type=\"text/css\">\n    <link href='http://fonts.googleapis.com/css?family=Oswald' rel='stylesheet' type='text/css'>\n    <link href=\"/main.css\" rel=\"stylesheet\" type=\"text/css\">\n  </head>\n  <body>\n    <div class=\"outer-container\">\n      <header>\n        <nav>\n          <ul>\n            <li><a href=\"/\">Home</a></li>\n            <li><a href=\"/search\">Search</a></li>\n            <li><a href=\"/new-movie\">New Movie</a></li>\n          </ul>\n        </nav>\n        <h1>Movie Information</h1>\n      </header>\n      <div class=\"body\">\n{{end}}\n\n{{define \"footer\"}}\n      </div>\n    </div>\n  </body>\n</html>\n{{end}}\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/02_image-upload-GCS/templates/new-movie.gohtml",
    "content": "{{define \"new-movie\"}}\n{{template \"header\"}}\n<h2>New Movie</h2>\n{{if .CreatedID}}\n<strong>Created {{.CreatedID}}</strong>\n{{end}}\n<form action=\"/new-movie\" method=\"POST\" enctype=\"multipart/form-data\">\n  <label>Title:<br>\n    <input type=\"text\" name=\"title\" placeholder=\"Title\">\n  </label><br>\n  <label>Summary:<br>\n    <textarea name=\"summary\"\n              placeholder=\"Summary\"></textarea>\n  </label><br>\n  <label>Poster:<br>\n    <input type=\"file\"\n           name=\"poster\"\n           placeholder=\"Poster\">\n  </label><br>\n  <input type=\"submit\">\n</form>\n{{template \"footer\"}}\n{{end}}\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/02_image-upload-GCS/templates/search.gohtml",
    "content": "{{define \"search\"}}\n\n{{template \"header\"}}\n\n<h2>Search</h2>\n<form action=\"/search\" method=\"GET\">\n  <label>Query:<br>\n    <input type=\"text\" name=\"q\" placeholder=\"Query\">\n  </label><br>\n  <input type=\"submit\">\n</form>\n\n<table>\n  <thead>\n    <tr>\n      <th>Title</th>\n      <th>Summary</th>\n    </tr>\n  </thead>\n  <tbody>\n{{range .Movies}}\n    <tr>\n      <td>{{.Title}}</td>\n      <td>{{.Summary}}</td>\n      <td>\n        {{if .PosterID}}\n        <img src=\"/posters/{{.PosterID}}\">\n        {{end}}\n      </td>\n    </tr>\n{{end}}\n  </tbody>\n</table>\n\n{{template \"footer\"}}\n\n{{end}}\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/02_image-upload-GCS/templates.go",
    "content": "package movieinfo\n\nimport \"github.com/alecthomas/template\"\n\nvar tpl = template.Must(\n\ttemplate.New(\"\").\n\t\tFuncs(template.FuncMap{}).\n\t\tParseGlob(\"templates/*.gohtml\"),\n)\n"
  },
  {
    "path": "27_code-in-process/60_movie-website/02_image-upload-GCS/types.go",
    "content": "package movieinfo\n\nimport \"google.golang.org/appengine/search\"\n\ntype Movie struct {\n\tTitle    string\n\tSummary  search.HTML\n\tPosterID string\n}\n"
  },
  {
    "path": "27_code-in-process/61_http-giffy/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/61_http-giffy/http.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/urlfetch\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleGetGif)\n}\n\nfunc handleGetGif(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tclient := urlfetch.Client(ctx)\n\tresult, err := client.Get(\"http://api.giphy.com/v1/gifs/search?q=funny+cat&api_key=dc6zaTOxFJmzC\")\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tdefer result.Body.Close()\n\tvar obj struct {\n\t\tData []struct {\n\t\t\tURL    string `json:\"url\"`\n\t\t\tImages struct {\n\t\t\t\tOriginal struct {\n\t\t\t\t\tURL string\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\terr = json.NewDecoder(result.Body).Decode(&obj)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tfor _, img := range obj.Data {\n\t\tfmt.Fprintf(res, `<a href=\"%v\">%v</a><img src=\"%v\"><br>`, img.URL, img.URL, img.Images.Original.URL)\n\t}\n}\n\n// https://github.com/Giphy/GiphyAPI\n"
  },
  {
    "path": "27_code-in-process/62_self-destructing-message/01/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/62_self-destructing-message/01/routes.go",
    "content": "package selfdestruct\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/nu7hatch/gouuid\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n\thttp.HandleFunc(\"/msg/\", handleMessage)\n}\n\n// create a message\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\n\t// form submit\n\tif req.Method == \"POST\" {\n\t\tmsg := req.FormValue(\"message\")\n\t\tkey, _ := uuid.NewV4()\n\t\t// store the message in memcache\n\t\titem := &memcache.Item{\n\t\t\tKey:   key.String(),\n\t\t\tValue: []byte(msg),\n\t\t}\n\t\terr := memcache.Add(ctx, item)\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <head>\n\n  </head>\n  <body>\n    Here is your self-destructing secret message ID:\n    <a href=\"/msg/`+key.String()+`\">`+key.String()+`</a>\n  </body>\n</html>`)\n\t} else {\n\n\t\t// render the form\n\t\tio.WriteString(res, `<!DOCTYPE html>\n  <html>\n    <head>\n\n    </head>\n    <body>\n      <form method=\"POST\">\n        <label>Message:\n          <textarea name=\"message\"></textarea>\n        </label><br>\n        <input type=\"submit\">\n      </form>\n    </body>\n  </html>`)\n\t}\n\n}\n\n// return a message based on its id\nfunc handleMessage(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\t// get key from URL\n\tkey := strings.SplitN(req.URL.Path, \"/\", 3)[2]\n\t// get item from memcache\n\titem, err := memcache.Get(ctx, key)\n\tif err != nil {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\n\t// delete msg after it is viewed\n\t// this way:\n\t// memcache.Delete(ctx, key)\n\t// or this way:\n\tif item.Flags == 0 {\n\t\titem.Expiration = 10 * time.Second\n\t\titem.Flags = 1\n\t\tmemcache.Set(ctx, item)\n\t}\n\n\tres.Write(item.Value)\n}\n"
  },
  {
    "path": "27_code-in-process/62_self-destructing-message/02_crypto/01_nonce/main.go",
    "content": "package main\n\nimport (\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"io\"\n)\n\nfunc main() {\n\tvar nonce [24]byte\n\tfmt.Println(nonce)\n\tio.ReadFull(rand.Reader, nonce[:])\n\tfmt.Println(nonce)\n}\n"
  },
  {
    "path": "27_code-in-process/62_self-destructing-message/02_crypto/02_encrypt/main.go",
    "content": "package main\n\nimport (\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"golang.org/x/crypto/nacl/secretbox\"\n\t\"io\"\n)\n\nfunc main() {\n\tdecrypted := \"some message that has not yet been encrypted.\"\n\t// the nonce must be unique for every message encrypted\n\tvar nonce [24]byte\n\tio.ReadAtLeast(rand.Reader, nonce[:], 24)\n\t// the password must be unique for every message encrypted\n\tvar password [32]byte\n\tio.ReadAtLeast(rand.Reader, password[:], 32)\n\tencrypted := secretbox.Seal(nil, []byte(decrypted), &nonce, &password)\n\tfmt.Println(\"-----DECRYPTED-----\")\n\tfmt.Println(decrypted)\n\tfmt.Println(\"-----ENCRYPTED-----\")\n\tfmt.Println(\"encrypted\", encrypted)\n\tfmt.Println(\"len\", len(encrypted))\n\tfmt.Println(\"string\", string(encrypted))\n\tfmt.Println(\"nonce\", nonce)\n\tfmt.Println(\"nonce\", nonce[:])\n\tfmt.Printf(\"%x:%x \\n\", nonce[:], encrypted)\n}\n"
  },
  {
    "path": "27_code-in-process/62_self-destructing-message/02_crypto/03_decrypt/main.go",
    "content": "package main\n\nimport (\n\t\"crypto/rand\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"golang.org/x/crypto/nacl/secretbox\"\n\t\"io\"\n\t\"strings\"\n)\n\nfunc main() {\n\tdecrypted := \"some message that you want to store / send securely\"\n\tfmt.Println(\"BEFORE ENCRYPTION:\", decrypted)\n\n\tvar nonce [24]byte\n\tio.ReadAtLeast(rand.Reader, nonce[:], 24)\n\tvar password [32]byte\n\tio.ReadAtLeast(rand.Reader, password[:], 32)\n\tencrypted := secretbox.Seal(nil, []byte(decrypted), &nonce, &password)\n\t// fmt.Printf(\"%T \\n\", encrypted)\n\tenHex := fmt.Sprintf(\"%x:%x\", nonce[:], encrypted)\n\tfmt.Println(\"ENCRYPTED:\", enHex)\n\n\t// decrypt\n\tvar nonce2 [24]byte\n\tparts := strings.SplitN(enHex, \":\", 2)\n\tif len(parts) < 2 {\n\t\tfmt.Errorf(\"expected nonce\")\n\t}\n\t//get nonce\n\tbs, err := hex.DecodeString(parts[0])\n\tif err != nil || len(bs) != 24 {\n\t\tfmt.Errorf(\"invalid nonce\")\n\t}\n\tcopy(nonce2[:], bs)\n\t// get message\n\tbs, err = hex.DecodeString(parts[1])\n\tif err != nil {\n\t\tfmt.Errorf(\"invalid message\")\n\t}\n\t// you need the password to open the sealed secret box\n\tmsg, ok := secretbox.Open(nil, bs, &nonce2, &password)\n\tif !ok {\n\t\tfmt.Errorf(\"invalid message\")\n\t}\n\tfmt.Println(\"AFTER DECRYPTING:\", string(msg))\n}\n"
  },
  {
    "path": "27_code-in-process/62_self-destructing-message/02_crypto/04_complete/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/62_self-destructing-message/02_crypto/04_complete/routes.go",
    "content": "package selfdestruct\n\nimport (\n\t\"crypto/rand\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\t\"golang.org/x/crypto/nacl/secretbox\"\n\n\t\"github.com/nu7hatch/gouuid\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n\thttp.HandleFunc(\"/msg/\", handleMessage)\n}\n\nfunc encrypt(decrypted string, password [32]byte) string {\n\tvar nonce [24]byte\n\tio.ReadAtLeast(rand.Reader, nonce[:], 24)\n\tencrypted := secretbox.Seal(nil, []byte(decrypted), &nonce, &password)\n\treturn fmt.Sprintf(\"%x:%x\", nonce[:], encrypted)\n}\n\nfunc decrypt(encrypted string, password [32]byte) (string, error) {\n\tvar nonce [24]byte\n\tparts := strings.SplitN(encrypted, \":\", 2)\n\tif len(parts) < 2 {\n\t\treturn \"\", fmt.Errorf(\"expected nonce\")\n\t}\n\tbs, err := hex.DecodeString(parts[0])\n\tif err != nil || len(bs) != 24 {\n\t\treturn \"\", fmt.Errorf(\"invalid nonce\")\n\t}\n\tcopy(nonce[:], bs)\n\tbs, err = hex.DecodeString(parts[1])\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"invalid message\")\n\t}\n\tdecrypted, ok := secretbox.Open(nil, bs, &nonce, &password)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"invalid message\")\n\t}\n\treturn string(decrypted), nil\n}\n\nfunc generatePassword() [32]byte {\n\tvar password [32]byte\n\tio.ReadAtLeast(rand.Reader, password[:], 32)\n\treturn password\n}\n\n// create a message\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\n\t// form submit\n\tif req.Method == \"POST\" {\n\t\tmsg := req.FormValue(\"message\")\n\t\tsecretKey := generatePassword()\n\t\tencryptedMessage := encrypt(msg, secretKey)\n\n\t\tmessageKey, _ := uuid.NewV4()\n\t\t// store the message in memcache\n\t\titem := &memcache.Item{\n\t\t\tKey:   messageKey.String(),\n\t\t\tValue: []byte(encryptedMessage),\n\t\t}\n\t\terr := memcache.Add(ctx, item)\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <head>\n\n  </head>\n  <body>\n    Here is your self-destructing secret message ID:\n    <a href=\"/msg/`+messageKey.String()+`?secret=`+fmt.Sprintf(\"%x\", secretKey)+`\">`+messageKey.String()+`</a>\n    Send it to Peter Graves.\n    <p>The encrypted message:</p>\n    <p>`+encryptedMessage+`</p>\n  </body>\n</html>`)\n\t} else {\n\n\t\t// render the form\n\t\tio.WriteString(res, `<!DOCTYPE html>\n  <html>\n    <head>\n\n    </head>\n    <body>\n      <form method=\"POST\">\n        <label>Message:\n          <textarea name=\"message\"></textarea>\n        </label><br>\n        <input type=\"submit\">\n      </form>\n    </body>\n  </html>`)\n\t}\n\n}\n\n// return a message based on its id\nfunc handleMessage(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\t// get key from URL\n\tkey := strings.SplitN(req.URL.Path, \"/\", 3)[2]\n\t// get item from memcache\n\titem, err := memcache.Get(ctx, key)\n\tif err != nil {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\n\tvar secretKey [32]byte\n\tbs, err := hex.DecodeString(req.FormValue(\"secret\"))\n\tif err != nil || len(bs) != 32 {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\tcopy(secretKey[:], bs)\n\n\tmsg, err := decrypt(string(item.Value), secretKey)\n\tif err != nil {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\n\t// if this is the first time the message is viewed\n\tif item.Flags == 0 {\n\t\titem.Expiration = 30 * time.Second\n\t\titem.Flags = 1\n\t\tmemcache.Set(ctx, item)\n\t}\n\n\tres.Write([]byte(msg))\n}\n"
  },
  {
    "path": "27_code-in-process/63_GCS-filebrowser/README.txt",
    "content": "Go to\nconsole.developers.google.com/apis/credentials\n\nClick on\nAdd Credentials / Service Account\n\nCreate a\nJSON Key\n\nThen\nPut that JSON key into the root of your app\n\nAnd\nChange the code to access **YOUR** JSON key\n\nAnd also\nChange the app.YAML"
  },
  {
    "path": "27_code-in-process/63_GCS-filebrowser/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/63_GCS-filebrowser/routes.go",
    "content": "package filebrowser\n\nimport (\n\t\"html/template\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"google.golang.org/appengine\"\n)\n\nvar tpls *template.Template\n\nfunc init() {\n\ttpls = template.Must(template.ParseGlob(\"templates/*.html\"))\n\thttp.HandleFunc(\"/\", index)\n\thttp.HandleFunc(\"/browse/\", browse)\n}\n\nfunc index(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path != \"/\" {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\n\tctx := appengine.NewContext(req)\n\n\t// get session\n\tsession := getSession(ctx, req)\n\t// update session\n\tif req.Method == \"POST\" {\n\t\tsession.Bucket = req.FormValue(\"bucket\")\n\t\tsession.Credentials = req.FormValue(\"credentials\")\n\t\tputSession(ctx, res, session)\n\t\t// redirect to browse\n\t\thttp.Redirect(res, req, \"/browse/\", 302)\n\t\treturn\n\t}\n\n\terr := tpls.ExecuteTemplate(res, \"index.html\", nil)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t}\n}\n\ntype browseModel struct {\n\tBucket     string\n\tFolder     string\n\tFiles      []string\n\tSubFolders []string\n}\n\nfunc browse(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tsession := getSession(ctx, req)\n\n\t// if no bucket has been chosen\n\tif session.Bucket == \"\" {\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t\treturn\n\t}\n\n\tfolder := strings.SplitN(req.URL.Path, \"/\", 3)[2]\n\n\tif req.Method == \"POST\" {\n\t\tfile, hdr, err := req.FormFile(\"file\")\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t\terr = putFile(ctx, session.Bucket, folder+hdr.Filename, file)\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t}\n\n\t// list the bucket\n\tfiles, subfolders, err := listBucket(ctx, session.Bucket, folder)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tmodel := &browseModel{\n\t\tBucket:     session.Bucket,\n\t\tFolder:     folder,\n\t\tFiles:      files,\n\t\tSubFolders: subfolders,\n\t}\n\n\terr = tpls.ExecuteTemplate(res, \"browse.html\", model)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/63_GCS-filebrowser/session.go",
    "content": "package filebrowser\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"google.golang.org/appengine/memcache\"\n\n\t\"github.com/nu7hatch/gouuid\"\n\n\t\"golang.org/x/net/context\"\n)\n\ntype Session struct {\n\tID                  string\n\tBucket, Credentials string\n}\n\nfunc getSession(ctx context.Context, req *http.Request) Session {\n\tcookie, err := req.Cookie(\"sessionid\")\n\tif err != nil || cookie.Value == \"\" {\n\t\tsessionID, _ := uuid.NewV4()\n\t\tcookie = &http.Cookie{\n\t\t\tName:  \"sessionid\",\n\t\t\tValue: sessionID.String(),\n\t\t}\n\t}\n\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\titem = &memcache.Item{\n\t\t\tKey:   cookie.Value,\n\t\t\tValue: []byte(\"\"),\n\t\t}\n\t}\n\n\tvar session Session\n\tjson.Unmarshal(item.Value, &session)\n\tsession.ID = cookie.Value\n\treturn session\n}\n\nfunc putSession(ctx context.Context, res http.ResponseWriter, session Session) {\n\tbs, err := json.Marshal(session)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tmemcache.Set(ctx, &memcache.Item{\n\t\tKey:   session.ID,\n\t\tValue: bs,\n\t})\n\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:  \"sessionid\",\n\t\tValue: session.ID,\n\t})\n}\n"
  },
  {
    "path": "27_code-in-process/63_GCS-filebrowser/storage.go",
    "content": "package filebrowser\n\nimport (\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/cloud/storage\"\n\t\"io\"\n)\n\nfunc listBucket(ctx context.Context, bucketName, folder string) ([]string, []string, error) {\n\tclient, err := storage.NewClient(ctx)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tdefer client.Close()\n\n\tvar files, folders []string\n\n\tquery := &storage.Query{\n\t\tDelimiter: \"/\",\n\t\tPrefix:    folder,\n\t}\n\t// objs is *storage.Objects\n\tobjs, err := client.Bucket(bucketName).List(ctx, query)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tfor _, subfolder := range objs.Prefixes {\n\t\tfolders = append(folders, subfolder[len(folder):])\n\t}\n\n\tfor _, obj := range objs.Results {\n\t\tfiles = append(files, obj.Name)\n\t}\n\n\treturn files, folders, nil\n}\n\nfunc putFile(ctx context.Context, bucketName, fileName string, rdr io.Reader) error {\n\tclient, err := storage.NewClient(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer client.Close()\n\twriter := client.Bucket(bucketName).Object(fileName).NewWriter(ctx)\n\twriter.ACL = []storage.ACLRule{\n\t\t{storage.AllUsers, storage.RoleReader},\n\t}\n\tio.Copy(writer, rdr)\n\treturn writer.Close()\n}\n"
  },
  {
    "path": "27_code-in-process/63_GCS-filebrowser/templates/browse.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n   <meta charset=\"UTF-8\">\n   <title></title>\n   <style>\n       ul\n       {\n           list-style-type: none;\n       }\n\n   </style>\n</head>\n<body>\n  <h1>Bucket: {{.Bucket}}</h1>\n\n  <div class=\"files\">\n    <h2>Folder: {{.Folder}}</h2>\n    <ul>\n      <!-- Folders -->\n      {{range .SubFolders}}\n      <li>\n        <a href=\"{{.}}\">{{.}}</a>\n      </li>\n      {{end}}\n      <!-- Files -->\n      {{range .Files}}\n      <li>{{.}}</li>\n      {{end}}\n    </ul>\n  </div>\n\n  <form method=\"POST\" enctype=\"multipart/form-data\">\n    <label>File:\n      <input type=\"file\" name=\"file\">\n    </label>\n    <input type=\"submit\">\n  </form>\n\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/63_GCS-filebrowser/templates/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n   <meta charset=\"UTF-8\">\n   <title></title>\n   <style>\n       form {\n           max-width: 600px;\n       }\n       label {\n           display: flex;\n           flex-direction: column;\n       }\n   </style>\n</head>\n<body>\n<form action=\"/\" method=\"POST\">\n   <label>\n       Bucket:\n       <input type=\"text\" name=\"bucket\">\n   </label>\n   <label>\n       Credentials:\n       <textarea name=\"credentials\"\n                 id=\"credentials\"\n                 cols=\"30\"\n                 rows=\"10\"></textarea>\n   </label>\n   <input type=\"submit\">\n\n</form>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/64_csv-example/01/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/64_csv-example/01/routes.go",
    "content": "package csvexample\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleInput)\n\thttp.HandleFunc(\"/madoff\", handleOutput)\n}\n\nfunc handleInput(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <head></head>\n  <body>\n    <form method=\"GET\" action=\"/madoff\">\n      <label>Symbol #1:\n        <input type=\"text\" name=\"symbol1\">\n      </label>\n      <input type=\"submit\">\n    </form>\n  </body>\n</html>`)\n}\n\nfunc handleOutput(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\n\tsymbol1 := req.FormValue(\"symbol1\")\n\n\tgetData(ctx, symbol1)\n\n}\n"
  },
  {
    "path": "27_code-in-process/64_csv-example/01/stats.go",
    "content": "package csvexample\n\nimport (\n\t\"fmt\"\n\n\t\"google.golang.org/appengine/urlfetch\"\n\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine/log\"\n\t\"io/ioutil\"\n)\n\nfunc getData(ctx context.Context, symbol string) {\n\turl := fmt.Sprintf(\n\t\t\"http://real-chart.finance.yahoo.com/table.csv\"+\n\t\t\t\"?s=%s\"+\n\t\t\t\"&d=6\"+\n\t\t\t\"&e=1\"+\n\t\t\t\"&f=2015\"+\n\t\t\t\"&g=m\"+\n\t\t\t\"&a=6\"+\n\t\t\t\"&b=1\"+\n\t\t\t\"&c=1986\"+\n\t\t\t\"&ignore=.csv\",\n\t\tsymbol,\n\t)\n\tclient := urlfetch.Client(ctx)\n\n\tresult, err := client.Get(url)\n\tif err != nil {\n\t\treturn\n\t}\n\tdefer result.Body.Close()\n\n\tbs, _ := ioutil.ReadAll(result.Body)\n\tlog.Infof(ctx, \"RESULT: %v\", string(bs))\n}\n"
  },
  {
    "path": "27_code-in-process/64_csv-example/02/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/64_csv-example/02/routes.go",
    "content": "package csvexample\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleInput)\n\thttp.HandleFunc(\"/madoff\", handleOutput)\n}\n\nfunc handleInput(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <head></head>\n  <body>\n    <form method=\"GET\" action=\"/madoff\">\n      <label>Symbol #1:\n        <input type=\"text\" name=\"symbol1\">\n      </label>\n      <label>Symbol #2:\n        <input type=\"text\" name=\"symbol2\">\n      </label>\n      <input type=\"submit\">\n    </form>\n  </body>\n</html>`)\n}\n\nfunc handleOutput(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\n\tsymbol1, symbol2 := req.FormValue(\"symbol1\"), req.FormValue(\"symbol2\")\n\n\tdata1, err := getData(ctx, symbol1)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tdata2, err := getData(ctx, symbol2)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tdata1json, _ := json.Marshal(data1)\n\tdata2json, _ := json.Marshal(data2)\n\n\tc := correlation(data1, data2)\n\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <head>\n    <script src=\"//cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.js\"></script>\n  </head>\n  <body>\n    <canvas id=\"myChart\" width=\"400\" height=\"400\"></canvas>\n\n\n    SYMBOL 1: `+symbol1+`<br>\n    SYMBOL 2: `+symbol2+`<br>\n    CORRELATION: <strong>`+fmt.Sprintf(\"%.4f\", c)+`</strong>\n\n    <script>\nvar ctx = document.getElementById(\"myChart\").getContext(\"2d\");\nvar myNewChart = new Chart(ctx).Line({\n  labels: [\n  \"January\",\"February\"\n  ],\n  datasets: [\n    {\n      label: \"`+symbol1+`\",\n      fillColor: \"rgba(220,220,220,0.2)\",\n      strokeColor: \"rgba(220,220,220,1)\",\n      pointColor: \"rgba(220,220,220,1)\",\n      pointStrokeColor: \"#fff\",\n      pointHighlightFill: \"#fff\",\n      pointHighlightStroke: \"rgba(220,220,220,1)\",\n      data: `+string(data1json)+`\n    },\n    {\n      label: \"`+symbol2+`\",\n      fillColor: \"rgba(151,187,205,0.2)\",\n      strokeColor: \"rgba(151,187,205,1)\",\n      pointColor: \"rgba(151,187,205,1)\",\n      pointStrokeColor: \"#fff\",\n      pointHighlightFill: \"#fff\",\n      pointHighlightStroke: \"rgba(151,187,205,1)\",\n      data: `+string(data2json)+`\n    }\n  ]\n}, null);\n    </script>\n  </body>\n</html>\n`)\n\n}\n"
  },
  {
    "path": "27_code-in-process/64_csv-example/02/stats.go",
    "content": "package csvexample\n\nimport (\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n\n\t\"google.golang.org/appengine/urlfetch\"\n\n\t\"golang.org/x/net/context\"\n)\n\nfunc correlation(xs, ys []float64) float64 {\n\treturn covariance(xs, ys) / (standardDeviation(xs) * standardDeviation(ys))\n}\n\nfunc covariance(x, y []float64) float64 {\n\tif len(x) != len(y) {\n\t\tpanic(\"Vector lengths must be the same\")\n\t}\n\n\tn := len(x)\n\tsum, xsum, xmean, ysum, ymean := 0.0, 0.0, 0.0, 0.0, 0.0\n\n\tfor i := 0; i < n; i++ {\n\t\txsum += x[i]\n\t\tysum += y[i]\n\t}\n\txmean = xsum / float64(n)\n\tymean = ysum / float64(n)\n\n\tfor i := 0; i < n; i++ {\n\t\tsum += (x[i] - xmean) * (y[i] - ymean)\n\t}\n\n\treturn sum / float64(n-1)\n}\n\nfunc getData(ctx context.Context, symbol string) ([]float64, error) {\n\turl := fmt.Sprintf(\n\t\t\"http://real-chart.finance.yahoo.com/table.csv\"+\n\t\t\t\"?s=%s\"+\n\t\t\t\"&d=6\"+\n\t\t\t\"&e=1\"+\n\t\t\t\"&f=2015\"+\n\t\t\t\"&g=m\"+\n\t\t\t\"&a=6\"+\n\t\t\t\"&b=1\"+\n\t\t\t\"&c=2014\"+\n\t\t\t\"&ignore=.csv\",\n\t\tsymbol,\n\t)\n\tclient := urlfetch.Client(ctx)\n\n\tresult, err := client.Get(url)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer result.Body.Close()\n\n\t// parse the csv file\n\treader := csv.NewReader(result.Body)\n\trecords, err := reader.ReadAll()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// convert the rows to floats\n\tconst (\n\t\tdateColumn  = 0\n\t\tcloseColumn = 4\n\t)\n\tvar data []float64\n\tfor i, row := range records {\n\t\tif i == 0 || len(row) < 5 {\n\t\t\tcontinue\n\t\t}\n\t\tval, _ := strconv.ParseFloat(row[closeColumn], 64)\n\t\tdata = append(data, val)\n\t}\n\treturn relativize(data), nil\n}\n\nfunc standardDeviation(xs []float64) float64 {\n\treturn math.Sqrt(variance(xs))\n}\n\nfunc variance(vector []float64) float64 {\n\tn := 0.0\n\tmean := 0.0\n\tS := 0.0\n\tdelta := 0.0\n\n\tfor _, v := range vector {\n\t\tn++\n\t\tdelta = v - mean\n\t\tmean = mean + (delta / n)\n\t\tS += delta * (v - mean)\n\t}\n\n\treturn S / (n - 1)\n}\n\nfunc relativize(data []float64) []float64 {\n\tnv := make([]float64, len(data)-1)\n\tfor i := 1; i < len(data); i++ {\n\t\tnv[i-1] = (data[i] - data[i-1]) / data[i-1]\n\t}\n\treturn nv\n}\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/01_basic-setup/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/01_basic-setup/routes.go",
    "content": "package stripeexample\n\nimport (\n\t\"net/http\"\n\n\t\"html/template\"\n)\n\nvar tpls *template.Template\n\nfunc init() {\n\ttpls = template.Must(template.ParseGlob(\"templates/*.gohtml\"))\n\thttp.HandleFunc(\"/\", handleIndex)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\ttpls.ExecuteTemplate(res, \"index.gohtml\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/01_basic-setup/templates/index.gohtml",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Guaranteed Investments</title>\n  </head>\n  <body>\n    <h1>Guaranteed Investments</h1>\n    <p>\n      Invest with us and get a free box of cookies.\n    </p>\n    <form action=\"\" method=\"POST\">\n        <script\n                src=\"https://checkout.stripe.com/checkout.js\" class=\"stripe-button\"\n                data-key=\"pk_test_4K9M7SfBD4eU1mcrEZgn7HAA\"\n                data-amount=\"2000\"\n                data-name=\"Demo Site\"\n                data-description=\"2 widgets ($20.00)\"\n                data-image=\"/128x128.png\"\n                data-locale=\"auto\">\n        </script>\n    </form>\n  </body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/02_customizing_UI/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/02_customizing_UI/routes.go",
    "content": "package stripeexample\n\nimport (\n\t\"net/http\"\n\n\t\"html/template\"\n)\n\nvar tpls *template.Template\n\nfunc init() {\n\ttpls = template.Must(template.ParseGlob(\"templates/*.gohtml\"))\n\thttp.HandleFunc(\"/\", handleIndex)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path == \"/minions.jpg\" {\n\t\thttp.ServeFile(res, req, \"minions.jpg\")\n\t\treturn\n\t}\n\ttpls.ExecuteTemplate(res, \"index.gohtml\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/02_customizing_UI/templates/index.gohtml",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Guaranteed Investments</title>\n  </head>\n  <body>\n    <h1>Guaranteed Investments</h1>\n    <p>\n      Invest with us and get a free box of cookies.\n    </p>\n    <form action=\"\" method=\"POST\">\n        <script\n                src=\"https://checkout.stripe.com/checkout.js\" class=\"stripe-button\"\n                data-key=\"pk_test_4K9M7SfBD4eU1mcrEZgn7HAA\"\n                data-amount=\"20000000\"\n                data-name=\"Guaranteed Investments\"\n                data-description=\"High Returns\"\n                data-image=\"/minions.jpg\"\n                data-locale=\"auto\">\n        </script>\n    </form>\n  </body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/03_stripe-token/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/03_stripe-token/routes.go",
    "content": "package stripeexample\n\nimport (\n\t\"net/http\"\n\n\t\"fmt\"\n\t\"html/template\"\n)\n\nvar tpls *template.Template\n\nfunc init() {\n\ttpls = template.Must(template.ParseGlob(\"templates/*.gohtml\"))\n\thttp.HandleFunc(\"/\", handleIndex)\n\thttp.HandleFunc(\"/payment\", handlePayment)\n\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path == \"/minions.jpg\" {\n\t\thttp.ServeFile(res, req, \"minions.jpg\")\n\t\treturn\n\t}\n\ttpls.ExecuteTemplate(res, \"index.gohtml\", nil)\n}\n\nfunc handlePayment(res http.ResponseWriter, req *http.Request) {\n\tif req.Method != \"POST\" {\n\t\thttp.Error(res, \"Method Not Allowed\", http.StatusMethodNotAllowed)\n\t\treturn\n\t}\n\tstripeToken := req.FormValue(\"stripeToken\")\n\tfmt.Fprintln(res, stripeToken)\n\n}\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/03_stripe-token/templates/index.gohtml",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Guaranteed Investments</title>\n  </head>\n  <body>\n    <h1>Guaranteed Investments</h1>\n    <p>\n      Invest with us and get a free box of cookies.\n    </p>\n    <form action=\"/payment\" method=\"POST\">\n        <script\n                src=\"https://checkout.stripe.com/checkout.js\" class=\"stripe-button\"\n                data-key=\"pk_test_4K9M7SfBD4eU1mcrEZgn7HAA\"\n                data-amount=\"20000000\"\n                data-name=\"Guaranteed Investments\"\n                data-description=\"High Returns\"\n                data-image=\"/minions.jpg\"\n                data-locale=\"auto\">\n        </script>\n    </form>\n  </body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/04_err-because-of-app-engine/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/04_err-because-of-app-engine/routes.go",
    "content": "package stripeexample\n\nimport (\n\t\"net/http\"\n\n\t\"fmt\"\n\t\"google.golang.org/appengine\"\n\t\"html/template\"\n)\n\nvar tpls *template.Template\n\nfunc init() {\n\ttpls = template.Must(template.ParseGlob(\"templates/*.gohtml\"))\n\thttp.HandleFunc(\"/\", handleIndex)\n\thttp.HandleFunc(\"/payment\", handlePayment)\n\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path == \"/minions.jpg\" {\n\t\thttp.ServeFile(res, req, \"minions.jpg\")\n\t\treturn\n\t}\n\ttpls.ExecuteTemplate(res, \"index.gohtml\", nil)\n}\n\nfunc handlePayment(res http.ResponseWriter, req *http.Request) {\n\tif req.Method != \"POST\" {\n\t\thttp.Error(res, \"Method Not Allowed\", http.StatusMethodNotAllowed)\n\t\treturn\n\t}\n\tctx := appengine.NewContext(req)\n\tstripeToken := req.FormValue(\"stripeToken\")\n\terr := chargeAccount(ctx, stripeToken)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tfmt.Fprintln(res, \"Thank You for the Money Sucka\")\n\n}\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/04_err-because-of-app-engine/stripe.go",
    "content": "package stripeexample\n\nimport (\n\t\"github.com/stripe/stripe-go\"\n\t\"github.com/stripe/stripe-go/charge\"\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine/log\"\n)\n\nfunc init() {\n\tstripe.Key = \"sk_test_8bZtX27RlHVMwe0YexxgBB1s\"\n}\n\nfunc chargeAccount(ctx context.Context, stripeToken string) error {\n\tchargeParams := &stripe.ChargeParams{\n\t\tAmount:   100 * 200000,\n\t\tCurrency: \"usd\",\n\t\tDesc:     \"Charge for test@example.com\",\n\t}\n\tchargeParams.SetSource(stripeToken)\n\tch, err := charge.New(chargeParams)\n\tif err != nil {\n\t\treturn err\n\t}\n\tlog.Infof(ctx, \"CHARGE: %v\", ch)\n\treturn nil\n}\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/04_err-because-of-app-engine/templates/index.gohtml",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Guaranteed Investments</title>\n  </head>\n  <body>\n    <h1>Guaranteed Investments</h1>\n    <p>\n      Invest with us and get a free box of cookies.\n    </p>\n    <form action=\"/payment\" method=\"POST\">\n        <script\n                src=\"https://checkout.stripe.com/checkout.js\" class=\"stripe-button\"\n                data-key=\"pk_test_4K9M7SfBD4eU1mcrEZgn7HAA\"\n                data-amount=\"20000000\"\n                data-name=\"Guaranteed Investments\"\n                data-description=\"High Returns\"\n                data-image=\"/minions.jpg\"\n                data-locale=\"auto\">\n        </script>\n    </form>\n  </body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/05_charging/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/05_charging/routes.go",
    "content": "package stripeexample\n\nimport (\n\t\"net/http\"\n\n\t\"fmt\"\n\t\"google.golang.org/appengine\"\n\t\"html/template\"\n)\n\nvar tpls *template.Template\n\nfunc init() {\n\ttpls = template.Must(template.ParseGlob(\"templates/*.gohtml\"))\n\thttp.HandleFunc(\"/\", handleIndex)\n\thttp.HandleFunc(\"/payment\", handlePayment)\n\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path == \"/minions.jpg\" {\n\t\thttp.ServeFile(res, req, \"minions.jpg\")\n\t\treturn\n\t}\n\ttpls.ExecuteTemplate(res, \"index.gohtml\", nil)\n}\n\nfunc handlePayment(res http.ResponseWriter, req *http.Request) {\n\tif req.Method != \"POST\" {\n\t\thttp.Error(res, \"Method Not Allowed\", http.StatusMethodNotAllowed)\n\t\treturn\n\t}\n\tctx := appengine.NewContext(req)\n\tstripeToken := req.FormValue(\"stripeToken\")\n\terr := chargeAccount(ctx, stripeToken)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tfmt.Fprintln(res, \"Thank You for the Money Sucka\")\n\n}\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/05_charging/stripe.go",
    "content": "package stripeexample\n\nimport (\n\t\"github.com/stripe/stripe-go\"\n\t\"github.com/stripe/stripe-go/charge\"\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/urlfetch\"\n)\n\nfunc init() {\n\tstripe.Key = \"sk_test_8bZtX27RlHVMwe0YexxgBB1s\"\n}\n\nfunc chargeAccount(ctx context.Context, stripeToken string) error {\n\t// because we're on app engine, use a custom http client\n\t// this is being set globally, however\n\t// if we wanted to do it this way, we'd have to use a lock\n\t// https://youtu.be/KT4ki_ClX2A?t=1018\n\thc := urlfetch.Client(ctx)\n\tstripe.SetHTTPClient(hc)\n\tchargeParams := &stripe.ChargeParams{\n\t\tAmount:   100 * 200000,\n\t\tCurrency: \"usd\",\n\t\tDesc:     \"Charge for test@example.com\",\n\t}\n\tchargeParams.SetSource(stripeToken)\n\tch, err := charge.New(chargeParams)\n\tif err != nil {\n\t\treturn err\n\t}\n\tlog.Infof(ctx, \"CHARGE: %v\", ch)\n\treturn nil\n}\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/05_charging/templates/index.gohtml",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Guaranteed Investments</title>\n  </head>\n  <body>\n    <h1>Guaranteed Investments</h1>\n    <p>\n      Invest with us and get a free box of cookies.\n    </p>\n    <form action=\"/payment\" method=\"POST\">\n        <script\n                src=\"https://checkout.stripe.com/checkout.js\" class=\"stripe-button\"\n                data-key=\"pk_test_4K9M7SfBD4eU1mcrEZgn7HAA\"\n                data-amount=\"20000000\"\n                data-name=\"Guaranteed Investments\"\n                data-description=\"High Returns\"\n                data-image=\"/minions.jpg\"\n                data-locale=\"auto\">\n        </script>\n    </form>\n  </body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/06_idempotent/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/06_idempotent/routes.go",
    "content": "package stripeexample\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n\n\t\"html/template\"\n)\n\nvar tpls *template.Template\n\nfunc init() {\n\ttpls = template.Must(template.ParseGlob(\"templates/*.gohtml\"))\n\thttp.HandleFunc(\"/\", handleIndex)\n\thttp.HandleFunc(\"/payment\", handlePayment)\n}\n\nfunc handlePayment(res http.ResponseWriter, req *http.Request) {\n\tif req.Method != \"POST\" {\n\t\thttp.Error(res, \"Method Not Allowed\", http.StatusMethodNotAllowed)\n\t\treturn\n\t}\n\tctx := appengine.NewContext(req)\n\tstripeToken := req.FormValue(\"stripeToken\")\n\terr := chargeAccount(ctx, stripeToken)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tfmt.Fprintln(res, \"Thank You for the Money Sucka\")\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path == \"/minions.jpg\" {\n\t\thttp.ServeFile(res, req, \"minions.jpg\")\n\t\treturn\n\t}\n\ttpls.ExecuteTemplate(res, \"index.gohtml\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/06_idempotent/stripe.go",
    "content": "package stripeexample\n\nimport (\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/nu7hatch/gouuid\"\n\t\"github.com/stripe/stripe-go\"\n\t\"github.com/stripe/stripe-go/charge\"\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/urlfetch\"\n)\n\nfunc init() {\n\tstripe.Key = \"sk_test_oh4N9TLop9gVlVQ1N05IGamg\"\n}\n\nfunc chargeAccount(ctx context.Context, stripeToken string) error {\n\t// because we're on app engine, use a custom http client\n\t// this is being set globally, however\n\t// if we wanted to do it this way, we'd have to use a lock\n\t// https://youtu.be/KT4ki_ClX2A?t=1018\n\thc := urlfetch.Client(ctx)\n\tstripe.SetHTTPClient(hc)\n\n\tid, _ := uuid.NewV4()\n\n\tfor {\n\t\tchargeParams := &stripe.ChargeParams{\n\t\t\tAmount:   100 * 200000,\n\t\t\tCurrency: \"usd\",\n\t\t\tDesc:     \"Charge for test@example.com\",\n\t\t}\n\t\tchargeParams.IdempotencyKey = id.String()\n\t\tchargeParams.SetSource(stripeToken)\n\t\tch, err := charge.New(chargeParams)\n\t\t// https://youtu.be/KT4ki_ClX2A?t=1310\n\t\tif err != nil {\n\t\t\tif nerr, ok := err.(net.Error); ok && nerr.Temporary() {\n\t\t\t\ttime.Sleep(time.Second)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t\tlog.Infof(ctx, \"CHARGE: %v\", ch)\n\t\tlog.Infof(ctx, \"IDEMPOTENCY: %v\", chargeParams.IdempotencyKey)\n\t\treturn nil\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/06_idempotent/templates/index.gohtml",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Guaranteed Investments</title>\n  </head>\n  <body>\n    <h1>Guaranteed Investments</h1>\n    <p>\n      Invest with us and get a free box of cookies.\n    </p>\n    <form action=\"/payment\" method=\"POST\">\n      <script\n        src=\"https://checkout.stripe.com/checkout.js\" class=\"stripe-button\"\n        data-key=\"pk_test_G3cgqRLDvnf48gKZLo2WTvp5\"\n        data-amount=\"20000000\"\n        data-name=\"Guaranteed Investments\"\n        data-description=\"High Returns\"\n        data-image=\"/minions.jpg\">\n      </script>\n    </form>\n  </body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/07_complete/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/07_complete/routes.go",
    "content": "package stripeexample\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n\n\t\"html/template\"\n)\n\nvar tpls *template.Template\n\nfunc init() {\n\ttpls = template.Must(template.ParseGlob(\"templates/*.gohtml\"))\n\thttp.HandleFunc(\"/\", handleIndex)\n\thttp.HandleFunc(\"/payment\", handlePayment)\n}\n\nfunc handlePayment(res http.ResponseWriter, req *http.Request) {\n\tif req.Method != \"POST\" {\n\t\thttp.Error(res, \"Method Not Allowed\", http.StatusMethodNotAllowed)\n\t\treturn\n\t}\n\tctx := appengine.NewContext(req)\n\tstripeToken := req.FormValue(\"stripeToken\")\n\terr := chargeAccount(ctx, stripeToken)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tfmt.Fprintln(res, \"Thank You for the Money Sucka\")\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path == \"/minions.jpg\" {\n\t\thttp.ServeFile(res, req, \"minions.jpg\")\n\t\treturn\n\t}\n\ttpls.ExecuteTemplate(res, \"index.gohtml\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/07_complete/stripe.go",
    "content": "package stripeexample\n\nimport (\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/nu7hatch/gouuid\"\n\t\"github.com/stripe/stripe-go\"\n\t\"github.com/stripe/stripe-go/charge\"\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/urlfetch\"\n)\n\nfunc init() {\n\tstripe.Key = \"sk_test_oh4N9TLop9gVlVQ1N05IGamg\"\n}\n\nfunc chargeAccount(ctx context.Context, stripeToken string) error {\n\t// because we're on app engine, use a custom http client\n\tb := stripe.BackendConfiguration{\n\t\tstripe.APIBackend,\n\t\t\"https://api.stripe.com/v1\",\n\t\turlfetch.Client(ctx),\n\t}\n\n\tid, _ := uuid.NewV4()\n\n\tfor {\n\t\tchargeParams := &stripe.ChargeParams{\n\t\t\tAmount:   100 * 200000,\n\t\t\tCurrency: \"usd\",\n\t\t\tDesc:     \"Charge for test@example.com\",\n\t\t}\n\t\tchargeParams.IdempotencyKey = id.String()\n\t\tchargeParams.SetSource(stripeToken)\n\t\tchargeClient := &charge.Client{\n\t\t\tKey: stripe.Key,\n\t\t\tB:   b,\n\t\t}\n\t\tch, err := chargeClient.New(chargeParams)\n\t\tif err != nil {\n\t\t\tif nerr, ok := err.(net.Error); ok && nerr.Temporary() {\n\t\t\t\ttime.Sleep(time.Second)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t\tlog.Infof(ctx, \"CHARGE: %v\", ch)\n\t\treturn nil\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/65_accepting-credit-cards/07_complete/templates/index.gohtml",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Guaranteed Investments</title>\n  </head>\n  <body>\n    <h1>Guaranteed Investments</h1>\n    <p>\n      Invest with us and get a free box of cookies.\n    </p>\n    <form action=\"/payment\" method=\"POST\">\n      <script\n        src=\"https://checkout.stripe.com/checkout.js\" class=\"stripe-button\"\n        data-key=\"pk_test_G3cgqRLDvnf48gKZLo2WTvp5\"\n        data-amount=\"20000000\"\n        data-name=\"Guaranteed Investments\"\n        data-description=\"High Returns\"\n        data-image=\"/minions.jpg\">\n      </script>\n    </form>\n  </body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/01_app-engine-auth_REVIEW/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /admin/.*\n  script: _go_app\n  login: admin\n- url: /.*\n  script: _go_app\n  login: required\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/01_app-engine-auth_REVIEW/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/user\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", index)\n\thttp.HandleFunc(\"/admin/\", admin)\n}\n\nfunc index(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\turl, _ := user.LogoutURL(ctx, \"/\")\n\tres.Header().Set(\"Content-Type\", \"text/html\")\n\tfmt.Fprintf(res, `Welcome, %s! <br>`, u.Email)\n\tfmt.Fprintf(res, `You are admin: %v  <br>`, u.Admin)\n\tif u.Admin {\n\t\tfmt.Fprint(res, `(<a href=\"/admin\">go to admin</a>) <br>`)\n\t}\n\tfmt.Fprintf(res, `(<a href=\"%s\">sign out</a>)`, url)\n}\n\nfunc admin(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\turl, _ := user.LogoutURL(ctx, \"/\")\n\tres.Header().Set(\"Content-Type\", \"text/html\")\n\tfmt.Fprintf(res, `Welcome ADMIN, %s! <br>`, u.Email)\n\tfmt.Fprintf(res, `(<a href=\"%s\">sign out</a>)`, url)\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/01_cookie_REVIEW/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/\", foo)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n\nfunc foo(res http.ResponseWriter, req *http.Request) {\n\n\tcookie, err := req.Cookie(\"logged-in\")\n\n\t// no cookie\n\tif err == http.ErrNoCookie {\n\t\tcookie = &http.Cookie{\n\t\t\tName:  \"logged-in\",\n\t\t\tValue: \"0\",\n\t\t}\n\t}\n\n\t// check log in: password entered == \"secret\"?\n\tif req.Method == \"POST\" {\n\t\tpassword := req.FormValue(\"password\")\n\t\tif password == \"secret\" {\n\t\t\tcookie = &http.Cookie{\n\t\t\t\tName:  \"logged-in\",\n\t\t\t\tValue: \"1\",\n\t\t\t}\n\t\t}\n\t}\n\n\t// if logout, then logout and destroy cookie\n\tif req.URL.Path == \"/logout\" {\n\t\tcookie = &http.Cookie{\n\t\t\tName:   \"logged-in\",\n\t\t\tValue:  \"0\",\n\t\t\tMaxAge: -1,\n\t\t}\n\t}\n\n\thttp.SetCookie(res, cookie)\n\n\t// create string with html for response\n\tvar html string\n\n\t// not logged in\n\tif cookie.Value == strconv.Itoa(0) {\n\t\thtml = `\n\t\t\t<!DOCTYPE html>\n\t\t\t<html lang=\"en\">\n\t\t\t<head>\n\t\t\t\t<meta charset=\"UTF-8\">\n\t\t\t\t<title></title>\n\t\t\t</head>\n\t\t\t<body>\n\t\t\t<h1>LOG IN</h1>\n\t\t\t<form method=\"post\" action=\"/\">\n\t\t\t\t<h3>User name</h3>\n\t\t\t\t<input type=\"text\" name=\"userName\">\n\t\t\t\t<h3>Password</h3>\n\t\t\t\t<input type=\"text\" name=\"password\">\n\t\t\t\t<br>\n\t\t\t\t<input type=\"submit\">\n\t\t\t\t<input type=\"submit\" name=\"logout\" value=\"logout\">\n\t\t\t</form>\n\t\t\t</body>\n\t\t\t</html>`\n\t}\n\n\t// logged in\n\tif cookie.Value == strconv.Itoa(1) {\n\t\thtml = `\n\t\t\t<!DOCTYPE html>\n\t\t\t<html lang=\"en\">\n\t\t\t<head>\n\t\t\t\t<meta charset=\"UTF-8\">\n\t\t\t\t<title></title>\n\t\t\t</head>\n\t\t\t<body>\n\t\t\t<h1><a href=\"/logout\">LOG OUT</a></h1>\n\t\t\t</body>\n\t\t\t</html>`\n\t}\n\n\tio.WriteString(res, html)\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/02_gorilla_REVIEW_photo-blog/01_simple/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/gorilla/context\"\n\t\"github.com/gorilla/sessions\"\n\t\"io\"\n\t\"net/http\"\n)\n\nvar store = sessions.NewCookieStore([]byte(\"secret-password\"))\n\nfunc main() {\n\thttp.HandleFunc(\"/\", foo)\n\thttp.ListenAndServe(\":8080\", context.ClearHandler(http.DefaultServeMux))\n}\n\nfunc foo(res http.ResponseWriter, req *http.Request) {\n\tsession, _ := store.Get(req, \"session\")\n\tif req.FormValue(\"email\") != \"\" {\n\t\tsession.Values[\"email\"] = req.FormValue(\"email\")\n\t}\n\tsession.Save(req, res)\n\n\tio.WriteString(res, `<!DOCTYPE html>\n\t<html>\n\t  <body>\n\t\t<form method=\"POST\">\n\t\t\t`+fmt.Sprint(session.Values[\"email\"])+`\n\t\t  <input type=\"email\" name=\"email\">\n\t\t  <input type=\"submit\">\n\t\t</form>\n\t  </body>\n\t</html>`)\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/02_gorilla_REVIEW_photo-blog/02_photo-blog/assets/templates/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n</head>\n<body>\n<h1><a href=\"/logout\">LOG OUT</a></h1>\n<p><img src=\"/assets/imgs/01.jpg\"></p>\n<h1>ADD PHOTO</h1>\n<form method=\"POST\" action=\"/\" enctype=\"multipart/form-data\">\n    <input type=\"file\" name=\"data\">\n    <input type=\"submit\">\n</form>\n<p>\n    {{range .}}\n    <img src=\"/assets/imgs/{{.}}\">\n    {{end}}\n</p>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/02_gorilla_REVIEW_photo-blog/02_photo-blog/assets/templates/login.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n</head>\n<body>\n<h1>LOG IN</h1>\n<form method=\"post\" action=\"http://localhost:8080/login\">\n    <h3>User name</h3>\n    <input type=\"text\" name=\"userName\" id=\"userName\">\n    <h3>Password</h3>\n    <input type=\"text\" name=\"password\" id=\"password\">\n    <br>\n    <input type=\"submit\">\n    <input type=\"submit\" name=\"logout\" value=\"logout\">\n</form>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/02_gorilla_REVIEW_photo-blog/02_photo-blog/main.go",
    "content": "package main\n\nimport (\n\t\"crypto/sha1\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/gorilla/context\"\n\t\"github.com/gorilla/sessions\"\n\t\"html/template\"\n\t\"io\"\n\t\"mime/multipart\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\nvar tpl *template.Template\nvar store = sessions.NewCookieStore([]byte(\"secret-password\"))\n\nfunc init() {\n\ttpl, _ = template.ParseGlob(\"assets/templates/*.html\")\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", index)\n\thttp.HandleFunc(\"/login\", login)\n\thttp.HandleFunc(\"/logout\", logout)\n\thttp.Handle(\"/assets/imgs/\", http.StripPrefix(\"/assets/imgs\", http.FileServer(http.Dir(\"./assets/imgs\"))))\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.ListenAndServe(\":8080\", context.ClearHandler(http.DefaultServeMux))\n}\n\nfunc index(res http.ResponseWriter, req *http.Request) {\n\tsession, _ := store.Get(req, \"session\")\n\t// authenticate\n\tif session.Values[\"loggedin\"] == \"false\" || session.Values[\"loggedin\"] == nil {\n\t\thttp.Redirect(res, req, \"/login\", 302)\n\t\treturn\n\t}\n\t// upload photo\n\tsrc, hdr, err := req.FormFile(\"data\")\n\tif req.Method == \"POST\" && err == nil {\n\t\tuploadPhoto(src, hdr, session)\n\t}\n\t// save session\n\tsession.Save(req, res)\n\t// get photos\n\tdata := getPhotos(session)\n\t// execute template\n\ttpl.ExecuteTemplate(res, \"index.html\", data)\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request) {\n\tsession, _ := store.Get(req, \"session\")\n\tsession.Values[\"loggedin\"] = \"false\"\n\tsession.Save(req, res)\n\thttp.Redirect(res, req, \"/login\", 302)\n}\n\nfunc login(res http.ResponseWriter, req *http.Request) {\n\tsession, _ := store.Get(req, \"session\")\n\tif req.Method == \"POST\" && req.FormValue(\"password\") == \"secret\" {\n\t\tsession.Values[\"loggedin\"] = \"true\"\n\t\tsession.Save(req, res)\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t\treturn\n\t}\n\t// execute template\n\ttpl.ExecuteTemplate(res, \"login.html\", nil)\n}\n\nfunc uploadPhoto(src multipart.File, hdr *multipart.FileHeader, session *sessions.Session) {\n\tdefer src.Close()\n\tfName := getSha(src) + \".jpg\"\n\twd, _ := os.Getwd()\n\tpath := filepath.Join(wd, \"assets\", \"imgs\", fName)\n\tdst, _ := os.Create(path)\n\tdefer dst.Close()\n\tsrc.Seek(0, 0)\n\tio.Copy(dst, src)\n\taddPhoto(fName, session)\n}\n\nfunc getSha(src multipart.File) string {\n\th := sha1.New()\n\tio.Copy(h, src)\n\treturn fmt.Sprintf(\"%x\", h.Sum(nil))\n}\n\nfunc addPhoto(fName string, session *sessions.Session) {\n\tdata := getPhotos(session)\n\tdata = append(data, fName)\n\tbs, _ := json.Marshal(data)\n\tsession.Values[\"data\"] = string(bs)\n}\n\nfunc getPhotos(session *sessions.Session) []string {\n\tvar data []string\n\tjsonData := session.Values[\"data\"]\n\tif jsonData != nil {\n\t\tjson.Unmarshal([]byte(jsonData.(string)), &data)\n\t}\n\treturn data\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/README.txt",
    "content": "ENCRYPT / HASH passwords\n- make your hash slow\n--- prevents brute force\n- salt your hash\n--- store your salt with your hash so you can use it\n--- each salt is unique to each password\n- Corey used bcrypt to do this:\ngolang.org/x/crypto/bcrypt\n- golang.org/x/ are maybe experimental projects made by google and not yet in standard library\n- you could also us a second salt, called a pepper sometimes\n-- this is a code unique to the whole website\n-- it's not stored with the passwords\nhttps://github.com/Saxleader/fall2015/tree/master/code-review_improvement\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/api.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"golang.org/x/crypto/bcrypt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc checkUserName(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tbs, err := ioutil.ReadAll(req.Body)\n\tsbs := string(bs)\n\tlog.Infof(ctx, \"REQUEST BODY: %v\", sbs)\n\tvar user User\n\tkey := datastore.NewKey(ctx, \"Users\", sbs, 0, nil)\n\terr = datastore.Get(ctx, key, &user)\n\t// if there is an err, there is NO user\n\tlog.Infof(ctx, \"ERR: %v\", err)\n\tif err != nil {\n\t\t// there is an err, there is a NO user\n\t\tfmt.Fprint(res, \"false\")\n\t\treturn\n\t} else {\n\t\tfmt.Fprint(res, \"true\")\n\t}\n}\n\nfunc createUser(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\thashedPass, err := bcrypt.GenerateFromPassword([]byte(req.FormValue(\"password\")), bcrypt.DefaultCost)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error creating password: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tuser := User{\n\t\tEmail:    req.FormValue(\"email\"),\n\t\tUserName: req.FormValue(\"userName\"),\n\t\tPassword: string(hashedPass),\n\t}\n\tkey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey, err = datastore.Put(ctx, key, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tcreateSession(res, req, user)\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc loginProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tkey := datastore.NewKey(ctx, \"Users\", req.FormValue(\"userName\"), 0, nil)\n\tvar user User\n\terr := datastore.Get(ctx, key, &user)\n\tif err != nil || bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.FormValue(\"password\"))) != nil {\n\t\t// failure logging in\n\t\tvar sd SessionData\n\t\tsd.LoginFail = true\n\t\ttpl.ExecuteTemplate(res, \"login.html\", sd)\n\t\treturn\n\t} else {\n\t\tuser.UserName = req.FormValue(\"userName\")\n\t\t// success logging in\n\t\tcreateSession(res, req, user)\n\t\t// redirect\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t}\n}\n\nfunc createSession(res http.ResponseWriter, req *http.Request, user User) {\n\tctx := appengine.NewContext(req)\n\t// SET COOKIE\n\tid, _ := uuid.NewV4()\n\tcookie := &http.Cookie{\n\t\tName:  \"session\",\n\t\tValue: id.String(),\n\t\tPath:  \"/\",\n\t\t// twenty minute session:\n\t\tMaxAge: 60 * 20,\n\t\t//\t\tUNCOMMENT WHEN DEPLOYED:\n\t\t//\t\tSecure: true,\n\t\t//\t\tHttpOnly: true,\n\t}\n\thttp.SetCookie(res, cookie)\n\n\t// SET MEMCACHE session data (sd)\n\tjson, err := json.Marshal(user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error marshalling during user creation: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd := memcache.Item{\n\t\tKey:   id.String(),\n\t\tValue: json,\n\t}\n\tmemcache.Set(ctx, &sd)\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\t// cookie is not set\n\tif err != nil {\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t\treturn\n\t}\n\n\t// clear memcache\n\tsd := memcache.Item{\n\t\tKey:        cookie.Value,\n\t\tValue:      []byte(\"\"),\n\t\tExpiration: time.Duration(1 * time.Microsecond),\n\t}\n\tmemcache.Set(ctx, &sd)\n\n\t// clear the cookie\n\tcookie.MaxAge = -1\n\thttp.SetCookie(res, cookie)\n\n\t// redirect\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc tweetProcess(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to post tweet from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// declare a variable of type tweet\n\t// initialize it with values\n\tlog.Infof(ctx, user.UserName)\n\ttweet := Tweet{\n\t\tMsg:      req.FormValue(\"tweet\"),\n\t\tTime:     time.Now(),\n\t\tUserName: user.UserName,\n\t}\n\t// put in datastore\n\terr = putTweet(req, &user, &tweet)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding todo: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// redirect\n\ttime.Sleep(time.Millisecond * 500) // This is not the best code, probably. Thoughts?\n\thttp.Redirect(res, req, \"/\", 302)\n}\n\nfunc follow(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t// get session\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to follow from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// get the datastore key for the follower\n\tfollowerKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\t// get a datastore key for the followee\n\tfolloweeKey := datastore.NewKey(ctx, \"Follows\", ps.ByName(\"user\"), 0, followerKey)\n\t// the follower is following the followee\n\t// put this into the datastore\n\t_, err = datastore.Put(ctx, followeeKey, &F{ps.ByName(\"user\"), user.UserName})\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error adding followee: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// send the \"you are being followed\" email\n\temailKey := datastore.NewKey(ctx, \"Users\", ps.ByName(\"user\"), 0, nil)\n\tvar u User\n\terr = datastore.Get(ctx, emailKey, &u)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting followee's email user data: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tfollowedEmail(res, req, u.Email)\n\t// return to user account\n\thttp.Redirect(res, req, \"/user/\"+ps.ByName(\"user\"), 302)\n}\n\nfunc unfollow(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t// get session\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to unfollow from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\t// declare a variable of type user\n\t// initialize user with values from memcache item\n\tvar user User\n\tjson.Unmarshal(memItem.Value, &user)\n\t// get the datastore key for the follower\n\tfollowerKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\t// get a datastore key for the followee\n\tfolloweeKey := datastore.NewKey(ctx, \"Follows\", ps.ByName(\"user\"), 0, followerKey)\n\t// delete entry in datastore\n\terr = datastore.Delete(ctx, followeeKey)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error deleting followee: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\thttp.Redirect(res, req, \"/user/\"+ps.ByName(\"user\"), 302)\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/app.yaml",
    "content": "application: twitmock-1012\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /form/.*\n  script: _go_app\n  secure: always\n- url: /.*\n  script: _go_app\n\n# order matters"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/doc.go",
    "content": "/*\nOur web app will be a micro-blogging site. It will only allow people to\nshare 140 characters of their thoughts per post. GL2U.\n\nAn example of a tweet could be:\n\nGOLANG WEB APP TRAININGS from Silicon Valley Code @sv_code_camp 1 of 2:\nhttps://youtu.be/qeREX9r20YQ 2 of 2: https://youtu.be/cIatklLmr5I\n\nLearn more about documenting your code:\nhttps://golang.org/doc/effective_go.html#commentary\nhttp://blog.golang.org/godoc-documenting-go-code\n\nUse the godoc command to see your documentation:\nhttps://godoc.org/golang.org/x/tools/cmd/godoc\n\nTry these godoc commands:\ngodoc .\ngodoc -http=:6060\n*/\npackage main\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/email.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/mail\"\n\t\"net/http\"\n)\n\nfunc followedEmail(w http.ResponseWriter, r *http.Request, email string) {\n\tctx := appengine.NewContext(r)\n\tmsg := &mail.Message{\n\t\tSender:  \"TwitClone Support <support@example.com>\",\n\t\tTo:      []string{email},\n\t\tSubject: \"You are being followed\",\n\t\tBody:    fmt.Sprintf(confirmMessage),\n\t}\n\tif err := mail.Send(ctx, msg); err != nil {\n\t\tlog.Errorf(ctx, \"Couldn't send email: %v\", err)\n\t}\n}\n\nconst confirmMessage = `\nSomeone is now following you. Don't say you didn't ask for it.\n`\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/following.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"net/http\"\n)\n\nfunc following(follower, followee string, req *http.Request) (bool, error) {\n\tctx := appengine.NewContext(req)\n\tuserKey := datastore.NewKey(ctx, \"Users\", follower, 0, nil)\n\tx, err := datastore.NewQuery(\"Follows\").Ancestor(userKey).Filter(\"Following =\", followee).Count(ctx)\n\treturn x > 0, err\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/index.yaml",
    "content": "indexes:\n\n# AUTOGENERATED\n\n# This index.yaml is automatically updated whenever the dev_appserver\n# detects that a new type of query is run.  If you want to manage the\n# index.yaml file manually, remove the above marker line (the line\n# saying \"# AUTOGENERATED\").  If you want to manage some indexes\n# manually, move them above the marker line.  The index.yaml file is\n# automatically uploaded to the admin console when you next deploy\n# your application using appcfg.py.\n\n- kind: Follows\n  ancestor: yes\n  properties:\n  - name: Follower\n\n- kind: Follows\n  ancestor: yes\n  properties:\n  - name: Following\n\n- kind: Tweets\n  ancestor: yes\n  properties:\n  - name: Time\n    direction: desc\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"html/template\"\n\t\"net/http\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\tr := httprouter.New()\n\thttp.Handle(\"/\", r)\n\tr.GET(\"/\", home)\n\tr.GET(\"/following\", fing)\n\tr.GET(\"/followingme\", fingme)\n\tr.GET(\"/user/:user\", user)\n\tr.GET(\"/form/login\", login)\n\tr.GET(\"/form/signup\", signup)\n\tr.POST(\"/api/checkusername\", checkUserName)\n\tr.POST(\"/api/createuser\", createUser)\n\tr.POST(\"/api/login\", loginProcess)\n\tr.POST(\"/api/tweet\", tweetProcess)\n\tr.GET(\"/api/logout\", logout)\n\tr.GET(\"/api/follow/:user\", follow)\n\tr.GET(\"/api/unfollow/:user\", unfollow)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.Handle(\"/public/\", http.StripPrefix(\"/public\", http.FileServer(http.Dir(\"public/\"))))\n\n\ttpl = template.New(\"roottemplate\")\n\ttpl = tpl.Funcs(template.FuncMap{\n\t\t\"humanize_time\": humanize.Time,\n\t})\n\n\ttpl = template.Must(tpl.ParseGlob(\"templates/html/*.html\"))\n}\n\nfunc home(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t//get tweets\n\ttweets, err := getTweets(req, nil)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting tweets: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// get session\n\tmemItem, err := getSession(req)\n\tvar sd SessionData\n\tif err == nil {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t}\n\tsd.Tweets = tweets\n\ttpl.ExecuteTemplate(res, \"home.html\", &sd)\n}\n\nfunc user(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tuser := User{UserName: ps.ByName(\"user\")}\n\t//get tweets\n\ttweets, err := getTweets(req, &user)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting tweets: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\t// get session\n\tmemItem, err := getSession(req)\n\tvar sd SessionData\n\tif err == nil {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t\tsd.ViewingUser = user.UserName\n\t\tsd.FollowingUser, err = following(sd.UserName, user.UserName, req)\n\t\tif err != nil {\n\t\t\tlog.Errorf(ctx, \"error running following query: %v\", err)\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t}\n\tsd.Tweets = tweets\n\ttpl.ExecuteTemplate(res, \"user.html\", &sd)\n}\n\nfunc fing(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t// get session\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to see following from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\tvar sd SessionData\n\tif err == nil {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t}\n\t// Get followees\n\t// get the datastore key for the follower\n\tfollowerKey := datastore.NewKey(ctx, \"Users\", sd.UserName, 0, nil)\n\tvar XF []F\n\t_, err = datastore.NewQuery(\"Follows\").Ancestor(followerKey).Project(\"Following\").GetAll(ctx, &XF)\n\tlog.Infof(ctx, \"here is type %T \\n and value %v\", XF, XF)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting followees: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd.Following = XF\n\ttpl.ExecuteTemplate(res, \"follow.html\", &sd)\n}\n\nfunc fingme(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\t// get session\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\tlog.Infof(ctx, \"Attempt to see followingme from logged out user\")\n\t\thttp.Error(res, \"You must be logged in\", http.StatusForbidden)\n\t\treturn\n\t}\n\tvar sd SessionData\n\tif err == nil {\n\t\t// logged in\n\t\tjson.Unmarshal(memItem.Value, &sd)\n\t\tsd.LoggedIn = true\n\t}\n\t// get those who are following this user\n\tvar XF []F\n\t_, err = datastore.NewQuery(\"Follows\").Filter(\"Following =\", sd.UserName).GetAll(ctx, &XF)\n\tlog.Errorf(ctx, \"here is type %T \\n and value %v\", XF, XF)\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"error getting followees: %v\", err)\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tsd.Following = XF\n\ttpl.ExecuteTemplate(res, \"followingme.html\", &sd)\n}\n\nfunc login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"login.html\")\n}\n\nfunc signup(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tserveTemplate(res, req, \"signup.html\")\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/model.go",
    "content": "package main\n\nimport \"time\"\n\ntype User struct {\n\tEmail    string\n\tUserName string `datastore:\"-\"`\n\tPassword string `json:\"-\"`\n}\n\ntype SessionData struct {\n\tUser\n\tLoggedIn      bool\n\tLoginFail     bool\n\tTweets        []Tweet\n\tViewingUser   string\n\tFollowingUser bool\n\tFollowing     []F\n}\n\ntype Tweet struct {\n\tMsg      string\n\tTime     time.Time\n\tUserName string\n}\n\ntype F struct {\n\tFollowing string\n\tFollower  string\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/public/css/login.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}\n\n#create-account {\n    color: #2ec371;\n    display: flex;\n    justify-content: center;\n    margin-top: 10px;\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/public/css/modal-tweet.css",
    "content": ".modalDialog {\n    position: fixed;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    background: rgba(255, 255, 255, 0.7);\n    z-index: 99999;\n    opacity:0;\n    -webkit-transition: opacity 400ms ease-in;\n    -moz-transition: opacity 400ms ease-in;\n    transition: opacity 400ms ease-in;\n    pointer-events: none;\n}\n.modalDialog:target {\n    opacity:1;\n    pointer-events: auto;\n}\n.modalDialog > div {\n    border: 4px solid #2ec371;\n    width: 70%;\n    position: relative;\n    margin: 10% auto;\n    padding: 5px 20px 13px 20px;\n    border-radius: 10px;\n    background: rgba(46, 195, 113, 0.6);\n}\n.modal-close {\n    border: 1px solid #2ec371;\n    background: #2ec371;\n    color: #FFFFFF;\n    line-height: 20px;\n    position: absolute;\n    right: 0px;\n    text-align: center;\n    top: 0px;\n    width: 24px;\n    text-decoration: none;\n    border-radius: 0px 6px 0px 4px;\n}\n.modal-close:hover {\n    background: #2ec371;\n}\n\n#modal-tweet {\n    width: 100%;\n    border-radius: 10px;\n    border: 1px solid #2ec371;\n    margin: 20px 0 0 0;\n    font-size: 40px;\n}\n\n#modal-submit {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n    margin: 15px 15px 0 0;\n    font-family: 'Lobster', cursive;\n    font-size: 25px;\n    background-color: #2ec371;\n}\n\n#modal-submit:hover {\n    background-color: #00acc1;\n}\n\n\n\n#modal-form {\n    display: flex;\n    flex-direction: column;\n    align-items: flex-end;\n}"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/public/css/reset.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/public/css/signup.css",
    "content": "form {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    border: 1px solid #2ec371;\n    border-radius: 4px;\n    padding: 20px;\n    background-color: #f3f3f3;\n    box-shadow: 0px 2px 2px 1px rgba(0, 0, 0, 0.2);\n    margin-top: 40px;\n}\n\n.fa-5x {\n    color: #2ec371;\n    border: 1px solid #2ec371;\n    border-radius: 100%;\n    padding: 15px;\n    margin-bottom: 10px;;\n}\n\ninput, button {\n    height: 40px;\n    width: 250px;\n    font-size: 16px;\n    margin: 4px 0;\n    padding: 10px;\n}\n\nbutton {\n    background-color: #2ec371;\n    border: 0px;\n    border-radius: 3px;\n    font-size: 14px;\n    color: #fff;\n}\n\n.form-field-err {\n    width: 250px;\n    text-align: left;\n    padding: 0 0 0 5px;\n    color: red;\n    font-size: 14px;\n}"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/public/css/styles.css",
    "content": "* {\n    box-sizing: border-box;\n    font-family: 'Open Sans', sans-serif;\n}\n\nbody {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #f5f5f5;\n}\n\n#top {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    background-color: #2ec371;\n    padding: 0 0 35px 0;\n    width: 100%\n}\n\nheader {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 25px 75px;\n    width: 100%;\n\n}\n\nheader nav {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n}\n\n.loginOut {\n    border: 1px solid #fff;\n    border-radius: 5px;\n    padding: 14px 28px;\n    font-size: 18px;\n    color: #fff;\n    margin-left: 10px;\n}\n\n.loginOut:hover {\n    background-color: #00acc1;\n}\n\na {\n    text-decoration: none;\n}\n\n.fa-heart-o {\n    color: #fff;\n}\n\n.fa-heart-o:hover {\n    color: #f00;\n}\n\n#motto {\n    font-family: 'Lobster', cursive;\n    font-size: 40px;\n    color: #f5f5f5;\n    text-align: center;\n    line-height: 47px;\n}\n\nmain {\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    padding: 4px 0 35px 0;\n    width: 100%;\n}\n\nsection {\n    display: flex;\n    justify-content: flex-start;\n    align-items: center;\n    border: 1px solid rgba(0, 0, 0, 0.19);\n    width: 60%;\n    padding: 10px;\n    margin: 4px;\n    background-color: #fff;\n}\n\n.post {\n    padding: 10px 10px 0 10px;\n}\n\n.post-meta {\n    font-size: 12px;\n    padding: 0;\n    border: 0;\n    margin: 2px 0 0 20px;\n}"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/session.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"net/http\"\n)\n\nfunc getSession(req *http.Request) (*memcache.Item, error) {\n\tctx := appengine.NewContext(req)\n\n\tcookie, err := req.Cookie(\"session\")\n\tif err != nil {\n\t\treturn &memcache.Item{}, err\n\t}\n\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\treturn &memcache.Item{}, err\n\t}\n\treturn item, nil\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/template.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n)\n\nfunc serveTemplate(res http.ResponseWriter, req *http.Request, templateName string) {\n\tmemItem, err := getSession(req)\n\tif err != nil {\n\t\t// not logged in\n\t\ttpl.ExecuteTemplate(res, templateName, SessionData{})\n\t\treturn\n\t}\n\t// logged in\n\tvar sd SessionData\n\tjson.Unmarshal(memItem.Value, &sd)\n\tsd.LoggedIn = true\n\ttpl.ExecuteTemplate(res, templateName, &sd)\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/templates/html/follow.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Following}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post-meta\">{{.Following}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/templates/html/followingme.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Following}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post-meta\">{{.Follower}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/templates/html/headersFooters.html",
    "content": "{{define \"header\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Twitter Mock</title>\n    <link rel=\"stylesheet\" href=\"/public/css/reset.css\">\n    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lobster|Open+Sans'>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css\">\n    <link rel=\"stylesheet\" href=\"/public/css/styles.css\">\n{{end}}\n\n{{define \"header2\"}}</head>\n<body>\n<div id=\"top\">\n    <header>\n        <a href=\"/\"><i class=\"fa fa-heart-o fa-3x\"></i></a>\n        <nav>\n            {{if .LoggedIn}}\n            {{template \"modal-tweet\"}}\n                {{if .ViewingUser}}\n                    {{if .FollowingUser}}\n                    <a href=\"/api/unfollow/{{.ViewingUser}}\"><p class=\"loginOut\">Unfollow</p></a>\n                    {{else}}\n                    <a href=\"/api/follow/{{.ViewingUser}}\"><p class=\"loginOut\">Follow</p></a>\n                    {{end}}\n                {{end}}\n            <a href=\"/api/logout\"><p class=\"loginOut\">Log Out</p></a>\n            {{else}}\n            <a href=\"/form/login\"><p class=\"loginOut\">Log In</p></a>\n            {{end}}\n        </nav>\n    </header>\n    <p id=\"motto\">Seven Deadly Sins</p>\n    <p id=\"motto\">One convenient location</p>\n</div>\n{{end}}\n\n    {{ define \"footer\" }}</body>\n</html>{{ end }}"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/templates/html/home.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Tweets}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post\">{{.Msg}}</p>\n            <p class=\"post-meta\">{{.UserName}}</p>\n            <p class=\"post-meta\">{{humanize_time .Time}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/templates/html/login.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/login.css\">\n{{template \"header2\" .}}\n    <form method=\"POST\" action=\"/api/login\">\n        <i class=\"fa fa-user fa-5x\"></i>\n        <input id=\"userName\" name=\"userName\" placeholder=\"Enter your user name\" autofocus>\n        <p class=\"form-field-err\"></p>\n        <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Enter your password\">\n        <p class=\"form-field-err\"></p>\n        <button>Submit</button>\n    </form>\n    <a href=\"/form/signup\" id=\"create-account\">Create account</a>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/templates/html/modal-tweet.html",
    "content": "{{ define \"modal-tweet\"}}\n<a href=\"#openModal\" id=\"opens-modal\"><p class=\"loginOut\">Tweet</p></a>\n\n<div id=\"openModal\" class=\"modalDialog\">\n    <div>\t<a href=\"#close\" title=\"Close\" class=\"modal-close\">X</a>\n        <form method=\"POST\" id=\"modal-form\" action=\"/api/tweet\">\n            <textarea name=\"tweet\" id=\"modal-tweet\" rows=\"4\" maxlength=\"140\"></textarea>\n            <input type=\"submit\" id=\"modal-submit\" value=\"Tweet\">\n        </form>\n    </div>\n</div>\n    {{end}}\n\n    {{ define \"modal-tweet-css\"}}\n    <link rel=\"stylesheet\" href=\"/public/css/modal-tweet.css\">\n    {{end}}"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/templates/html/signup.html",
    "content": "{{template \"header\"}}\n<link rel=\"stylesheet\" href=\"/public/css/signup.css\">\n{{template \"header2\" .}}\n<form method=\"POST\" action=\"/api/createuser\" id=\"form-create-user\">\n    <i class=\"fa fa-user fa-5x\"></i>\n    <input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Enter your email\" autofocus>\n    <p class=\"form-field-err\"></p>\n    <input id=\"userName\" name=\"userName\" placeholder=\"Enter a twitter name\" autocomplete=\"off\">\n    <p class=\"form-field-err\" id=\"username-err\"></p>\n    <input id=\"password\" name=\"password\" type=\"password\" placeholder=\"Create your password\">\n    <input id=\"password2\" name=\"password2\" type=\"password\" placeholder=\"Retype your password\">\n    <p class=\"form-field-err\" id=\"password-err\"></p>\n    <button id=\"btn-create-account\">Create Account</button>\n</form>\n<script>\n    var formUser = document.querySelector('#form-create-user');\n    var userName = document.querySelector('#userName');\n    var p1 = document.querySelector('#password');\n    var p2 = document.querySelector('#password2');\n    var btnSubmit = document.querySelector('#btn-create-account');\n\n    var nameErr = document.querySelector('#username-err');\n    var pErr = document.querySelector('#password-err');\n\n    //    username must be unique\n    userName.addEventListener('input', function(){\n        console.log(userName.value);\n        var xhr = new XMLHttpRequest();\n        xhr.open('POST', '/api/checkUserName');\n        xhr.send(userName.value);\n        xhr.addEventListener('readystatechange', function(){\n            if (xhr.readyState === 4) {\n                var item = xhr.responseText;\n                console.log(item);\n                if (item == 'true') {\n                    nameErr.textContent = 'Username taken - Try another name!';\n                } else {\n                    nameErr.textContent = '';\n                }\n            }\n        });\n    });\n\n    //    Validate passwords\n    //    listen for submit button click\n    formUser.addEventListener('submit', function(e){\n        var ok = validatePasswords();\n        if (!ok) {\n            e.preventDefault();\n            return;\n        }\n    });\n\n    function validatePasswords() {\n        pErr.textContent = '';\n        if (p1.value === '') {\n            pErr.textContent = 'Enter a password.';\n            return false;\n        }\n        if (p1.value !== p2.value) {\n            pErr.textContent = 'Your passwords did not match. Please re-enter your passwords.';\n            p1.value = '';\n            p2.value = '';\n            return false;\n        }\n        return true;\n    };\n</script>\n{{template \"footer\"}}"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/templates/html/user.html",
    "content": "{{template \"header\"}}\n{{template \"modal-tweet-css\"}}\n{{template \"header2\" .}}\n<main>\n    {{range .Tweets}}\n    <section>\n        <i class=\"fa fa-user fa-2x\"></i>\n        <div>\n            <p class=\"post\">{{.Msg}}</p>\n            <p class=\"post-meta\">{{.UserName}}</p>\n            <p class=\"post-meta\">{{humanize_time .Time}}</p>\n        </div>\n    </section>\n    {{end}}\n</main>\n{{template \"footer\"}}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/03_memcache_REVIEW_twitter/tweets.go",
    "content": "package main\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"net/http\"\n)\n\nfunc putTweet(req *http.Request, user *User, tweet *Tweet) error {\n\tctx := appengine.NewContext(req)\n\tuserKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\tkey := datastore.NewIncompleteKey(ctx, \"Tweets\", userKey)\n\t_, err := datastore.Put(ctx, key, tweet)\n\treturn err\n}\n\nfunc getTweets(req *http.Request, user *User) ([]Tweet, error) {\n\tctx := appengine.NewContext(req)\n\n\tvar tweets []Tweet\n\tq := datastore.NewQuery(\"Tweets\")\n\n\tif user != nil {\n\t\t// show tweets of a specific user\n\t\tuserKey := datastore.NewKey(ctx, \"Users\", user.UserName, 0, nil)\n\t\tq = q.Ancestor(userKey)\n\t}\n\n\tq = q.Order(\"-Time\").Limit(20)\n\t_, err := q.GetAll(ctx, &tweets)\n\treturn tweets, err\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/04_bcrypt/01/README.txt",
    "content": "https://godoc.org/golang.org/x/crypto/bcrypt#GenerateFromPassword"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/04_bcrypt/01/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"golang.org/x/crypto/bcrypt\"\n)\n\nfunc main() {\n\tp := \"mywifesnameandbirthday\"\n\tbs, _ := bcrypt.GenerateFromPassword([]byte(p), bcrypt.MinCost)\n\tfmt.Println(bs)\n\t//\tfmt.Println(string(bs))\n\tfmt.Printf(\"%X \\n\", bs)\n\n\terr := bcrypt.CompareHashAndPassword(bs, []byte(p))\n\tif err != nil {\n\t\tfmt.Println(\"Doesn't match\")\n\t} else {\n\t\tfmt.Println(\"match\")\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/02_manual-auth/04_bcrypt/02/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"golang.org/x/crypto/bcrypt\"\n)\n\nfunc main() {\n\tp := \"todd\"\n\tbs, _ := bcrypt.GenerateFromPassword([]byte(p), bcrypt.MinCost)\n\tfmt.Printf(\"PASSWORD ONE: %x \\n\", bs)\n\n\tp2 := \"todd\"\n\tbs2, _ := bcrypt.GenerateFromPassword([]byte(p2), bcrypt.MinCost)\n\tfmt.Printf(\"PASSWORD TWO: %x \\n\", bs2)\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/03_oauth-github/00_readme/README.txt",
    "content": "OAUTH\nhttps://en.wikipedia.org/wiki/OAuth\n\nGOLANG DOCs\nhttps://godoc.org/golang.org/x/oauth2\n\nGITHUB EXAMPLE\n\n(1)\nlearn about github oauth\nhttps://help.github.com/articles/connecting-with-third-party-applications/\n\n(2)\nthis is what we want to build - oauth like this\nhttps://forum.golangbridge.org/\nhttp://codepen.io/\nhttps://jsbin.com/\n\n(3)\ngithub oauth docs\nhttps://developer.github.com/v3/oauth/\nhttps://developer.github.com/v3/oauth/#web-application-flow\n\nEXAMPLE:\n(customized for my registered application, which we'll do next)\n--local development---\nhttps://github.com/login/oauth/authorize?client_id=fbbaa8ce5c394b7c3198&redirect_uri=http://localhost:8080/oauth2callback&state=233453423232\n--deployment---\nhttps://github.com/login/oauth/authorize?client_id=fbbaa8ce5c394b7c3198&redirect_uri=http://learning-1130.appspot.com/oauth2callback&state=233453423232\n\n(4)\nregister your application\nhttps://github.com/settings/applications/new\nsee pic_01.png, pic_02.png\n\n(5)\nRedirect users to request GitHub access\nhttps://developer.github.com/v3/oauth/#web-application-flow\n\n(6)\ncreate a callback to receive authorization code\n\n(7)\nexchange authorization code for an access token\n***AUTHORIZATION CODE***\n- the authorization code is the AUTHORIZATION FROM THE USER\n-- requires our github oauth api Client ID\n***ACCESS TOKEN***\n- the access token is the AUTHORIZATION OF THE APPLICATION\n-- requires our github oauth api Client Secret\n-- we wouldn't want to pass our Client Secret in the URL\n\nhttps://youtu.be/oxogqJiFVYI?t=2547\n\n(8)\nGet user information\nEMAIL EXAMPLE in code\n\n(9)\nApplication flow:\n- now that you have someone's VERIFIED email (github verifies emails)\n-- you can associate that email with a user's account on your site\n\n----\n\nXSFR\nhttps://en.wikipedia.org/wiki/Cross-site_request_forgery\n\nBank Example:\nSomeone is already logged into their bank\nBank uses GET (url) to send parameters\nHacker creates a url that transfers money to his account\nHacker puts that url in an img tag on web pages\nwhen people view that webpage, that img tag makes a GET request\n- not for an img, but just going to that url\n- an img tag automatically fires the GET request\n-- give me this img\n- but instead of an img, they've made the GET request to transfer funds\nbada-bing, bada-bang!\nDEFEAT:\nunique code\n-github \"state\"\n-you add a code to all URLs\n-any requests must have this unique code\n-it's impossible for others to know this beforehand\nPOST\n-now hacker has to submit to your server using the POST method\n-requires having the user fill out a form\n\nhttps://youtu.be/oxogqJiFVYI?t=1001\n\n----\n\n\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/03_oauth-github/01_authorization-code/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/03_oauth-github/01_authorization-code/login.go",
    "content": "package githubexample\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"github.com/nu7hatch/gouuid\"\n\t\"google.golang.org/appengine\"\n)\n\n// change redirectURI for deployment; eg, http://<yourAppId>.appspot.com/oauth2callback\nconst redirectURI = \"http://localhost:8080/oauth2callback\"\nconst githubAPIURL = \"https://api.github.com\"\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n\thttp.HandleFunc(\"/github-login\", handleGithubLogin)\n\thttp.HandleFunc(\"/oauth2callback\", handleOauth2Callback)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <head></head>\n  <body>\n    <a href=\"/github-login\">LOGIN WITH GITHUB</a>\n  </body>\n</html>`)\n}\n\nvar githubScopes = []string{\n\t\"user:email\",\n\t\"read:org\",\n}\n\nfunc handleGithubLogin(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\t// get the session\n\tsession := getSession(ctx, req)\n\tid, _ := uuid.NewV4()\n\n\tvalues := make(url.Values)\n\tvalues.Add(\"client_id\", \"fbbaa8ce5c394b7c3198\")\n\tvalues.Add(\"redirect_uri\", redirectURI)\n\tvalues.Add(\"scope\", strings.Join(githubScopes, \",\"))\n\tvalues.Add(\"state\", id.String())\n\n\t// save the session\n\tsession.State = id.String()\n\tputSession(ctx, res, session)\n\n\thttp.Redirect(res, req, fmt.Sprintf(\n\t\t\"https://github.com/login/oauth/authorize?%s\",\n\t\tvalues.Encode(),\n\t), 302)\n}\n\nfunc handleOauth2Callback(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\t// get the session\n\tsession := getSession(ctx, req)\n\n\tstate := req.FormValue(\"state\")\n\tcode := req.FormValue(\"code\")\n\n\tif state != session.State {\n\t\thttp.Error(res, \"invalid state\", 401)\n\t\treturn\n\t}\n\n\tfmt.Fprintln(res, code)\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/03_oauth-github/01_authorization-code/session.go",
    "content": "package githubexample\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"google.golang.org/appengine/memcache\"\n\n\t\"github.com/nu7hatch/gouuid\"\n\n\t\"golang.org/x/net/context\"\n)\n\ntype Session struct {\n\tID    string\n\tState string\n\tEmail string\n}\n\nfunc getSession(ctx context.Context, req *http.Request) Session {\n\tcookie, err := req.Cookie(\"sessionid\")\n\tif err != nil || cookie.Value == \"\" {\n\t\tsessionID, _ := uuid.NewV4()\n\t\tcookie = &http.Cookie{\n\t\t\tName:  \"sessionid\",\n\t\t\tValue: sessionID.String(),\n\t\t}\n\t}\n\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\titem = &memcache.Item{\n\t\t\tKey:   cookie.Value,\n\t\t\tValue: []byte(\"\"),\n\t\t}\n\t}\n\n\tvar session Session\n\tjson.Unmarshal(item.Value, &session)\n\tsession.ID = cookie.Value\n\treturn session\n}\n\nfunc putSession(ctx context.Context, res http.ResponseWriter, session Session) {\n\tbs, err := json.Marshal(session)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tmemcache.Set(ctx, &memcache.Item{\n\t\tKey:   session.ID,\n\t\tValue: bs,\n\t})\n\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:  \"sessionid\",\n\t\tValue: session.ID,\n\t})\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/03_oauth-github/02_access-token/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/03_oauth-github/02_access-token/login.go",
    "content": "package githubexample\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"github.com/nu7hatch/gouuid\"\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/urlfetch\"\n\t\"io/ioutil\"\n)\n\n// change redirectURI for deployment; eg, http://<yourAppId>.appspot.com/oauth2callback\nconst redirectURI = \"http://localhost:8080/oauth2callback\"\nconst githubAPIURL = \"https://api.github.com\"\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n\thttp.HandleFunc(\"/github-login\", handleGithubLogin)\n\thttp.HandleFunc(\"/oauth2callback\", handleOauth2Callback)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <head></head>\n  <body>\n    <a href=\"/github-login\">LOGIN WITH GITHUB</a>\n  </body>\n</html>`)\n}\n\nvar githubScopes = []string{\n\t\"user:email\",\n\t\"read:org\",\n}\n\nfunc handleGithubLogin(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\t// get the session\n\tsession := getSession(ctx, req)\n\tid, _ := uuid.NewV4()\n\n\tvalues := make(url.Values)\n\tvalues.Add(\"client_id\", \"fbbaa8ce5c394b7c3198\")\n\tvalues.Add(\"redirect_uri\", redirectURI)\n\tvalues.Add(\"scope\", strings.Join(githubScopes, \",\"))\n\tvalues.Add(\"state\", id.String())\n\n\t// save the session\n\tsession.State = id.String()\n\tputSession(ctx, res, session)\n\n\thttp.Redirect(res, req, fmt.Sprintf(\n\t\t\"https://github.com/login/oauth/authorize?%s\",\n\t\tvalues.Encode(),\n\t), 302)\n}\n\nfunc handleOauth2Callback(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\t// get the session\n\tsession := getSession(ctx, req)\n\n\tstate := req.FormValue(\"state\")\n\tcode := req.FormValue(\"code\")\n\n\tif state != session.State {\n\t\thttp.Error(res, \"invalid state\", 401)\n\t\treturn\n\t}\n\n\tfmt.Fprintln(res, \"AUTHORIZATION CODE \"+code)\n\n\taccessToken, err := getAccessToken(ctx, state, code)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tfmt.Fprintln(res, \"ACCESS TOKEN \"+accessToken)\n\n}\n\nfunc getAccessToken(ctx context.Context, state, code string) (string, error) {\n\tvalues := make(url.Values)\n\tvalues.Add(\"client_id\", \"fbbaa8ce5c394b7c3198\")\n\tvalues.Add(\"client_secret\", \"1b450ffb26982847d1c92eadd8a6d4932a79f225\")\n\tvalues.Add(\"code\", code)\n\tvalues.Add(\"state\", state)\n\tclient := urlfetch.Client(ctx)\n\tresponse, err := client.PostForm(\"https://github.com/login/oauth/access_token\", values)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer response.Body.Close()\n\tbs, _ := ioutil.ReadAll(response.Body)\n\treturn string(bs), nil\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/03_oauth-github/02_access-token/session.go",
    "content": "package githubexample\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"google.golang.org/appengine/memcache\"\n\n\t\"github.com/nu7hatch/gouuid\"\n\n\t\"golang.org/x/net/context\"\n)\n\ntype Session struct {\n\tID    string\n\tState string\n\tEmail string\n}\n\nfunc getSession(ctx context.Context, req *http.Request) Session {\n\tcookie, err := req.Cookie(\"sessionid\")\n\tif err != nil || cookie.Value == \"\" {\n\t\tsessionID, _ := uuid.NewV4()\n\t\tcookie = &http.Cookie{\n\t\t\tName:  \"sessionid\",\n\t\t\tValue: sessionID.String(),\n\t\t}\n\t}\n\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\titem = &memcache.Item{\n\t\t\tKey:   cookie.Value,\n\t\t\tValue: []byte(\"\"),\n\t\t}\n\t}\n\n\tvar session Session\n\tjson.Unmarshal(item.Value, &session)\n\tsession.ID = cookie.Value\n\treturn session\n}\n\nfunc putSession(ctx context.Context, res http.ResponseWriter, session Session) {\n\tbs, err := json.Marshal(session)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tmemcache.Set(ctx, &memcache.Item{\n\t\tKey:   session.ID,\n\t\tValue: bs,\n\t})\n\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:  \"sessionid\",\n\t\tValue: session.ID,\n\t})\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/03_oauth-github/03_url-ParseQuery/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/03_oauth-github/03_url-ParseQuery/login.go",
    "content": "package githubexample\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"github.com/nu7hatch/gouuid\"\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/urlfetch\"\n\t\"io/ioutil\"\n)\n\n// change redirectURI for deployment; eg, http://<yourAppId>.appspot.com/oauth2callback\nconst redirectURI = \"http://localhost:8080/oauth2callback\"\nconst githubAPIURL = \"https://api.github.com\"\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n\thttp.HandleFunc(\"/github-login\", handleGithubLogin)\n\thttp.HandleFunc(\"/oauth2callback\", handleOauth2Callback)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <head></head>\n  <body>\n    <a href=\"/github-login\">LOGIN WITH GITHUB</a>\n  </body>\n</html>`)\n}\n\nvar githubScopes = []string{\n\t\"user:email\",\n\t\"read:org\",\n}\n\nfunc handleGithubLogin(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\t// get the session\n\tsession := getSession(ctx, req)\n\tid, _ := uuid.NewV4()\n\n\tvalues := make(url.Values)\n\tvalues.Add(\"client_id\", \"fbbaa8ce5c394b7c3198\")\n\tvalues.Add(\"redirect_uri\", redirectURI)\n\tvalues.Add(\"scope\", strings.Join(githubScopes, \",\"))\n\tvalues.Add(\"state\", id.String())\n\n\t// save the session\n\tsession.State = id.String()\n\tputSession(ctx, res, session)\n\n\thttp.Redirect(res, req, fmt.Sprintf(\n\t\t\"https://github.com/login/oauth/authorize?%s\",\n\t\tvalues.Encode(),\n\t), 302)\n}\n\nfunc handleOauth2Callback(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\t// get the session\n\tsession := getSession(ctx, req)\n\n\tstate := req.FormValue(\"state\")\n\tcode := req.FormValue(\"code\")\n\n\tif state != session.State {\n\t\thttp.Error(res, \"invalid state\", 401)\n\t\treturn\n\t}\n\n\tfmt.Fprintln(res, \"AUTHORIZATION CODE \"+code)\n\n\taccessToken, err := getAccessToken(ctx, state, code)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tfmt.Fprintln(res, \"ACCESS TOKEN \"+accessToken)\n\n}\n\nfunc getAccessToken(ctx context.Context, state, code string) (string, error) {\n\tvalues := make(url.Values)\n\tvalues.Add(\"client_id\", \"fbbaa8ce5c394b7c3198\")\n\tvalues.Add(\"client_secret\", \"1b450ffb26982847d1c92eadd8a6d4932a79f225\")\n\tvalues.Add(\"code\", code)\n\tvalues.Add(\"state\", state)\n\tclient := urlfetch.Client(ctx)\n\tresponse, err := client.PostForm(\"https://github.com/login/oauth/access_token\", values)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer response.Body.Close()\n\tbs, _ := ioutil.ReadAll(response.Body)\n\tv, _ := url.ParseQuery(string(bs))\n\treturn v.Get(\"access_token\"), nil\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/03_oauth-github/03_url-ParseQuery/session.go",
    "content": "package githubexample\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"google.golang.org/appengine/memcache\"\n\n\t\"github.com/nu7hatch/gouuid\"\n\n\t\"golang.org/x/net/context\"\n)\n\ntype Session struct {\n\tID    string\n\tState string\n\tEmail string\n}\n\nfunc getSession(ctx context.Context, req *http.Request) Session {\n\tcookie, err := req.Cookie(\"sessionid\")\n\tif err != nil || cookie.Value == \"\" {\n\t\tsessionID, _ := uuid.NewV4()\n\t\tcookie = &http.Cookie{\n\t\t\tName:  \"sessionid\",\n\t\t\tValue: sessionID.String(),\n\t\t}\n\t}\n\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\titem = &memcache.Item{\n\t\t\tKey:   cookie.Value,\n\t\t\tValue: []byte(\"\"),\n\t\t}\n\t}\n\n\tvar session Session\n\tjson.Unmarshal(item.Value, &session)\n\tsession.ID = cookie.Value\n\treturn session\n}\n\nfunc putSession(ctx context.Context, res http.ResponseWriter, session Session) {\n\tbs, err := json.Marshal(session)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tmemcache.Set(ctx, &memcache.Item{\n\t\tKey:   session.ID,\n\t\tValue: bs,\n\t})\n\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:  \"sessionid\",\n\t\tValue: session.ID,\n\t})\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/03_oauth-github/04_user-email/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/03_oauth-github/04_user-email/login.go",
    "content": "package githubexample\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"encoding/json\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/urlfetch\"\n\t\"io/ioutil\"\n)\n\n// change redirectURI for deployment; eg, http://<yourAppId>.appspot.com/oauth2callback\nconst redirectURI = \"http://localhost:8080/oauth2callback\"\nconst githubAPIURL = \"https://api.github.com\"\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n\thttp.HandleFunc(\"/github-login\", handleGithubLogin)\n\thttp.HandleFunc(\"/oauth2callback\", handleOauth2Callback)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <head></head>\n  <body>\n    <a href=\"/github-login\">LOGIN WITH GITHUB</a>\n  </body>\n</html>`)\n}\n\nvar githubScopes = []string{\n\t\"user:email\",\n\t\"read:org\",\n}\n\nfunc handleGithubLogin(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\t// get the session\n\tsession := getSession(ctx, req)\n\tid, _ := uuid.NewV4()\n\n\tvalues := make(url.Values)\n\tvalues.Add(\"client_id\", \"fbbaa8ce5c394b7c3198\")\n\tvalues.Add(\"redirect_uri\", redirectURI)\n\tvalues.Add(\"scope\", strings.Join(githubScopes, \",\"))\n\tvalues.Add(\"state\", id.String())\n\n\t// save the session\n\tsession.State = id.String()\n\tputSession(ctx, res, session)\n\n\thttp.Redirect(res, req, fmt.Sprintf(\n\t\t\"https://github.com/login/oauth/authorize?%s\",\n\t\tvalues.Encode(),\n\t), 302)\n}\n\nfunc handleOauth2Callback(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\t// get the session\n\tsession := getSession(ctx, req)\n\n\tstate := req.FormValue(\"state\")\n\tcode := req.FormValue(\"code\")\n\n\tif state != session.State {\n\t\thttp.Error(res, \"invalid state\", 401)\n\t\treturn\n\t}\n\n\tfmt.Fprintln(res, \"AUTHORIZATION CODE \"+code)\n\n\taccessToken, err := getAccessToken(ctx, state, code)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tfmt.Fprintln(res, \"ACCESS TOKEN \"+accessToken)\n\n\temail, err := getEmail(ctx, accessToken)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tfmt.Fprintln(res, \"EMAIL \"+email)\n\n}\n\nfunc getAccessToken(ctx context.Context, state, code string) (string, error) {\n\tvalues := make(url.Values)\n\tvalues.Add(\"client_id\", \"fbbaa8ce5c394b7c3198\")\n\tvalues.Add(\"client_secret\", \"1b450ffb26982847d1c92eadd8a6d4932a79f225\")\n\tvalues.Add(\"code\", code)\n\tvalues.Add(\"state\", state)\n\tclient := urlfetch.Client(ctx)\n\tresponse, err := client.PostForm(\"https://github.com/login/oauth/access_token\", values)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer response.Body.Close()\n\tbs, _ := ioutil.ReadAll(response.Body)\n\tv, _ := url.ParseQuery(string(bs))\n\treturn v.Get(\"access_token\"), nil\n}\n\nfunc getEmail(ctx context.Context, accessToken string) (string, error) {\n\tclient := urlfetch.Client(ctx)\n\tresponse, err := client.Get(\"https://api.github.com/user/emails?access_token=\" + accessToken)\n\tif err != nil {\n\t\treturn \"\", nil\n\t}\n\tdefer response.Body.Close()\n\n\tvar data []struct {\n\t\tEmail    string\n\t\tVerified bool\n\t\tPrimary  bool\n\t}\n\terr = json.NewDecoder(response.Body).Decode(&data)\n\tif err != nil {\n\t\treturn \"\", nil\n\t}\n\tif len(data) == 0 {\n\t\treturn \"\", fmt.Errorf(\"no email found\")\n\t}\n\treturn data[0].Email, nil\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/03_oauth-github/04_user-email/session.go",
    "content": "package githubexample\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"google.golang.org/appengine/memcache\"\n\n\t\"github.com/nu7hatch/gouuid\"\n\n\t\"golang.org/x/net/context\"\n)\n\ntype Session struct {\n\tID    string\n\tState string\n\tEmail string\n}\n\nfunc getSession(ctx context.Context, req *http.Request) Session {\n\tcookie, err := req.Cookie(\"sessionid\")\n\tif err != nil || cookie.Value == \"\" {\n\t\tsessionID, _ := uuid.NewV4()\n\t\tcookie = &http.Cookie{\n\t\t\tName:  \"sessionid\",\n\t\t\tValue: sessionID.String(),\n\t\t}\n\t}\n\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\titem = &memcache.Item{\n\t\t\tKey:   cookie.Value,\n\t\t\tValue: []byte(\"\"),\n\t\t}\n\t}\n\n\tvar session Session\n\tjson.Unmarshal(item.Value, &session)\n\tsession.ID = cookie.Value\n\treturn session\n}\n\nfunc putSession(ctx context.Context, res http.ResponseWriter, session Session) {\n\tbs, err := json.Marshal(session)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tmemcache.Set(ctx, &memcache.Item{\n\t\tKey:   session.ID,\n\t\tValue: bs,\n\t})\n\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:  \"sessionid\",\n\t\tValue: session.ID,\n\t})\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/03_oauth-github/05_configuration_scheduled-tasks_cron/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/03_oauth-github/05_configuration_scheduled-tasks_cron/cron.yaml",
    "content": "cron:\n- description: daily summary job\n  url: /scheduled\n  schedule: every 1 minutes\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/03_oauth-github/05_configuration_scheduled-tasks_cron/login.go",
    "content": "package githubexample\n\nimport (\n\t\"fmt\"\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\t\"net/http\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tfmt.Fprintln(res, \"Go look at the log\")\n\tctx := appengine.NewContext(req)\n\tlog.Infof(ctx, \"checking that log.infof prints to terminal\")\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/03_oauth-github/05_configuration_scheduled-tasks_cron/scheduled.go",
    "content": "package githubexample\n\nimport (\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/scheduled\", handleScheduleExample)\n}\n\nfunc handleScheduleExample(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tlog.Infof(ctx, \"in the scheduler\")\n\n\tif req.Header.Get(\"X-Appengine-Cron\") != \"true\" {\n\t\thttp.Error(res, \"Forbidden\", http.StatusForbidden)\n\t\treturn\n\t}\n\n\tlog.Infof(ctx, \"I was Scheduled!!!\")\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/03_oauth-github/06-complete/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/03_oauth-github/06-complete/cron.yaml",
    "content": "cron:\n- description: daily summary job\n  url: /schedule-example\n  schedule: every 1 minutes\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/03_oauth-github/06-complete/github.go",
    "content": "package githubexample\n\nimport (\n\t\"encoding/json\"\n\t\"io/ioutil\"\n\t\"net/url\"\n\t\"sync\"\n\t\"time\"\n\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/delay\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/urlfetch\"\n)\n\n// change redirectURI for deployment; eg, http://<yourAppId>.appspot.com/oauth2callback\nconst redirectURI = \"http://localhost:8080/oauth2callback\"\nconst githubAPIURL = \"https://api.github.com\"\n\nvar delayedGetStats *delay.Function\n\nfunc init() {\n\tdelayedGetStats = delay.Func(\n\t\t\"my-favorite-dog\",\n\t\tfunc(ctx context.Context, accessToken, username string) error {\n\t\t\tapi := &GithubAPI{\n\t\t\t\tctx:         ctx,\n\t\t\t\taccessToken: accessToken,\n\t\t\t\tusername:    username,\n\t\t\t}\n\t\t\tsince := time.Now().Add(-time.Hour * 24 * 30)\n\t\t\tstats, err := api.getCommitSummaryStats(since)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tlog.Infof(ctx, \"STATS: %v\", stats)\n\n\t\t\tkey := datastore.NewKey(ctx, \"Stats\", username, 0, nil)\n\t\t\t_, err = datastore.Put(ctx, key, &stats)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t)\n}\n\ntype GithubAPI struct {\n\tctx         context.Context\n\taccessToken string\n\tusername    string\n}\n\ntype CommitStats struct {\n\tAdditions, Deletions int\n}\n\nfunc NewGithubAPI(ctx context.Context) *GithubAPI {\n\treturn &GithubAPI{\n\t\tctx: ctx,\n\t}\n}\n\nfunc (api *GithubAPI) getUsername() (string, error) {\n\tclient := urlfetch.Client(api.ctx)\n\tresponse, err := client.Get(\n\t\tgithubAPIURL + \"/user?access_token=\" + api.accessToken)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer response.Body.Close()\n\n\tvar data struct {\n\t\tLogin string\n\t}\n\terr = json.NewDecoder(response.Body).Decode(&data)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn data.Login, nil\n}\n\nfunc (api *GithubAPI) getAccessToken(state, code string) (string, error) {\n\tvalues := make(url.Values)\n\tvalues.Add(\"client_id\", \"0ccd33716940f347065e\")\n\tvalues.Add(\"client_secret\", \"4c21ab338de0449ae13019de25629a7b85e08641\")\n\tvalues.Add(\"code\", code)\n\tvalues.Add(\"state\", state)\n\n\tclient := urlfetch.Client(api.ctx)\n\tresponse, err := client.PostForm(\"https://github.com/login/oauth/access_token\", values)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer response.Body.Close()\n\n\tbs, err := ioutil.ReadAll(response.Body)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tvalues, err = url.ParseQuery(string(bs))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn values.Get(\"access_token\"), nil\n}\n\nfunc (api *GithubAPI) getCommitSummaryStats(since time.Time) (CommitStats, error) {\n\tvar stats CommitStats\n\n\ttype Repo struct {\n\t\tOrganization, Repository string\n\t}\n\n\tvar wg sync.WaitGroup\n\trepositoryChannel := make(chan Repo)\n\tstatsChannel := make(chan CommitStats)\n\tfor i := 0; i < 10; i++ {\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tfor repo := range repositoryChannel {\n\t\t\t\t// list all commits for repository: GET /repos/:owner/:repo/commits\n\t\t\t\tshas, err := api.getUserCommitShas(repo.Organization, repo.Repository, since)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Errorf(api.ctx, \"Error getting user commit shas: %v\", err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tlog.Infof(api.ctx, \"REPO: %v, SHAS:%v\", repo, shas)\n\t\t\t\tfor _, sha := range shas {\n\t\t\t\t\t// get a single commit: GET /repos/:owner/:repo/commits/:sha\n\t\t\t\t\tcs, err := api.getCommitStats(repo.Organization, repo.Repository, sha)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlog.Errorf(api.ctx, \"Error getting stats: %v\", err)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tstatsChannel <- cs\n\t\t\t\t}\n\t\t\t}\n\t\t\twg.Done()\n\t\t}()\n\t}\n\n\t// list organizations: GET /user/orgs\n\tgo func() {\n\t\torganizations, err := api.getOrganizations()\n\t\tif err != nil {\n\t\t\tlog.Errorf(api.ctx, \"ERROR GETTING ORGANIZATIONS: %v\", err)\n\t\t\treturn\n\t\t}\n\t\tfor _, organization := range organizations {\n\t\t\t// list repositories: GET /orgs/:org/repos\n\t\t\trepositories, err := api.getRepositories(organization)\n\t\t\tif err != nil {\n\t\t\t\tlog.Errorf(api.ctx, \"ERROR GETTING REPOSITORIES: %v\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlog.Infof(api.ctx, \"REPOSITORIES:%v\", repositories)\n\t\t\tfor _, repository := range repositories {\n\t\t\t\trepositoryChannel <- Repo{organization, repository}\n\t\t\t}\n\t\t}\n\t\tclose(repositoryChannel)\n\t}()\n\n\tgo func() {\n\t\twg.Wait()\n\t\tclose(statsChannel)\n\t}()\n\n\tfor cs := range statsChannel {\n\t\tstats.Additions += cs.Additions\n\t\tstats.Deletions += cs.Deletions\n\t}\n\n\treturn stats, nil\n}\n\nfunc (api *GithubAPI) getOrganizations() ([]string, error) {\n\tendpoint := \"/user/orgs\"\n\tvar data []struct {\n\t\tLogin string `json:\"login\"`\n\t}\n\terr := api.makeAPIRequest(endpoint, nil, &data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnames := make([]string, len(data))\n\tfor i, v := range data {\n\t\tnames[i] = v.Login\n\t}\n\n\treturn names, nil\n}\n\nfunc (api *GithubAPI) getRepositories(organization string) ([]string, error) {\n\t// GET /orgs/:org/repos\n\tvar data []struct {\n\t\tName string `json:\"name\"`\n\t}\n\terr := api.makeAPIRequest(\"/orgs/\"+organization+\"/repos\", nil, &data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tnames := make([]string, len(data))\n\tfor i, v := range data {\n\t\tnames[i] = v.Name\n\t}\n\treturn names, nil\n}\n\nfunc (api *GithubAPI) getUserCommitShas(organization, repository string, since time.Time) ([]string, error) {\n\tvalues := make(url.Values)\n\tvalues.Add(\"author\", api.username)\n\tvalues.Add(\"since\", since.Format(time.RFC3339))\n\t// GET /repos/:owner/:repo/commits\n\tendpoint := \"/repos/\" + organization + \"/\" + repository + \"/commits\"\n\tvar data []struct {\n\t\tSHA string `json:\"sha\"`\n\t}\n\terr := api.makeAPIRequest(endpoint, values, &data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tshas := make([]string, len(data))\n\tfor i, v := range data {\n\t\tshas[i] = v.SHA\n\t}\n\treturn shas, nil\n}\n\nfunc (api *GithubAPI) getCommitStats(organization, repository, sha string) (CommitStats, error) {\n\tvar stats CommitStats\n\tendpoint := \"/repos/\" + organization + \"/\" + repository + \"/commits/\" + sha\n\tvar data struct {\n\t\tStats struct {\n\t\t\tAdditions int `json:\"additions\"`\n\t\t\tDeletions int `json:\"deletions\"`\n\t\t} `json:\"stats\"`\n\t}\n\terr := api.makeAPIRequest(endpoint, nil, &data)\n\tif err != nil {\n\t\treturn stats, err\n\t}\n\tstats.Additions = data.Stats.Additions\n\tstats.Deletions = data.Stats.Deletions\n\treturn stats, nil\n}\n\nfunc (api *GithubAPI) makeAPIRequest(endpoint string, values url.Values, dst interface{}) error {\n\tclient := urlfetch.Client(api.ctx)\n\tif values == nil {\n\t\tvalues = make(url.Values)\n\t}\n\tvalues.Add(\"access_token\", api.accessToken)\n\t// GET /user/orgs\n\tresponse, err := client.Get(githubAPIURL + endpoint + \"?\" + values.Encode())\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer response.Body.Close()\n\n\tbs, _ := ioutil.ReadAll(response.Body)\n\t//log.Infof(api.ctx, \"GET %s RESPONSE: %s\", endpoint, string(bs))\n\treturn json.Unmarshal(bs, dst)\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/03_oauth-github/06-complete/login.go",
    "content": "package githubexample\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\n\t\"github.com/nu7hatch/gouuid\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n\thttp.HandleFunc(\"/github-login\", handleGithubLogin)\n\thttp.HandleFunc(\"/oauth2callback\", handleOauth2Callback)\n\thttp.HandleFunc(\"/github-info\", handleGithubInfo)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <head></head>\n  <body>\n    <a href=\"/github-login\">LOGIN WITH GITHUB</a>\n  </body>\n</html>`)\n}\n\nvar githubScopes = []string{\n\t\"user:email\",\n\t\"read:org\",\n}\n\nfunc handleGithubLogin(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\t// get the session\n\tsession := getSession(ctx, req)\n\tid, _ := uuid.NewV4()\n\n\tvalues := make(url.Values)\n\tvalues.Add(\"client_id\", \"0ccd33716940f347065e\")\n\tvalues.Add(\"redirect_uri\", redirectURI)\n\tvalues.Add(\"scope\", strings.Join(githubScopes, \",\"))\n\tvalues.Add(\"state\", id.String())\n\n\t// save the session\n\tsession.State = id.String()\n\tputSession(ctx, res, session)\n\n\thttp.Redirect(res, req, fmt.Sprintf(\n\t\t\"https://github.com/login/oauth/authorize?%s\",\n\t\tvalues.Encode(),\n\t), 302)\n}\n\nfunc handleOauth2Callback(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tapi := NewGithubAPI(ctx)\n\t// get the session\n\tsession := getSession(ctx, req)\n\n\tstate := req.FormValue(\"state\")\n\tcode := req.FormValue(\"code\")\n\n\tif state != session.State {\n\t\thttp.Error(res, \"invalid state\", 401)\n\t\treturn\n\t}\n\n\taccessToken, err := api.getAccessToken(state, code)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tapi.accessToken = accessToken\n\n\tusername, err := api.getUsername()\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tsession.Username = username\n\tsession.AccessToken = accessToken\n\tputSession(ctx, res, session)\n\n\tdelayedGetStats.Call(ctx, accessToken, username)\n\thttp.Redirect(res, req, \"/github-info\", 302)\n\n}\n\nfunc handleGithubInfo(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tsession := getSession(ctx, req)\n\n\tvar stats CommitStats\n\n\tkey := datastore.NewKey(ctx, \"Stats\", session.Username, 0, nil)\n\terr := datastore.Get(ctx, key, &stats)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\t// stats, err := api.getCommitSummaryStats(since)\n\t// if err != nil {\n\t// \thttp.Error(res, err.Error(), 500)\n\t// \treturn\n\t// }\n\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n\t<head>\n\n\t</head>\n\t<body>\n\t\tIn the last month you have:\n\t\t<table>\n\t\t\t<tr>\n\t\t\t\t<th>additions</th>\n\t\t\t\t<td>`+fmt.Sprint(stats.Additions)+`</td>\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t<th>deletions</th>\n\t\t\t\t<td>`+fmt.Sprint(stats.Deletions)+`</td>\n\t\t\t</tr>\n\t\t</table>\n\t</body>\n</html>`)\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/03_oauth-github/06-complete/scheduled.go",
    "content": "package githubexample\n\nimport (\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/schedule-example\", handleScheduleExample)\n}\n\nfunc handleScheduleExample(res http.ResponseWriter, req *http.Request) {\n\tif req.Header.Get(\"X-Appengine-Cron\") != \"true\" {\n\t\thttp.Error(res, \"Forbidden\", http.StatusForbidden)\n\t\treturn\n\t}\n\tctx := appengine.NewContext(req)\n\tlog.Infof(ctx, \"I was Scheduled!!!\")\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/03_oauth-github/06-complete/session.go",
    "content": "package githubexample\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"google.golang.org/appengine/memcache\"\n\n\t\"github.com/nu7hatch/gouuid\"\n\n\t\"golang.org/x/net/context\"\n)\n\ntype Session struct {\n\tID          string\n\tState       string\n\tUsername    string\n\tAccessToken string\n}\n\nfunc getSession(ctx context.Context, req *http.Request) Session {\n\tcookie, err := req.Cookie(\"sessionid\")\n\tif err != nil || cookie.Value == \"\" {\n\t\tsessionID, _ := uuid.NewV4()\n\t\tcookie = &http.Cookie{\n\t\t\tName:  \"sessionid\",\n\t\t\tValue: sessionID.String(),\n\t\t}\n\t}\n\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\titem = &memcache.Item{\n\t\t\tKey:   cookie.Value,\n\t\t\tValue: []byte(\"\"),\n\t\t}\n\t}\n\n\tvar session Session\n\tjson.Unmarshal(item.Value, &session)\n\tsession.ID = cookie.Value\n\treturn session\n}\n\nfunc putSession(ctx context.Context, res http.ResponseWriter, session Session) {\n\tbs, err := json.Marshal(session)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tmemcache.Set(ctx, &memcache.Item{\n\t\tKey:   session.ID,\n\t\tValue: bs,\n\t})\n\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:  \"sessionid\",\n\t\tValue: session.ID,\n\t})\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/04_oauth-twitter/00_readme/README.txt",
    "content": "OAUTH\nhttps://en.wikipedia.org/wiki/OAuth\n\nGOLANG DOCs\nhttps://godoc.org/golang.org/x/oauth2\n\nTWITTER EXAMPLE\nsignin with twitter\n\n(1)\nlearn about twitter oauth\nhttps://dev.twitter.com/web/sign-in\nhttps://dev.twitter.com/web/sign-in/desktop-browser\n\n(2)\nthis is what we want to build - oauth like this\n\n\n(3)\ntwitter oauth docs\n\n\nEXAMPLE:\n(customized for my registered application, which we'll do next)\n--local development---\n--deployment---\n\n(4)\nregister your application\n\n(5)\nRedirect users to request GitHub access\n\n(6)\ncreate a callback to receive authorization code\n\n(7)\nexchange authorization code for an access token\n***AUTHORIZATION CODE***\n- the authorization code is the AUTHORIZATION OF THE USER\n-- requires our github oauth api Client ID\n***ACCESS TOKEN***\n- the access token is the AUTHORIZATION OF THE APPLICATION\n-- requires our github oauth api Client Secret\n-- we wouldn't want to pass our Client Secret in the URL\n\n\n(8)\nGet user information\nEMAIL EXAMPLE in code\n\n(9)\nApplication flow:\n- now that you have someone's VERIFIED email (github verifies emails)\n-- you can associate that email with a user's account on your site"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/05_oauth-facebook/00_readme/README.txt",
    "content": "OAUTH\nhttps://en.wikipedia.org/wiki/OAuth\n\nGOLANG DOCs\nhttps://godoc.org/golang.org/x/oauth2\n\nTWITTER EXAMPLE\nsignin with twitter\n\n(1)\nlearn about twitter oauth\nhttps://dev.twitter.com/web/sign-in\nhttps://dev.twitter.com/web/sign-in/desktop-browser\n\n(2)\nthis is what we want to build - oauth like this\n\n\n(3)\ntwitter oauth docs\n\n\nEXAMPLE:\n(customized for my registered application, which we'll do next)\n--local development---\n--deployment---\n\n(4)\nregister your application\n\n(5)\nRedirect users to request GitHub access\n\n(6)\ncreate a callback to receive authorization code\n\n(7)\nexchange authorization code for an access token\n***AUTHORIZATION CODE***\n- the authorization code is the AUTHORIZATION OF THE USER\n-- requires our github oauth api Client ID\n***ACCESS TOKEN***\n- the access token is the AUTHORIZATION OF THE APPLICATION\n-- requires our github oauth api Client Secret\n-- we wouldn't want to pass our Client Secret in the URL\n\n\n(8)\nGet user information\nEMAIL EXAMPLE in code\n\n(9)\nApplication flow:\n- now that you have someone's VERIFIED email (github verifies emails)\n-- you can associate that email with a user's account on your site"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/05_oauth-google/00_readme/README.txt",
    "content": "OAUTH\nhttps://en.wikipedia.org/wiki/OAuth\n\nGOLANG DOCs\nhttps://godoc.org/golang.org/x/oauth2\n\nTWITTER EXAMPLE\nsignin with twitter\n\n(1)\nlearn about twitter oauth\nhttps://dev.twitter.com/web/sign-in\nhttps://dev.twitter.com/web/sign-in/desktop-browser\n\n(2)\nthis is what we want to build - oauth like this\n\n\n(3)\ntwitter oauth docs\n\n\nEXAMPLE:\n(customized for my registered application, which we'll do next)\n--local development---\n--deployment---\n\n(4)\nregister your application\n\n(5)\nRedirect users to request GitHub access\n\n(6)\ncreate a callback to receive authorization code\n\n(7)\nexchange authorization code for an access token\n***AUTHORIZATION CODE***\n- the authorization code is the AUTHORIZATION OF THE USER\n-- requires our github oauth api Client ID\n***ACCESS TOKEN***\n- the access token is the AUTHORIZATION OF THE APPLICATION\n-- requires our github oauth api Client Secret\n-- we wouldn't want to pass our Client Secret in the URL\n\n\n(8)\nGet user information\nEMAIL EXAMPLE in code\n\n(9)\nApplication flow:\n- now that you have someone's VERIFIED email (github verifies emails)\n-- you can associate that email with a user's account on your site"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/05_oauth-google/app.yaml",
    "content": "application: practical-scion-114602\nversion: alpha-01\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  secure: always\n  script: _go_app"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/05_oauth-google/routes.go",
    "content": "package googleOauth2\n\nimport (\n\t\"github.com/julienschmidt/httprouter\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\n\t\"google.golang.org/api/gmail/v1\"\n\n\t\"golang.org/x/oauth2\"\n\t\"golang.org/x/oauth2/google\"\n\n\t\"github.com/nu7hatch/gouuid\"\n\t\"io\"\n\t\"net/http\"\n)\n\nvar conf = &oauth2.Config{\n\tClientID:     \"979509136073-10ce3r5s8mka304l6od82t3nltp9cf8s.apps.googleusercontent.com\",\n\tClientSecret: \"5zwpEL5WwwekeMsZoz6mcC0s\",\n\tRedirectURL:  \"https://practical-scion-114602.appspot.com/oauth2callback\",\n\tScopes:       []string{\"https://www.googleapis.com/auth/gmail.readonly\"},\n\tEndpoint:     google.Endpoint,\n}\n\nfunc init() {\n\tr := httprouter.New()\n\tr.GET(\"/\", handleIndex)\n\tr.GET(\"/login\", handleLogin)\n\tr.GET(\"/oauth2callback\", handleAuthorize)\n\thttp.Handle(\"/\", r)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <head></head>\n  <body>\n\t<a href=\"/login\">Login with Google to read your mail</a>\n  </body>\n</html>`)\n}\n\nfunc handleLogin(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\n\t//get session for storing state to check on callback\n\ts := getSession(ctx, req)\n\n\t//generate state for checking later\n\tstate, err := uuid.NewV4()\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n\n\t//put state in session and putting to memcache to check on callback\n\ts.State = state.String()\n\terr = putSession(ctx, res, s)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n\n\t//generate the authorization url that goes to the login and consent page for google.\n\t//I set the ApprovalForce option so that it asks for consent each time so that we can see it.\n\t//Shows application asking to \"Have offline access\" each time. can remove second arg to remove this.\n\turl := conf.AuthCodeURL(s.State, oauth2.ApprovalForce)\n\thttp.Redirect(res, req, url, http.StatusSeeOther)\n}\n\nfunc handleAuthorize(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\n\t//retrieve code and state from the callback\n\tcode, state := req.FormValue(\"code\"), req.FormValue(\"state\")\n\n\t//get session from memcache\n\ts := getSession(ctx, req)\n\n\t//compare state from callback with state stored in memcache\n\tif state != s.State {\n\t\thttp.Error(res, \"Detected cross-site attack\", http.StatusUnauthorized)\n\t\tlog.Criticalf(ctx, \"Non-matching states from %s\", req.RemoteAddr)\n\t\treturn\n\t}\n\n\t//exchange the auth code given for an access token\n\ttok, err := conf.Exchange(ctx, code)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n\n\t//create a client from the token\n\tclient := conf.Client(ctx, tok)\n\n\t//create a gmail service from the client\n\tsrv, err := gmail.New(client)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n\n\t//request a list of messages in the user's mailbox\n\tlist, err := srv.Users.Threads.List(\"me\").Do()\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n\n\t//loop through and print out the first 25 message threads from your mailbox\n\toutput := \"<p>Messages:</p>\"\n\tif len(list.Threads) > 0 {\n\t\ti := 1\n\t\tfor _, val := range list.Threads {\n\t\t\toutput += \"<p>- \" + val.Snippet + \"...</p>\"\n\t\t\tif i > 25 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ti++\n\t\t}\n\t} else {\n\t\toutput += \"<p>You have no messages!</p>\"\n\t}\n\tio.WriteString(res, output)\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/05_oauth-google/session.go",
    "content": "package googleOauth2\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"github.com/nu7hatch/gouuid\"\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine/memcache\"\n)\n\nconst cookieName = \"sessionid\"\n\ntype session struct {\n\tID    string `json:\"-\"`\n\tState string\n}\n\nfunc getSession(ctx context.Context, req *http.Request) session {\n\tcookie, err := req.Cookie(cookieName)\n\tif err != nil || cookie.Value == \"\" {\n\t\tuid, _ := uuid.NewV4()\n\t\tcookie = &http.Cookie{\n\t\t\tName:  cookieName,\n\t\t\tValue: uid.String(),\n\t\t}\n\t}\n\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\titem = &memcache.Item{\n\t\t\tKey:   cookie.Value,\n\t\t\tValue: []byte(\"\"),\n\t\t}\n\t}\n\n\tvar s session\n\tjson.Unmarshal(item.Value, &s)\n\ts.ID = cookie.Value\n\treturn s\n}\n\nfunc putSession(ctx context.Context, res http.ResponseWriter, s session) error {\n\tbs, err := json.Marshal(s)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = memcache.Set(ctx, &memcache.Item{\n\t\tKey:   s.ID,\n\t\tValue: bs,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:  cookieName,\n\t\tValue: s.ID,\n\t})\n\n\treturn nil\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/06_oauth-linkedin/00_readme/README.txt",
    "content": "OAUTH\nhttps://en.wikipedia.org/wiki/OAuth\n\nGOLANG DOCs\nhttps://godoc.org/golang.org/x/oauth2\n\nTWITTER EXAMPLE\nsignin with twitter\n\n(1)\nlearn about twitter oauth\nhttps://dev.twitter.com/web/sign-in\nhttps://dev.twitter.com/web/sign-in/desktop-browser\n\n(2)\nthis is what we want to build - oauth like this\n\n\n(3)\ntwitter oauth docs\n\n\nEXAMPLE:\n(customized for my registered application, which we'll do next)\n--local development---\n--deployment---\n\n(4)\nregister your application\n\n(5)\nRedirect users to request GitHub access\n\n(6)\ncreate a callback to receive authorization code\n\n(7)\nexchange authorization code for an access token\n***AUTHORIZATION CODE***\n- the authorization code is the AUTHORIZATION OF THE USER\n-- requires our github oauth api Client ID\n***ACCESS TOKEN***\n- the access token is the AUTHORIZATION OF THE APPLICATION\n-- requires our github oauth api Client Secret\n-- we wouldn't want to pass our Client Secret in the URL\n\n\n(8)\nGet user information\nEMAIL EXAMPLE in code\n\n(9)\nApplication flow:\n- now that you have someone's VERIFIED email (github verifies emails)\n-- you can associate that email with a user's account on your site"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/07_oauth-vk/00_readme/README.txt",
    "content": "OAUTH\nhttps://en.wikipedia.org/wiki/OAuth\n\nGOLANG DOCs\nhttps://godoc.org/golang.org/x/oauth2\n\nTWITTER EXAMPLE\nsignin with twitter\n\n(1)\nlearn about twitter oauth\nhttps://dev.twitter.com/web/sign-in\nhttps://dev.twitter.com/web/sign-in/desktop-browser\n\n(2)\nthis is what we want to build - oauth like this\n\n\n(3)\ntwitter oauth docs\n\n\nEXAMPLE:\n(customized for my registered application, which we'll do next)\n--local development---\n--deployment---\n\n(4)\nregister your application\n\n(5)\nRedirect users to request GitHub access\n\n(6)\ncreate a callback to receive authorization code\n\n(7)\nexchange authorization code for an access token\n***AUTHORIZATION CODE***\n- the authorization code is the AUTHORIZATION OF THE USER\n-- requires our github oauth api Client ID\n***ACCESS TOKEN***\n- the access token is the AUTHORIZATION OF THE APPLICATION\n-- requires our github oauth api Client Secret\n-- we wouldn't want to pass our Client Secret in the URL\n\n\n(8)\nGet user information\nEMAIL EXAMPLE in code\n\n(9)\nApplication flow:\n- now that you have someone's VERIFIED email (github verifies emails)\n-- you can associate that email with a user's account on your site"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/08_oauth-dropbox/00_readme/README.txt",
    "content": "OAUTH\nhttps://en.wikipedia.org/wiki/OAuth\n\nGOLANG DOCs\nhttps://godoc.org/golang.org/x/oauth2\n\nTWITTER EXAMPLE\nsignin with twitter\n\n(1)\nlearn about twitter oauth\nhttps://dev.twitter.com/web/sign-in\nhttps://dev.twitter.com/web/sign-in/desktop-browser\n\n(2)\nthis is what we want to build - oauth like this\n\n\n(3)\ntwitter oauth docs\n\n\nEXAMPLE:\n(customized for my registered application, which we'll do next)\n--local development---\n--deployment---\n\n(4)\nregister your application\n\n(5)\nRedirect users to request GitHub access\n\n(6)\ncreate a callback to receive authorization code\n\n(7)\nexchange authorization code for an access token\n***AUTHORIZATION CODE***\n- the authorization code is the AUTHORIZATION OF THE USER\n-- requires our github oauth api Client ID\n***ACCESS TOKEN***\n- the access token is the AUTHORIZATION OF THE APPLICATION\n-- requires our github oauth api Client Secret\n-- we wouldn't want to pass our Client Secret in the URL\n\n\n(8)\nGet user information\nEMAIL EXAMPLE in code\n\n(9)\nApplication flow:\n- now that you have someone's VERIFIED email (github verifies emails)\n-- you can associate that email with a user's account on your site"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/08_oauth-dropbox/app.yaml",
    "content": "application: learning-1130\nversion: dropbox\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  secure: always\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/08_oauth-dropbox/routes.go",
    "content": "package dropbox\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\n\t\"golang.org/x/net/context\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/urlfetch\"\n\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n)\n\nfunc init() {\n\tr := httprouter.New()\n\tr.GET(\"/\", handleIndex)\n\tr.GET(\"/login\", handleLogin)\n\tr.GET(\"/oauth2\", handleAuthorize)\n\thttp.Handle(\"/\", r)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <head></head>\n  <body>\n    <a href=\"/login\">Login with Dropbox</a>\n  </body>\n</html>`)\n}\n\nfunc handleLogin(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\ts := getSession(ctx, req)\n\tstate, err := uuid.NewV4()\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n\tv := url.Values{}\n\tv.Add(\"response_type\", \"code\")\n\tv.Add(\"client_id\", \"2be6c5b4z9uhar7\")\n\tv.Add(\"redirect_uri\", \"http://localhost:8080/oauth2\")\n\tv.Add(\"state\", state.String())\n\ts.State = state.String()\n\terr = putSession(ctx, res, s)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n\thttp.Redirect(res, req, \"https://www.dropbox.com/1/oauth2/authorize?\"+v.Encode(), http.StatusSeeOther)\n}\n\ntype dropboxData struct {\n\tAccessToken string `json:\"access_token\"`\n\tTokenType   string `json:\"token_type\"`\n\tUID         string `json:\"uid\"`\n}\n\nfunc handleAuthorize(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tcode, state := req.FormValue(\"code\"), req.FormValue(\"state\")\n\ts := getSession(ctx, req)\n\tif s.State != state {\n\t\thttp.Error(res, \"Detected cross-site attack\", http.StatusUnauthorized)\n\t\tlog.Criticalf(ctx, \"Non-matching states from %s\", req.RemoteAddr)\n\t\treturn\n\t}\n\tdata, err := getToken(ctx, code)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n\tio.WriteString(res, data.UID)\n}\n\nfunc getToken(ctx context.Context, code string) (*dropboxData, error) {\n\tv := url.Values{}\n\tv.Add(\"code\", code)\n\tv.Add(\"grant_type\", \"authorization_code\")\n\tv.Add(\"client_id\", \"2be6c5b4z9uhar7\")\n\tv.Add(\"client_secret\", \"kdbp5bt12vodkz5\")\n\tv.Add(\"redirect_uri\", \"http://localhost:8080/oauth2\")\n\tclient := urlfetch.Client(ctx)\n\tres, err := client.PostForm(\"https://api.dropbox.com/1/oauth2/token\", v)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer res.Body.Close()\n\tvar data dropboxData\n\terr = json.NewDecoder(res.Body).Decode(&data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlog.Debugf(ctx, \"%v\", data)\n\treturn &data, nil\n}\n"
  },
  {
    "path": "27_code-in-process/66_authentication_OAUTH/08_oauth-dropbox/session.go",
    "content": "package dropbox\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"github.com/nu7hatch/gouuid\"\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine/memcache\"\n)\n\nconst cookieName = \"sessionid\"\n\ntype session struct {\n\tID    string `json:\"-\"`\n\tState string\n}\n\nfunc getSession(ctx context.Context, req *http.Request) session {\n\tcookie, err := req.Cookie(cookieName)\n\tif err != nil || cookie.Value == \"\" {\n\t\tuid, _ := uuid.NewV4()\n\t\tcookie = &http.Cookie{\n\t\t\tName:  cookieName,\n\t\t\tValue: uid.String(),\n\t\t}\n\t}\n\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\titem = &memcache.Item{\n\t\t\tKey:   cookie.Value,\n\t\t\tValue: []byte(\"\"),\n\t\t}\n\t}\n\n\tvar s session\n\tjson.Unmarshal(item.Value, &s)\n\ts.ID = cookie.Value\n\treturn s\n}\n\nfunc putSession(ctx context.Context, res http.ResponseWriter, s session) error {\n\tbs, err := json.Marshal(s)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = memcache.Set(ctx, &memcache.Item{\n\t\tKey:   s.ID,\n\t\tValue: bs,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:  cookieName,\n\t\tValue: s.ID,\n\t})\n\n\treturn nil\n}\n"
  },
  {
    "path": "27_code-in-process/67_digital-ocean_aerospike/01_helloWorld/testServer.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/\", index)\n\thttp.ListenAndServe(\":9000\", nil)\n}\n\nfunc index(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path != \"/\" {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\tio.WriteString(res, \"Hello World!\")\n}\n"
  },
  {
    "path": "27_code-in-process/67_digital-ocean_aerospike/02_fullsite/.gitignore",
    "content": "users.json\nlogfile.txt"
  },
  {
    "path": "27_code-in-process/67_digital-ocean_aerospike/02_fullsite/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"html/template\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n\t\"os/signal\"\n\t\"strings\"\n\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"golang.org/x/crypto/bcrypt\"\n)\n\ntype user struct {\n\tUsername string\n\tPassword []byte\n\tID       string\n}\n\nvar tpl *template.Template\nvar users = map[string]user{}\nvar idUsers = map[string]user{}\n\nfunc main() {\n\ttpl = template.Must(template.ParseGlob(\"templates/*.gohtml\"))\n\n\tf, err := os.OpenFile(\"logfile.txt\", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0664)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer f.Close()\n\tlog.SetOutput(f)\n\n\tloadUsers()\n\n\trouter := httprouter.New()\n\trouter.GET(\"/\", index)\n\trouter.GET(\"/login\", loginPage)\n\trouter.POST(\"/login\", login)\n\trouter.GET(\"/logout\", logout)\n\trouter.GET(\"/create\", createPage)\n\trouter.POST(\"/create\", create)\n\tgo func() {\n\t\terr = http.ListenAndServe(\":9000\", router)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t}()\n\n\tc := make(chan os.Signal, 1)\n\tsignal.Notify(c, os.Interrupt, os.Kill)\n\t<-c\n\tsaveUsers()\n}\n\nfunc loadUsers() {\n\tvar rdr io.Reader\n\tf, err := os.Open(\"users.json\")\n\tif err != nil {\n\t\trdr = strings.NewReader(\"{}\")\n\t} else {\n\t\tdefer f.Close()\n\t\trdr = f\n\t}\n\terr = json.NewDecoder(rdr).Decode(&users)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfor _, u := range users {\n\t\tidUsers[u.ID] = u\n\t}\n}\n\nfunc saveUsers() {\n\tf, err := os.Create(\"users.json\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer f.Close()\n\terr = json.NewEncoder(f).Encode(users)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc index(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tvar username string\n\tc, err := req.Cookie(\"login\")\n\tif err == nil {\n\t\tid := c.Value\n\t\tu, ok := idUsers[id]\n\t\tif !ok {\n\t\t\tlog.Printf(\"error getting logged in user with id %s\\n\", id)\n\t\t} else {\n\t\t\tusername = u.Username\n\t\t}\n\t}\n\terr = tpl.ExecuteTemplate(res, \"index\", username)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Printf(\"error running index template: %s\\n\", err.Error())\n\t\treturn\n\t}\n}\n\nfunc loginPage(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\terr := tpl.ExecuteTemplate(res, \"login\", req.FormValue(\"msg\"))\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Printf(\"error running login template: %s\\n\", err.Error())\n\t\treturn\n\t}\n}\n\nfunc login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tname := req.FormValue(\"username\")\n\tp := req.FormValue(\"password\")\n\n\tu, ok := users[name]\n\tif !ok {\n\t\tlog.Printf(\"error logging in, no such user: %s\\n\", name)\n\t\thttp.Redirect(res, req, \"/login?msg=No such user\", http.StatusSeeOther)\n\t\treturn\n\t}\n\tif bcrypt.CompareHashAndPassword(u.Password, []byte(p)) != nil {\n\t\thttp.Redirect(res, req, \"/login?msg=Incorrect password\", http.StatusSeeOther)\n\t\treturn\n\t}\n\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:  \"login\",\n\t\tValue: u.ID,\n\t})\n\thttp.Redirect(res, req, \"/\", http.StatusSeeOther)\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:   \"login\",\n\t\tMaxAge: -1,\n\t})\n\thttp.Redirect(res, req, \"/\", http.StatusSeeOther)\n}\n\nfunc createPage(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\terr := tpl.ExecuteTemplate(res, \"create\", req.FormValue(\"msg\"))\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Printf(\"error running create template: %s\\n\", err.Error())\n\t\treturn\n\t}\n}\n\nfunc create(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tname := req.FormValue(\"username\")\n\tp := req.FormValue(\"password\")\n\tif len(name) < 3 || len(p) < 3 {\n\t\thttp.Redirect(res, req, \"/create?msg=Requires longer attributes\", http.StatusSeeOther)\n\t\treturn\n\t}\n\tid, err := uuid.NewV4()\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Printf(\"error generating uuid: %s\\n\", err.Error())\n\t\treturn\n\t}\n\thashPass, err := bcrypt.GenerateFromPassword([]byte(p), bcrypt.DefaultCost)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Printf(\"error hashing password: %s\\n\", err.Error())\n\t\treturn\n\t}\n\tu := user{\n\t\tUsername: name,\n\t\tPassword: hashPass,\n\t\tID:       id.String(),\n\t}\n\tusers[name] = u\n\tidUsers[id.String()] = u\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:  \"login\",\n\t\tValue: id.String(),\n\t})\n\thttp.Redirect(res, req, \"/\", http.StatusSeeOther)\n}\n"
  },
  {
    "path": "27_code-in-process/67_digital-ocean_aerospike/02_fullsite/templates/create.gohtml",
    "content": "{{define \"create\"}}\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<title>Create user</title>\n</head>\n<body>\n\t{{if .}}\n\t<p style=\"color: red;\">{{.}}</p>\n\t{{end}}\n\t<form method=\"POST\">\n\t\t<input type=\"text\" name=\"username\" placeholder=\"Username\" autofocus>\n\t\t<input type=\"password\" name=\"password\" placeholder=\"Password\">\n\t\t<input type=\"submit\" value=\"Create\">\n\t</form>\n</body>\n</html>\n{{end}}"
  },
  {
    "path": "27_code-in-process/67_digital-ocean_aerospike/02_fullsite/templates/index.gohtml",
    "content": "{{define \"index\"}}\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<title>Main Page</title>\n</head>\n<body>\n\t<h1>This is a website!</h1>\n\t{{if not .}}\n\t<a href=\"/login\">Login!</a>\n\t{{else}}\n\t<p>Welcome {{.}}!</p>\n\t<a href=\"/logout\">Log out</a>\n\t{{end}}\n</body>\n</html>\n{{end}}"
  },
  {
    "path": "27_code-in-process/67_digital-ocean_aerospike/02_fullsite/templates/login.gohtml",
    "content": "{{define \"login\"}}\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<title>Login</title>\n</head>\n<body>\n\t{{if .}}\n\t<p style=\"color: red;\">{{.}}</p>\n\t{{end}}\n\t<form method=\"POST\">\n\t\t<input type=\"text\" name=\"username\" placeholder=\"Username\" autofocus>\n\t\t<input type=\"password\" name=\"password\" placeholder=\"Password\">\n\t\t<input type=\"submit\" value=\"Login\">\n\t</form>\n\t<a href=\"/create\">Create new account</a>\n</body>\n</html>\n{{end}}"
  },
  {
    "path": "27_code-in-process/67_digital-ocean_aerospike/03-aerospike/main.go",
    "content": "package main\n\nimport (\n\t\"html/template\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n\n\t\"golang.org/x/crypto/bcrypt\"\n\n\tas \"github.com/aerospike/aerospike-client-go\"\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n)\n\ntype user struct {\n\tUsername string\n\tPassword string\n\tID       string\n}\n\nvar tpl *template.Template\nvar client *as.Client\n\nfunc main() {\n\ttpl = template.Must(template.ParseGlob(\"templates/*.gohtml\"))\n\n\tf, err := os.OpenFile(\"logfile.txt\", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0664)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer f.Close()\n\tlog.SetOutput(f)\n\n\tclient, err = as.NewClient(\"127.0.0.1\", 3000)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer client.Close()\n\n\trouter := httprouter.New()\n\trouter.GET(\"/\", index)\n\trouter.GET(\"/login\", loginPage)\n\trouter.POST(\"/login\", login)\n\trouter.GET(\"/logout\", logout)\n\trouter.GET(\"/create\", createPage)\n\trouter.POST(\"/create\", create)\n\terr = http.ListenAndServe(\":9000\", router)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc index(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tvar username string\n\tc, err := req.Cookie(\"login\")\n\tif err == nil {\n\t\tid := c.Value\n\t\tkey, err := as.NewKey(\"bar\", \"users\", id)\n\t\tif err != nil {\n\t\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\t\tlog.Printf(\"error creating key: %s\\n\", err.Error())\n\t\t\treturn\n\t\t}\n\t\texists, err := client.Exists(nil, key)\n\t\tif err != nil {\n\t\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\t\tlog.Printf(\"error checking existance: %s\\n\", err.Error())\n\t\t\treturn\n\t\t}\n\t\tif !exists {\n\t\t\tlog.Printf(\"error getting logged in user with id %s\\n\", id)\n\t\t} else {\n\t\t\tvar u user\n\t\t\terr = client.GetObject(nil, key, &u)\n\t\t\tif err != nil {\n\t\t\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\t\t\tlog.Printf(\"error getting value: %s\\n\", err.Error())\n\t\t\t\treturn\n\t\t\t}\n\t\t\tusername = u.Username\n\t\t}\n\t}\n\terr = tpl.ExecuteTemplate(res, \"index\", username)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Printf(\"error running index template: %s\\n\", err.Error())\n\t\treturn\n\t}\n}\n\nfunc loginPage(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\terr := tpl.ExecuteTemplate(res, \"login\", req.FormValue(\"msg\"))\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Printf(\"error running login template: %s\\n\", err.Error())\n\t\treturn\n\t}\n}\n\nfunc login(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tname := req.FormValue(\"username\")\n\tp := req.FormValue(\"password\")\n\n\tvar u *user\n\n\t// statements are query statements\n\t// namespace, set/kind, ...fieldsWeWant\n\t// note: usernames must be unique; not checked in this example\n\tstmt := as.NewStatement(\"bar\", \"users\", \"Username\", \"Password\", \"ID\")\n\tstmt.Addfilter(as.NewEqualFilter(\"Username\", name))\n\trs, err := client.Query(nil, stmt)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Printf(\"error querying: %s\\n\", err.Error())\n\t\treturn\n\t}\n\tdefer rs.Close()\n\tfor res := range rs.Results() {\n\t\tif res.Err != nil {\n\t\t\tlog.Printf(\"error querying specific data: %s\\n\", err.Error())\n\t\t} else {\n\t\t\tu = &user{\n\t\t\t\tUsername: res.Record.Bins[\"Username\"].(string),\n\t\t\t\tPassword: res.Record.Bins[\"Password\"].(string),\n\t\t\t\tID:       res.Record.Bins[\"ID\"].(string),\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif u == nil {\n\t\tlog.Printf(\"error logging in, no such user: %s\\n\", name)\n\t\thttp.Redirect(res, req, \"/login?msg=No such user\", http.StatusSeeOther)\n\t\treturn\n\t}\n\tif bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(p)) != nil {\n\t\thttp.Redirect(res, req, \"/login?msg=Incorrect password\", http.StatusSeeOther)\n\t\treturn\n\t}\n\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:  \"login\",\n\t\tValue: u.ID,\n\t})\n\thttp.Redirect(res, req, \"/\", http.StatusSeeOther)\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:   \"login\",\n\t\tMaxAge: -1,\n\t})\n\thttp.Redirect(res, req, \"/\", http.StatusSeeOther)\n}\n\nfunc createPage(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\terr := tpl.ExecuteTemplate(res, \"create\", req.FormValue(\"msg\"))\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Printf(\"error running create template: %s\\n\", err.Error())\n\t\treturn\n\t}\n}\n\nfunc create(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tname := req.FormValue(\"username\")\n\tp := req.FormValue(\"password\")\n\tif len(name) < 3 || len(p) < 3 {\n\t\thttp.Redirect(res, req, \"/create?msg=Requires longer attributes\", http.StatusSeeOther)\n\t\treturn\n\t}\n\tid, err := uuid.NewV4()\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Printf(\"error generating uuid: %s\\n\", err.Error())\n\t\treturn\n\t}\n\thashPass, err := bcrypt.GenerateFromPassword([]byte(p), bcrypt.DefaultCost)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Printf(\"error hashing password: %s\\n\", err.Error())\n\t\treturn\n\t}\n\tu := user{\n\t\tUsername: name,\n\t\tPassword: string(hashPass),\n\t\tID:       id.String(),\n\t}\n\n\tkey, err := as.NewKey(\"bar\", \"users\", id.String())\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Printf(\"error creating key: %s\\n\", err.Error())\n\t\treturn\n\t}\n\terr = client.PutObject(nil, key, &u)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Printf(\"error saving object: %s\\n\", err.Error())\n\t\treturn\n\t}\n\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:  \"login\",\n\t\tValue: id.String(),\n\t})\n\thttp.Redirect(res, req, \"/\", http.StatusSeeOther)\n}\n"
  },
  {
    "path": "27_code-in-process/67_digital-ocean_aerospike/03-aerospike/templates/create.gohtml",
    "content": "{{define \"create\"}}\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<title>Create user</title>\n</head>\n<body>\n\t{{if .}}\n\t<p style=\"color: red;\">{{.}}</p>\n\t{{end}}\n\t<form method=\"POST\">\n\t\t<input type=\"text\" name=\"username\" placeholder=\"Username\" autofocus>\n\t\t<input type=\"password\" name=\"password\" placeholder=\"Password\">\n\t\t<input type=\"submit\" value=\"Create\">\n\t</form>\n</body>\n</html>\n{{end}}"
  },
  {
    "path": "27_code-in-process/67_digital-ocean_aerospike/03-aerospike/templates/index.gohtml",
    "content": "{{define \"index\"}}\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<title>Main Page</title>\n</head>\n<body>\n\t<h1>This is a website!</h1>\n\t{{if not .}}\n\t<a href=\"/login\">Login!</a>\n\t{{else}}\n\t<p>Welcome {{.}}!</p>\n\t<a href=\"/logout\">Log out</a>\n\t{{end}}\n</body>\n</html>\n{{end}}"
  },
  {
    "path": "27_code-in-process/67_digital-ocean_aerospike/03-aerospike/templates/login.gohtml",
    "content": "{{define \"login\"}}\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<title>Login</title>\n</head>\n<body>\n\t{{if .}}\n\t<p style=\"color: red;\">{{.}}</p>\n\t{{end}}\n\t<form method=\"POST\">\n\t\t<input type=\"text\" name=\"username\" placeholder=\"Username\" autofocus>\n\t\t<input type=\"password\" name=\"password\" placeholder=\"Password\">\n\t\t<input type=\"submit\" value=\"Login\">\n\t</form>\n\t<a href=\"/create\">Create new account</a>\n</body>\n</html>\n{{end}}"
  },
  {
    "path": "27_code-in-process/67_digital-ocean_aerospike/README.md",
    "content": "# How to setup Go and Aerospike in digitalocean Ubuntu 15.10\n\n## Setup Ubuntu user account\n1. Create a ssh key\n\t* unix users\n\t\t* at terminal:\n\t\t\t* cat ~/.ssh/id_rsa.pub\n\t\t\t\t* checks to see if you have a key in this location\n\t\t\t* ssh-keygen\n\t\t\t\t* creates a key\n\t\t\t\t* if it's production code, set a password\n\t\t\t* cat ~/.ssh/id_rsa.pub\n\t\t\t\t* .pub is the public key\n\t\t\t\t* never show anyone your private key which was also created\n\t\t\t\t\t* it doesn't have an extension, just: id_rsa\n\t* windows users\n\t\t* use putty program; download it from online\n1. Setup Github to use your SSH\n\t* https://github.com/settings/ssh\n\t* we can give our public key to github\n\t\t* this allows us to connect to github and not have to enter a password\n\t\t* our machine will send a message to github\n\t\t\t* github will use our public key\n\t\t\t* if it can decrypt the message, no other password is needed\n\t* at terminal:\n\t\t* ssh -T git@github.com\n\t\t* Hi GoesToEleven! You've successfully authenticated, but GitHub does not provide shell access.\n1. Create a server.\n    * create droplet\n    * hostname\n    \t* digital ocean recommends your url, eg, www.mcleods.com-1\n    \t* use \"dash digit\" for multiple servers, eg, www.mcleods.com-2 ... www.mcleods.com-9\n    * Make sure to set the server to ubuntu 15.10.\n    * 32-bit is recommended unless you have more than 4gb of RAM,\n    \t* EXCEPT for if you use AEROSPIKE, which requires 64-bit for both main database and API.\n    * Make sure you turn on private networking\n    \t* so you can connect to your database without using up bandwidth.\n    * Make sure you have put in an ssh key here\n    \t* to avoid unsecure password logins.\n\t* you'll need your IP address\n\t\t* once your server is created, you'll see this\n\t\t* copy it: eg, 192.241.219.56\n1. Connect to server's root account.\n    * Use ssh on unix machines.\n        * `ssh root@<ip_address>`\n        * eg, ssh root@192.241.219.56\n    * Make sure you have setup ssh keys with your computer.\n    \t* which we did above in these notes\n    \t* Windows user should use putty.\n\t* after running the `ssh root@<ip_address>` command\n\t\t* your terminal is now ON the server\n1. Create a user with sudo access.\n    * you're logged into the server with full admin access\n    * it's better to create a user with more limited access\n    \t* `adduser <username>`\n    \t* this creates a folder with the username\n    \t* the user has access to that folder\n    * Make sure to put in a good password!\n    * You can leave the other settings blank, just keep pressing enter.\n    * Give the user sudo access.\n        * `gpasswd -a <username> sudo`\n1. Add ssh key access to new user account.\n    * Flip your access to the new user.\n        * `su <username>`\n    * Move to the home directory.\n        * `cd`\n    * Create folder and restrict access to only yourself.\n        * `mkdir .ssh`\n        * `chmod 700 .ssh`\n    * Create a file and add ssh key to it.\n        * `nano .ssh/authorized_keys`\n        * Paste key into file and save and exit with Ctrl-X.\n        \t* cat ~/.ssh/authorized_keys\n            * Ctrl-Shift-V for unix users to paste.\n            * Right-click in window to paste for putty.\n    * Restrict the permissions of the file.\n        * `chmod 600 .ssh/authorized_keys`\n    * Return to root.\n        * `exit`\n    * Test if it worked.\n        * Connect to your new account with either putty or ssh\n            * `ssh <username>@<ip_address>`\n        * If it asks for your password, something went wrong.\n1. Restrict ssh access to root and password connections.\n    * As root, edit the settings in the ssh config file.\n        * `nano /etc/ssh/sshd_config`\n        * Set the line `PermitRootLogin` to no to disable root login.\n        * Set the line `PasswordAuthentication` to no to disable logging in with a password.\n            * Make sure to uncomment the line as well.\n        * Restart the ssh service.\n          * `service ssh restart`\n    * Make sure you test if you can still access it with normal connection\n    \t* BEFORE you disconnect the root terminal.\n    \t\t* new tab in terminal\n    \t\t* ssh <username>@IP, eg, ssh todd@192.241.219.56\n    * And test that the root login really is disabled.\n    \t\t* ssh root@192.241.219.56\n\n## Setup additional helpful items\n1. Setup firewall.\n    * Allow ssh through the firewall.\n        * this way\n        \t* `sudo ufw allow ssh`\n        * OR\n        \t* `sudo ufw allow 22/tcp`\n    * Examine the rules.\n        * `sudo ufw show added`\n    * If everything looks right, enable the firewall.\n        * `sudo ufw enable`\n    * Make sure everything is running right.\n        * `sudo ufw status`\n1. Synchronize the system clock.\n    * Set timezone.\n        * `sudo dpkg-reconfigure tzdata`\n        * A graphical menu will allow you to choose a city to sync time with.\n    * Install NTP\n        * If you have not used apt-get yet, run `sudo apt-get update`\n        \t* apt-get is a package manager for debian unix and above\n        * `sudo apt-get install ntp`\n        * ntp will automatically place enable run on boot.\n1. Create a swapspace.\n    * Reserve the space.\n        * `sudo fallocate -l <size> /swapfile`\n        * `<size>` is something like `1G` or `512M`\n        \t* recommended size: equal or double your RAM\n    * Restrict access to root only.\n        * `sudo chmod 600 /swapfile`\n    * Configure into a swapfile.\n        * `sudo mkswap /swapfile`\n    * Start using the swapfile.\n        * `sudo swapon /swapfile`\n    * Setup automatically using the swapfile on boot.\n        * `sudo sh -c 'echo \"/swapfile none swap sw 0 0\" >> /etc/fstab'`\n1. This is a good point to make a snapshot of your server.\n    * Shut the server down.\n        * `sudo poweroff`\n    * Save a snapshot in the digitalocean console.\n    \t* goto www.digitalocean.com\n    \t* make the snapshot\n    \t\t* go into your server\n    \t\t* refresh until \"OFF\"\n    \t\t* take snapshot\n\n## Get a Go server running\n1. (optional) install Go.\n    * If you have Go 1.5 or newer, you can cross compile most programs and transfer the executable.\n    \t* at terminal:\n\t\t\t* go\n\t\t\t\t* see all of the go commands\n\t\t\t* go help environment\n\t\t\t* you can set your build on your dev machine for your destination machine\n\t\t\t\t* eg, GOOS=linux GOARCH=amd64 go build\n\t\t\t\t* you could then take your binary and run it on your destination machine\n    * Some packages still require a native Go install to build though.\n    * Download Go.\n        * `wget <url>`\n        * The url for 1.5.1 is `https://storage.googleapis.com/golang/go1.5.1.linux-amd64.tar.gz`\n        * eg, `wget https://storage.googleapis.com/golang/go1.5.1.linux-amd64.tar.gz`\n    * Extract Go from the archive file.\n        * `tar -xzf <filename>`\n        \t* x is for extract\n        \t* z is for giz\n        \t* f is for file\n    * Move Go to the default install location.\n        * `sudo mv go /usr/local/go`\n    * Change owner to root and alter permissions.\n        * `sudo chown -R root:root /usr/local/go`\n        * `sudo chmod 755 /usr/local/go`\n    * Create workspace folder.\n    \t* cd ~\n        * `mkdir <workspace_name>{,/bin,/pkg,/src}`\n        \t* eg, `mkdir goworkspace{,/bin,/pkg,/src}`\n    * Edit environment variables.\n    \t* `sudo nano /etc/profile`\n        \t* Add `export PATH=$PATH:/usr/local/go/bin` to `/etc/profile` file\n        * cd ~\n        * nano ~/.profile\n\t\t\t* Add `export GOPATH=$HOME/<workspace_name>` to `~/.profile` file\n\t\t\t* Add `export PATH=$HOME/<workspace_name>/bin:$PATH` to `~/.profile`\n    * Delete the go archive file.\n        * `rm <filename>`\n        \t* eg, `rm go1.5.1.linux-amd64.tar.gz`\n    * Install git.\n        * `sudo apt-get install git`\n    * Reconnect to the server to allow environment variables to update.\n1. Adjust firewall to allow http connections.\n    * Allow http through the firewall.\n        * `sudo ufw allow http`\n        * OR `sudo ufw allow 80/tcp`\n    * Allow https through the firewall, if needed.\n        * `sudo ufw allow https`\n        * or `sudo ufw allow 443/tcp`\n\t* Run this to make sure the rules got added\n\t\t* `sudo ufw status`\n1. Setup haproxy (high availability proxy)\n    * Install haproxy.\n        * `sudo apt-get install haproxy`\n    * Configure haproxy.\n        * Edit this `/etc/haproxy/haproxy.cfg` with sudo nano\n        \t* eg, `sudo nano /etc/haproxy/haproxy.cfg`\n        * Add to the default section:\n         \t* `retries 3`\n\t\t\t* `option redispatch`\n\t\t\t* Add the following block to the end of the file:\n```\nlisten app 0.0.0.0:80\n\tmode http\n\toption http-server-close\n\ttimeout http-keep-alive 3000\n\tserver serv 127.0.0.1:9000 check\n```\n\n    * More information available [here](https://www.digitalocean.com/community/tutorials/how-to-use-haproxy-to-set-up-http-load-balancing-on-an-ubuntu-vps).\n  * Reload haproxy\n    * `sudo service haproxy reload`\n1. Get your code onto the server.\n    * secure copy to copy your files over:\n\t\t* WINDOWS\n\t\t\t* use WinSCP\n\t\t* UNIX machine\n\t\t\t* use scp:\n\t\t\t\t* `scp <source> <destination>`\n\t\t\t\t\t* Add -rp if it is a folder you are transfering.\n\t\t\t\t\t* `scp -rp <source> <destination>`\n\t\t\t\t* The format for remote connections is `<username>@<ip_address>:<path>`\n\t\t\t\t\t* Example: `scp -rp ~/Desktop/testServer daniel@107.170.246.157:~/testServer`\n\t\t\t\t\t* Another Example: `scp -rp 01_helloWorld/ todd@192.241.219.56:~/01_helloWorld`\n\t\t* Make sure it is built, whether on your system or on the server directly.\n\t\t\t* on your server:\n\t\t\t\t* go run testServer.go\n1. Configure systemd.\n\t* systemd is system daemon\n\t\t* like all good demons, system daemon does not require direct supervision\n\t\t* this means we can shut off our dev machine and the website will still serve\n\t* wikipedia:\n\t\t* In multitasking computer operating systems, a daemon (/ˈdiːmən/ or /ˈdeɪmən/)[1] is a computer program that runs as a background process, rather than being under the direct control of an interactive user. Traditionally daemon names end with the letter d. For example, syslogd is the daemon that implements the system logging facility, and sshd is a daemon that services incoming SSH connections.\n    * Create configuration file: `sudo nano /etc/systemd/system/<filename>.service`\n    \t* eg, `sudo nano /etc/systemd/system/serveityo.service`\n    * Add the following code to the file:\n    ```\n[Unit]\nDescription=Go Server\n\n[Service]\nExecStart=/home/<username>/<exepath>\nWorkingDirectory=/home/<username>/<exefolderpath>\nUser=<username>\nGroup=<username>\nRestart=always\n\n[Install]\nWantedBy=multi-user.target\n    ```\n\n    * eg,\n    ```\n[Unit]\nDescription=Go Server\n\n[Service]\nExecStart=/home/todd/01_helloWorld/01_helloWorld\nWorkingDirectory=/home/todd/01_helloWorld\nUser=todd\nGroup=todd\nRestart=always\n\n[Install]\nWantedBy=multi-user.target\n    ```\n\n    * Add the service to systemd.\n        * `sudo systemctl enable <filename>.service`\n        * eg, `sudo systemctl enable serveityo.service`\n    * Activate the service.\n        * `sudo systemctl start <filename>.service`\n        * eg, `sudo systemctl start serveityo.service`\n    * Check if systemd started it.\n        * `sudo systemctl status <filename>.service`\n        * eg, `sudo systemctl status serveityo.service`\n    * if you get this ERROR:\n    \t* Failed to start Go Server.\n    \t* make sure you build your file:\n    \t\t* go build\n    * More information about systemd commands can be found [here](http://www.linux.com/learn/tutorials/788613-understanding-and-using-systemd/).\n    * Check if the server is running with your web-browser, just use the server ip address as the url.\n\n## Setup Aerospike server\n1. Download and install Aerospike.\n  * Aerospike only works for 64-bit machines unless you build it from source yourself, and recommends at least 2gb of RAM.\n  * You can get step-by-step instructions for installation [here](http://www.aerospike.com/get-started/#/linux).\n  * Download the archive file.\n    * `wget -O aerospike.tgz 'http://aerospike.com/download/server/latest/artifact/ubuntu12'`\n  * Extract the archive file.\n    * `tar -xvf aerospike.tgz`\n  * Go into the directory on run the installer.\n    * `cd aerospike-server-community-<enter your version here>-ubuntu12`\n    \t* eg, `cd aerospike-server-community-3.6.4-ubuntu12.04/`\n    * `sudo ./asinstall`\n  * Allow the database port through the firewall.\n  \t* you don't need this if you're running everything on the same server:\n    \t* `sudo ufw allow in on eth1 to any port 3000 proto tcp`\n  * Start the service.\n    * `sudo service aerospike start`\n    * Check when it is ready with: `sudo tail -f /var/log/aerospike/aerospike.log | grep cake`\n    \t* ctrl+c\n    \t* stops monitoring the file with tail\n  * Delete the aerospike install files.\n    * rm -rf aerospike*\n1. Install Aerospike management server (optional).\n  * Install python2.x, python development libraries, and gcc\n    * `sudo apt-get install python gcc python-dev`\n  * Download the package file.\n    * `wget -O amc.deb http://www.aerospike.com/download/amc/latest/artifact/ubuntu12`\n  * Install the server.\n    * `sudo dpkg -i amc.deb`\n  * Allow the server port through the firewall.\n    * `sudo ufw allow 8081/tcp`\n  * Start the server.\n    * `sudo /etc/init.d/amc start`\n  * Examine the amc in your web-browser, address is: `<server_ip>:8081`\n  \t* eg, `192.241.219.56:8081`\n    * When it asks you for the ip of a node, enter the localhost ip: `127.0.0.1`\n  * Delete amc install file.\n    * `rm amc.deb`\n1. Configure Aerospike.\n  * Add namespaces as needed.\n    * `sudo nano /etc/aerospike/aerospike.conf`\n    * At the bottom of the file is the test and bar namespaces, comment them out and use them as examples.\n    * This is also the file where you can configure having multiple nodes in a cluster. More information on configuring Aerospike [here](http://www.aerospike.com/docs/operations/configure/network/).\n  * Restart Aerospike.\n    * `sudo service aerospike restart`\n\n## Get Go Aerospike library and test server\n  1. On the server (and your dev machine if you haven't already):\n  \t* Get the go client library (64-bit only).\n    * `go get github.com/aerospike/aerospike-client-go`\n  1. Run the benchmark tool, (64-bit only).\n    * Change into the client code directory, tools/benchmark\n      * `cd $GOPATH/src/github.com/aerospike/aerospike-client-go/tools/benchmark`\n    * Run the tool.\n      * `go run benchmark.go -h <ip_address>`\n      \t* eg, `go run benchmark.go -h 127.0.0.1`\n      * Note this will only work from a server in digitalocean, since the firewall is configured to only allow connections from eth1, which is the private network.\n      * Private ip address can be found with: `ifconfig | grep \"inet addr\"`, the middle address should be the private one.\n\n## Additional API help\n  * The [godoc](https://godoc.org/github.com/aerospike/aerospike-client-go) page is very large, but has everything, including enterprise edition commands.\n  * Information on connecting can be found [here](http://www.aerospike.com/docs/client/go/usage/connect/).\n  * Information on writing a record, including how to write to a single value in a field and how to set an expiration date for data can be found [here](http://www.aerospike.com/docs/client/go/usage/kvs/write.html).\n  * Information on reading a record, including only getting parts of an object, can be found [here](http://www.aerospike.com/docs/client/go/usage/kvs/read.html).\n  * Information on queries can be found [here](http://www.aerospike.com/docs/client/go/usage/query/query.html).\n  * When you are querying on something, make sure you add a secondary index for that field. You can do that programmatically with Go, or using the Aerospike management server.\n"
  },
  {
    "path": "27_code-in-process/68_task-queue/01_delay/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/68_task-queue/01_delay/delayed.go",
    "content": "package taskexample\n\nimport (\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine/delay\"\n\t\"google.golang.org/appengine/log\"\n)\n\nvar delayedPuppy *delay.Function\n\nfunc init() {\n\tdelayedPuppy = delay.Func(\"delayedPuppy\", runLater)\n}\n\nfunc runLater(ctx context.Context) {\n\tlog.Infof(ctx, \"delayedPuppy ran\")\n}\n"
  },
  {
    "path": "27_code-in-process/68_task-queue/01_delay/routes.go",
    "content": "package taskexample\n\nimport (\n\t\"google.golang.org/appengine\"\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tdelayedPuppy.Call(ctx)\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <head></head>\n  <body>\n    <p>Nothing to do</p>\n  </body>\n</html>`)\n}\n"
  },
  {
    "path": "27_code-in-process/68_task-queue/02_delay-cron/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/68_task-queue/02_delay-cron/cron.yaml",
    "content": "cron:\n- description: daily summary job\n  url: /schedule-example\n  schedule: every 1 minutes\n"
  },
  {
    "path": "27_code-in-process/68_task-queue/02_delay-cron/delayed.go",
    "content": "package taskexample\n\nimport (\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine/delay\"\n\t\"google.golang.org/appengine/log\"\n)\n\nvar delayedPuppy *delay.Function\n\nfunc init() {\n\tdelayedPuppy = delay.Func(\"delayedPuppy\", runLater)\n}\n\nfunc runLater(ctx context.Context) {\n\tlog.Infof(ctx, \"delayedPuppy ran\")\n}\n"
  },
  {
    "path": "27_code-in-process/68_task-queue/02_delay-cron/routes.go",
    "content": "package taskexample\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <head></head>\n  <body>\n    <p>Nothing to do</p>\n  </body>\n</html>`)\n}\n"
  },
  {
    "path": "27_code-in-process/68_task-queue/02_delay-cron/scheduled.go",
    "content": "package taskexample\n\nimport (\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/schedule-example\", handleScheduleExample)\n}\n\nfunc handleScheduleExample(res http.ResponseWriter, req *http.Request) {\n\tif req.Header.Get(\"X-Appengine-Cron\") != \"true\" {\n\t\thttp.Error(res, \"Forbidden\", http.StatusForbidden)\n\t\treturn\n\t}\n\tctx := appengine.NewContext(req)\n\tlog.Infof(ctx, \"I was Scheduled!!!\")\n\tdelayedPuppy.Call(ctx)\n}\n"
  },
  {
    "path": "27_code-in-process/68_task-queue/03_github/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/68_task-queue/03_github/github.go",
    "content": "package githubexample\n\nimport (\n\t\"encoding/json\"\n\t\"io/ioutil\"\n\t\"net/url\"\n\t\"sync\"\n\t\"time\"\n\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/delay\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/urlfetch\"\n)\n\nconst redirectURI = \"http://localhost:8080/oauth2callback\"\nconst githubAPIURL = \"https://api.github.com\"\n\nvar delayedGetStats *delay.Function\n\nfunc init() {\n\tdelayedGetStats = delay.Func(\n\t\t\"my-favorite-dog\",\n\t\tfunc(ctx context.Context, accessToken, username string) error {\n\t\t\tlog.Infof(ctx, \"delayedGetStats CALLED\")\n\t\t\tapi := &GithubAPI{\n\t\t\t\tctx:         ctx,\n\t\t\t\taccessToken: accessToken,\n\t\t\t\tusername:    username,\n\t\t\t}\n\t\t\tsince := time.Now().Add(-time.Hour * 24 * 30)\n\t\t\tstats, err := api.getCommitSummaryStats(since)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tlog.Infof(ctx, \"STATS: %v\", stats)\n\n\t\t\tkey := datastore.NewKey(ctx, \"Stats\", username, 0, nil)\n\t\t\t_, err = datastore.Put(ctx, key, &stats)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t)\n}\n\ntype GithubAPI struct {\n\tctx         context.Context\n\taccessToken string\n\tusername    string\n}\n\ntype CommitStats struct {\n\tAdditions, Deletions int\n}\n\nfunc NewGithubAPI(ctx context.Context) *GithubAPI {\n\treturn &GithubAPI{\n\t\tctx: ctx,\n\t}\n}\n\nfunc (api *GithubAPI) getUsername() (string, error) {\n\tclient := urlfetch.Client(api.ctx)\n\tresponse, err := client.Get(\n\t\tgithubAPIURL + \"/user?access_token=\" + api.accessToken)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer response.Body.Close()\n\n\tvar data struct {\n\t\tLogin string\n\t}\n\terr = json.NewDecoder(response.Body).Decode(&data)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn data.Login, nil\n}\n\nfunc (api *GithubAPI) getAccessToken(state, code string) (string, error) {\n\tvalues := make(url.Values)\n\tvalues.Add(\"client_id\", \"767154e6915134caade5\")\n\tvalues.Add(\"client_secret\", \"50648a71510c21bb77e229692fc882dfbe8ea35d\")\n\tvalues.Add(\"code\", code)\n\tvalues.Add(\"state\", state)\n\n\tclient := urlfetch.Client(api.ctx)\n\tresponse, err := client.PostForm(\"https://github.com/login/oauth/access_token\", values)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer response.Body.Close()\n\n\tbs, err := ioutil.ReadAll(response.Body)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tvalues, err = url.ParseQuery(string(bs))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn values.Get(\"access_token\"), nil\n}\n\nfunc (api *GithubAPI) getCommitSummaryStats(since time.Time) (CommitStats, error) {\n\tvar stats CommitStats\n\n\ttype Repo struct {\n\t\tOrganization, Repository string\n\t}\n\n\tvar wg sync.WaitGroup\n\trepositoryChannel := make(chan Repo)\n\tstatsChannel := make(chan CommitStats)\n\tfor i := 0; i < 10; i++ {\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tfor repo := range repositoryChannel {\n\t\t\t\t// list all commits for repository: GET /repos/:owner/:repo/commits\n\t\t\t\tshas, err := api.getUserCommitShas(repo.Organization, repo.Repository, since)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Errorf(api.ctx, \"Error getting user commit shas: %v\", err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tlog.Infof(api.ctx, \"REPO: %v, SHAS:%v\", repo, shas)\n\t\t\t\tfor _, sha := range shas {\n\t\t\t\t\t// get a single commit: GET /repos/:owner/:repo/commits/:sha\n\t\t\t\t\tcs, err := api.getCommitStats(repo.Organization, repo.Repository, sha)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlog.Errorf(api.ctx, \"Error getting stats: %v\", err)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tstatsChannel <- cs\n\t\t\t\t}\n\t\t\t}\n\t\t\twg.Done()\n\t\t}()\n\t}\n\n\t// list organizations: GET /user/orgs\n\tgo func() {\n\t\torganizations, err := api.getOrganizations()\n\t\tif err != nil {\n\t\t\tlog.Errorf(api.ctx, \"ERROR GETTING ORGANIZATIONS: %v\", err)\n\t\t\treturn\n\t\t}\n\t\tfor _, organization := range organizations {\n\t\t\t// list repositories: GET /orgs/:org/repos\n\t\t\trepositories, err := api.getRepositories(organization)\n\t\t\tif err != nil {\n\t\t\t\tlog.Errorf(api.ctx, \"ERROR GETTING REPOSITORIES: %v\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlog.Infof(api.ctx, \"REPOSITORIES:%v\", repositories)\n\t\t\tfor _, repository := range repositories {\n\t\t\t\trepositoryChannel <- Repo{organization, repository}\n\t\t\t}\n\t\t}\n\t\tclose(repositoryChannel)\n\t}()\n\n\tgo func() {\n\t\twg.Wait()\n\t\tclose(statsChannel)\n\t}()\n\n\tfor cs := range statsChannel {\n\t\tstats.Additions += cs.Additions\n\t\tstats.Deletions += cs.Deletions\n\t}\n\n\treturn stats, nil\n}\n\nfunc (api *GithubAPI) getOrganizations() ([]string, error) {\n\tendpoint := \"/user/orgs\"\n\tvar data []struct {\n\t\tLogin string `json:\"login\"`\n\t}\n\terr := api.makeAPIRequest(endpoint, nil, &data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnames := make([]string, len(data))\n\tfor i, v := range data {\n\t\tnames[i] = v.Login\n\t}\n\n\treturn names, nil\n}\n\nfunc (api *GithubAPI) getRepositories(organization string) ([]string, error) {\n\t// GET /orgs/:org/repos\n\tvar data []struct {\n\t\tName string `json:\"name\"`\n\t}\n\terr := api.makeAPIRequest(\"/orgs/\"+organization+\"/repos\", nil, &data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tnames := make([]string, len(data))\n\tfor i, v := range data {\n\t\tnames[i] = v.Name\n\t}\n\treturn names, nil\n}\n\nfunc (api *GithubAPI) getUserCommitShas(organization, repository string, since time.Time) ([]string, error) {\n\tvalues := make(url.Values)\n\tvalues.Add(\"author\", api.username)\n\tvalues.Add(\"since\", since.Format(time.RFC3339))\n\t// GET /repos/:owner/:repo/commits\n\tendpoint := \"/repos/\" + organization + \"/\" + repository + \"/commits\"\n\tvar data []struct {\n\t\tSHA string `json:\"sha\"`\n\t}\n\terr := api.makeAPIRequest(endpoint, values, &data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tshas := make([]string, len(data))\n\tfor i, v := range data {\n\t\tshas[i] = v.SHA\n\t}\n\treturn shas, nil\n}\n\nfunc (api *GithubAPI) getCommitStats(organization, repository, sha string) (CommitStats, error) {\n\tvar stats CommitStats\n\tendpoint := \"/repos/\" + organization + \"/\" + repository + \"/commits/\" + sha\n\tvar data struct {\n\t\tStats struct {\n\t\t\tAdditions int `json:\"additions\"`\n\t\t\tDeletions int `json:\"deletions\"`\n\t\t} `json:\"stats\"`\n\t}\n\terr := api.makeAPIRequest(endpoint, nil, &data)\n\tif err != nil {\n\t\treturn stats, err\n\t}\n\tstats.Additions = data.Stats.Additions\n\tstats.Deletions = data.Stats.Deletions\n\treturn stats, nil\n}\n\nfunc (api *GithubAPI) makeAPIRequest(endpoint string, values url.Values, dst interface{}) error {\n\tclient := urlfetch.Client(api.ctx)\n\tif values == nil {\n\t\tvalues = make(url.Values)\n\t}\n\tvalues.Add(\"access_token\", api.accessToken)\n\t// GET /user/orgs\n\tresponse, err := client.Get(githubAPIURL + endpoint + \"?\" + values.Encode())\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer response.Body.Close()\n\n\tbs, _ := ioutil.ReadAll(response.Body)\n\t//log.Infof(api.ctx, \"GET %s RESPONSE: %s\", endpoint, string(bs))\n\treturn json.Unmarshal(bs, dst)\n}\n"
  },
  {
    "path": "27_code-in-process/68_task-queue/03_github/login.go",
    "content": "package githubexample\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\n\t\"github.com/nu7hatch/gouuid\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n\thttp.HandleFunc(\"/github-login\", handleGithubLogin)\n\thttp.HandleFunc(\"/oauth2callback\", handleOauth2Callback)\n\thttp.HandleFunc(\"/github-info\", handleGithubInfo)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <head></head>\n  <body>\n    <a href=\"/github-login\">LOGIN WITH GITHUB</a>\n  </body>\n</html>`)\n}\n\nvar githubScopes = []string{\n\t\"user:email\",\n\t\"read:org\",\n}\n\nfunc handleGithubLogin(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\t// get the session\n\tsession := getSession(ctx, req)\n\tid, _ := uuid.NewV4()\n\n\tvalues := make(url.Values)\n\tvalues.Add(\"client_id\", \"767154e6915134caade5\")\n\tvalues.Add(\"redirect_uri\", redirectURI)\n\tvalues.Add(\"scope\", strings.Join(githubScopes, \",\"))\n\tvalues.Add(\"state\", id.String())\n\n\t// save the session\n\tsession.State = id.String()\n\tputSession(ctx, res, session)\n\n\thttp.Redirect(res, req, fmt.Sprintf(\n\t\t\"https://github.com/login/oauth/authorize?%s\",\n\t\tvalues.Encode(),\n\t), 302)\n}\n\nfunc handleOauth2Callback(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tapi := NewGithubAPI(ctx)\n\t// get the session\n\tsession := getSession(ctx, req)\n\n\tstate := req.FormValue(\"state\")\n\tcode := req.FormValue(\"code\")\n\n\tif state != session.State {\n\t\thttp.Error(res, \"invalid state\", 401)\n\t\treturn\n\t}\n\n\taccessToken, err := api.getAccessToken(state, code)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tapi.accessToken = accessToken\n\n\tusername, err := api.getUsername()\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tsession.Username = username\n\tsession.AccessToken = accessToken\n\tputSession(ctx, res, session)\n\n\tdelayedGetStats.Call(ctx, accessToken, username)\n\thttp.Redirect(res, req, \"/github-info\", 302)\n\n}\n\nfunc handleGithubInfo(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tsession := getSession(ctx, req)\n\n\tvar stats CommitStats\n\n\tkey := datastore.NewKey(ctx, \"Stats\", session.Username, 0, nil)\n\terr := datastore.Get(ctx, key, &stats)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\t// stats, err := api.getCommitSummaryStats(since)\n\t// if err != nil {\n\t// \thttp.Error(res, err.Error(), 500)\n\t// \treturn\n\t// }\n\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n\t<head>\n\n\t</head>\n\t<body>\n\t\tIn the last month you have:\n\t\t<table>\n\t\t\t<tr>\n\t\t\t\t<th>additions</th>\n\t\t\t\t<td>`+fmt.Sprint(stats.Additions)+`</td>\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t<th>deletions</th>\n\t\t\t\t<td>`+fmt.Sprint(stats.Deletions)+`</td>\n\t\t\t</tr>\n\t\t</table>\n\t</body>\n</html>`)\n}\n"
  },
  {
    "path": "27_code-in-process/68_task-queue/03_github/session.go",
    "content": "package githubexample\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"google.golang.org/appengine/memcache\"\n\n\t\"github.com/nu7hatch/gouuid\"\n\n\t\"golang.org/x/net/context\"\n)\n\ntype Session struct {\n\tID          string\n\tState       string\n\tUsername    string\n\tAccessToken string\n}\n\nfunc getSession(ctx context.Context, req *http.Request) Session {\n\tcookie, err := req.Cookie(\"sessionid\")\n\tif err != nil || cookie.Value == \"\" {\n\t\tsessionID, _ := uuid.NewV4()\n\t\tcookie = &http.Cookie{\n\t\t\tName:  \"sessionid\",\n\t\t\tValue: sessionID.String(),\n\t\t}\n\t}\n\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\titem = &memcache.Item{\n\t\t\tKey:   cookie.Value,\n\t\t\tValue: []byte(\"\"),\n\t\t}\n\t}\n\n\tvar session Session\n\tjson.Unmarshal(item.Value, &session)\n\tsession.ID = cookie.Value\n\treturn session\n}\n\nfunc putSession(ctx context.Context, res http.ResponseWriter, session Session) {\n\tbs, err := json.Marshal(session)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tmemcache.Set(ctx, &memcache.Item{\n\t\tKey:   session.ID,\n\t\tValue: bs,\n\t})\n\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:  \"sessionid\",\n\t\tValue: session.ID,\n\t})\n}\n"
  },
  {
    "path": "27_code-in-process/68_task-queue/04_github-goroutines/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/68_task-queue/04_github-goroutines/github.go",
    "content": "package githubexample\n\nimport (\n\t\"encoding/json\"\n\t\"io/ioutil\"\n\t\"net/url\"\n\t\"sync\"\n\t\"time\"\n\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/delay\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/urlfetch\"\n)\n\nconst redirectURI = \"http://localhost:8080/oauth2callback\"\nconst githubAPIURL = \"https://api.github.com\"\n\nvar delayedGetStats *delay.Function\n\nfunc init() {\n\tdelayedGetStats = delay.Func(\n\t\t\"my-favorite-dog\",\n\t\tfunc(ctx context.Context, accessToken, username string) error {\n\t\t\tlog.Infof(ctx, \"delayedGetStats CALLED\")\n\t\t\tapi := &GithubAPI{\n\t\t\t\tctx:         ctx,\n\t\t\t\taccessToken: accessToken,\n\t\t\t\tusername:    username,\n\t\t\t}\n\t\t\tsince := time.Now().Add(-time.Hour * 24 * 30)\n\t\t\tstats, err := api.getCommitSummaryStats(since)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tlog.Infof(ctx, \"STATS: %v\", stats)\n\n\t\t\tkey := datastore.NewKey(ctx, \"Stats\", username, 0, nil)\n\t\t\t_, err = datastore.Put(ctx, key, &stats)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t)\n}\n\ntype GithubAPI struct {\n\tctx         context.Context\n\taccessToken string\n\tusername    string\n}\n\ntype CommitStats struct {\n\tAdditions, Deletions int\n}\n\nfunc NewGithubAPI(ctx context.Context) *GithubAPI {\n\treturn &GithubAPI{\n\t\tctx: ctx,\n\t}\n}\n\nfunc (api *GithubAPI) getUsername() (string, error) {\n\tclient := urlfetch.Client(api.ctx)\n\tresponse, err := client.Get(\n\t\tgithubAPIURL + \"/user?access_token=\" + api.accessToken)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer response.Body.Close()\n\n\tvar data struct {\n\t\tLogin string\n\t}\n\terr = json.NewDecoder(response.Body).Decode(&data)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn data.Login, nil\n}\n\nfunc (api *GithubAPI) getAccessToken(state, code string) (string, error) {\n\tvalues := make(url.Values)\n\tvalues.Add(\"client_id\", \"767154e6915134caade5\")\n\tvalues.Add(\"client_secret\", \"50648a71510c21bb77e229692fc882dfbe8ea35d\")\n\tvalues.Add(\"code\", code)\n\tvalues.Add(\"state\", state)\n\n\tclient := urlfetch.Client(api.ctx)\n\tresponse, err := client.PostForm(\"https://github.com/login/oauth/access_token\", values)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer response.Body.Close()\n\n\tbs, err := ioutil.ReadAll(response.Body)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tvalues, err = url.ParseQuery(string(bs))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn values.Get(\"access_token\"), nil\n}\n\nfunc (api *GithubAPI) getCommitSummaryStats(since time.Time) (CommitStats, error) {\n\tvar stats CommitStats\n\n\ttype Repo struct {\n\t\tOrganization, Repository string\n\t}\n\n\tvar wg sync.WaitGroup\n\trepositoryChannel := make(chan Repo)\n\tstatsChannel := make(chan CommitStats)\n\tfor i := 0; i < 10; i++ {\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tfor repo := range repositoryChannel {\n\t\t\t\t// list all commits for repository: GET /repos/:owner/:repo/commits\n\t\t\t\tshas, err := api.getUserCommitShas(repo.Organization, repo.Repository, since)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Errorf(api.ctx, \"Error getting user commit shas: %v\", err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tlog.Infof(api.ctx, \"REPO: %v, SHAS:%v\", repo, shas)\n\t\t\t\tfor _, sha := range shas {\n\t\t\t\t\t// get a single commit: GET /repos/:owner/:repo/commits/:sha\n\t\t\t\t\tcs, err := api.getCommitStats(repo.Organization, repo.Repository, sha)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlog.Errorf(api.ctx, \"Error getting stats: %v\", err)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tstatsChannel <- cs\n\t\t\t\t}\n\t\t\t}\n\t\t\twg.Done()\n\t\t}()\n\t}\n\n\t// list organizations: GET /user/orgs\n\tgo func() {\n\t\torganizations, err := api.getOrganizations()\n\t\tif err != nil {\n\t\t\tlog.Errorf(api.ctx, \"ERROR GETTING ORGANIZATIONS: %v\", err)\n\t\t\treturn\n\t\t}\n\t\tfor _, organization := range organizations {\n\t\t\t// list repositories: GET /orgs/:org/repos\n\t\t\trepositories, err := api.getRepositories(organization)\n\t\t\tif err != nil {\n\t\t\t\tlog.Errorf(api.ctx, \"ERROR GETTING REPOSITORIES: %v\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlog.Infof(api.ctx, \"REPOSITORIES:%v\", repositories)\n\t\t\tfor _, repository := range repositories {\n\t\t\t\trepositoryChannel <- Repo{organization, repository}\n\t\t\t}\n\t\t}\n\t\tclose(repositoryChannel)\n\t}()\n\n\tgo func() {\n\t\twg.Wait()\n\t\tclose(statsChannel)\n\t}()\n\n\tfor cs := range statsChannel {\n\t\tstats.Additions += cs.Additions\n\t\tstats.Deletions += cs.Deletions\n\t}\n\n\treturn stats, nil\n}\n\nfunc (api *GithubAPI) getOrganizations() ([]string, error) {\n\tendpoint := \"/user/orgs\"\n\tvar data []struct {\n\t\tLogin string `json:\"login\"`\n\t}\n\terr := api.makeAPIRequest(endpoint, nil, &data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnames := make([]string, len(data))\n\tfor i, v := range data {\n\t\tnames[i] = v.Login\n\t}\n\n\treturn names, nil\n}\n\nfunc (api *GithubAPI) getRepositories(organization string) ([]string, error) {\n\t// GET /orgs/:org/repos\n\tvar data []struct {\n\t\tName string `json:\"name\"`\n\t}\n\terr := api.makeAPIRequest(\"/orgs/\"+organization+\"/repos\", nil, &data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tnames := make([]string, len(data))\n\tfor i, v := range data {\n\t\tnames[i] = v.Name\n\t}\n\treturn names, nil\n}\n\nfunc (api *GithubAPI) getUserCommitShas(organization, repository string, since time.Time) ([]string, error) {\n\tvalues := make(url.Values)\n\tvalues.Add(\"author\", api.username)\n\tvalues.Add(\"since\", since.Format(time.RFC3339))\n\t// GET /repos/:owner/:repo/commits\n\tendpoint := \"/repos/\" + organization + \"/\" + repository + \"/commits\"\n\tvar data []struct {\n\t\tSHA string `json:\"sha\"`\n\t}\n\terr := api.makeAPIRequest(endpoint, values, &data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tshas := make([]string, len(data))\n\tfor i, v := range data {\n\t\tshas[i] = v.SHA\n\t}\n\treturn shas, nil\n}\n\nfunc (api *GithubAPI) getCommitStats(organization, repository, sha string) (CommitStats, error) {\n\tvar stats CommitStats\n\tendpoint := \"/repos/\" + organization + \"/\" + repository + \"/commits/\" + sha\n\tvar data struct {\n\t\tStats struct {\n\t\t\tAdditions int `json:\"additions\"`\n\t\t\tDeletions int `json:\"deletions\"`\n\t\t} `json:\"stats\"`\n\t}\n\terr := api.makeAPIRequest(endpoint, nil, &data)\n\tif err != nil {\n\t\treturn stats, err\n\t}\n\tstats.Additions = data.Stats.Additions\n\tstats.Deletions = data.Stats.Deletions\n\treturn stats, nil\n}\n\nfunc (api *GithubAPI) makeAPIRequest(endpoint string, values url.Values, dst interface{}) error {\n\tclient := urlfetch.Client(api.ctx)\n\tif values == nil {\n\t\tvalues = make(url.Values)\n\t}\n\tvalues.Add(\"access_token\", api.accessToken)\n\t// GET /user/orgs\n\tresponse, err := client.Get(githubAPIURL + endpoint + \"?\" + values.Encode())\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer response.Body.Close()\n\n\tbs, _ := ioutil.ReadAll(response.Body)\n\t//log.Infof(api.ctx, \"GET %s RESPONSE: %s\", endpoint, string(bs))\n\treturn json.Unmarshal(bs, dst)\n}\n"
  },
  {
    "path": "27_code-in-process/68_task-queue/04_github-goroutines/login.go",
    "content": "package githubexample\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\n\t\"github.com/nu7hatch/gouuid\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n\thttp.HandleFunc(\"/github-login\", handleGithubLogin)\n\thttp.HandleFunc(\"/oauth2callback\", handleOauth2Callback)\n\thttp.HandleFunc(\"/github-info\", handleGithubInfo)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <head></head>\n  <body>\n    <a href=\"/github-login\">LOGIN WITH GITHUB</a>\n  </body>\n</html>`)\n}\n\nvar githubScopes = []string{\n\t\"user:email\",\n\t\"read:org\",\n}\n\nfunc handleGithubLogin(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\t// get the session\n\tsession := getSession(ctx, req)\n\tid, _ := uuid.NewV4()\n\n\tvalues := make(url.Values)\n\tvalues.Add(\"client_id\", \"767154e6915134caade5\")\n\tvalues.Add(\"redirect_uri\", redirectURI)\n\tvalues.Add(\"scope\", strings.Join(githubScopes, \",\"))\n\tvalues.Add(\"state\", id.String())\n\n\t// save the session\n\tsession.State = id.String()\n\tputSession(ctx, res, session)\n\n\thttp.Redirect(res, req, fmt.Sprintf(\n\t\t\"https://github.com/login/oauth/authorize?%s\",\n\t\tvalues.Encode(),\n\t), 302)\n}\n\nfunc handleOauth2Callback(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tapi := NewGithubAPI(ctx)\n\t// get the session\n\tsession := getSession(ctx, req)\n\n\tstate := req.FormValue(\"state\")\n\tcode := req.FormValue(\"code\")\n\n\tif state != session.State {\n\t\thttp.Error(res, \"invalid state\", 401)\n\t\treturn\n\t}\n\n\taccessToken, err := api.getAccessToken(state, code)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tapi.accessToken = accessToken\n\n\tusername, err := api.getUsername()\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tsession.Username = username\n\tsession.AccessToken = accessToken\n\tputSession(ctx, res, session)\n\n\tdelayedGetStats.Call(ctx, accessToken, username)\n\thttp.Redirect(res, req, \"/github-info\", 302)\n\n}\n\nfunc handleGithubInfo(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tsession := getSession(ctx, req)\n\n\tvar stats CommitStats\n\n\tkey := datastore.NewKey(ctx, \"Stats\", session.Username, 0, nil)\n\terr := datastore.Get(ctx, key, &stats)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\t// stats, err := api.getCommitSummaryStats(since)\n\t// if err != nil {\n\t// \thttp.Error(res, err.Error(), 500)\n\t// \treturn\n\t// }\n\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n\t<head>\n\n\t</head>\n\t<body>\n\t\tIn the last month you have:\n\t\t<table>\n\t\t\t<tr>\n\t\t\t\t<th>additions</th>\n\t\t\t\t<td>`+fmt.Sprint(stats.Additions)+`</td>\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t<th>deletions</th>\n\t\t\t\t<td>`+fmt.Sprint(stats.Deletions)+`</td>\n\t\t\t</tr>\n\t\t</table>\n\t</body>\n</html>`)\n}\n"
  },
  {
    "path": "27_code-in-process/68_task-queue/04_github-goroutines/session.go",
    "content": "package githubexample\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"google.golang.org/appengine/memcache\"\n\n\t\"github.com/nu7hatch/gouuid\"\n\n\t\"golang.org/x/net/context\"\n)\n\ntype Session struct {\n\tID          string\n\tState       string\n\tUsername    string\n\tAccessToken string\n}\n\nfunc getSession(ctx context.Context, req *http.Request) Session {\n\tcookie, err := req.Cookie(\"sessionid\")\n\tif err != nil || cookie.Value == \"\" {\n\t\tsessionID, _ := uuid.NewV4()\n\t\tcookie = &http.Cookie{\n\t\t\tName:  \"sessionid\",\n\t\t\tValue: sessionID.String(),\n\t\t}\n\t}\n\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\titem = &memcache.Item{\n\t\t\tKey:   cookie.Value,\n\t\t\tValue: []byte(\"\"),\n\t\t}\n\t}\n\n\tvar session Session\n\tjson.Unmarshal(item.Value, &session)\n\tsession.ID = cookie.Value\n\treturn session\n}\n\nfunc putSession(ctx context.Context, res http.ResponseWriter, session Session) {\n\tbs, err := json.Marshal(session)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tmemcache.Set(ctx, &memcache.Item{\n\t\tKey:   session.ID,\n\t\tValue: bs,\n\t})\n\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:  \"sessionid\",\n\t\tValue: session.ID,\n\t})\n}\n"
  },
  {
    "path": "27_code-in-process/68_task-queue/05_github-cron/app.yaml",
    "content": "application: learning-1130\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/68_task-queue/05_github-cron/cron.yaml",
    "content": "cron:\n- description: daily summary job\n  url: /schedule-example\n  schedule: every 1 minutes\n"
  },
  {
    "path": "27_code-in-process/68_task-queue/05_github-cron/github.go",
    "content": "package githubexample\n\nimport (\n\t\"encoding/json\"\n\t\"io/ioutil\"\n\t\"net/url\"\n\t\"sync\"\n\t\"time\"\n\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/delay\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/urlfetch\"\n)\n\nconst redirectURI = \"http://localhost:8080/oauth2callback\"\nconst githubAPIURL = \"https://api.github.com\"\n\nvar delayedGetStats *delay.Function\n\nfunc init() {\n\tdelayedGetStats = delay.Func(\n\t\t\"my-favorite-dog\",\n\t\tfunc(ctx context.Context, accessToken, username string) error {\n\t\t\tapi := &GithubAPI{\n\t\t\t\tctx:         ctx,\n\t\t\t\taccessToken: accessToken,\n\t\t\t\tusername:    username,\n\t\t\t}\n\t\t\tsince := time.Now().Add(-time.Hour * 24 * 30)\n\t\t\tstats, err := api.getCommitSummaryStats(since)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tlog.Infof(ctx, \"STATS: %v\", stats)\n\n\t\t\tkey := datastore.NewKey(ctx, \"Stats\", username, 0, nil)\n\t\t\t_, err = datastore.Put(ctx, key, &stats)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t)\n}\n\ntype GithubAPI struct {\n\tctx         context.Context\n\taccessToken string\n\tusername    string\n}\n\ntype CommitStats struct {\n\tAdditions, Deletions int\n}\n\nfunc NewGithubAPI(ctx context.Context) *GithubAPI {\n\treturn &GithubAPI{\n\t\tctx: ctx,\n\t}\n}\n\nfunc (api *GithubAPI) getUsername() (string, error) {\n\tclient := urlfetch.Client(api.ctx)\n\tresponse, err := client.Get(\n\t\tgithubAPIURL + \"/user?access_token=\" + api.accessToken)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer response.Body.Close()\n\n\tvar data struct {\n\t\tLogin string\n\t}\n\terr = json.NewDecoder(response.Body).Decode(&data)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn data.Login, nil\n}\n\nfunc (api *GithubAPI) getAccessToken(state, code string) (string, error) {\n\tvalues := make(url.Values)\n\tvalues.Add(\"client_id\", \"767154e6915134caade5\")\n\tvalues.Add(\"client_secret\", \"50648a71510c21bb77e229692fc882dfbe8ea35d\")\n\tvalues.Add(\"code\", code)\n\tvalues.Add(\"state\", state)\n\n\tclient := urlfetch.Client(api.ctx)\n\tresponse, err := client.PostForm(\"https://github.com/login/oauth/access_token\", values)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer response.Body.Close()\n\n\tbs, err := ioutil.ReadAll(response.Body)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tvalues, err = url.ParseQuery(string(bs))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn values.Get(\"access_token\"), nil\n}\n\nfunc (api *GithubAPI) getCommitSummaryStats(since time.Time) (CommitStats, error) {\n\tvar stats CommitStats\n\n\ttype Repo struct {\n\t\tOrganization, Repository string\n\t}\n\n\tvar wg sync.WaitGroup\n\trepositoryChannel := make(chan Repo)\n\tstatsChannel := make(chan CommitStats)\n\tfor i := 0; i < 10; i++ {\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tfor repo := range repositoryChannel {\n\t\t\t\t// list all commits for repository: GET /repos/:owner/:repo/commits\n\t\t\t\tshas, err := api.getUserCommitShas(repo.Organization, repo.Repository, since)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Errorf(api.ctx, \"Error getting user commit shas: %v\", err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tlog.Infof(api.ctx, \"REPO: %v, SHAS:%v\", repo, shas)\n\t\t\t\tfor _, sha := range shas {\n\t\t\t\t\t// get a single commit: GET /repos/:owner/:repo/commits/:sha\n\t\t\t\t\tcs, err := api.getCommitStats(repo.Organization, repo.Repository, sha)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlog.Errorf(api.ctx, \"Error getting stats: %v\", err)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tstatsChannel <- cs\n\t\t\t\t}\n\t\t\t}\n\t\t\twg.Done()\n\t\t}()\n\t}\n\n\t// list organizations: GET /user/orgs\n\tgo func() {\n\t\torganizations, err := api.getOrganizations()\n\t\tif err != nil {\n\t\t\tlog.Errorf(api.ctx, \"ERROR GETTING ORGANIZATIONS: %v\", err)\n\t\t\treturn\n\t\t}\n\t\tfor _, organization := range organizations {\n\t\t\t// list repositories: GET /orgs/:org/repos\n\t\t\trepositories, err := api.getRepositories(organization)\n\t\t\tif err != nil {\n\t\t\t\tlog.Errorf(api.ctx, \"ERROR GETTING REPOSITORIES: %v\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlog.Infof(api.ctx, \"REPOSITORIES:%v\", repositories)\n\t\t\tfor _, repository := range repositories {\n\t\t\t\trepositoryChannel <- Repo{organization, repository}\n\t\t\t}\n\t\t}\n\t\tclose(repositoryChannel)\n\t}()\n\n\tgo func() {\n\t\twg.Wait()\n\t\tclose(statsChannel)\n\t}()\n\n\tfor cs := range statsChannel {\n\t\tstats.Additions += cs.Additions\n\t\tstats.Deletions += cs.Deletions\n\t}\n\n\treturn stats, nil\n}\n\nfunc (api *GithubAPI) getOrganizations() ([]string, error) {\n\tendpoint := \"/user/orgs\"\n\tvar data []struct {\n\t\tLogin string `json:\"login\"`\n\t}\n\terr := api.makeAPIRequest(endpoint, nil, &data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnames := make([]string, len(data))\n\tfor i, v := range data {\n\t\tnames[i] = v.Login\n\t}\n\n\treturn names, nil\n}\n\nfunc (api *GithubAPI) getRepositories(organization string) ([]string, error) {\n\t// GET /orgs/:org/repos\n\tvar data []struct {\n\t\tName string `json:\"name\"`\n\t}\n\terr := api.makeAPIRequest(\"/orgs/\"+organization+\"/repos\", nil, &data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tnames := make([]string, len(data))\n\tfor i, v := range data {\n\t\tnames[i] = v.Name\n\t}\n\treturn names, nil\n}\n\nfunc (api *GithubAPI) getUserCommitShas(organization, repository string, since time.Time) ([]string, error) {\n\tvalues := make(url.Values)\n\tvalues.Add(\"author\", api.username)\n\tvalues.Add(\"since\", since.Format(time.RFC3339))\n\t// GET /repos/:owner/:repo/commits\n\tendpoint := \"/repos/\" + organization + \"/\" + repository + \"/commits\"\n\tvar data []struct {\n\t\tSHA string `json:\"sha\"`\n\t}\n\terr := api.makeAPIRequest(endpoint, values, &data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tshas := make([]string, len(data))\n\tfor i, v := range data {\n\t\tshas[i] = v.SHA\n\t}\n\treturn shas, nil\n}\n\nfunc (api *GithubAPI) getCommitStats(organization, repository, sha string) (CommitStats, error) {\n\tvar stats CommitStats\n\tendpoint := \"/repos/\" + organization + \"/\" + repository + \"/commits/\" + sha\n\tvar data struct {\n\t\tStats struct {\n\t\t\tAdditions int `json:\"additions\"`\n\t\t\tDeletions int `json:\"deletions\"`\n\t\t} `json:\"stats\"`\n\t}\n\terr := api.makeAPIRequest(endpoint, nil, &data)\n\tif err != nil {\n\t\treturn stats, err\n\t}\n\tstats.Additions = data.Stats.Additions\n\tstats.Deletions = data.Stats.Deletions\n\treturn stats, nil\n}\n\nfunc (api *GithubAPI) makeAPIRequest(endpoint string, values url.Values, dst interface{}) error {\n\tclient := urlfetch.Client(api.ctx)\n\tif values == nil {\n\t\tvalues = make(url.Values)\n\t}\n\tvalues.Add(\"access_token\", api.accessToken)\n\t// GET /user/orgs\n\tresponse, err := client.Get(githubAPIURL + endpoint + \"?\" + values.Encode())\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer response.Body.Close()\n\n\tbs, _ := ioutil.ReadAll(response.Body)\n\t//log.Infof(api.ctx, \"GET %s RESPONSE: %s\", endpoint, string(bs))\n\treturn json.Unmarshal(bs, dst)\n}\n"
  },
  {
    "path": "27_code-in-process/68_task-queue/05_github-cron/login.go",
    "content": "package githubexample\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\n\t\"github.com/nu7hatch/gouuid\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n\thttp.HandleFunc(\"/github-login\", handleGithubLogin)\n\thttp.HandleFunc(\"/oauth2callback\", handleOauth2Callback)\n\thttp.HandleFunc(\"/github-info\", handleGithubInfo)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <head></head>\n  <body>\n    <a href=\"/github-login\">LOGIN WITH GITHUB</a>\n  </body>\n</html>`)\n}\n\nvar githubScopes = []string{\n\t\"user:email\",\n\t\"read:org\",\n}\n\nfunc handleGithubLogin(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\t// get the session\n\tsession := getSession(ctx, req)\n\tid, _ := uuid.NewV4()\n\n\tvalues := make(url.Values)\n\tvalues.Add(\"client_id\", \"767154e6915134caade5\")\n\tvalues.Add(\"redirect_uri\", redirectURI)\n\tvalues.Add(\"scope\", strings.Join(githubScopes, \",\"))\n\tvalues.Add(\"state\", id.String())\n\n\t// save the session\n\tsession.State = id.String()\n\tputSession(ctx, res, session)\n\n\thttp.Redirect(res, req, fmt.Sprintf(\n\t\t\"https://github.com/login/oauth/authorize?%s\",\n\t\tvalues.Encode(),\n\t), 302)\n}\n\nfunc handleOauth2Callback(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tapi := NewGithubAPI(ctx)\n\t// get the session\n\tsession := getSession(ctx, req)\n\n\tstate := req.FormValue(\"state\")\n\tcode := req.FormValue(\"code\")\n\n\tif state != session.State {\n\t\thttp.Error(res, \"invalid state\", 401)\n\t\treturn\n\t}\n\n\taccessToken, err := api.getAccessToken(state, code)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tapi.accessToken = accessToken\n\n\tusername, err := api.getUsername()\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tsession.Username = username\n\tsession.AccessToken = accessToken\n\tputSession(ctx, res, session)\n\n\tdelayedGetStats.Call(ctx, accessToken, username)\n\thttp.Redirect(res, req, \"/github-info\", 302)\n\n}\n\nfunc handleGithubInfo(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tsession := getSession(ctx, req)\n\n\tvar stats CommitStats\n\n\tkey := datastore.NewKey(ctx, \"Stats\", session.Username, 0, nil)\n\terr := datastore.Get(ctx, key, &stats)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\t// stats, err := api.getCommitSummaryStats(since)\n\t// if err != nil {\n\t// \thttp.Error(res, err.Error(), 500)\n\t// \treturn\n\t// }\n\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n\t<head>\n\n\t</head>\n\t<body>\n\t\tIn the last month you have:\n\t\t<table>\n\t\t\t<tr>\n\t\t\t\t<th>additions</th>\n\t\t\t\t<td>`+fmt.Sprint(stats.Additions)+`</td>\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t<th>deletions</th>\n\t\t\t\t<td>`+fmt.Sprint(stats.Deletions)+`</td>\n\t\t\t</tr>\n\t\t</table>\n\t</body>\n</html>`)\n}\n"
  },
  {
    "path": "27_code-in-process/68_task-queue/05_github-cron/scheduled.go",
    "content": "package githubexample\n\nimport (\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/schedule-example\", handleScheduleExample)\n}\n\nfunc handleScheduleExample(res http.ResponseWriter, req *http.Request) {\n\tif req.Header.Get(\"X-Appengine-Cron\") != \"true\" {\n\t\thttp.Error(res, \"Forbidden\", http.StatusForbidden)\n\t\treturn\n\t}\n\tctx := appengine.NewContext(req)\n\tlog.Infof(ctx, \"I was Scheduled!!!\")\n}\n"
  },
  {
    "path": "27_code-in-process/68_task-queue/05_github-cron/session.go",
    "content": "package githubexample\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"google.golang.org/appengine/memcache\"\n\n\t\"github.com/nu7hatch/gouuid\"\n\n\t\"golang.org/x/net/context\"\n)\n\ntype Session struct {\n\tID          string\n\tState       string\n\tUsername    string\n\tAccessToken string\n}\n\nfunc getSession(ctx context.Context, req *http.Request) Session {\n\tcookie, err := req.Cookie(\"sessionid\")\n\tif err != nil || cookie.Value == \"\" {\n\t\tsessionID, _ := uuid.NewV4()\n\t\tcookie = &http.Cookie{\n\t\t\tName:  \"sessionid\",\n\t\t\tValue: sessionID.String(),\n\t\t}\n\t}\n\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\titem = &memcache.Item{\n\t\t\tKey:   cookie.Value,\n\t\t\tValue: []byte(\"\"),\n\t\t}\n\t}\n\n\tvar session Session\n\tjson.Unmarshal(item.Value, &session)\n\tsession.ID = cookie.Value\n\treturn session\n}\n\nfunc putSession(ctx context.Context, res http.ResponseWriter, session Session) {\n\tbs, err := json.Marshal(session)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tmemcache.Set(ctx, &memcache.Item{\n\t\tKey:   session.ID,\n\t\tValue: bs,\n\t})\n\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:  \"sessionid\",\n\t\tValue: session.ID,\n\t})\n}\n"
  },
  {
    "path": "27_code-in-process/90_append-to-file/01-get-files/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n)\n\nfunc main() {\n\n\tfilepath.Walk(\"../../\", func(path string, info os.FileInfo, err error) error {\n\t\tif info.IsDir() {\n\t\t\treturn nil\n\t\t}\n\n\t\tif !strings.Contains(path, \".go\") {\n\t\t\treturn nil\n\t\t}\n\n\t\tfmt.Println(path)\n\t\treturn nil\n\n\t})\n}\n"
  },
  {
    "path": "27_code-in-process/90_append-to-file/02-apply/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n)\n\nfunc main() {\n\n\tfilepath.Walk(\"../../\", func(path string, info os.FileInfo, err error) error {\n\t\tif info.IsDir() {\n\t\t\treturn nil\n\t\t}\n\n\t\tif !strings.Contains(path, \".go\") {\n\t\t\treturn nil\n\t\t}\n\n\t\tfmt.Println(path)\n\t\tf, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY, 0600)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\n\t\tdefer f.Close()\n\n\t\ttext := `\n\n\n/*\nAll material is licensed under the Apache License Version 2.0, January 2004\nhttp://www.apache.org/licenses/LICENSE-2.0\n*/`\n\n\t\tif _, err = f.WriteString(text); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "27_code-in-process/97_temp/01/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n)\n\nfunc main() {\n\tvar count int64\n\tc := make(chan int64)\n\tvar wg sync.WaitGroup\n\n\t// bees\n\tfor i := 0; i < 5000; i++ {\n\t\twg.Add(1)\n\t\tgo func(in chan int64) {\n\t\t\tdefer wg.Done()\n\t\t\ttime.Sleep(100)\n\t\t\tin <- 2\n\t\t}(c)\n\t}\n\n\t// hive\n\tgo func() {\n\t\tfor out := range c {\n\t\t\tcount += out\n\t\t}\n\t}()\n\n\twg.Wait()\n\t// bang! but why?\n\tfmt.Println(count)\n}\n"
  },
  {
    "path": "27_code-in-process/97_temp/02/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc init() {\n\tfmt.Println(\"Who ran first?\", x)\n}\n\nfunc main() {\n\tfmt.Println(\"Hello world.\")\n}\n\nvar x int = 17\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week1/blog/blog.css",
    "content": "main {\n    display: -webkit-box;\n    display: -webkit-flex;\n    display: flex;\n    max-width: 1020px;\n    margin: 30px auto;\n}\n\nh3 {\n    font-size: 30px;\n}\n\nh4 {\n    font-size: 22px;\n}\n\np {\n    font-size: 20px;\n}\n\narticle {\n    -webkit-box-flex: 2;\n    -webkit-flex: 2 1 0;\n    flex: 2 1 0;\n    background-color: red;\n    padding: 30px;\n    min-height: 600px;\n}\n\narticle a {\n    border-radius: 100%;\n    background-color: #0b97c4;\n    color: #010101;\n    padding: 5px 9px;\n    display: inline-block;\n}\n\naside {\n    -webkit-box-flex: 1;\n    -webkit-flex: 1 1 0;\n    flex: 1 1 0;\n    background-color: green;\n    padding: 20px;\n    min-height: 600px;\n}\n\n@media (max-width: 768px) {\n    main {\n        -webkit-box-orient: vertical;\n        -webkit-box-direction: normal;\n        -webkit-flex-direction: column;\n        flex-direction: column;\n    }\n}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week1/blog/blog.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Generic Blog</title>\n    <meta name=\"description\" content=\"This is a generic blog template made for a class.\" />\n\n    <meta name=\"twitter:card\" value=\"summary\">\n\n    <meta property=\"og:title\" content=\"Generic Blog\" />\n    <meta property=\"og:type\" content=\"article\" />\n    <meta property=\"og:url\" content=\"http://oralordos.github.io/blog.html\" />\n    <meta property=\"og:image\" content=\"\" />\n    <meta property=\"og:description\" content=\"This is a generic blog template made for a class.\" />\n\n    <link rel=\"stylesheet\" href=\"../../../reset.css\"/>\n    <link rel=\"stylesheet\" href=\"../../../font-awesome/css/font-awesome.min.css\"/>\n    <link rel=\"stylesheet\" href=\"blog.css\"/>\n</head>\n<body>\n<main>\n    <aside>\n        <h4>This is the header of the aside.</h4>\n\n        <p>This is the body of the aside.</p>\n    </aside>\n    <article>\n        <h3>This is the header of an article.</h3>\n\n        <p>This is the body of an article.</p>\n        <a href=\"http://www.facebook.com/\"><span class=\"fa fa-facebook\"></span></a>\n    </article>\n    <aside>\n        <h4>This is the header of the aside.</h4>\n\n        <p>This is the body of the aside.</p>\n    </aside>\n</main>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week1/fullscreen/fullscreen-style.css",
    "content": "* {\n    box-sizing: border-box;\n}\n\na {\n    text-decoration: none;\n}\n\nbody {\n    font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n    font-weight: 500;;\n    color: #555;\n    margin-top: 50px;\n}\n\nheader {\n    position: fixed;\n    height: 50px;\n    top: 0;\n    left: 0;\n    right: 0;\n    background: #fff;\n}\n\nheader nav {\n    height: 100%;\n}\n\n.header-flex {\n    display: -webkit-flex;\n    display: -webkit-box;\n    display: flex;\n    -webkit-align-items: center;\n    -webkit-box-align: center;\n    align-items: center;\n    height: 100%;\n    text-align: center;\n}\n\n.header-flex li {\n    -webkit-flex-grow: 1;\n    -ms-flex-positive: 1;\n    -webkit-box-flex: 1;\n    flex-grow: 1;\n    border: 1px solid #111;\n    border-top-width: 0;\n    border-left-width: 0;\n    height: 100%;\n}\n\n.header-flex li:first-child {\n    border-left-width: 1px;\n}\n\n.header-flex a {\n    height: 100%;\n    width: 100%;\n    color: #444;\n    display: -webkit-flex;\n    display: -webkit-box;\n    display: flex;\n    -webkit-align-items: center;\n    -webkit-box-align: center;\n    align-items: center;\n    -webkit-justify-content: center;\n    -webkit-box-pack: center;\n    justify-content: center;\n}\n\n#example {\n    -webkit-flex: 0 1 426px;\n    -webkit-box-flex: 0;\n    flex: 0 1 426px;\n}\n\n.header-flex a:hover {\n    background-color: #2ec371;\n    color: #fff;\n}\n\naside {\n    position: fixed;\n    width: 426px;\n    border: 1px solid;\n    bottom: 0;\n    left: 0;\n    top: 50px;\n    overflow: auto;\n}\n\narticle {\n    margin-left: 436px;\n}\n\naside a {\n    display: block;\n    padding: 11px 16px;\n    background: #f7f7f7;\n    font-size: 15px;\n    color: #425252;\n}\n\nh1 {\n    font-size: 33px;\n}\n\nh2 {\n    font-size: 22px;\n}\n\nh3 {\n    font-size: 20px;\n}\n\nh4 {\n    font-size: 19px;\n}\n\nh6 {\n    font-size: 20px;\n}\n\narticle p {\n    font-size: 19px;\n    line-height: 30px;\n    margin-bottom: 22px;\n    /*noinspection CssFloatPxLength*/\n    letter-spacing: 0.1px;\n    font-family: 'Homemade Apple', cursive;\n}\n\narticle li {\n    font-size: 17px;\n    font-weight: normal;\n    line-height: 26px;\n    margin-bottom: 15px;\n}\n\n.show-small {\n    display: none;\n}\n\n.hide-small {\n    display: inline;\n}\n\n@media (min-width: 768px) and (max-width: 991px) {\n    aside {\n        width: 276px;\n    }\n\n    article {\n        margin-left: 286px;\n    }\n\n    #example {\n        -webkit-flex: 0 1 276px;\n                -webkit-box-flex: 0;\n                flex: 0 1 276px;\n    }\n}\n\n@media (max-width: 767px) {\n    aside {\n        display: none;\n    }\n\n    article {\n        margin-left: 0;\n    }\n\n    #example {\n        -webkit-flex: 0 1 56px;\n                -webkit-box-flex: 0;\n                flex: 0 1 56px;\n    }\n\n    .show-small {\n        display: inline;\n    }\n\n    .hide-small {\n        display: none;\n    }\n}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week1/fullscreen/fullscreen.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Fullscreen</title>\n    <link rel=\"stylesheet\" href=\"../../../reset.css\"/>\n    <link rel=\"stylesheet\" href=\"../../../font-awesome/css/font-awesome.css\"/>\n    <link href='http://fonts.googleapis.com/css?family=Homemade+Apple' rel='stylesheet' type='text/css'>\n    <link rel=\"stylesheet\" href=\"fullscreen-style.css\"/>\n</head>\n<body>\n<header>\n    <nav>\n        <ul class=\"header-flex\">\n            <li id=\"example\">\n                <a href=\"#\">\n                    <span class=\"fa fa-list fa-2x show-small\"></span>\n                    <span class=\"hide-small\">Menu</span>\n                </a>\n            </li>\n            <li>\n                <a href=\"#\">\n                    <span class=\"fa fa-arrow-left fa-lg\"></span>previous\n                </a>\n            </li>\n            <li>\n                <a href=\"#\">continue<span class=\"fa fa-arrow-right fa-lg\"></span></a>\n            </li>\n        </ul>\n    </nav>\n\n    <main>\n        <aside>\n            <h2>Heading</h2>\n            <nav>\n                <ul>\n                    <li>\n                        <h6>section 1</h6>\n                    </li>\n                    <li><a href=\"#\">Chapter 1</a></li>\n                    <li><a href=\"#\">Chapter 2</a></li>\n                    <li><a href=\"#\">Chapter 3</a></li>\n                    <li><a href=\"#\">Chapter 4</a></li>\n                    <li><a href=\"#\">Chapter 5</a></li>\n                    <li><a href=\"#\">Chapter 6</a></li>\n                    <li><a href=\"#\">Chapter 7</a></li>\n                    <li><a href=\"#\">Chapter 8</a></li>\n                    <li><a href=\"#\">Chapter 9</a></li>\n                    <li><a href=\"#\">Chapter 10</a></li>\n                    <li>\n                        <h6>section 2</h6>\n                    </li>\n                    <li><a href=\"#\">Chapter 1</a></li>\n                    <li><a href=\"#\">Chapter 2</a></li>\n                    <li><a href=\"#\">Chapter 3</a></li>\n                    <li><a href=\"#\">Chapter 4</a></li>\n                    <li><a href=\"#\">Chapter 5</a></li>\n                    <li><a href=\"#\">Chapter 6</a></li>\n                    <li><a href=\"#\">Chapter 7</a></li>\n                    <li><a href=\"#\">Chapter 8</a></li>\n                    <li><a href=\"#\">Chapter 9</a></li>\n                    <li><a href=\"#\">Chapter 10</a></li>\n                    <li>\n                        <h6>section 3</h6>\n                    </li>\n                    <li><a href=\"#\">Chapter 1</a></li>\n                    <li><a href=\"#\">Chapter 2</a></li>\n                    <li><a href=\"#\">Chapter 3</a></li>\n                    <li><a href=\"#\">Chapter 4</a></li>\n                    <li><a href=\"#\">Chapter 5</a></li>\n                    <li><a href=\"#\">Chapter 6</a></li>\n                    <li><a href=\"#\">Chapter 7</a></li>\n                    <li><a href=\"#\">Chapter 8</a></li>\n                    <li><a href=\"#\">Chapter 9</a></li>\n                    <li><a href=\"#\">Chapter 10</a></li>\n                    <li>\n                        <h6>section 4</h6>\n                    </li>\n                    <li><a href=\"#\">Chapter 1</a></li>\n                    <li><a href=\"#\">Chapter 2</a></li>\n                    <li><a href=\"#\">Chapter 3</a></li>\n                    <li><a href=\"#\">Chapter 4</a></li>\n                    <li><a href=\"#\">Chapter 5</a></li>\n                    <li><a href=\"#\">Chapter 6</a></li>\n                    <li><a href=\"#\">Chapter 7</a></li>\n                    <li><a href=\"#\">Chapter 8</a></li>\n                    <li><a href=\"#\">Chapter 9</a></li>\n                    <li><a href=\"#\">Chapter 10</a></li>\n                    <li>\n                        <h6>section 5</h6>\n                    </li>\n                    <li><a href=\"#\">Chapter 1</a></li>\n                    <li><a href=\"#\">Chapter 2</a></li>\n                    <li><a href=\"#\">Chapter 3</a></li>\n                    <li><a href=\"#\">Chapter 4</a></li>\n                    <li><a href=\"#\">Chapter 5</a></li>\n                    <li><a href=\"#\">Chapter 6</a></li>\n                    <li><a href=\"#\">Chapter 7</a></li>\n                    <li><a href=\"#\">Chapter 8</a></li>\n                    <li><a href=\"#\">Chapter 9</a></li>\n                    <li><a href=\"#\">Chapter 10</a></li>\n                    <li>\n                        <h6>section 6</h6>\n                    </li>\n                    <li><a href=\"#\">Chapter 1</a></li>\n                    <li><a href=\"#\">Chapter 2</a></li>\n                    <li><a href=\"#\">Chapter 3</a></li>\n                    <li><a href=\"#\">Chapter 4</a></li>\n                    <li><a href=\"#\">Chapter 5</a></li>\n                    <li><a href=\"#\">Chapter 6</a></li>\n                    <li><a href=\"#\">Chapter 7</a></li>\n                    <li><a href=\"#\">Chapter 8</a></li>\n                    <li><a href=\"#\">Chapter 9</a></li>\n                    <li><a href=\"#\">Chapter 10</a></li>\n                    <li>\n                        <h6>section 7</h6>\n                    </li>\n                    <li><a href=\"#\">Chapter 1</a></li>\n                    <li><a href=\"#\">Chapter 2</a></li>\n                    <li><a href=\"#\">Chapter 3</a></li>\n                    <li><a href=\"#\">Chapter 4</a></li>\n                    <li><a href=\"#\">Chapter 5</a></li>\n                    <li><a href=\"#\">Chapter 6</a></li>\n                    <li><a href=\"#\">Chapter 7</a></li>\n                    <li><a href=\"#\">Chapter 8</a></li>\n                    <li><a href=\"#\">Chapter 9</a></li>\n                    <li><a href=\"#\">Chapter 10</a></li>\n                    <li>\n                        <h6>section 8</h6>\n                    </li>\n                    <li><a href=\"#\">Chapter 1</a></li>\n                    <li><a href=\"#\">Chapter 2</a></li>\n                    <li><a href=\"#\">Chapter 3</a></li>\n                    <li><a href=\"#\">Chapter 4</a></li>\n                    <li><a href=\"#\">Chapter 5</a></li>\n                    <li><a href=\"#\">Chapter 6</a></li>\n                    <li><a href=\"#\">Chapter 7</a></li>\n                    <li><a href=\"#\">Chapter 8</a></li>\n                    <li><a href=\"#\">Chapter 9</a></li>\n                    <li><a href=\"#\">Chapter 10</a></li>\n                    <li>\n                        <h6>section 9</h6>\n                    </li>\n                    <li><a href=\"#\">Chapter 1</a></li>\n                    <li><a href=\"#\">Chapter 2</a></li>\n                    <li><a href=\"#\">Chapter 3</a></li>\n                    <li><a href=\"#\">Chapter 4</a></li>\n                    <li><a href=\"#\">Chapter 5</a></li>\n                    <li><a href=\"#\">Chapter 6</a></li>\n                    <li><a href=\"#\">Chapter 7</a></li>\n                    <li><a href=\"#\">Chapter 8</a></li>\n                    <li><a href=\"#\">Chapter 9</a></li>\n                    <li><a href=\"#\">Chapter 10</a></li>\n                    <li>\n                        <h6>section 10</h6>\n                    </li>\n                    <li><a href=\"#\">Chapter 1</a></li>\n                    <li><a href=\"#\">Chapter 2</a></li>\n                    <li><a href=\"#\">Chapter 3</a></li>\n                    <li><a href=\"#\">Chapter 4</a></li>\n                    <li><a href=\"#\">Chapter 5</a></li>\n                    <li><a href=\"#\">Chapter 6</a></li>\n                    <li><a href=\"#\">Chapter 7</a></li>\n                    <li><a href=\"#\">Chapter 8</a></li>\n                    <li><a href=\"#\">Chapter 9</a></li>\n                    <li><a href=\"#\">Chapter 10</a></li>\n                    <li>\n                        <h6>section 11</h6>\n                    </li>\n                    <li><a href=\"#\">Chapter 1</a></li>\n                    <li><a href=\"#\">Chapter 2</a></li>\n                    <li><a href=\"#\">Chapter 3</a></li>\n                    <li><a href=\"#\">Chapter 4</a></li>\n                    <li><a href=\"#\">Chapter 5</a></li>\n                    <li><a href=\"#\">Chapter 6</a></li>\n                    <li><a href=\"#\">Chapter 7</a></li>\n                    <li><a href=\"#\">Chapter 8</a></li>\n                    <li><a href=\"#\">Chapter 9</a></li>\n                    <li><a href=\"#\">Chapter 10</a></li>\n                    <li>\n                        <h6>section 12</h6>\n                    </li>\n                    <li><a href=\"#\">Chapter 1</a></li>\n                    <li><a href=\"#\">Chapter 2</a></li>\n                    <li><a href=\"#\">Chapter 3</a></li>\n                    <li><a href=\"#\">Chapter 4</a></li>\n                    <li><a href=\"#\">Chapter 5</a></li>\n                    <li><a href=\"#\">Chapter 6</a></li>\n                    <li><a href=\"#\">Chapter 7</a></li>\n                    <li><a href=\"#\">Chapter 8</a></li>\n                    <li><a href=\"#\">Chapter 9</a></li>\n                    <li><a href=\"#\">Chapter 10</a></li>\n                    <li>\n                        <h6>section 13</h6>\n                    </li>\n                    <li><a href=\"#\">Chapter 1</a></li>\n                    <li><a href=\"#\">Chapter 2</a></li>\n                    <li><a href=\"#\">Chapter 3</a></li>\n                    <li><a href=\"#\">Chapter 4</a></li>\n                    <li><a href=\"#\">Chapter 5</a></li>\n                    <li><a href=\"#\">Chapter 6</a></li>\n                    <li><a href=\"#\">Chapter 7</a></li>\n                    <li><a href=\"#\">Chapter 8</a></li>\n                    <li><a href=\"#\">Chapter 9</a></li>\n                    <li><a href=\"#\">Chapter 10</a></li>\n                    <li>\n                        <h6>section 14</h6>\n                    </li>\n                    <li><a href=\"#\">Chapter 1</a></li>\n                    <li><a href=\"#\">Chapter 2</a></li>\n                    <li><a href=\"#\">Chapter 3</a></li>\n                    <li><a href=\"#\">Chapter 4</a></li>\n                    <li><a href=\"#\">Chapter 5</a></li>\n                    <li><a href=\"#\">Chapter 6</a></li>\n                    <li><a href=\"#\">Chapter 7</a></li>\n                    <li><a href=\"#\">Chapter 8</a></li>\n                    <li><a href=\"#\">Chapter 9</a></li>\n                    <li><a href=\"#\">Chapter 10</a></li>\n                    <li>\n                        <h6>section 15</h6>\n                    </li>\n                    <li><a href=\"#\">Chapter 1</a></li>\n                    <li><a href=\"#\">Chapter 2</a></li>\n                    <li><a href=\"#\">Chapter 3</a></li>\n                    <li><a href=\"#\">Chapter 4</a></li>\n                    <li><a href=\"#\">Chapter 5</a></li>\n                    <li><a href=\"#\">Chapter 6</a></li>\n                    <li><a href=\"#\">Chapter 7</a></li>\n                    <li><a href=\"#\">Chapter 8</a></li>\n                    <li><a href=\"#\">Chapter 9</a></li>\n                    <li><a href=\"#\">Chapter 10</a></li>\n                    <li>\n                        <h6>section 16</h6>\n                    </li>\n                    <li><a href=\"#\">Chapter 1</a></li>\n                    <li><a href=\"#\">Chapter 2</a></li>\n                    <li><a href=\"#\">Chapter 3</a></li>\n                    <li><a href=\"#\">Chapter 4</a></li>\n                    <li><a href=\"#\">Chapter 5</a></li>\n                    <li><a href=\"#\">Chapter 6</a></li>\n                    <li><a href=\"#\">Chapter 7</a></li>\n                    <li><a href=\"#\">Chapter 8</a></li>\n                    <li><a href=\"#\">Chapter 9</a></li>\n                    <li><a href=\"#\">Chapter 10</a></li>\n                    <li>\n                        <h6>section 17</h6>\n                    </li>\n                    <li><a href=\"#\">Chapter 1</a></li>\n                    <li><a href=\"#\">Chapter 2</a></li>\n                    <li><a href=\"#\">Chapter 3</a></li>\n                    <li><a href=\"#\">Chapter 4</a></li>\n                    <li><a href=\"#\">Chapter 5</a></li>\n                    <li><a href=\"#\">Chapter 6</a></li>\n                    <li><a href=\"#\">Chapter 7</a></li>\n                    <li><a href=\"#\">Chapter 8</a></li>\n                    <li><a href=\"#\">Chapter 9</a></li>\n                    <li><a href=\"#\">Chapter 10</a></li>\n                    <li>\n                        <h6>section 18</h6>\n                    </li>\n                    <li><a href=\"#\">Chapter 1</a></li>\n                    <li><a href=\"#\">Chapter 2</a></li>\n                    <li><a href=\"#\">Chapter 3</a></li>\n                    <li><a href=\"#\">Chapter 4</a></li>\n                    <li><a href=\"#\">Chapter 5</a></li>\n                    <li><a href=\"#\">Chapter 6</a></li>\n                    <li><a href=\"#\">Chapter 7</a></li>\n                    <li><a href=\"#\">Chapter 8</a></li>\n                    <li><a href=\"#\">Chapter 9</a></li>\n                    <li><a href=\"#\">Chapter 10</a></li>\n                    <li>\n                        <h6>section 19</h6>\n                    </li>\n                    <li><a href=\"#\">Chapter 1</a></li>\n                    <li><a href=\"#\">Chapter 2</a></li>\n                    <li><a href=\"#\">Chapter 3</a></li>\n                    <li><a href=\"#\">Chapter 4</a></li>\n                    <li><a href=\"#\">Chapter 5</a></li>\n                    <li><a href=\"#\">Chapter 6</a></li>\n                    <li><a href=\"#\">Chapter 7</a></li>\n                    <li><a href=\"#\">Chapter 8</a></li>\n                    <li><a href=\"#\">Chapter 9</a></li>\n                    <li><a href=\"#\">Chapter 10</a></li>\n                    <li>\n                        <h6>section 20</h6>\n                    </li>\n                    <li><a href=\"#\">Chapter 1</a></li>\n                    <li><a href=\"#\">Chapter 2</a></li>\n                    <li><a href=\"#\">Chapter 3</a></li>\n                    <li><a href=\"#\">Chapter 4</a></li>\n                    <li><a href=\"#\">Chapter 5</a></li>\n                    <li><a href=\"#\">Chapter 6</a></li>\n                    <li><a href=\"#\">Chapter 7</a></li>\n                    <li><a href=\"#\">Chapter 8</a></li>\n                    <li><a href=\"#\">Chapter 9</a></li>\n                    <li><a href=\"#\">Chapter 10</a></li>\n                </ul>\n            </nav>\n        </aside>\n        <article>\n            <h1>Intro To The First Site</h1>\n            <p>Lets take a quick look at what we'll be building throughout the course and the tools we need to get\n                started</p>\n            <h3>What We'll be Building</h3>\n            <p>Throughout this course we're going to learn HTML and CSS by building out the One Million Lines (make sure\n                to click here for the link to where the OML site is now) site. In the process of making the site you will learn everything you need to know about HTML and CSS so that you can create any site you want.</p>\n        </article>\n    </main>\n</header>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week1/google/google.css",
    "content": "* {\n    box-sizing: border-box;\n}\n\nbody {\n    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n\na {\n    color: #404040;\n    text-decoration: none;\n}\n\na:hover {\n    text-decoration: underline;\n}\n\n.header-right {\n    position: absolute;\n    right: 0;\n    font-size: 13px;\n    padding-right: 25px;\n}\n\nul {\n    margin-top: 1em;\n    margin-bottom: 1em;\n}\n\nli {\n    display: inline-block;\n    padding: 0 10px;\n}\n\n.circle {\n    color: #fff;\n    background: rgba(219, 68, 55, .8);\n    border-radius: 50% 50%;\n    display: inline-block;\n    padding: 5px 9px;\n}\n\n.circle:hover {\n    background: rgba(219, 68, 55, 1);\n}\n\n#logo {\n    height: 95px;\n    width: 269px;\n    margin-top: 190px;\n}\n\n.middle-logo {\n    text-align: center;\n}\n\n.middle-logo fieldset {\n    width: 360px;\n    margin: 15px auto;\n    position: relative;\n}\n\n#mic {\n    top: 3px;\n    right: 4px;\n    position: absolute;\n}\n\n#mic img {\n    height: 15px;\n}\n\n.middle-logo input[type=\"text\"] {\n    width: 100%;\n    margin-bottom: 10px;\n}\n\n.btn {\n    border-radius: 2px;\n    background-color: #f9f9f9;\n    border: 1px solid #cecece;\n    padding: 5px;\n}\n\nfooter {\n    position: fixed;\n    bottom: 0;\n    width: 100%;\n    height: 30px;\n    background: #f2f2f2;\n    font-size: 12px;\n    padding: 0 5px;\n}\n\n.footer-right {\n    position: absolute;\n    bottom: 0;\n    right: 0;\n}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week1/google/google.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Google</title>\n    <link rel=\"stylesheet\" href=\"../../../reset.css\"/>\n    <link rel=\"stylesheet\" href=\"google.css\"/>\n</head>\n<body>\n<header>\n    <nav class=\"header-right\">\n        <ul>\n            <li><a href=\"#\">+Ryan</a></li>\n            <li><a href=\"#\">Gmail</a></li>\n            <li><a href=\"#\">Images</a></li>\n            <li><a href=\"#\">Apps</a></li>\n            <li><a class=\"circle\" href=\"#\">5</a></li>\n            <li><a href=\"#\">+</a></li>\n            <li><a href=\"#\">Ryan</a></li>\n        </ul>\n    </nav>\n</header>\n<section class=\"middle-logo\">\n    <img id=\"logo\" src=\"logo11w.png\" alt=\"Google Logo\"/>\n\n    <form>\n        <fieldset>\n            <!--noinspection HtmlFormInputWithoutAnAssociatedLabel-->\n            <input type=\"text\" name=\"name\" id=\"name\" tabindex=\"1\" title=\"name\"/>\n            <a id=\"mic\" href=\"#\"><img src=\"mic.gif\" alt=\"Microphone picture\"/></a>\n\n            <div>\n                <input class=\"btn\" type=\"submit\" value=\"Google Search\"/>\n                <input class=\"btn\" type=\"submit\" value=\"I'm Feeling Lucky\"/>\n            </div>\n        </fieldset>\n    </form>\n</section>\n\n<footer>\n    <ul class=\"footer-right\">\n        <li><a href=\"#\">Privacy</a></li>\n        <li><a href=\"#\">Terms</a></li>\n        <li><a href=\"#\">Settings</a></li>\n    </ul>\n    <ul>\n        <li><a href=\"#\">Advertising</a></li>\n        <li><a href=\"#\">Business</a></li>\n        <li><a href=\"#\">About</a></li>\n    </ul>\n</footer>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week1/treehouse/treehouse.css",
    "content": "* {\n    box-sizing: border-box;\n}\n\nbody {\n    font-family: sans-serif;\n}\n\nheader {\n    border-bottom: 1px solid black;\n}\n\n.container {\n    max-width: 1000px;\n    margin: 0 auto;\n    /*background: #fafafa;*/\n    height: 85px;\n    display: -webkit-flex;\n    display: -webkit-box;\n    display: flex;\n    -webkit-justify-content: space-between;\n    -webkit-box-pack: justify;\n    justify-content: space-between;\n    -webkit-align-items: center;\n    -webkit-box-align: center;\n    align-items: center;\n}\n\n.container > a {\n    color: rgba(102, 206, 102, 0.7);\n    float: left;\n    font-size: 25px;\n    margin-left: 3px;\n    text-decoration: none;\n    font-family: 'Share', cursive;\n}\n\n.container > a:hover {\n    color: rgba(102, 206, 102, 1);\n}\n\nnav {\n    height: 100%;\n}\n\nnav ul {\n    font-size: 15px;\n    font-weight: 500;\n    display: -webkit-flex;\n    display: -webkit-box;\n    display: flex;\n    -webkit-align-items: center;\n    -webkit-box-align: center;\n    align-items: center;\n    height: 100%;\n}\n\nnav ul li {\n    height: 100%;\n    position: relative;\n}\n\nnav ul li ul {\n    background-color: #4fdc4a;\n    -webkit-box-orient: vertical;\n    -webkit-box-direction: normal;\n    -webkit-flex-direction: column;\n    flex-direction: column;\n    position: absolute;\n    top: 100%;\n    left: 0;\n    width: auto;\n    height: auto;\n    /*overflow: hidden;*/\n    /*max-height: 0;*/\n}\n\nnav ul li ul li {\n    -webkit-box-flex: 1;\n    -webkit-flex: 1 1 auto;\n    flex: 1 1 auto;\n}\n\nnav ul li ul li a {\n    box-sizing: content-box;\n    background-color: #5E740B;\n    color: #fefefe;\n    padding: 20px 10px;\n    width: 100%;\n    height: 100%;\n}\n\nnav ul li:hover ul {\n    max-height: 500px;\n}\n\nnav ul li a {\n    color: rgba(0, 0, 0, 0.3);\n    text-decoration: none;\n    display: -webkit-flex;\n    display: -webkit-box;\n    display: flex;\n    -webkit-justify-content: center;\n    -webkit-box-pack: center;\n    justify-content: center;\n    -webkit-align-items: center;\n    -webkit-box-align: center;\n    align-items: center;\n    padding: 0 15px;\n    height: 100%;\n}\n\nnav > ul > li:last-child a {\n    color: rgba(102, 206, 102, 1);\n}\n\nnav ul li a:hover {\n    background-color: rgba(102, 206, 102, 1);\n    color: white;\n}\n\n@media (max-width: 768px) {\n    * {\n        box-sizing: content-box;\n    }\n\n    .container {\n        -webkit-flex-direction: column;\n        -webkit-box-orient: vertical;\n        -webkit-box-direction: normal;\n        flex-direction: column;\n        max-width: none;\n        margin: 0;\n        height: auto;\n    }\n\n    .container > a {\n        padding: 25px 0;\n    }\n\n    nav {\n        width: 100%;\n    }\n\n    nav ul {\n        -webkit-flex-direction: column;\n        -webkit-box-orient: vertical;\n        -webkit-box-direction: normal;\n        flex-direction: column;\n        width: 100%;\n    }\n\n    nav ul li {\n        border-top: 1px solid black;\n        height: auto;\n        width: 100%;\n    }\n\n    nav ul li a {\n        padding: 30px 0;\n        width: 100%;\n    }\n}\n\nmain {\n    text-align: center;\n    max-width: 900px;\n    margin: 20px auto;\n}\n\nh3 {\n    font-size: 28px;\n    margin-bottom: 20px;\n}\n\nh6 {\n    font-size: 26px;\n    margin: 5px 0;\n}\n\np {\n    line-height: 1.6em;\n    color: #cecece;\n}\n\n.multi-article {\n    display: -webkit-box;\n    display: -webkit-flex;\n    display: flex;\n    -webkit-flex-flow: row nowrap;\n    flex-flow: row nowrap;\n}\n\n.multi-article article span {\n    color: white;\n    border-radius: 100%;\n    padding: 30px;\n}\n\n.multi-article article:first-child span {\n    background-color: #75bbbb;\n}\n\n.multi-article article:nth-child(2) span {\n    background-color: #fffe4e;\n}\n\n.multi-article article:last-child span {\n    background-color: #ff92f7;\n}\n\n.multi-article article {\n    -webkit-box-flex: 1;\n    -webkit-flex: 1 1 0;\n    flex: 1 1 0;\n    margin-top: 30px;\n}\n\n.multi-article article p {\n    margin-top: 20px;\n}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week1/treehouse/treehouse.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Treehouse</title>\n    <link rel=\"stylesheet\" href=\"../../../reset.css\"/>\n    <link rel=\"stylesheet\" href=\"../../../font-awesome/css/font-awesome.min.css\"/>\n    <link href='http://fonts.googleapis.com/css?family=Share:400' rel='stylesheet' type='text/css'>\n    <link rel=\"stylesheet\" href=\"treehouse.css\"/>\n</head>\n<body>\n<header>\n    <div class=\"container\">\n        <a href=\"#\">treehouse</a>\n        <nav>\n            <ul>\n                <li><a href=\"#\">Features</a>\n                    <!--<ul>\n                        <li><a href=\"#\">Get Tutors</a></li>\n                        <li><a href=\"#\">Get Teachers</a></li>\n                        <li><a href=\"#\">All Cheap</a></li>\n                    </ul>-->\n                </li>\n                <li><a href=\"#\">Stories</a></li>\n                <li><a href=\"#\">Pricing</a></li>\n                <li><a href=\"#\">Sign in</a></li>\n                <li><a href=\"#\">Free trial</a></li>\n            </ul>\n        </nav>\n    </div>\n</header>\n<main>\n    <h3>Tech education redesigned</h3>\n\n    <p>We've rethought the learning process and build a proven system to get you the skills and knowledge you need to\n        accomplish your goals.</p>\n    <section class=\"multi-article\">\n        <article>\n            <span class=\"fa fa-gear fa-5x\"></span>\n            <h6>Get started</h6>\n\n            <p>We're here to help you get started. Whether you are looking for a new career, want to learn to code for fun, or want to keep your skills cutting edge for your job, we will help you start down the right path.</p>\n        </article>\n        <article>\n            <span class=\"fa fa-wrench fa-5x\"></span>\n            <h6>Learn & build</h6>\n\n            <p>Learn by actually building something yourself! By watching our course videos and coding along in Workspaces, our browser-based code editor, you can see the results of your work in real-time.</p>\n        </article>\n        <article>\n            <span class=\"fa fa-heart fa-5x\"></span>\n            <h6>Share your work</h6>\n\n            <p>Take advantage of our robust community of students, alumni and teachers who can review your work, problem-solve and offer support.</p>\n        </article>\n    </section>\n</main>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week10/dropbox-api/app.yaml",
    "content": "application: xenon-petal-100822\nversion: dropbox\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  secure: always\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week10/dropbox-api/routes.go",
    "content": "package dropbox\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\n\t\"golang.org/x/net/context\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/urlfetch\"\n\n\t\"github.com/julienschmidt/httprouter\"\n\t\"github.com/nu7hatch/gouuid\"\n)\n\nfunc init() {\n\tr := httprouter.New()\n\tr.GET(\"/\", handleIndex)\n\tr.GET(\"/login\", handleLogin)\n\tr.GET(\"/oauth2\", handleAuthorize)\n\thttp.Handle(\"/\", r)\n}\n\ntype dropboxData struct {\n\tAccessToken string `json:\"access_token\"`\n\tTokenType   string `json:\"token_type\"`\n\tUID         string `json:\"uid\"`\n}\n\nfunc getToken(ctx context.Context, code string) (*dropboxData, error) {\n\tv := url.Values{}\n\tv.Add(\"code\", code)\n\tv.Add(\"grant_type\", \"authorization_code\")\n\tv.Add(\"client_id\", \"2be6c5b4z9uhar7\")\n\tv.Add(\"client_secret\", \"kdbp5bt12vodkz5\")\n\tv.Add(\"redirect_uri\", \"http://localhost:8080/oauth2\")\n\tclient := urlfetch.Client(ctx)\n\tres, err := client.PostForm(\"https://api.dropbox.com/1/oauth2/token\", v)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer res.Body.Close()\n\tvar data dropboxData\n\terr = json.NewDecoder(res.Body).Decode(&data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlog.Debugf(ctx, \"%v\", data)\n\treturn &data, nil\n}\n\nfunc handleAuthorize(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\tcode, state := req.FormValue(\"code\"), req.FormValue(\"state\")\n\ts := getSession(ctx, req)\n\tif s.State != state {\n\t\thttp.Error(res, \"Detected cross-site attack\", http.StatusUnauthorized)\n\t\tlog.Criticalf(ctx, \"Non-matching states from %s\", req.RemoteAddr)\n\t\treturn\n\t}\n\tdata, err := getToken(ctx, code)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n\tio.WriteString(res, data.UID)\n}\n\nfunc handleLogin(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\ts := getSession(ctx, req)\n\tstate, err := uuid.NewV4()\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n\tv := url.Values{}\n\tv.Add(\"response_type\", \"code\")\n\tv.Add(\"client_id\", \"2be6c5b4z9uhar7\")\n\tv.Add(\"redirect_uri\", \"http://localhost:8080/oauth2\")\n\tv.Add(\"state\", state.String())\n\ts.State = state.String()\n\terr = putSession(ctx, res, s)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n\thttp.Redirect(res, req, \"https://www.dropbox.com/1/oauth2/authorize?\"+v.Encode(), http.StatusSeeOther)\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <head></head>\n  <body>\n    <a href=\"/login\">Login with Dropbox</a>\n  </body>\n</html>`)\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week10/dropbox-api/session.go",
    "content": "package dropbox\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"github.com/nu7hatch/gouuid\"\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine/memcache\"\n)\n\nconst cookieName = \"sessionid\"\n\ntype session struct {\n\tID    string `json:\"-\"`\n\tState string\n}\n\nfunc getSession(ctx context.Context, req *http.Request) session {\n\tcookie, err := req.Cookie(cookieName)\n\tif err != nil || cookie.Value == \"\" {\n\t\tuid, _ := uuid.NewV4()\n\n\t\tcookie = &http.Cookie{\n\t\t\tName:  cookieName,\n\t\t\tValue: uid.String(),\n\t\t}\n\t}\n\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\titem = &memcache.Item{\n\t\t\tKey:   cookie.Value,\n\t\t\tValue: []byte(\"\"),\n\t\t}\n\t}\n\n\tvar s session\n\tjson.Unmarshal(item.Value, &s)\n\ts.ID = cookie.Value\n\treturn s\n}\n\nfunc putSession(ctx context.Context, res http.ResponseWriter, s session) error {\n\tbs, err := json.Marshal(s)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = memcache.Set(ctx, &memcache.Item{\n\t\tKey:   s.ID,\n\t\tValue: bs,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:  cookieName,\n\t\tValue: s.ID,\n\t})\n\n\treturn nil\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week10/filebrowser/app.yaml",
    "content": "application: xenon-petal-100822\nversion: browser\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /public\n  static_dir: public\n- url: /\n  secure: always\n  script: _go_app\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week10/filebrowser/browse.go",
    "content": "package browser\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\n\t\"github.com/julienschmidt/httprouter\"\n)\n\ntype browseModel struct {\n\tPath       string\n\tBucket     string\n\tSubfolders []string\n\tFiles      []string\n}\n\nfunc handlePath(res http.ResponseWriter, req *http.Request, p httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\ts := getSession(ctx, req)\n\tif s.Bucket == \"\" {\n\t\thttp.Redirect(res, req, \"/\", http.StatusSeeOther)\n\t\treturn\n\t}\n\n\tcctx, err := getCloudContext(ctx, s.Credentials)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n\n\tpath := p.ByName(\"path\")\n\n\tif !strings.HasSuffix(path, delimiter) {\n\t\tres.Header().Set(\"Content-Disposition\", \"attachment\")\n\t\tf, err := getFile(cctx, s.Bucket, path[1:])\n\t\tif err != nil {\n\t\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\t\tlog.Errorf(ctx, err.Error())\n\t\t\treturn\n\t\t}\n\t\tdefer f.Close()\n\t\tio.Copy(res, f)\n\t} else {\n\t\tfiles, subfolders, err := listFiles(cctx, s.Bucket, path[1:])\n\t\tif err != nil {\n\t\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\t\tlog.Errorf(ctx, err.Error())\n\t\t\treturn\n\t\t}\n\t\tdata := browseModel{\n\t\t\tPath:       path,\n\t\t\tBucket:     s.Bucket,\n\t\t\tSubfolders: subfolders,\n\t\t\tFiles:      files,\n\t\t}\n\t\terr = tpl.ExecuteTemplate(res, \"browse\", data)\n\t\tif err != nil {\n\t\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\t\tlog.Errorf(ctx, err.Error())\n\t\t\treturn\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week10/filebrowser/credentials.go",
    "content": "package browser\n\nimport (\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\n\t\"github.com/julienschmidt/httprouter\"\n)\n\nfunc handleCredentials(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\terr := tpl.ExecuteTemplate(res, \"credentials\", nil)\n\tif err != nil {\n\t\tctx := appengine.NewContext(req)\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n}\n\nfunc handleLogin(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\tctx := appengine.NewContext(req)\n\n\ts := getSession(ctx, req)\n\ts.Bucket = req.FormValue(\"bucket\")\n\ts.Credentials = req.FormValue(\"credentials\")\n\terr := putSession(ctx, res, s)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n\n\thttp.Redirect(res, req, \"/browse/\", http.StatusSeeOther)\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week10/filebrowser/public/styles.css",
    "content": "* {\n  box-sizing: border-box;\n  padding: 0;\n  margin: 0;\n}\n\nform label {\n  display: block;\n}\n\nh2 {\n  margin: 10px;\n}\n\n.filebrowser {\n  margin: 10px;\n  padding: 5px;\n  border: 1px solid black;\n}\n\n.filebrowser p {\n  font-size: 25px;\n}\n\n.filebrowser a {\n  display: block;\n}\n\n.filepath {\n  border-bottom: 1px solid black;\n}\n\n.upload {\n  margin: 10px;\n  padding: 5px;\n  border: 1px solid black;\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week10/filebrowser/routes.go",
    "content": "package browser\n\nimport (\n\t\"html/template\"\n\t\"net/http\"\n\n\t\"github.com/julienschmidt/httprouter\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\ttpl = template.Must(template.New(\"\").ParseGlob(\"templates/*.gohtml\"))\n\tr := httprouter.New()\n\tr.GET(\"/\", handleCredentials)\n\tr.POST(\"/\", handleLogin)\n\tr.GET(\"/browse/*path\", handlePath)\n\thttp.Handle(\"/\", r)\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week10/filebrowser/session.go",
    "content": "package browser\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"github.com/nu7hatch/gouuid\"\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine/memcache\"\n)\n\nconst cookieName = \"sessionid\"\n\ntype session struct {\n\tID          string `json:\"-\"`\n\tBucket      string\n\tCredentials string\n}\n\nfunc getSession(ctx context.Context, req *http.Request) session {\n\tcookie, err := req.Cookie(cookieName)\n\tif err != nil || cookie.Value == \"\" {\n\t\tuid, _ := uuid.NewV4()\n\n\t\tcookie = &http.Cookie{\n\t\t\tName:  cookieName,\n\t\t\tValue: uid.String(),\n\t\t}\n\t}\n\n\titem, err := memcache.Get(ctx, cookie.Value)\n\tif err != nil {\n\t\titem = &memcache.Item{\n\t\t\tKey:   cookie.Value,\n\t\t\tValue: []byte(\"\"),\n\t\t}\n\t}\n\n\tvar s session\n\tjson.Unmarshal(item.Value, &s)\n\ts.ID = cookie.Value\n\treturn s\n}\n\nfunc putSession(ctx context.Context, res http.ResponseWriter, s session) error {\n\tbs, err := json.Marshal(s)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = memcache.Set(ctx, &memcache.Item{\n\t\tKey:   s.ID,\n\t\tValue: bs,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:  cookieName,\n\t\tValue: s.ID,\n\t})\n\n\treturn nil\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week10/filebrowser/storage.go",
    "content": "package browser\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/urlfetch\"\n\t\"google.golang.org/cloud\"\n\t\"google.golang.org/cloud/storage\"\n\n\t\"golang.org/x/net/context\"\n\t\"golang.org/x/oauth2\"\n\t\"golang.org/x/oauth2/google\"\n)\n\nconst delimiter = \"/\"\n\ntype file struct {\n\tIsFolder bool\n\tFilename string\n\tURL      string\n}\n\nfunc getCloudContext(aeCtx context.Context, credentials string) (context.Context, error) {\n\tconf, err := google.JWTConfigFromJSON(\n\t\t[]byte(credentials),\n\t\tstorage.ScopeFullControl,\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttokenSource := conf.TokenSource(aeCtx)\n\n\thc := &http.Client{\n\t\tTransport: &oauth2.Transport{\n\t\t\tSource: tokenSource,\n\t\t\tBase:   &urlfetch.Transport{Context: aeCtx},\n\t\t},\n\t}\n\treturn cloud.NewContext(appengine.AppID(aeCtx), hc), nil\n}\n\nfunc listFiles(cctx context.Context, bucket, path string) ([]string, []string, error) {\n\tq := &storage.Query{\n\t\tDelimiter: delimiter,\n\t\tPrefix:    path,\n\t}\n\tobjs, err := storage.ListObjects(cctx, bucket, q)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tsubfolders := []string{}\n\tfor _, v := range objs.Prefixes {\n\t\tsubfolders = append(subfolders, strings.TrimPrefix(v, path))\n\t}\n\tfiles := []string{}\n\tfor _, v := range objs.Results {\n\t\tfiles = append(files, v.Name)\n\t}\n\treturn files, subfolders, nil\n}\n\nfunc getFile(cctx context.Context, bucket, path string) (io.ReadCloser, error) {\n\treturn storage.NewReader(cctx, bucket, path)\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week10/filebrowser/templates/browse.gohtml",
    "content": "{{define \"browse\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>File Browser: {{.Path}}</title>\n  <link rel=\"stylesheet\" href=\"/public/styles.css\">\n</head>\n<body>\n  <h2>Bucket: {{.Bucket}}</h2>\n  <section class=\"filebrowser\">\n    <p class=\"filepath\">{{.Path}}</p>\n    {{range .Subfolders}}\n    <a class=\"folder\" href=\"{{.}}\">{{.}}</a>\n    {{end}}\n    {{range .Files}}\n    <a class=\"file\" href=\"{{.}}\">{{.}}</a>\n    {{end}}\n  </section>\n  <section class=\"upload\">\n    <h1>Upload</h1>\n    <form method=\"POST\" enctype=\"multipart/form-data\">\n      <input type=\"file\" name=\"file\">\n      <input type=\"submit\" value=\"Upload\">\n    </form>\n  </section>\n</body>\n</html>\n{{end}}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week10/filebrowser/templates/credentials.gohtml",
    "content": "{{define \"credentials\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>File Browser</title>\n  <link rel=\"stylesheet\" href=\"/public/styles.css\">\n</head>\n<body>\n  <form method=\"POST\" class=\"credentials\">\n    <label>\n      Bucket\n      <input type=\"text\" name=\"bucket\" required>\n    </label>\n    <label>\n      Credentials\n      <textarea name=\"credentials\" rows=\"10\" cols=\"30\"></textarea>\n    </label>\n    <input type=\"submit\" value=\"Submit\">\n  </form>\n</body>\n</html>\n{{end}}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week10/payment/app.yaml",
    "content": "application: xenon-petal-100822\nversion: payment\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  secure: always\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week10/payment/routes.go",
    "content": "package payment\n\nimport (\n\t\"html/template\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/julienschmidt/httprouter\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n)\n\nvar tpl *template.Template\n\nfunc init() {\n\ttpl = template.Must(template.ParseGlob(\"templates/*.gohtml\"))\n\tr := httprouter.New()\n\tr.GET(\"/\", handleIndex)\n\tr.POST(\"/payment\", handlePayment)\n\thttp.Handle(\"/\", r)\n}\n\nfunc handlePayment(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\ttoken := req.FormValue(\"stripeToken\")\n\tctx := appengine.NewContext(req)\n\terr := chargeAccount(ctx, token)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\tio.WriteString(res, \"Thanks for the money\")\n}\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {\n\terr := tpl.ExecuteTemplate(res, \"index\", nil)\n\tif err != nil {\n\t\tctx := appengine.NewContext(req)\n\t\thttp.Error(res, \"Server error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week10/payment/stripe.go",
    "content": "package payment\n\nimport (\n\t\"github.com/stripe/stripe-go\"\n\t\"github.com/stripe/stripe-go/charge\"\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine/urlfetch\"\n)\n\nconst secretKey = \"sk_test_C4cVqiMxarOi7drYWgUsXmLr\"\n\nfunc chargeAccount(ctx context.Context, stripeToken string) error {\n\tb := stripe.BackendConfiguration{stripe.APIBackend, \"https://api.stripe.com/v1\", urlfetch.Client(ctx)}\n\tc := &charge.Client{Key: secretKey, B: b}\n\tchargeParams := &stripe.ChargeParams{\n\t\tAmount:   20000000,\n\t\tCurrency: \"usd\",\n\t\tDesc:     \"Charge for test@example.com\",\n\t}\n\tchargeParams.SetSource(stripeToken)\n\t_, err := c.New(chargeParams)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week10/payment/templates/index.gohtml",
    "content": "{{define \"index\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Guaranteed Investments</title>\n</head>\n<body>\n  <h1>Guaranteed Investments</h1>\n  <p>\n    Invest with us and get a free box of cookies.\n  </p>\n  <form action=\"/payment\" method=\"POST\">\n  <script\n    src=\"https://checkout.stripe.com/checkout.js\" class=\"stripe-button\"\n    data-key=\"pk_test_dFC6NnOkwF3BvJLpHXMmUna5\"\n    data-amount=\"20000000\"\n    data-name=\"Guaranteed Investments\"\n    data-description=\"High Returns ($200,000.00)\"\n    data-image=\"/128x128.png\">\n  </script>\n</form>\n</body>\n</html>\n{{end}}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week2/backgroundPreview/backgroundPreview.css",
    "content": "* {\n  padding: 0;\n  margin: 0;\n}\n\nhtml {\n  background: url('') no-repeat center center fixed;\n  background-size: cover;\n  -webkit-transition: background-image 1s;\n  transition: background-image 1s;\n}\n\nul {\n  position: fixed;\n  top: 5px;\n  left: 0;\n  right: 0;\n  display: -webkit-box;\n  display: -webkit-flex;\n  display: flex;\n  -webkit-justify-content: space-around;\n  justify-content: space-around;\n  list-style: none;\n}\n\nimg {\n  max-width: 100%;\n  max-height: 100px;\n}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week2/backgroundPreview/backgroundPreview.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <title>JS Bin</title>\n  <link rel=\"stylesheet\" href=\"backgroundPreview.css\">\n</head>\n<body>\n<ul>\n  <li><img src=\"../changingBackground/wallpapers/1036809-1440x900-[DesktopNexus.com].jpg\" alt=\"\"></li>\n  <li><img src=\"../changingBackground/wallpapers/1062969-1440x900-[DesktopNexus.com].jpg\" alt=\"\"></li>\n  <li><img src=\"../changingBackground/wallpapers/729965-1440x900-[DesktopNexus.com].jpg\" alt=\"\"></li>\n  <li><img src=\"../changingBackground/wallpapers/813495-1440x900-[DesktopNexus.com].jpg\" alt=\"\"></li>\n  <li><img src=\"../changingBackground/wallpapers/821425-1440x900-[DesktopNexus.com].jpg\" alt=\"\"></li>\n  <script src=\"backgroundPreview.js\"></script>\n</ul>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week2/backgroundPreview/backgroundPreview.js",
    "content": "function changeBackground(e) {\n  var html = document.querySelector('html');\n  html.style.backgroundImage = \"url('\" + e.target.src + \"')\";\n}\n\nvar images = document.querySelectorAll('img');\nfor (var i = 0; i < images.length; i++) {\n  images[i].addEventListener('click', changeBackground);\n}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week2/changingBackground/changingBackground.css",
    "content": "html {\n\tbackground: none no-repeat center center fixed;\n\tbackground-size: cover;\n\t-webkit-transition: background-image 2s;\n\ttransition: background-image 2s;\n}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week2/changingBackground/changingBackground.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<title>Background</title>\n\t<link rel=\"stylesheet\" href=\"changingBackground.css\">\n</head>\n<body>\n\t<script src=\"changingBackground.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week2/changingBackground/changingBackground.js",
    "content": "var backgrounds = [\n\t'wallpapers/729965-1440x900-[DesktopNexus.com].jpg',\n\t'wallpapers/813495-1440x900-[DesktopNexus.com].jpg',\n\t'wallpapers/821425-1440x900-[DesktopNexus.com].jpg',\n\t'wallpapers/1036809-1440x900-[DesktopNexus.com].jpg',\n\t'wallpapers/1062969-1440x900-[DesktopNexus.com].jpg'\n];\n\n\nfunction changeBackground(delta) {\n\t'use strict';\n\twindow.requestAnimationFrame(changeBackground);\n\tvar node = document.querySelector('html'),\n\t\t\tdateObject = new Date(),\n\t\t\tnow = dateObject.getSeconds(),\n\t\t\tbackgroundIndex = Math.floor(now / (60 / backgrounds.length));\n\n\tnode.style.backgroundImage = 'url(' + backgrounds[backgroundIndex] + ')';\n}\n\nchangeBackground(0);\n\n// preloading hack\nvar images = new Array();\nfunction preload() {\n\tfor (i = 0; i < backgrounds.length; i++) {\n\t\timages[i] = new Image();\n\t\timages[i].src = backgrounds[i];\n\t}\n}\npreload();"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week2/destructButton/destructButton.css",
    "content": "html {\n    background-color: #333;\n    -webkit-transition: background-color 1s linear;\n    transition: background-color 1s linear;\n}\n\n#hit {\n    width: 150px;\n    height: 150px;\n    font-size: 30px;\n    border-radius: 100%;\n    position: absolute;\n    top: 50px;\n    left: 50px;\n    z-index: 1;\n    -webkit-transition: left 1s linear, top 1s linear;\n    transition: left 1s linear, top 1s linear;\n}\n\n#abort {\n    width: 70px;\n    height: 70px;\n    border-radius: 100%;\n    position: absolute;\n    right: 10px;\n    bottom: 10px;\n}\n\n.centering {\n    display: -webkit-box;\n    display: -webkit-flex;\n    display: flex;\n    -webkit-flex-flow: column nowrap;\n    flex-flow: column nowrap;\n    -webkit-box-align: center;\n    -webkit-align-items: center;\n    align-items: center;\n    -webkit-box-pack: justify;\n    -webkit-justify-content: space-between;\n    justify-content: space-between;\n    margin-top: 15%;\n}\n\np {\n    text-align: center;\n}\n\n#timer {\n    font-size: 200px;\n    color: grey;\n}\n\n#message {\n    font-size: 100px;\n    color: lightcoral;\n}\n\n#failure {\n    z-index: 2;\n    position: absolute;\n    width: 100%;\n    height: 100%;\n    top: 0;\n    bottom: 0;\n    left: 0;\n    right: 0;\n    visibility: hidden;\n}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week2/destructButton/destructButton.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <meta charset=\"UTF-8\">\n    <title></title>\n    <link rel=\"stylesheet\" href=\"../../../reset.css\"/>\n    <link rel=\"stylesheet\" href=\"destructButton.css\"/>\n</head>\n<body>\n<button id=\"hit\">Hit Me!!</button>\n<button id=\"abort\">Abort</button>\n<div class=\"centering\">\n    <p id=\"timer\"></p>\n\n    <p id=\"message\"></p>\n</div>\n<img id=\"failure\" src=\"zombie.jpg\" alt=\"Zombie Picture\"/>\n<script src=\"destructButton.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week2/destructButton/destructButton.js",
    "content": "var timeLeft = null;\nvar timerId = null;\n\nfunction countdown() {\n    timeLeft--;\n    setTimer();\n    randomizeHitButton();\n}\n\nfunction randomizeHitButton() {\n    var button = document.querySelector('#hit');\n    button.style.left = Math.floor(Math.random() * (window.innerWidth - button.clientWidth)) + 'px';\n    button.style.top = Math.floor(Math.random() * (window.innerHeight - button.clientHeight)) + 'px';\n}\n\nfunction lerp(start, end, interval) {\n    return (end - start) * interval + start;\n}\n\nfunction setTimer() {\n    var extraS;\n    if (timeLeft === 1) {\n        extraS = '';\n    }\n    else {\n        extraS = 's';\n    }\n    document.querySelector('#timer').innerHTML = timeLeft + ' second' + extraS;\n    var interval = (108 - timeLeft) / 108;\n    var red = Math.floor(lerp(51, 255, interval));\n    var green = Math.floor(lerp(51, 0, interval));\n    var blue = Math.floor(lerp(51, 0, interval));\n    document.querySelector('html').style.backgroundColor = 'rgb(' + red + ',' + green + ',' + blue + ')';\n\n\n    if (timeLeft <= 5) {\n        document.querySelector('#message').innerHTML = 'You are all going to die!';\n    }\n    else if (timeLeft <= 10) {\n        document.querySelector('#message').innerHTML = 'Bad things will happen when time runs out!';\n    }\n    else if (timeLeft <= 15) {\n        document.querySelector('#message').innerHTML = 'Time is running low!';\n    }\n    else if (timeLeft <= 20) {\n        document.querySelector('#message').innerHTML = 'This is going to be dangerous!';\n    }\n    else if (timeLeft <= 25) {\n        document.querySelector('#message').innerHTML = 'The button needs to be pressed!';\n    }\n    else {\n        document.querySelector('#message').innerHTML = '';\n    }\n\n\n    if (timeLeft === 0) {\n        document.querySelector('#failure').style.visibility = 'visible';\n        abort();\n    }\n}\n\nfunction hitButton() {\n    timeLeft = 108;\n    if (timerId === null) {\n        timerId = setInterval(countdown, 1000);\n    }\n    setTimer();\n}\n\nfunction abort() {\n    if (timerId !== null) {\n        clearInterval(timerId);\n        timerId = null;\n    }\n    timeLeft = null;\n    document.querySelector('html').style.backgroundColor = 'rgb(51,51,51)';\n    document.querySelector('#timer').innerHTML = '';\n    document.querySelector('#message').innerHTML = '';\n}\n\ndocument.querySelector('#hit').addEventListener('click', hitButton);\ndocument.querySelector('#abort').addEventListener('click', abort);\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week2/generatedList/script.js",
    "content": "/*jslint plusplus: true, devel: true, indent: 2*/\n\nvar myLinks = [\n\t\"http://twitter.com/\",\n\t\"http://facebook.com/\",\n\t\"http://www.tumblr.com/\",\n\t\"https://linkedin.com/\",\n\t\"https://github.com/\",\n\t\"reddit.com\"\n];\n\nvar re = /^(?:https?:\\/\\/)?(?:www\\.)?([a-z0-9_\\-]+)\\./;\nvar output = '<style>\\n\\tli {\\n\\t\\tdisplay: inline-block;\\n\\t\\tmargin-left: 10px;\\n\\t}\\n</style>\\n<ul>';\nvar i;\nfor (i = 0; i < myLinks.length; i++) {\n\tvar reArray = re.exec(myLinks[i]);\n\tvar icon = reArray[1];\n\toutput += '\\n\\t<li><a href=\"' + myLinks[i] + '\" target=\"_blank\"><i class=\"fa fa-2x fa-' + icon + '\"></i></a></li>';\n}\noutput += '\\n</ul>';\n\nconsole.log(output);\n\ndocument.querySelector(\".links\").innerHTML = output;"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week2/generatedList/test.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<title>Test</title>\n\t<link rel=\"stylesheet\" href=\"../../../font-awesome/css/font-awesome.min.css\">\n</head>\n<body>\n<nav class=\"links\"></nav>\n\t<script src=\"script.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week2/imageListJavascript/imageListJavascript.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<title>Test</title>\n</head>\n<body>\n<script>\nvar container = document.createElement('div');\ncontainer.style.display = 'flex';\ncontainer.style.flexFlow = 'row wrap';\n\nfunction onEnter(event) {\n  var target = event.target;\n  target.style.width = '200px';\n  target.style.height = '200px';\n}\n\nfunction onLeave(event) {\n\tvar target = event.target; \n\ttarget.style.width = '100px';\n\ttarget.style.height = '100px';\n}\n\nfor (var i = 1; i < 10; i++) {\n  var image = document.createElement('img');\n  image.src = 'http://lorempixel.com/120/120/abstract/' + i;\n  image.alt = 'Sports Image ' + i;\n  image.className = 'getBig';\n  image.style.borderRadius = '50%';\n  image.style.margin = '10px';\n  image.addEventListener('mouseenter', onEnter);\n  image.addEventListener('mouseleave', onLeave);\n  image.style.width = '100px';\n  image.style.height = '100px';\n  image.style.transition = 'width 0.5s, height 0.5s';\n  container.appendChild(image);\n}\n\nvar bodyNode = document.querySelector('body');\nbodyNode.appendChild(container);\n</script>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week2/magic8ball/magic-ball.css",
    "content": "html {\n\tbackground-color: #333;\n}\n\n.questionEntry {\n\tdisplay: -webkit-box;\n\tdisplay: -webkit-flex;\n\tdisplay: flex;\n\twidth: 300px;\n\tmargin: 25px auto;\n}\n\n.questionEntry input {\n\t-webkit-box-flex: 1;\n\t-webkit-flex: 1 1 auto;\n\tflex: 1 1 auto;\n}\n\n#magic8 {\n\twidth: 500px;\n\theight: 500px;\n\tmargin: 25px auto;\n\t-webkit-transition: background-image 1s;\n\ttransition: background-image 1s;\n\tbackground-image: url('8ball/empty.png');\n\tbackground-size: contain;\n}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week2/magic8ball/magic-ball.js",
    "content": "function changeImage() {\n\t'use strict';\n\tvar image = document.querySelector('#magic8');\n\timage.style.backgroundImage = 'url(\"8ball/' + Math.ceil(Math.random() * 20) + '.png\")';\n}\n\ndocument.querySelector('button').addEventListener('click', changeImage);"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week2/magic8ball/magic8ball.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Magic 8 Ball</title>\n    <link rel=\"stylesheet\" href=\"../../../reset.css\">\n    <link rel=\"stylesheet\" href=\"magic-ball.css\">\n</head>\n<body>\n<div class=\"magic\">\n    <div class=\"questionEntry\">\n        <label>\n            <input type=\"text\">\n        </label>\n        <button>Ask your question</button>\n    </div>\n    <div id=\"magic8\"></div>\n</div>\n\n<!-- Image preloading hack -->\n<script src=\"magic-ball.js\"></script>\n<div class=\"hidden\">\n    <script type=\"text/javascript\">\n        var images = [];\n        function preload() {\n            for (var i = 0; i < 20; i++) {\n                images[i] = new Image();\n                images[i].src = '8ball/' + (i + 1) + '.png';\n            }\n        }\n        preload();\n    </script>\n</div>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week2/whackAMole/whackamole.css",
    "content": "* {\n    box-sizing: border-box;\n}\n\nhtml {\n    background-color: chocolate;\n}\n\nmain {\n    margin: 0 auto;\n    display: -webkit-box;\n    display: -webkit-flex;\n    display: flex;\n    -webkit-box-orient: vertical;\n    -webkit-box-direction: normal;\n    -webkit-flex-direction: column;\n    flex-direction: column;\n    -webkit-box-align: center;\n    -webkit-align-items: center;\n    align-items: center;\n}\n\n#game {\n    width: 100vw;\n    height: 90vh;\n    background-color: brown;\n    position: relative;\n}\n\n#score p {\n    display: inline-block;\n    font-size: 5vh;\n    height: 5vh;\n    margin: 0 1em;\n}\n\n.mole {\n    background: url(\"whackamole.png\") no-repeat center center;\n    background-size: cover;\n    display: inline-block;\n    padding: 4px;\n    opacity: 0.3;\n}\n\n.visible {\n    opacity: 1;\n}\n\n.boss {\n    background: url(\"whackamole.png\") no-repeat center center;\n    background-size: cover;\n    position: absolute;\n    left: 0;\n    top: 0;\n    -webkit-transition: left 1s linear, top 1s linear;\n    transition: left 1s linear, top 1s linear;\n}\n\n.hit {\n    -webkit-animation: smack 250ms linear;\n    animation: smack 250ms linear;\n}\n\n@-webkit-keyframes smack {\n    0% {\n        -webkit-transform: scale(1) translate(0, 0);\n        transform: scale(1) translate(0, 0);\n    }\n    20% {\n        -webkit-transform: scale(1.2) translate(0, 0);\n        transform: scale(1.2) translate(0, 0);\n    }\n    40% {\n        -webkit-transform: scale(1.2) translate(-7%, 0);\n        transform: scale(1.2) translate(-7%, 0);\n    }\n    60% {\n        -webkit-transform: scale(1.2) translate(7%, 0);\n        transform: scale(1.2) translate(7%, 0);\n    }\n    80% {\n        -webkit-transform: scale(1.2) translate(0, 0);\n        transform: scale(1.2) translate(0, 0);\n    }\n    100% {\n        -webkit-transform: scale(1) translate(0, 0);\n        transform: scale(1) translate(0, 0);\n    }\n}\n\n@keyframes smack {\n    0% {\n        -webkit-transform: scale(1) translate(0, 0);\n        transform: scale(1) translate(0, 0);\n    }\n    20% {\n        -webkit-transform: scale(1.2) translate(0, 0);\n        transform: scale(1.2) translate(0, 0);\n    }\n    40% {\n        -webkit-transform: scale(1.2) translate(-7%, 0);\n        transform: scale(1.2) translate(-7%, 0);\n    }\n    60% {\n        -webkit-transform: scale(1.2) translate(7%, 0);\n        transform: scale(1.2) translate(7%, 0);\n    }\n    80% {\n        -webkit-transform: scale(1.2) translate(0, 0);\n        transform: scale(1.2) translate(0, 0);\n    }\n    100% {\n        -webkit-transform: scale(1) translate(0, 0);\n        transform: scale(1) translate(0, 0);\n    }\n}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week2/whackAMole/whackamole.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Whack-a-Mole</title>\n    <link rel=\"stylesheet\" href=\"../../../reset.css\"/>\n    <link rel=\"stylesheet\" href=\"whackamole.css\"/>\n</head>\n<body>\n<main>\n    <div id=\"score\">\n        <p id=\"points\"></p>\n\n        <p id=\"level\"></p>\n    </div>\n    <div id=\"game\"></div>\n</main>\n<audio id=\"music\" autoplay loop src=\"I%20Don´t%20Understand.mp3\"></audio>\n<script src=\"whackamole.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week2/whackAMole/whackamole.js",
    "content": "var level = 1,\n    interval = 10,\n    onHit = 1,\n    onMiss = -1,\n    onBoss = 40;\n\nvar points = 0,\n    molePopup = null,\n    hits = (level - 1) * interval;\n\nfunction findMoleSize(size) {\n    var width = window.innerWidth,\n        height = Math.floor(window.innerHeight * 0.9),\n        moleWidth,\n        moleHeight;\n    if(width < height) {\n        moleWidth = width / size;\n        moleHeight = moleWidth * 195 / 259;\n    }\n    else {\n        moleHeight = height / size;\n        moleWidth = moleHeight * 259 / 195;\n    }\n    return {width: Math.floor(moleWidth), height: Math.floor(moleHeight)};\n}\n\nfunction sizeMoles() {\n    var size = level + 1,\n        game = document.querySelector('#game'),\n        moles = document.querySelectorAll('.mole'),\n        bosses = document.querySelectorAll('.boss'),\n        moleSize = findMoleSize(size);\n    game.style.width = moleSize.width * size + 'px';\n    game.style.height = moleSize.height * size + 'px';\n    for (var i = 0; i < moles.length; i++) {\n        var mole = moles[i];\n        mole.style.width = moleSize.width - 1 + 'px';\n        mole.style.height = moleSize.height - 3 + 'px';\n    }\n    for (var j = 0; j < bosses.length; j++) {\n        var boss = bosses[j];\n        boss.style.width = moleSize.width * 1.5 + 'px';\n        boss.style.height = moleSize.height * 1.5 + 'px';\n    }\n}\n\nfunction createMoles(size) {\n    var game = document.querySelector('#game');\n    for (var i = 0; i < size; i++) {\n        var newRow = document.createElement('div');\n        newRow.className = 'game-row';\n        for (var j = 0; j < size; j++) {\n            var newMole = document.createElement('div');\n            newMole.className = 'mole';\n            newMole.src = 'whackamole.png';\n            newMole.dataset.timerId = 'null';\n            newMole.addEventListener('click', onClickMole);\n            newRow.appendChild(newMole);\n        }\n        game.appendChild(newRow);\n    }\n    sizeMoles();\n    molePopup = setTimeout(randomMole, 2000);\n}\n\nfunction clearMoles() {\n    clearTimeout(molePopup);\n    molePopup = null;\n    var moles = document.querySelectorAll('.mole');\n    for (var i = 0; i < moles.length; i++) {\n        moles[i].parentNode.removeChild(moles[i]);\n    }\n    var rows = document.querySelectorAll('.game-row');\n    for (i = 0; i < rows.length; i++) {\n        rows[i].parentNode.removeChild(rows[i]);\n    }\n}\n\nfunction moveBossRandom() {\n    var boss = document.querySelector('.boss'),\n        game = document.querySelector('#game');\n    boss.style.left = Math.floor(Math.random() * (game.clientWidth - boss.clientWidth)) + 'px';\n    boss.style.top = Math.floor(Math.random() * (game.clientHeight - boss.clientHeight)) + 'px';\n}\n\nfunction getRelativePosition(element, relativeTo) {\n    var xPos = 0,\n        yPos = 0;\n    while (element != relativeTo) {\n        xPos += (element.offsetLeft - element.scrollLeft + element.clientLeft);\n        yPos += (element.offsetTop - element.scrollTop + element.clientTop);\n        element = element.offsetParent;\n    }\n    return {x: xPos, y: yPos};\n}\n\nfunction moveBossFarthest() {\n    var boss = document.querySelector('.boss'),\n        game = document.querySelector('#game'),\n        relativePos = getRelativePosition(boss, game);\n    if (relativePos.x < (game.clientWidth - boss.clientWidth) / 2) {\n        boss.style.left = (game.clientWidth - boss.clientWidth) + 'px';\n    }\n    else {\n        boss.style.left = '0';\n    }\n    if (relativePos.y < (game.clientHeight - boss.clientHeight) / 2) {\n        boss.style.top = (game.clientHeight - boss.clientHeight) + 'px';\n    }\n    else {\n        boss.style.top = '0';\n    }\n}\n\nfunction hitBoss() {\n    var boss = document.querySelector('.boss');\n    boss.dataset.health = boss.dataset.health - 1;\n    boss.removeEventListener('click', hitBoss);\n    boss.classList.add('hit');\n    setTimeout(function () {\n        boss.classList.remove('hit');\n        boss.addEventListener('click', hitBoss);\n    }, 250);\n    playHit();\n    if (boss.dataset.health <= 0) {\n        clearInterval(boss.dataset.intervalTimer);\n        boss.parentNode.removeChild(boss);\n        points += onBoss;\n        level++;\n        updateScores();\n        createMoles(level + 1);\n    }\n}\n\nfunction startBoss() {\n    clearMoles();\n    var boss = document.createElement('div');\n    boss.className = 'boss';\n    boss.dataset.health = 3;\n    boss.dataset.intervalTimer = setInterval(moveBossRandom, 1000);\n    boss.addEventListener('mouseenter', moveBossFarthest);\n    boss.addEventListener('click', hitBoss);\n    document.querySelector('#game').appendChild(boss);\n    sizeMoles();\n}\n\nfunction updateScores() {\n    document.querySelector('#points').innerHTML = 'Points: ' + points;\n    document.querySelector('#level').innerHTML = 'Level: ' + level;\n}\n\nfunction playHit() {\n    var newSound = document.createElement('audio');\n    newSound.src = 'Socapex%20-%20big%20punch.mp3';\n    newSound.play();\n    document.body.appendChild(newSound);\n    setTimeout(function () {\n        document.body.removeChild(newSound);\n    }, 800);\n}\n\nfunction onClickMole(e) {\n    if (e.target.dataset.timerId !== 'null') {\n        hits++;\n        points += onHit;\n        updateScores();\n        clearTimeout(e.target.dataset.timerId);\n        e.target.dataset.timerId = null;\n        e.target.classList.add('hit');\n        playHit();\n        setTimeout(function () {\n            e.target.classList.remove('visible');\n            e.target.classList.remove('hit');\n        }, 250);\n        if (hits >= level * interval) {\n            startBoss();\n        }\n    }\n}\n\nfunction randomMole() {\n    var moles = document.querySelectorAll('.mole');\n    var unavailableMoles = document.querySelectorAll('.visible, .hit');\n    var isDownMole = unavailableMoles.length !== moles.length;\n    var whichMole;\n    if (isDownMole) {\n        do {\n            whichMole = moles[Math.floor(Math.random() * moles.length)];\n        } while (whichMole.classList.contains('visible') || whichMole.classList.contains('hit'));\n        whichMole.classList.add('visible');\n        var delay = Math.floor(Math.random() * 4000 + 1000);\n        whichMole.dataset.timerId = setTimeout(function () {\n            whichMole.classList.remove('visible');\n            points += onMiss;\n            updateScores();\n            whichMole.dataset.timerId = 'null';\n        }, delay);\n    }\n    molePopup = setTimeout(randomMole, Math.floor(Math.random() * 2000 + 500));\n}\n\nfunction onLoad() {\n    createMoles(level + 1);\n    updateScores();\n    window.addEventListener('resize', sizeMoles);\n}\n\nwindow.addEventListener('load', onLoad);"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week3/audioPlayer/audioPlayer.css",
    "content": ".container {\n\tdisplay: -webkit-box;\n\tdisplay: -webkit-flex;\n\tdisplay: flex;\n\t-webkit-box-pack: center;\n\t-webkit-justify-content: center;\n\tjustify-content: center;\n\t-webkit-box-align: center;\n\t-webkit-align-items: center;\n\talign-items: center;\n\t-webkit-align-content: center;\n\talign-content: center;\n\twidth: 100vw;\n\theight: 100vh;\n}\n\n.playing {\n\tcolor: green;\n\tbox-shadow: none;\n}\n\n.paused {\n\tcolor: darkred;\n}\n\nli {\n\tmargin: 10px;\n\tfont-size: 30px;\n\tbackground-color: #fdd;\n\ttext-align: center;\n\tbox-shadow: 0 2px 2px 1px black;\n\t-webkit-user-select: none;\n\t-ms-user-select: none;\n\t-moz-user-select: none;\n\tuser-select: none;\n}\n\nhtml {\n\tbackground-color: lightgreen;\n}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week3/audioPlayer/audioPlayer.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<title>Audio Player</title>\n\t<link rel=\"stylesheet\" href=\"../../../reset.css\">\n\t<link rel=\"stylesheet\" href=\"audioPlayer.css\">\n</head>\n<body>\n<div class=\"container\">\n\t<ul id=\"player-list\"></ul>\n</div>\n<audio src=\"\"></audio>\n<script src=\"audioPlayer.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week3/audioPlayer/audioPlayer.js",
    "content": "var sounds = ['AmazingLee',\n\t\t\t  'EqueKenox',\n\t\t\t  'NightKitty',\n\t\t\t  'Phoebex',\n\t\t\t  'Shiloah'];\n\nfunction onClick(e) {\n\tvar player = document.querySelector('audio');\n\tif (e.target.className === 'playing') {\n\t\tplayer.pause();\n\t\te.target.className = 'paused';\n\t}\n\telse if (e.target.className === 'paused') {\n\t\tplayer.play();\n\t\te.target.className = 'playing';\n\t}\n\telse {\n\t\tvar lastSong = document.querySelector('.playing, .paused');\n\t\tif (lastSong !== null) {\n\t\t\tlastSong.className = '';\n\t\t}\n\t\tvar song = e.target.innerHTML;\n\t\tplayer.pause();\n\t\tplayer.src = 'audio/' + song + '.mp3';\n\t\tplayer.play();\n\t\te.target.className = 'playing';\n\t}\n}\n\nfunction onSongEnd() {\n\tvar song = document.querySelector('.playing, .paused');\n\tif (song !== null) {\n\t\tsong.className = '';\n\t}\n}\n\nfunction onLoad() {\n\tvar playerList = document.querySelector('#player-list');\n\tfor(var i = 0; i < sounds.length; i++) {\n\t\tvar newSong = document.createElement('li');\n\t\tnewSong.innerHTML = sounds[i];\n\t\tnewSong.addEventListener('click', onClick);\n\t\tplayerList.appendChild(newSong);\n\t}\n\tvar player = document.querySelector('audio');\n\tplayer.addEventListener('ended', onSongEnd);\n}\n\nwindow.addEventListener('load', onLoad);"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week3/hoverPreview/hoverPreview.css",
    "content": "#bigger {\n  -webkit-transition: -webkit-transform 1s ease 300ms;\n  transition: transform 1s ease 300ms;\n  background: none no-repeat center center;\n  background-size: cover;\n  width: 700px;\n  height: 700px;\n  -webkit-transform: scale(0);\n  transform: scale(0);\n  position: absolute;\n  border-radius: 50%;\n  box-shadow: 0 3px 6px 2px black\n}\n\nimg {\n  border-radius: 50%;\n  margin: 10px;\n  width: 100px;\n  height: 100px;\n}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week3/hoverPreview/hoverPreview.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<title>Test</title>\n  <link rel=\"stylesheet\" href=\"../../../reset.css\">\n  <link rel=\"stylesheet\" href=\"hoverPreview.css\">\n</head>\n<div id=\"bigger\"></div>\n<body>\n<script src=\"hoverPreview.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week3/hoverPreview/hoverPreview.js",
    "content": "var container = document.createElement('div');\ncontainer.style.display = 'flex';\ncontainer.style.flexFlow = 'row wrap';\n\nfunction onEnter(event) {\n  var big = document.querySelector('#bigger');\n  big.style.backgroundImage = 'url(\"' + event.target.src + '\")';\n  big.style.transform = 'scale(1)';\n}\n\nfunction onMove(event) {\n  var big = document.querySelector('#bigger');\n  big.style.left = event.clientX - 350 + 'px';\n  big.style.top = event.clientY + 10 + 'px';\n}\n\nfunction onLeave(event) {\n  var big = document.querySelector('#bigger');\n  big.style.transform = '';\n}\n\nfor (var i = 1; i < 10; i++) {\n  var image = document.createElement('img');\n  image.src = 'http://lorempixel.com/700/700/abstract/' + i;\n  image.alt = 'Sports Image ' + i;\n  image.addEventListener('mouseenter', onEnter);\n  image.addEventListener('mouseleave', onLeave);\n  image.addEventListener('mousemove', onMove);\n  container.appendChild(image);\n}\n\nvar bodyNode = document.querySelector('body');\nvar big = document.querySelector('#bigger');\nbodyNode.insertBefore(container, big);"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week3/loadImage/loadImage.css",
    "content": "html {\n\tbackground-color: brown;\n}\n\n.center {\n\tdisplay: -webkit-box;\n\tdisplay: -webkit-flex;\n\tdisplay: flex;\n\t-webkit-box-pack: center;\n\t-webkit-justify-content: center;\n\tjustify-content: center;\n\t-webkit-box-align: center;\n\t-webkit-align-items: center;\n\talign-items: center;\n\twidth: 100vw;\n\theight: 100vh;\n}\n\n.overlay {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\tdisplay: -webkit-box;\n\tdisplay: -webkit-flex;\n\tdisplay: flex;\n\t-webkit-box-pack: center;\n\t-webkit-justify-content: center;\n\tjustify-content: center;\n\t-webkit-box-align: center;\n\t-webkit-align-items: center;\n\talign-items: center;\n\twidth: 100vw;\n\theight: 100vh;\n}\n\n.overlay img {\n\tmax-width: 100vw;\n\tmax-height: 100vh;\n}\n\ni {\n\tcolor: white;\n}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week3/loadImage/loadImage.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<title>Load Image</title>\n\t<link rel=\"stylesheet\" href=\"../../../reset.css\">\n\t<link rel=\"stylesheet\" href=\"../../../font-awesome/css/font-awesome.min.css\">\n\t<link rel=\"stylesheet\" href=\"loadImage.css\">\n</head>\n<body>\n<div class=\"center\"></div>\n<div class=\"overlay\"></div>\n<script src=\"loadImage.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week3/loadImage/loadImage.js",
    "content": "var images = ['Barot_Bellingham',\n\t\t\t  'Constance_Smith',\n\t\t\t  'Hassum_Harrod',\n\t\t\t  'Hillary_Goldwynn',\n\t\t\t  'Hillary_Goldwynn_01',\n\t\t\t  'Hillary_Goldwynn_02',\n\t\t\t  'Hillary_Goldwynn_03',\n\t\t\t  'Hillary_Goldwynn_04',\n\t\t\t  'Hillary_Goldwynn_05',\n\t\t\t  'Hillary_Goldwynn_06',\n\t\t\t  'Hillary_Goldwynn_07',\n\t\t\t  'Jennifer_Jerome',\n\t\t\t  'Jonathan_Ferrar',\n\t\t\t  'LaVonne_LaRue',\n\t\t\t  'Lorenzo_Garcia_01',\n\t\t\t  'Lorenzo_Garcia_02',\n\t\t\t  'Lorenzo_Garcia_03',\n\t\t\t  'Lorenzo_Garcia_04',\n\t\t\t  'Riley_Rewington',\n\t\t\t  'Riley_Rewington_01',\n\t\t\t  'Riley_Rewington_02',\n\t\t\t  'Riley_Rewington_03',\n\t\t\t  'Riley_Rewington_04',\n\t\t\t  'Riley_Rewington_05',\n\t\t\t  'Riley_Rewington_06',\n\t\t\t  'Xhou_Ta'];\n\nfunction onImageLoad() {\n\tvar spinner = document.querySelector('i');\n\tspinner.parentNode.removeChild(spinner);\n}\n\nfunction onClick(e) {\n\tvar imageIndex = e.target.dataset.itemIndex,\n\t\toverlay = document.querySelector('.overlay');\n\t\tbigImage = document.createElement('img');\n\t\tspinner = document.createElement('i');\n\tbigImage.src = 'images/' + images[imageIndex] + '.jpg';\n\tbigImage.addEventListener('load', onImageLoad);\n\toverlay.appendChild(bigImage);\n\tspinner.className = 'fa fa-spinner fa-pulse fa-4x';\n\toverlay.appendChild(spinner);\n\toverlay.style.display = '';\n}\n\nfunction onPageLoad() {\n\tvar newImage = document.createElement('img');\n\tnewImage.dataset.itemIndex = Math.floor(Math.random() * images.length);\n\tnewImage.src = 'images/' + images[newImage.dataset.itemIndex] + '_tn.jpg';\n\tnewImage.addEventListener('click', onClick);\n\tdocument.querySelector('.center').appendChild(newImage);\n\tdocument.querySelector('.overlay').style.display = 'none';\n}\n\nwindow.addEventListener('load', onPageLoad);"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/angularAjax/data.json",
    "content": "[\n\t{\n\t\t\"name\": \"Bob\",\n\t\t\"age\": 27,\n\t\t\"job\": \"Businessman\"\n\t},\n\t{\n\t\t\"name\": \"Polly\",\n\t\t\"age\": 30,\n\t\t\"job\": \"Artists\"\n\t},\n\t{\n\t\t\"name\": \"Jeff\",\n\t\t\"age\": 15,\n\t\t\"job\": \"Student\"\n\t}\n]"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/angularAjax/gulpfile.js",
    "content": "var gulp = require('gulp'),\n\twebserver = require('gulp-webserver');\n\ngulp.task('webserver', function() {\n\tgulp.src('.')\n\t\t.pipe(webserver({\n\t\t\tport: 8080,\n\t\t\tlivereload: true,\n\t\t\topen: true\n\t\t}));\n});\n\ngulp.task('default', ['webserver']);"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/angularAjax/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" ng-app=\"app\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<title>Angular Ajax</title>\n\t<script src=\"https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js\"></script>\n\t<script src=\"script.js\"></script>\n</head>\n<body ng-controller=\"controller\">\n\t<section ng-repeat=\"item in people | orderBy: '-age'\">\n\t\t<h1>{{item.name}}</h1>\n\t\t<p>Age: {{item.age}}</p>\n\t\t<p>Job: {{item.job}}</p>\n\t</section>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/angularAjax/script.js",
    "content": "var app = angular.module('app', []);\n\napp.controller('controller', function($scope, $http) {\n\t$http.get('data.json').success(function(data) {\n\t\t$scope.people = data;\n\t})\n});"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/chat/chat.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Chatting</title>\n    <style>\n        * {\n            margin: 0;\n            padding: 0;\n        }\n\n        #rooms {\n            width: 100%;\n            height: 100%;\n        }\n\n        .chat {\n            width: 100%;\n            height: 25px;\n        }\n\n        .submit {\n            display: none;\n        }\n\n        main {\n            display: flex;\n            width: 100vw;\n            height: 100vh;\n        }\n\n        #sidebar {\n            flex-basis: 30%;\n            background: beige;\n        }\n\n        #chatArea {\n            background: bisque;\n            flex-basis: 70%;\n        }\n\n        .room {\n            border: 1px solid black;\n        }\n\n        h1 {\n            font-size: 25px;\n        }\n\n        .joined {\n            background: greenyellow;\n        }\n    </style>\n</head>\n<body>\n<main>\n    <section id=\"chatArea\">\n        <section id=\"rooms\">\n            <section class=\"room\" id=\"test\">\n                <section class=\"roomChat\">\n                    <p>Hello World!</p>\n                </section>\n\n                <form>\n                    <input type=\"text\" class=\"chat\"/>\n                    <input type=\"submit\" value=\"\" class=\"submit\"/>\n                </form>\n            </section>\n        </section>\n    </section>\n    <aside id=\"sidebar\">\n        <section id=\"roomSelect\"></section>\n    </aside>\n</main>\n<script src=\"https://cdn.firebase.com/js/client/2.2.7/firebase.js\"></script>\n<script>\n    var ref = new Firebase('https://chattersummerweb.firebaseio.com');\n    var regex = /^(?:https?:\\/\\/).+/;\n    var joinedRooms = [];\n    var uid = '~';\n\n    function submitMessage(e) {\n        e.preventDefault();\n        var textArea = e.target.previousSibling;\n        var message = textArea.value;\n        textArea.value = '';\n        var room = e.target.parentNode.parentNode.id;\n        ref.child('messages/' + room).push({\n            message: message,\n            owner: uid\n        })\n    }\n\n    function inArray(key, array) {\n        return array.some(function (x) {\n            return x === key;\n        });\n    }\n\n    function updateChatArea() {\n        var roomsArea = document.querySelector('#rooms');\n        var oldRooms = document.querySelectorAll('.room');\n        for (var i = 0; i < oldRooms.length; i++) {\n            var room = oldRooms[i];\n            ref.child('messages/' + room.id).off('value', displayRoom);\n        }\n        roomsArea.innerHTML = '';\n        joinedRooms.forEach(function (room) {\n            var newRoom = document.createElement('section');\n            newRoom.className = 'room';\n            newRoom.id = room;\n            newRoom.innerHTML = '<h1>' + room + '</h1><section class=\"roomChat\"></section>';\n            var newForm = document.createElement('form');\n            var newTextInput = document.createElement('input');\n            newTextInput.type = 'text';\n            newTextInput.className = 'chat';\n            newForm.appendChild(newTextInput);\n            var newSubmitButton = document.createElement('input');\n            newSubmitButton.type = 'submit';\n            newSubmitButton.value = '';\n            newSubmitButton.className = 'submit';\n            newSubmitButton.addEventListener('click', submitMessage);\n            newForm.appendChild(newSubmitButton);\n            newRoom.appendChild(newForm);\n//            console.log('#' + room + ' .submit');\n//            document.querySelector('#' + room + ' .submit').addEventListener(submitMessage);\n            roomsArea.appendChild(newRoom);\n            ref.child('messages/' + room).on('value', displayRoom);\n        });\n    }\n\n    function toggleRoom(e) {\n        var roomName = e.target.innerHTML;\n        var childArea = ref.child('users/' + uid + '/rooms/' + roomName);\n        var roomUser = ref.child('rooms/' + roomName + '/users/' + uid);\n        if (inArray(roomName, joinedRooms)) {\n            childArea.remove();\n            roomUser.remove();\n        }\n        else {\n            childArea.set(true);\n            roomUser.set(true);\n        }\n    }\n\n    function displayRoomsList(snapshot) {\n        var rooms = snapshot.val();\n        var roomArea = document.querySelector('#roomSelect');\n        roomArea.innerHTML = '';\n        for (var key in rooms) {\n            if (rooms.hasOwnProperty(key)) {\n                var newRoomTag = document.createElement('p');\n                newRoomTag.className = 'roomOption';\n                if (inArray(key, joinedRooms)) {\n                    newRoomTag.classList.add('joined');\n                }\n                newRoomTag.innerHTML = key;\n                newRoomTag.addEventListener('click', toggleRoom);\n                roomArea.appendChild(newRoomTag);\n            }\n        }\n    }\n\n    function displayRoom(snapshot) {\n        var messages = snapshot.val();\n        var room = document.querySelector('#' + snapshot.key() + ' .roomChat');\n        room.innerHTML = '';\n        for (var key in messages) {\n            if (messages.hasOwnProperty(key)) {\n                var newMessage = document.createElement('p');\n                newMessage.innerHTML = messages[key].message;\n                room.appendChild(newMessage);\n            }\n        }\n    }\n\n    function displayActiveRooms(snapshot) {\n        var activeRooms = snapshot.val();\n        joinedRooms = [];\n        for (var room in activeRooms) {\n            if (activeRooms.hasOwnProperty(room)) {\n                joinedRooms.push(room);\n            }\n        }\n        updateChatArea();\n    }\n\n    ref.child('users/' + uid + '/rooms').on('value', displayActiveRooms);\n    ref.child('rooms').on('value', displayRoomsList);\n</script>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/firebaseExample/firebaseExample.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Firebase Example</title>\n</head>\n<body>\n<form name=\"Add data\">\n    <label for=\"name\">Name:</label>\n    <input name=\"name\" id=\"name\" type=\"text\"/>\n    <label for=\"age\">Age:</label>\n    <input name=\"age\" id=\"age\" type=\"number\"/>\n    <label for=\"job\">Job:</label>\n    <input name=\"job\" id=\"job\" type=\"text\"/>\n    <input id=\"submit\" type=\"submit\" value=\"Add Item\"/>\n</form>\n<section class=\"data\"></section>\n<script src=\"https://cdn.firebase.com/js/client/2.2.7/firebase.js\"></script>\n<script>\n    function addSection(parent, data) {\n        var newList = document.createElement('ul');\n        for (var key in data) {\n            if (typeof data[key] === 'object') {\n                newList.innerHTML += '<li>' + key + '</li>';\n                addSection(newList, data[key]);\n            }\n            else {\n                newList.innerHTML += '<li>' + key + ': ' + data[key] + '</li>';\n            }\n        }\n        parent.appendChild(newList);\n    }\n\n    var ref = new Firebase('https://dazzling-inferno-8957.firebaseio.com/');\n    ref.on('value', function(snapshot) {\n        var data = snapshot.val(),\n            section = document.querySelector('.data');\n        section.innerHTML = '';\n        addSection(section, data);\n    });\n    document.querySelector('#submit').addEventListener('click', function(e) {\n        var form = e.target.parentNode;\n        e.preventDefault();\n        ref.push({\n            name: form.name.value,\n            age: form.age.value,\n            job: form.job.value\n        });\n        form.name.value = '';\n        form.age.value = '';\n        form.job.value = '';\n        form.name.focus();\n    })\n</script>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/flickrFeed/flickr.css",
    "content": "* {\n\tmargin: 0;\n\tpadding: 0;\n}\n\nhtml {\n\tbackground-color: lightgreen;\n}\n\n.overlay {\n\tbackground-color: rgba(0, 0, 0, 0.8);\n\twidth: 100vw;\n\theight: 100vh;\n\tdisplay: -webkit-box;\n\tdisplay: -webkit-flex;\n\tdisplay: flex;\n\t-webkit-box-pack: center;\n\t-webkit-justify-content: center;\n\tjustify-content: center;\n\t-webkit-box-align: center;\n\t-webkit-align-items: center;\n\talign-items: center;\n\tposition: absolute;\n\tleft: 0;\n\ttop: 0;\n}\n\n.overlay img {\n\tmax-width: 100%;\n\tmax-height: 100%;\n}\n\n#photos {\n\tdisplay: -webkit-box;\n\tdisplay: -webkit-flex;\n\tdisplay: flex;\n\t-webkit-flex-wrap: wrap;\n\tflex-wrap: wrap;\n\t-webkit-justify-content: space-around;\n\tjustify-content: space-around;\n\t-webkit-box-align: center;\n\t-webkit-align-items: center;\n\talign-items: center;\n\t-webkit-align-content: space-around;\n\talign-content: space-around;\n\tmin-width: 98vw;\n\tmin-height: 100vh;\n}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/flickrFeed/flickr.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<title>Flickr Feed</title>\n\t<link rel=\"stylesheet\" href=\"flickr.css\">\n</head>\n<body>\n<div id=\"photos\"></div>\n<script id=\"template\" type=\"text/template\">\n{{#.}}\n{{#formatImage}}\n\t<img onclick=\"onClick(this)\" src=\"{{media.m}}\" />\n{{/formatImage}}\n{{/.}}\n</script>\n<script src=\"http://cdn.jsdelivr.net/mustache.js/2.1.0/mustache.min.js\"></script>\n<script src=\"flickr.js\"></script>\n<script src=\"http://api.flickr.com/services/feeds/photos_public.gne?id=73845487@N00&format=json&tags=portfolio\"></script>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/flickrFeed/flickr.js",
    "content": "function formatImage() {\n\treturn function(item, render) {\n\t\tvar parsed = render(item);\n\t\treturn parsed.slice(0, -10) + 's' + parsed.slice(-9);\n\t};\n}\n\nfunction jsonFlickrFeed(data) {\n\tdata.items.forEach(function(item) {\n\t\titem.formatImage = formatImage;\n\t});\n\tvar template = document.querySelector('#template').innerHTML,\n\t\thtml = Mustache.to_html(template, data.items);\n\tdocument.querySelector('#photos').innerHTML = html;\n}\n\nfunction onClick(target) {\n\tvar overlay = document.createElement('div'),\n\t\timage = document.createElement('img');\n\toverlay.className = 'overlay';\n\toverlay.addEventListener('click', onCloseClick);\n\timage.src = target.src.slice(0, -5) + 'b' + target.src.slice(-4);\n\toverlay.appendChild(image);\n\tdocument.body.appendChild(overlay);\n}\n\nfunction onCloseClick(target) {\n\tvar overlay = document.querySelector('.overlay');\n\toverlay.parentNode.removeChild(overlay);\n}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/flickrFeed/gulpfile.js",
    "content": "var gulp = require('gulp'),\n\twebserver = require('gulp-webserver');\n\ngulp.task('webserver', function() {\n\tgulp.src('.')\n\t\t.pipe(webserver({\n\t\t\tport: 8080,\n\t\t\tlivereload: true,\n\t\t\topen: true,\n\t\t\tfallback: 'flickr.html'\n\t\t}));\n});\n\ngulp.task('default', ['webserver']);"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/flickrFeed/package.json",
    "content": "{\n  \"name\": \"flickr-feed\",\n  \"version\": \"0.0.1\",\n  \"author\": \"Daniel\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"gulp\": \"^3.9.0\",\n    \"gulp-webserver\": \"^0.9.1\"\n  }\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/liveSearch/data.json",
    "content": "[\n  {\n    \"name\":\"Barot Bellingham\",\n    \"shortname\":\"Barot_Bellingham\",\n    \"reknown\":\"Royal Academy of Painting and Sculpture\",\n    \"bio\":\"Barot has just finished his final year at The Royal Academy of Painting and Sculpture, where he excelled in glass etching paintings and portraiture. Hailed as one of the most diverse artists of his generation, Barot is equally as skilled with watercolors as he is with oils, and is just as well-balanced in different subject areas. Barot's collection entitled \\\"The Un-Collection\\\" will adorn the walls of Gilbert Hall.\"\n  },\n  {\n    \"name\":\"Jonathan G. Ferrar II\",\n    \"shortname\":\"Jonathan_Ferrar\",\n    \"reknown\":\"Artist to Watch in 2012\",\n    \"bio\":\"The Artist to Watch in 2012 by the London Review, Johnathan has already sold one of the highest priced-commissions paid to an art student, ever on record. The piece, entitled Gratitude Resort, a work in oil and mixed media, was sold for $750,000 and Jonathan donated all the proceeds to Art for Peace, an organization that provides college art scholarships for creative children in developing nations\"\n  },\n  {\n    \"name\":\"Hillary Hewitt Goldwynn-Post\",\n    \"shortname\":\"Hillary_Goldwynn\",\n    \"reknown\":\"New York University\",\n    \"bio\":\"Hillary is a sophomore art sculpture student at New York University, and has already won all the major international prizes for new sculptors, including the Divinity Circle, the International Sculptor's Medal, and the Academy of Paris Award. Hillary's CAC exhibit features 25 abstract watercolor paintings that contain only water images including waves, deep sea, and river.\"\n  },\n  {\n    \"name\":\"Hassum Harrod\",\n    \"shortname\":\"Hassum_Harrod\",\n    \"reknown\":\"Art College in New Dehli\",\n    \"bio\":\"The Art College in New Dehli has sponsored Hassum on scholarship for his entire undergraduate career at the university, seeing great promise in his contemporary paintings of landscapes - that use equal parts muted and vibrant tones, and are almost a contradiction in art. Hassum will be speaking on \\\"The use and absence of color in modern art\\\" during Thursday's agenda.\"\n  },\n  {\n    \"name\":\"Jennifer Jerome\",\n    \"shortname\":\"Jennifer_Jerome\",\n    \"reknown\":\"New Orleans, LA\",\n    \"bio\":\"A native of New Orleans, much of Jennifer's work has centered around abstract images that depict flooding and rebuilding, having grown up as a teenager in the post-flood years. Despite the sadness of devastation and lives lost, Jennifer's work also depicts the hope and togetherness of a community that has persevered. Jennifer's exhibit will be discussed during Tuesday's Water in Art theme.\"\n  },\n  {\n    \"name\":\"LaVonne L. LaRue\",\n    \"shortname\":\"LaVonne_LaRue\",\n    \"reknown\":\"Chicago, IL\",\n    \"bio\":\"LaVonne's giant-sized paintings all around Chicago tell the story of love, nature, and conservation - themes that are central to her heart. LaVonne will share her love and skill of graffiti art on Monday's schedule, as she starts the painting of a 20-foot high wall in the Rousseau Room of Hotel Contempo in front of a standing-room only audience in Art in Unexpected Places.\"\n  },\n  {\n    \"name\":\"Constance Olivia Smith\",\n    \"shortname\":\"Constance_Smith\",\n    \"reknown\":\"Fullerton-Brighton-Norwell Award\",\n    \"bio\":\"Constance received the Fullerton-Brighton-Norwell Award for Modern Art for her mixed-media image of a tree of life, with jewel-adorned branches depicting the arms of humanity, and precious gemstone-decorated leaves representing the spouting buds of togetherness. The daughter of a New York jeweler, Constance has been salvaging the discarded remnants of her father's jewelry-making since she was five years old, and won the New York State Fair grand prize at the age of 8 years old for a gem-adorned painting of the Manhattan Bridge.\"\n  },\n  {\n    \"name\":\"Riley Rudolph Rewington\",\n    \"shortname\":\"Riley_Rewington\",\n    \"reknown\":\"Roux Academy of Art, Media, and Design\",\n    \"bio\":\"A first-year student at the Roux Academy of Art, Media, and Design, Riley is already changing the face of modern art at the university. Riley's exquisite abstract pieces have no intention of ever being understood, but instead beg the viewer to dream, create, pretend, and envision with their mind's eye. Riley will be speaking on the \\\"Art of Abstract\\\" during Thursday's schedule\"\n  },\n  {\n    \"name\":\"Xhou Ta\",\n    \"shortname\":\"Xhou_Ta\",\n    \"reknown\":\"China International Art University\",\n    \"bio\":\"A senior at the China International Art University, Xhou has become well-known for his miniature sculptures, often the size of a rice granule, that are displayed by rear projection of microscope images on canvas. Xhou will discuss the art and science behind his incredibly detailed works of art.\"\n  }\n]"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/liveSearch/gulpfile.js",
    "content": "var gulp = require('gulp'),\n    webserver = require('gulp-webserver');\n\ngulp.task('webserver', function() {\n    gulp.src('.')\n        .pipe(webserver({\n            port: 8080,\n            livereload: true,\n            open: true,\n            fallback: 'liveSearch.html'\n        }));\n});\n\ngulp.task('default', ['webserver']);"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/liveSearch/liveSearch.css",
    "content": "* {\n    margin: 0;\n    padding: 0;\n}\n\n.relative {\n    position: relative;\n}\n\n.person {\n    width: 1080px;\n    max-height: 40px;\n    -webkit-transition: top 250ms, max-height 250ms;\n    transition: top 250ms, max-height 250ms;\n    overflow: hidden;\n    position: absolute;\n    border: 1px solid black;\n    background-color: beige;\n}\n\n.person:hover {\n    max-height: 100px;\n}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/liveSearch/liveSearch.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Live Search</title>\n    <link rel=\"stylesheet\" href=\"liveSearch.css\"/>\n</head>\n<body>\n<form name=\"search\">\n    <fieldset name=\"searchGroup\">\n        <label for=\"searchBox\">Search:</label>\n        <input name=\"searchBox\" id=\"searchBox\" type=\"text\"/>\n    </fieldset>\n</form>\n<section class=\"relative\">\n    <section id=\"data-display\"></section>\n</section>\n\n<script id=\"template\" type=\"text/template\">\n    {{#.}}\n    <section class=\"person\">\n        <h3 class=\"name\">{{name}}</h3>\n        <h4>{{reknown}}</h4>\n        <h6>{{bio}}</h6>\n    </section>\n    {{/.}}\n</script>\n<script src=\"http://cdn.jsdelivr.net/mustache.js/2.1.0/mustache.min.js\"></script>\n<script src=\"liveSearch.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/liveSearch/liveSearch.js",
    "content": "var searchBox = document.forms.search.searchBox;\n\nfunction onKeyUp() {\n    var regex = new RegExp(searchBox.value, 'i'),\n        names = document.querySelectorAll('.name');\n    for (var i = 0; i < names.length; i++) {\n        var obj = names[i];\n        if (obj.innerHTML.search(regex) === -1) {\n            obj.parentNode.style.display = 'none';\n        }\n        else {\n            obj.parentNode.style.display = 'block';\n        }\n    }\n}\n\nfunction positionPeople() {\n    var people = document.querySelectorAll('.person'),\n        currentPosition = 0;\n    for (var i = 0; i < people.length; i++) {\n        var person = people[i];\n        if (person.style.display !== 'none') {\n            console.log(person);\n            person.style.top = currentPosition + 'px';\n            currentPosition += person.clientHeight;\n        }\n    }\n}\n\nfunction getNames() {\n    var request = new XMLHttpRequest();\n    request.open('GET', 'data.json');\n    request.addEventListener('readystatechange', function () {\n        if (request.status === 200 && request.readyState === 4) {\n            var data = JSON.parse(request.responseText),\n                template = document.querySelector('#template').innerHTML;\n            document.querySelector('#data-display').innerHTML = Mustache.to_html(template, data);\n        }\n    });\n    request.send();\n}\n\nfunction onLoad() {\n    getNames();\n    searchBox.addEventListener('keyup', onKeyUp);\n    setInterval(positionPeople, 100);\n}\n\nwindow.addEventListener('load', onLoad);"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/liveSearch/package.json",
    "content": "{\n  \"name\": \"live-search\",\n  \"version\": \"0.0.1\",\n  \"author\": \"Daniel\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"gulp\": \"^3.9.0\",\n    \"gulp-webserver\": \"^0.9.1\"\n  }\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/mustacheTemplate/data.json",
    "content": "[\n\t{\n\t\t\"name\": \"Bob\",\n\t\t\"age\": 27,\n\t\t\"job\": \"Businessman\"\n\t},\n\t{\n\t\t\"name\": \"Polly\",\n\t\t\"age\": 30,\n\t\t\"job\": \"Artists\"\n\t},\n\t{\n\t\t\"name\": \"Jeff\",\n\t\t\"age\": 15,\n\t\t\"job\": \"Student\"\n\t}\n]"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/mustacheTemplate/gulpfile.js",
    "content": "var gulp = require('gulp'),\n\twebserver = require('gulp-webserver');\n\ngulp.task('webserver', function() {\n\tgulp.src('.')\n\t\t.pipe(webserver({\n\t\t\tport: 8080,\n\t\t\tlivereload: true,\n\t\t\topen: true,\n\t\t\tfallback: 'mustache.html'\n\t\t}));\n});\n\ngulp.task('default', ['webserver']);"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/mustacheTemplate/mustache.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<title>Mustache</title>\n\t<style>\n\t\t.person {\n\t\t\tbox-shadow: 1px 1px 2px 1px black;\n\t\t\tbackground-color: lightgreen;\n\t\t\tpadding: 1px;\n\t\t\tmargin: 10px;\n\t\t}\n\t</style>\n</head>\n<body>\n<section id=\"data-display\"></section>\n<script id=\"template\" type=\"text/template\">\n{{#.}}\n<section class=\"person\">\n\t<h3>{{name}}</h3>\n\t<h4>{{job}}</h4>\n\t<h6>{{age}}</h6>\n</section>\n{{/.}}\n</script>\n<script src=\"http://cdn.jsdelivr.net/mustache.js/2.1.0/mustache.min.js\"></script>\n<script src=\"mustache.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/mustacheTemplate/mustache.js",
    "content": "var request = new XMLHttpRequest();\nrequest.open('GET', 'data.json');\nrequest.addEventListener('readystatechange', function() {\n\tif (request.status === 200 && request.readyState === 4) {\n\t\tvar data = JSON.parse(request.responseText),\n\t\t\ttemplate = document.querySelector('#template').innerHTML,\n\t\t\thtml = Mustache.to_html(template, data);\n\t\tdocument.querySelector('#data-display').innerHTML = html;\n\t}\n});\nrequest.send();"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/mustacheTemplate/package.json",
    "content": "{\n  \"name\": \"mustache-template\",\n  \"version\": \"0.0.1\",\n  \"author\": \"Daniel\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"gulp\": \"^3.9.0\",\n    \"gulp-webserver\": \"^0.9.1\"\n  }\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/routing/app.js",
    "content": "myApp = angular.module('myApp', ['ngRoute', 'artists']);\n\nmyApp.config(['$routeProvider', function($routeProvider) {\n    $routeProvider.when('/list', {\n        templateUrl: 'list.html',\n        controller: 'listController'\n    })\n    .when('/details/:person', {\n        templateUrl: 'detail.html',\n        controller: 'detailController'\n    })\n    .otherwise({\n        redirectTo: '/list'\n    });\n}]);"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/routing/artists.js",
    "content": "var artistApp = angular.module('artists', ['firebase', 'ngAnimate']);\n\nartistApp.controller('listController', ['$scope', '$firebaseArray', function($scope, $firebaseArray) {\n    var ref = new Firebase('https://angular-bootcamp.firebaseio.com/people');\n\n    $scope.people = $firebaseArray(ref);\n    $scope.delete = function(itemId) {\n        ref.child(itemId).remove();\n    };\n    $scope.add = function() {\n        if($scope.newItem.name && $scope.newItem.reknown && $scope.newItem.bio) {\n            var reader = new FileReader();\n            reader.addEventListener('load', function(e) {\n                $scope.newItem.image = e.target.result;\n                ref.push($scope.newItem);\n                $scope.newItem = {};\n            });\n            reader.readAsDataURL(document.forms.addPerson.picture.files[0]);\n        }\n    }\n}]);\n\nartistApp.controller('detailController', ['$scope', '$routeParams', '$firebaseObject', function($scope, $routeParams, $firebaseObject) {\n    var ref = new Firebase('https://angular-bootcamp.firebaseio.com/people');\n    var person = $firebaseObject(ref.child($routeParams.person));\n    person.$bindTo($scope, 'person');\n}]);"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/routing/detail.html",
    "content": "<a href=\"#/list\">&lt;&lt;Back</a>\n<h1>{{person.name}}</h1>\n<h2>{{person.reknown}}</h2>\n<p>{{person.bio}}</p>\n<img ng-src=\"{{person.image}}\"/>\n\n<input type=\"text\" ng-model=\"person.name\"/>\n<input type=\"text\" ng-model=\"person.reknown\"/>\n<textarea ng-model=\"person.bio\" cols=\"50\" rows=\"10\"></textarea>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/routing/list.html",
    "content": "<form ng-submit=\"add()\" name=\"addPerson\" novalidate>\n    <h2>Add Person</h2>\n    <input name=\"name\" type=\"text\" ng-model=\"newItem.name\" placeholder=\"Name\" ng-required=\"true\"/>\n    <p ng-show=\"addPerson.name.$invalid && addPerson.name.$touched\">Name is required</p>\n    <label for=\"picture\">Image</label>\n    <input type=\"file\" id=\"picture\" accept=\"image/*\" name=\"picture\" ng-required=\"true\" placeholder=\"Picture\"/>\n    <p ng-show=\"addPerson.picture.$invalid && addPerson.picture.$touched\">Image is required</p>\n    <input name=\"renown\" type=\"text\" ng-model=\"newItem.reknown\" placeholder=\"Renown\" ng-required=\"true\"/>\n    <p ng-show=\"addPerson.renown.$invalid && addPerson.renown.$touched\">Renown is required</p>\n    <textarea name=\"bio\" placeholder=\"Bio\" ng-model=\"newItem.bio\" cols=\"30\" rows=\"5\" ng-required=\"true\"></textarea>\n    <p ng-show=\"addPerson.bio.$invalid && addPerson.bio.$touched\">Bio is required</p>\n    <input type=\"submit\" ng-disabled=\"addPerson.$invalid\"/>\n</form>\n\n<input type=\"text\" ng-model=\"query\" placeholder=\"Search\"/>\n\n<div class=\"person\" ng-repeat=\"person in people | filter: {name:query}\">\n    <a href=\"#/details/{{person.$id}}\">\n        <h1>{{person.name}}</h1>\n\n        <h3>{{person.reknown}}</h3>\n\n        <img ng-src=\"{{person.image}}\" alt=\"Image of {{person.name}}\"/>\n    </a>\n    <button ng-click=\"delete(person.$id)\">Delete</button>\n</div>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/routing/routing.html",
    "content": "<!doctype html>\n<html lang=\"en\" ng-app=\"myApp\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Routing</title>\n    <script src=\"https://ajax.googleapis.com/ajax/libs/angularjs/1.3.16/angular.min.js\"></script>\n    <script src=\"https://ajax.googleapis.com/ajax/libs/angularjs/1.3.16/angular-route.min.js\"></script>\n    <script src=\"https://ajax.googleapis.com/ajax/libs/angularjs/1.3.16/angular-animate.min.js\"></script>\n    <script src=\"https://cdn.firebase.com/js/client/2.2.4/firebase.js\"></script>\n    <script src=\"https://cdn.firebase.com/libs/angularfire/1.1.1/angularfire.min.js\"></script>\n    <script src=\"artists.js\"></script>\n    <script src=\"app.js\"></script>\n    <link rel=\"stylesheet\" href=\"style.css\"/>\n</head>\n<body ng-view>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week4/routing/style.css",
    "content": ".person.ng-enter,\n.person.ng-leave,\n.person.ng-move {\n    transition: all 500ms linear;\n}\n\n.person.ng-enter,\n.person.ng-move {\n    opacity: 0;\n    max-height: 0;\n    overflow: hidden;\n}\n\n.person.ng-move.ng-move-active,\n.person.ng-enter.ng-enter-active {\n    opacity: 1;\n    max-height: 500px;\n}\n\n.person.ng-leave {\n    opacity: 1;\n    overflow: hidden;\n    max-height: 500px;\n}\n\n.person.ng-leave.ng-leave-active {\n    opacity: 0;\n    max-height: 0;\n}\n\na {\n    text-decoration: none;\n}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Andrew Rota\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/README.md",
    "content": "# Web Components Training Exercsies\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/breaking-shadow-dom-polyfill/another-component/index.html",
    "content": "<template id=\"template\">\n    <p>Child Component</p>\n</template>\n<script>\n    var createElement = function(tagName, templateId, basePrototype) {\n        var currentScript = document._currentScript || document.currentScript;\n        basePrototype = basePrototype || HTMLElement.prototype;\n        var template = currentScript.ownerDocument.getElementById(templateId).content;\n        var customElementPrototype = Object.create(basePrototype);\n        customElementPrototype.createdCallback = function() {\n            var shadowRoot = this.createShadowRoot();\n            var clone = document.importNode(template, true);\n            shadowRoot.appendChild(clone);\n        };\n        return document.registerElement(tagName, {\n            prototype: customElementPrototype\n        });\n    };\n    createElement('another-component', 'template');\n</script>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/breaking-shadow-dom-polyfill/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <meta charset=\"UTF-8\">\n    <title>Breaking the Shadow DOM Polyfill</title>\n    <script>if (window.Platform && window.Platform.ShadowCSS) Platform.ShadowCSS.strictStyling = true;</script>\n    <link rel=\"import\" href=\"my-component/index.html\"/>\n    <link rel=\"import\" href=\"another-component/index.html\"/>\n</head>\n<body>\n<style>body p { color: red;}</style>\n<my-component></my-component>\n\n<!-- Exercise instructions: This exercise will demonstrate how the Shadow DOM polyfill\n     works...and doesn't.\n\n     1. Download webcomponents.js polyfill from http://webcomponents.org/polyfills/\n        - It's also included in this directory as webcomponents.js already!\n     2. Include polyfill on page\n     3. Demonstrate difference between upper and lower bound encapsulation\n     4. Experiment with differences with shadow DOM between supported and unsupported browsers\n -->\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/breaking-shadow-dom-polyfill/my-component/index.html",
    "content": "<template id=\"template\">\n    <style> p { color: blue; } </style>\n    <p>Parent Component </p>\n    <another-component></another-component>\n</template>\n<script>\n    var createElement = function(tagName, templateId, basePrototype) {\n        var currentScript = document._currentScript || document.currentScript;\n        basePrototype = basePrototype || HTMLElement.prototype;\n        var template = currentScript.ownerDocument.getElementById(templateId).content;\n        var customElementPrototype = Object.create(basePrototype);\n        customElementPrototype.createdCallback = function() {\n            var shadowRoot = this.createShadowRoot();\n            var clone = document.importNode(template, true);\n            shadowRoot.appendChild(clone);\n        };\n        return document.registerElement(tagName, {\n            prototype: customElementPrototype\n        });\n    };\n    createElement('my-component', 'template');\n</script>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/breaking-shadow-dom-polyfill/webcomponents.js",
    "content": "/**\n * @license\n * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.\n * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\n * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\n * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\n * Code distributed by Google as part of the polymer project is also\n * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n */\n// @version 0.6.1\nwindow.WebComponents = window.WebComponents || {};\n\n(function(scope) {\n  var flags = scope.flags || {};\n  var file = \"webcomponents.js\";\n  var script = document.querySelector('script[src*=\"' + file + '\"]');\n  if (!flags.noOpts) {\n    location.search.slice(1).split(\"&\").forEach(function(option) {\n      var parts = option.split(\"=\");\n      var match;\n      if (parts[0] && (match = parts[0].match(/wc-(.+)/))) {\n        flags[match[1]] = parts[1] || true;\n      }\n    });\n    if (script) {\n      for (var i = 0, a; a = script.attributes[i]; i++) {\n        if (a.name !== \"src\") {\n          flags[a.name] = a.value || true;\n        }\n      }\n    }\n    if (flags.log && flags.log.split) {\n      var parts = flags.log.split(\",\");\n      flags.log = {};\n      parts.forEach(function(f) {\n        flags.log[f] = true;\n      });\n    } else {\n      flags.log = {};\n    }\n  }\n  flags.shadow = flags.shadow || flags.shadowdom || flags.polyfill;\n  if (flags.shadow === \"native\") {\n    flags.shadow = false;\n  } else {\n    flags.shadow = flags.shadow || !HTMLElement.prototype.createShadowRoot;\n  }\n  if (flags.register) {\n    window.CustomElements = window.CustomElements || {\n      flags: {}\n    };\n    window.CustomElements.flags.register = flags.register;\n  }\n  scope.flags = flags;\n})(WebComponents);\n\nif (WebComponents.flags.shadow) {\n  if (typeof WeakMap === \"undefined\") {\n    (function() {\n      var defineProperty = Object.defineProperty;\n      var counter = Date.now() % 1e9;\n      var WeakMap = function() {\n        this.name = \"__st\" + (Math.random() * 1e9 >>> 0) + (counter++ + \"__\");\n      };\n      WeakMap.prototype = {\n        set: function(key, value) {\n          var entry = key[this.name];\n          if (entry && entry[0] === key) entry[1] = value; else defineProperty(key, this.name, {\n            value: [ key, value ],\n            writable: true\n          });\n          return this;\n        },\n        get: function(key) {\n          var entry;\n          return (entry = key[this.name]) && entry[0] === key ? entry[1] : undefined;\n        },\n        \"delete\": function(key) {\n          var entry = key[this.name];\n          if (!entry || entry[0] !== key) return false;\n          entry[0] = entry[1] = undefined;\n          return true;\n        },\n        has: function(key) {\n          var entry = key[this.name];\n          if (!entry) return false;\n          return entry[0] === key;\n        }\n      };\n      window.WeakMap = WeakMap;\n    })();\n  }\n  window.ShadowDOMPolyfill = {};\n  (function(scope) {\n    \"use strict\";\n    var constructorTable = new WeakMap();\n    var nativePrototypeTable = new WeakMap();\n    var wrappers = Object.create(null);\n    function detectEval() {\n      if (typeof chrome !== \"undefined\" && chrome.app && chrome.app.runtime) {\n        return false;\n      }\n      if (navigator.getDeviceStorage) {\n        return false;\n      }\n      try {\n        var f = new Function(\"return true;\");\n        return f();\n      } catch (ex) {\n        return false;\n      }\n    }\n    var hasEval = detectEval();\n    function assert(b) {\n      if (!b) throw new Error(\"Assertion failed\");\n    }\n    var defineProperty = Object.defineProperty;\n    var getOwnPropertyNames = Object.getOwnPropertyNames;\n    var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;\n    function mixin(to, from) {\n      var names = getOwnPropertyNames(from);\n      for (var i = 0; i < names.length; i++) {\n        var name = names[i];\n        defineProperty(to, name, getOwnPropertyDescriptor(from, name));\n      }\n      return to;\n    }\n    function mixinStatics(to, from) {\n      var names = getOwnPropertyNames(from);\n      for (var i = 0; i < names.length; i++) {\n        var name = names[i];\n        switch (name) {\n         case \"arguments\":\n         case \"caller\":\n         case \"length\":\n         case \"name\":\n         case \"prototype\":\n         case \"toString\":\n          continue;\n        }\n        defineProperty(to, name, getOwnPropertyDescriptor(from, name));\n      }\n      return to;\n    }\n    function oneOf(object, propertyNames) {\n      for (var i = 0; i < propertyNames.length; i++) {\n        if (propertyNames[i] in object) return propertyNames[i];\n      }\n    }\n    var nonEnumerableDataDescriptor = {\n      value: undefined,\n      configurable: true,\n      enumerable: false,\n      writable: true\n    };\n    function defineNonEnumerableDataProperty(object, name, value) {\n      nonEnumerableDataDescriptor.value = value;\n      defineProperty(object, name, nonEnumerableDataDescriptor);\n    }\n    getOwnPropertyNames(window);\n    function getWrapperConstructor(node) {\n      var nativePrototype = node.__proto__ || Object.getPrototypeOf(node);\n      if (isFirefox) {\n        try {\n          getOwnPropertyNames(nativePrototype);\n        } catch (error) {\n          nativePrototype = nativePrototype.__proto__;\n        }\n      }\n      var wrapperConstructor = constructorTable.get(nativePrototype);\n      if (wrapperConstructor) return wrapperConstructor;\n      var parentWrapperConstructor = getWrapperConstructor(nativePrototype);\n      var GeneratedWrapper = createWrapperConstructor(parentWrapperConstructor);\n      registerInternal(nativePrototype, GeneratedWrapper, node);\n      return GeneratedWrapper;\n    }\n    function addForwardingProperties(nativePrototype, wrapperPrototype) {\n      installProperty(nativePrototype, wrapperPrototype, true);\n    }\n    function registerInstanceProperties(wrapperPrototype, instanceObject) {\n      installProperty(instanceObject, wrapperPrototype, false);\n    }\n    var isFirefox = /Firefox/.test(navigator.userAgent);\n    var dummyDescriptor = {\n      get: function() {},\n      set: function(v) {},\n      configurable: true,\n      enumerable: true\n    };\n    function isEventHandlerName(name) {\n      return /^on[a-z]+$/.test(name);\n    }\n    function isIdentifierName(name) {\n      return /^[a-zA-Z_$][a-zA-Z_$0-9]*$/.test(name);\n    }\n    function getGetter(name) {\n      return hasEval && isIdentifierName(name) ? new Function(\"return this.__impl4cf1e782hg__.\" + name) : function() {\n        return this.__impl4cf1e782hg__[name];\n      };\n    }\n    function getSetter(name) {\n      return hasEval && isIdentifierName(name) ? new Function(\"v\", \"this.__impl4cf1e782hg__.\" + name + \" = v\") : function(v) {\n        this.__impl4cf1e782hg__[name] = v;\n      };\n    }\n    function getMethod(name) {\n      return hasEval && isIdentifierName(name) ? new Function(\"return this.__impl4cf1e782hg__.\" + name + \".apply(this.__impl4cf1e782hg__, arguments)\") : function() {\n        return this.__impl4cf1e782hg__[name].apply(this.__impl4cf1e782hg__, arguments);\n      };\n    }\n    function getDescriptor(source, name) {\n      try {\n        return Object.getOwnPropertyDescriptor(source, name);\n      } catch (ex) {\n        return dummyDescriptor;\n      }\n    }\n    var isBrokenSafari = function() {\n      var descr = Object.getOwnPropertyDescriptor(Node.prototype, \"nodeType\");\n      return descr && !descr.get && !descr.set;\n    }();\n    function installProperty(source, target, allowMethod, opt_blacklist) {\n      var names = getOwnPropertyNames(source);\n      for (var i = 0; i < names.length; i++) {\n        var name = names[i];\n        if (name === \"polymerBlackList_\") continue;\n        if (name in target) continue;\n        if (source.polymerBlackList_ && source.polymerBlackList_[name]) continue;\n        if (isFirefox) {\n          source.__lookupGetter__(name);\n        }\n        var descriptor = getDescriptor(source, name);\n        var getter, setter;\n        if (allowMethod && typeof descriptor.value === \"function\") {\n          target[name] = getMethod(name);\n          continue;\n        }\n        var isEvent = isEventHandlerName(name);\n        if (isEvent) getter = scope.getEventHandlerGetter(name); else getter = getGetter(name);\n        if (descriptor.writable || descriptor.set || isBrokenSafari) {\n          if (isEvent) setter = scope.getEventHandlerSetter(name); else setter = getSetter(name);\n        }\n        var configurable = isBrokenSafari || descriptor.configurable;\n        defineProperty(target, name, {\n          get: getter,\n          set: setter,\n          configurable: configurable,\n          enumerable: descriptor.enumerable\n        });\n      }\n    }\n    function register(nativeConstructor, wrapperConstructor, opt_instance) {\n      var nativePrototype = nativeConstructor.prototype;\n      registerInternal(nativePrototype, wrapperConstructor, opt_instance);\n      mixinStatics(wrapperConstructor, nativeConstructor);\n    }\n    function registerInternal(nativePrototype, wrapperConstructor, opt_instance) {\n      var wrapperPrototype = wrapperConstructor.prototype;\n      assert(constructorTable.get(nativePrototype) === undefined);\n      constructorTable.set(nativePrototype, wrapperConstructor);\n      nativePrototypeTable.set(wrapperPrototype, nativePrototype);\n      addForwardingProperties(nativePrototype, wrapperPrototype);\n      if (opt_instance) registerInstanceProperties(wrapperPrototype, opt_instance);\n      defineNonEnumerableDataProperty(wrapperPrototype, \"constructor\", wrapperConstructor);\n      wrapperConstructor.prototype = wrapperPrototype;\n    }\n    function isWrapperFor(wrapperConstructor, nativeConstructor) {\n      return constructorTable.get(nativeConstructor.prototype) === wrapperConstructor;\n    }\n    function registerObject(object) {\n      var nativePrototype = Object.getPrototypeOf(object);\n      var superWrapperConstructor = getWrapperConstructor(nativePrototype);\n      var GeneratedWrapper = createWrapperConstructor(superWrapperConstructor);\n      registerInternal(nativePrototype, GeneratedWrapper, object);\n      return GeneratedWrapper;\n    }\n    function createWrapperConstructor(superWrapperConstructor) {\n      function GeneratedWrapper(node) {\n        superWrapperConstructor.call(this, node);\n      }\n      var p = Object.create(superWrapperConstructor.prototype);\n      p.constructor = GeneratedWrapper;\n      GeneratedWrapper.prototype = p;\n      return GeneratedWrapper;\n    }\n    function isWrapper(object) {\n      return object && object.__impl4cf1e782hg__;\n    }\n    function isNative(object) {\n      return !isWrapper(object);\n    }\n    function wrap(impl) {\n      if (impl === null) return null;\n      assert(isNative(impl));\n      return impl.__wrapper8e3dd93a60__ || (impl.__wrapper8e3dd93a60__ = new (getWrapperConstructor(impl))(impl));\n    }\n    function unwrap(wrapper) {\n      if (wrapper === null) return null;\n      assert(isWrapper(wrapper));\n      return wrapper.__impl4cf1e782hg__;\n    }\n    function unsafeUnwrap(wrapper) {\n      return wrapper.__impl4cf1e782hg__;\n    }\n    function setWrapper(impl, wrapper) {\n      wrapper.__impl4cf1e782hg__ = impl;\n      impl.__wrapper8e3dd93a60__ = wrapper;\n    }\n    function unwrapIfNeeded(object) {\n      return object && isWrapper(object) ? unwrap(object) : object;\n    }\n    function wrapIfNeeded(object) {\n      return object && !isWrapper(object) ? wrap(object) : object;\n    }\n    function rewrap(node, wrapper) {\n      if (wrapper === null) return;\n      assert(isNative(node));\n      assert(wrapper === undefined || isWrapper(wrapper));\n      node.__wrapper8e3dd93a60__ = wrapper;\n    }\n    var getterDescriptor = {\n      get: undefined,\n      configurable: true,\n      enumerable: true\n    };\n    function defineGetter(constructor, name, getter) {\n      getterDescriptor.get = getter;\n      defineProperty(constructor.prototype, name, getterDescriptor);\n    }\n    function defineWrapGetter(constructor, name) {\n      defineGetter(constructor, name, function() {\n        return wrap(this.__impl4cf1e782hg__[name]);\n      });\n    }\n    function forwardMethodsToWrapper(constructors, names) {\n      constructors.forEach(function(constructor) {\n        names.forEach(function(name) {\n          constructor.prototype[name] = function() {\n            var w = wrapIfNeeded(this);\n            return w[name].apply(w, arguments);\n          };\n        });\n      });\n    }\n    scope.assert = assert;\n    scope.constructorTable = constructorTable;\n    scope.defineGetter = defineGetter;\n    scope.defineWrapGetter = defineWrapGetter;\n    scope.forwardMethodsToWrapper = forwardMethodsToWrapper;\n    scope.isIdentifierName = isIdentifierName;\n    scope.isWrapper = isWrapper;\n    scope.isWrapperFor = isWrapperFor;\n    scope.mixin = mixin;\n    scope.nativePrototypeTable = nativePrototypeTable;\n    scope.oneOf = oneOf;\n    scope.registerObject = registerObject;\n    scope.registerWrapper = register;\n    scope.rewrap = rewrap;\n    scope.setWrapper = setWrapper;\n    scope.unsafeUnwrap = unsafeUnwrap;\n    scope.unwrap = unwrap;\n    scope.unwrapIfNeeded = unwrapIfNeeded;\n    scope.wrap = wrap;\n    scope.wrapIfNeeded = wrapIfNeeded;\n    scope.wrappers = wrappers;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    function newSplice(index, removed, addedCount) {\n      return {\n        index: index,\n        removed: removed,\n        addedCount: addedCount\n      };\n    }\n    var EDIT_LEAVE = 0;\n    var EDIT_UPDATE = 1;\n    var EDIT_ADD = 2;\n    var EDIT_DELETE = 3;\n    function ArraySplice() {}\n    ArraySplice.prototype = {\n      calcEditDistances: function(current, currentStart, currentEnd, old, oldStart, oldEnd) {\n        var rowCount = oldEnd - oldStart + 1;\n        var columnCount = currentEnd - currentStart + 1;\n        var distances = new Array(rowCount);\n        for (var i = 0; i < rowCount; i++) {\n          distances[i] = new Array(columnCount);\n          distances[i][0] = i;\n        }\n        for (var j = 0; j < columnCount; j++) distances[0][j] = j;\n        for (var i = 1; i < rowCount; i++) {\n          for (var j = 1; j < columnCount; j++) {\n            if (this.equals(current[currentStart + j - 1], old[oldStart + i - 1])) distances[i][j] = distances[i - 1][j - 1]; else {\n              var north = distances[i - 1][j] + 1;\n              var west = distances[i][j - 1] + 1;\n              distances[i][j] = north < west ? north : west;\n            }\n          }\n        }\n        return distances;\n      },\n      spliceOperationsFromEditDistances: function(distances) {\n        var i = distances.length - 1;\n        var j = distances[0].length - 1;\n        var current = distances[i][j];\n        var edits = [];\n        while (i > 0 || j > 0) {\n          if (i == 0) {\n            edits.push(EDIT_ADD);\n            j--;\n            continue;\n          }\n          if (j == 0) {\n            edits.push(EDIT_DELETE);\n            i--;\n            continue;\n          }\n          var northWest = distances[i - 1][j - 1];\n          var west = distances[i - 1][j];\n          var north = distances[i][j - 1];\n          var min;\n          if (west < north) min = west < northWest ? west : northWest; else min = north < northWest ? north : northWest;\n          if (min == northWest) {\n            if (northWest == current) {\n              edits.push(EDIT_LEAVE);\n            } else {\n              edits.push(EDIT_UPDATE);\n              current = northWest;\n            }\n            i--;\n            j--;\n          } else if (min == west) {\n            edits.push(EDIT_DELETE);\n            i--;\n            current = west;\n          } else {\n            edits.push(EDIT_ADD);\n            j--;\n            current = north;\n          }\n        }\n        edits.reverse();\n        return edits;\n      },\n      calcSplices: function(current, currentStart, currentEnd, old, oldStart, oldEnd) {\n        var prefixCount = 0;\n        var suffixCount = 0;\n        var minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);\n        if (currentStart == 0 && oldStart == 0) prefixCount = this.sharedPrefix(current, old, minLength);\n        if (currentEnd == current.length && oldEnd == old.length) suffixCount = this.sharedSuffix(current, old, minLength - prefixCount);\n        currentStart += prefixCount;\n        oldStart += prefixCount;\n        currentEnd -= suffixCount;\n        oldEnd -= suffixCount;\n        if (currentEnd - currentStart == 0 && oldEnd - oldStart == 0) return [];\n        if (currentStart == currentEnd) {\n          var splice = newSplice(currentStart, [], 0);\n          while (oldStart < oldEnd) splice.removed.push(old[oldStart++]);\n          return [ splice ];\n        } else if (oldStart == oldEnd) return [ newSplice(currentStart, [], currentEnd - currentStart) ];\n        var ops = this.spliceOperationsFromEditDistances(this.calcEditDistances(current, currentStart, currentEnd, old, oldStart, oldEnd));\n        var splice = undefined;\n        var splices = [];\n        var index = currentStart;\n        var oldIndex = oldStart;\n        for (var i = 0; i < ops.length; i++) {\n          switch (ops[i]) {\n           case EDIT_LEAVE:\n            if (splice) {\n              splices.push(splice);\n              splice = undefined;\n            }\n            index++;\n            oldIndex++;\n            break;\n\n           case EDIT_UPDATE:\n            if (!splice) splice = newSplice(index, [], 0);\n            splice.addedCount++;\n            index++;\n            splice.removed.push(old[oldIndex]);\n            oldIndex++;\n            break;\n\n           case EDIT_ADD:\n            if (!splice) splice = newSplice(index, [], 0);\n            splice.addedCount++;\n            index++;\n            break;\n\n           case EDIT_DELETE:\n            if (!splice) splice = newSplice(index, [], 0);\n            splice.removed.push(old[oldIndex]);\n            oldIndex++;\n            break;\n          }\n        }\n        if (splice) {\n          splices.push(splice);\n        }\n        return splices;\n      },\n      sharedPrefix: function(current, old, searchLength) {\n        for (var i = 0; i < searchLength; i++) if (!this.equals(current[i], old[i])) return i;\n        return searchLength;\n      },\n      sharedSuffix: function(current, old, searchLength) {\n        var index1 = current.length;\n        var index2 = old.length;\n        var count = 0;\n        while (count < searchLength && this.equals(current[--index1], old[--index2])) count++;\n        return count;\n      },\n      calculateSplices: function(current, previous) {\n        return this.calcSplices(current, 0, current.length, previous, 0, previous.length);\n      },\n      equals: function(currentValue, previousValue) {\n        return currentValue === previousValue;\n      }\n    };\n    scope.ArraySplice = ArraySplice;\n  })(window.ShadowDOMPolyfill);\n  (function(context) {\n    \"use strict\";\n    var OriginalMutationObserver = window.MutationObserver;\n    var callbacks = [];\n    var pending = false;\n    var timerFunc;\n    function handle() {\n      pending = false;\n      var copies = callbacks.slice(0);\n      callbacks = [];\n      for (var i = 0; i < copies.length; i++) {\n        (0, copies[i])();\n      }\n    }\n    if (OriginalMutationObserver) {\n      var counter = 1;\n      var observer = new OriginalMutationObserver(handle);\n      var textNode = document.createTextNode(counter);\n      observer.observe(textNode, {\n        characterData: true\n      });\n      timerFunc = function() {\n        counter = (counter + 1) % 2;\n        textNode.data = counter;\n      };\n    } else {\n      timerFunc = window.setTimeout;\n    }\n    function setEndOfMicrotask(func) {\n      callbacks.push(func);\n      if (pending) return;\n      pending = true;\n      timerFunc(handle, 0);\n    }\n    context.setEndOfMicrotask = setEndOfMicrotask;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var setEndOfMicrotask = scope.setEndOfMicrotask;\n    var wrapIfNeeded = scope.wrapIfNeeded;\n    var wrappers = scope.wrappers;\n    var registrationsTable = new WeakMap();\n    var globalMutationObservers = [];\n    var isScheduled = false;\n    function scheduleCallback(observer) {\n      if (observer.scheduled_) return;\n      observer.scheduled_ = true;\n      globalMutationObservers.push(observer);\n      if (isScheduled) return;\n      setEndOfMicrotask(notifyObservers);\n      isScheduled = true;\n    }\n    function notifyObservers() {\n      isScheduled = false;\n      while (globalMutationObservers.length) {\n        var notifyList = globalMutationObservers;\n        globalMutationObservers = [];\n        notifyList.sort(function(x, y) {\n          return x.uid_ - y.uid_;\n        });\n        for (var i = 0; i < notifyList.length; i++) {\n          var mo = notifyList[i];\n          mo.scheduled_ = false;\n          var queue = mo.takeRecords();\n          removeTransientObserversFor(mo);\n          if (queue.length) {\n            mo.callback_(queue, mo);\n          }\n        }\n      }\n    }\n    function MutationRecord(type, target) {\n      this.type = type;\n      this.target = target;\n      this.addedNodes = new wrappers.NodeList();\n      this.removedNodes = new wrappers.NodeList();\n      this.previousSibling = null;\n      this.nextSibling = null;\n      this.attributeName = null;\n      this.attributeNamespace = null;\n      this.oldValue = null;\n    }\n    function registerTransientObservers(ancestor, node) {\n      for (;ancestor; ancestor = ancestor.parentNode) {\n        var registrations = registrationsTable.get(ancestor);\n        if (!registrations) continue;\n        for (var i = 0; i < registrations.length; i++) {\n          var registration = registrations[i];\n          if (registration.options.subtree) registration.addTransientObserver(node);\n        }\n      }\n    }\n    function removeTransientObserversFor(observer) {\n      for (var i = 0; i < observer.nodes_.length; i++) {\n        var node = observer.nodes_[i];\n        var registrations = registrationsTable.get(node);\n        if (!registrations) return;\n        for (var j = 0; j < registrations.length; j++) {\n          var registration = registrations[j];\n          if (registration.observer === observer) registration.removeTransientObservers();\n        }\n      }\n    }\n    function enqueueMutation(target, type, data) {\n      var interestedObservers = Object.create(null);\n      var associatedStrings = Object.create(null);\n      for (var node = target; node; node = node.parentNode) {\n        var registrations = registrationsTable.get(node);\n        if (!registrations) continue;\n        for (var j = 0; j < registrations.length; j++) {\n          var registration = registrations[j];\n          var options = registration.options;\n          if (node !== target && !options.subtree) continue;\n          if (type === \"attributes\" && !options.attributes) continue;\n          if (type === \"attributes\" && options.attributeFilter && (data.namespace !== null || options.attributeFilter.indexOf(data.name) === -1)) {\n            continue;\n          }\n          if (type === \"characterData\" && !options.characterData) continue;\n          if (type === \"childList\" && !options.childList) continue;\n          var observer = registration.observer;\n          interestedObservers[observer.uid_] = observer;\n          if (type === \"attributes\" && options.attributeOldValue || type === \"characterData\" && options.characterDataOldValue) {\n            associatedStrings[observer.uid_] = data.oldValue;\n          }\n        }\n      }\n      for (var uid in interestedObservers) {\n        var observer = interestedObservers[uid];\n        var record = new MutationRecord(type, target);\n        if (\"name\" in data && \"namespace\" in data) {\n          record.attributeName = data.name;\n          record.attributeNamespace = data.namespace;\n        }\n        if (data.addedNodes) record.addedNodes = data.addedNodes;\n        if (data.removedNodes) record.removedNodes = data.removedNodes;\n        if (data.previousSibling) record.previousSibling = data.previousSibling;\n        if (data.nextSibling) record.nextSibling = data.nextSibling;\n        if (associatedStrings[uid] !== undefined) record.oldValue = associatedStrings[uid];\n        scheduleCallback(observer);\n        observer.records_.push(record);\n      }\n    }\n    var slice = Array.prototype.slice;\n    function MutationObserverOptions(options) {\n      this.childList = !!options.childList;\n      this.subtree = !!options.subtree;\n      if (!(\"attributes\" in options) && (\"attributeOldValue\" in options || \"attributeFilter\" in options)) {\n        this.attributes = true;\n      } else {\n        this.attributes = !!options.attributes;\n      }\n      if (\"characterDataOldValue\" in options && !(\"characterData\" in options)) this.characterData = true; else this.characterData = !!options.characterData;\n      if (!this.attributes && (options.attributeOldValue || \"attributeFilter\" in options) || !this.characterData && options.characterDataOldValue) {\n        throw new TypeError();\n      }\n      this.characterData = !!options.characterData;\n      this.attributeOldValue = !!options.attributeOldValue;\n      this.characterDataOldValue = !!options.characterDataOldValue;\n      if (\"attributeFilter\" in options) {\n        if (options.attributeFilter == null || typeof options.attributeFilter !== \"object\") {\n          throw new TypeError();\n        }\n        this.attributeFilter = slice.call(options.attributeFilter);\n      } else {\n        this.attributeFilter = null;\n      }\n    }\n    var uidCounter = 0;\n    function MutationObserver(callback) {\n      this.callback_ = callback;\n      this.nodes_ = [];\n      this.records_ = [];\n      this.uid_ = ++uidCounter;\n      this.scheduled_ = false;\n    }\n    MutationObserver.prototype = {\n      constructor: MutationObserver,\n      observe: function(target, options) {\n        target = wrapIfNeeded(target);\n        var newOptions = new MutationObserverOptions(options);\n        var registration;\n        var registrations = registrationsTable.get(target);\n        if (!registrations) registrationsTable.set(target, registrations = []);\n        for (var i = 0; i < registrations.length; i++) {\n          if (registrations[i].observer === this) {\n            registration = registrations[i];\n            registration.removeTransientObservers();\n            registration.options = newOptions;\n          }\n        }\n        if (!registration) {\n          registration = new Registration(this, target, newOptions);\n          registrations.push(registration);\n          this.nodes_.push(target);\n        }\n      },\n      disconnect: function() {\n        this.nodes_.forEach(function(node) {\n          var registrations = registrationsTable.get(node);\n          for (var i = 0; i < registrations.length; i++) {\n            var registration = registrations[i];\n            if (registration.observer === this) {\n              registrations.splice(i, 1);\n              break;\n            }\n          }\n        }, this);\n        this.records_ = [];\n      },\n      takeRecords: function() {\n        var copyOfRecords = this.records_;\n        this.records_ = [];\n        return copyOfRecords;\n      }\n    };\n    function Registration(observer, target, options) {\n      this.observer = observer;\n      this.target = target;\n      this.options = options;\n      this.transientObservedNodes = [];\n    }\n    Registration.prototype = {\n      addTransientObserver: function(node) {\n        if (node === this.target) return;\n        scheduleCallback(this.observer);\n        this.transientObservedNodes.push(node);\n        var registrations = registrationsTable.get(node);\n        if (!registrations) registrationsTable.set(node, registrations = []);\n        registrations.push(this);\n      },\n      removeTransientObservers: function() {\n        var transientObservedNodes = this.transientObservedNodes;\n        this.transientObservedNodes = [];\n        for (var i = 0; i < transientObservedNodes.length; i++) {\n          var node = transientObservedNodes[i];\n          var registrations = registrationsTable.get(node);\n          for (var j = 0; j < registrations.length; j++) {\n            if (registrations[j] === this) {\n              registrations.splice(j, 1);\n              break;\n            }\n          }\n        }\n      }\n    };\n    scope.enqueueMutation = enqueueMutation;\n    scope.registerTransientObservers = registerTransientObservers;\n    scope.wrappers.MutationObserver = MutationObserver;\n    scope.wrappers.MutationRecord = MutationRecord;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    function TreeScope(root, parent) {\n      this.root = root;\n      this.parent = parent;\n    }\n    TreeScope.prototype = {\n      get renderer() {\n        if (this.root instanceof scope.wrappers.ShadowRoot) {\n          return scope.getRendererForHost(this.root.host);\n        }\n        return null;\n      },\n      contains: function(treeScope) {\n        for (;treeScope; treeScope = treeScope.parent) {\n          if (treeScope === this) return true;\n        }\n        return false;\n      }\n    };\n    function setTreeScope(node, treeScope) {\n      if (node.treeScope_ !== treeScope) {\n        node.treeScope_ = treeScope;\n        for (var sr = node.shadowRoot; sr; sr = sr.olderShadowRoot) {\n          sr.treeScope_.parent = treeScope;\n        }\n        for (var child = node.firstChild; child; child = child.nextSibling) {\n          setTreeScope(child, treeScope);\n        }\n      }\n    }\n    function getTreeScope(node) {\n      if (node instanceof scope.wrappers.Window) {\n        debugger;\n      }\n      if (node.treeScope_) return node.treeScope_;\n      var parent = node.parentNode;\n      var treeScope;\n      if (parent) treeScope = getTreeScope(parent); else treeScope = new TreeScope(node, null);\n      return node.treeScope_ = treeScope;\n    }\n    scope.TreeScope = TreeScope;\n    scope.getTreeScope = getTreeScope;\n    scope.setTreeScope = setTreeScope;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var forwardMethodsToWrapper = scope.forwardMethodsToWrapper;\n    var getTreeScope = scope.getTreeScope;\n    var mixin = scope.mixin;\n    var registerWrapper = scope.registerWrapper;\n    var setWrapper = scope.setWrapper;\n    var unsafeUnwrap = scope.unsafeUnwrap;\n    var unwrap = scope.unwrap;\n    var wrap = scope.wrap;\n    var wrappers = scope.wrappers;\n    var wrappedFuns = new WeakMap();\n    var listenersTable = new WeakMap();\n    var handledEventsTable = new WeakMap();\n    var currentlyDispatchingEvents = new WeakMap();\n    var targetTable = new WeakMap();\n    var currentTargetTable = new WeakMap();\n    var relatedTargetTable = new WeakMap();\n    var eventPhaseTable = new WeakMap();\n    var stopPropagationTable = new WeakMap();\n    var stopImmediatePropagationTable = new WeakMap();\n    var eventHandlersTable = new WeakMap();\n    var eventPathTable = new WeakMap();\n    function isShadowRoot(node) {\n      return node instanceof wrappers.ShadowRoot;\n    }\n    function rootOfNode(node) {\n      return getTreeScope(node).root;\n    }\n    function getEventPath(node, event) {\n      var path = [];\n      var current = node;\n      path.push(current);\n      while (current) {\n        var destinationInsertionPoints = getDestinationInsertionPoints(current);\n        if (destinationInsertionPoints && destinationInsertionPoints.length > 0) {\n          for (var i = 0; i < destinationInsertionPoints.length; i++) {\n            var insertionPoint = destinationInsertionPoints[i];\n            if (isShadowInsertionPoint(insertionPoint)) {\n              var shadowRoot = rootOfNode(insertionPoint);\n              var olderShadowRoot = shadowRoot.olderShadowRoot;\n              if (olderShadowRoot) path.push(olderShadowRoot);\n            }\n            path.push(insertionPoint);\n          }\n          current = destinationInsertionPoints[destinationInsertionPoints.length - 1];\n        } else {\n          if (isShadowRoot(current)) {\n            if (inSameTree(node, current) && eventMustBeStopped(event)) {\n              break;\n            }\n            current = current.host;\n            path.push(current);\n          } else {\n            current = current.parentNode;\n            if (current) path.push(current);\n          }\n        }\n      }\n      return path;\n    }\n    function eventMustBeStopped(event) {\n      if (!event) return false;\n      switch (event.type) {\n       case \"abort\":\n       case \"error\":\n       case \"select\":\n       case \"change\":\n       case \"load\":\n       case \"reset\":\n       case \"resize\":\n       case \"scroll\":\n       case \"selectstart\":\n        return true;\n      }\n      return false;\n    }\n    function isShadowInsertionPoint(node) {\n      return node instanceof HTMLShadowElement;\n    }\n    function getDestinationInsertionPoints(node) {\n      return scope.getDestinationInsertionPoints(node);\n    }\n    function eventRetargetting(path, currentTarget) {\n      if (path.length === 0) return currentTarget;\n      if (currentTarget instanceof wrappers.Window) currentTarget = currentTarget.document;\n      var currentTargetTree = getTreeScope(currentTarget);\n      var originalTarget = path[0];\n      var originalTargetTree = getTreeScope(originalTarget);\n      var relativeTargetTree = lowestCommonInclusiveAncestor(currentTargetTree, originalTargetTree);\n      for (var i = 0; i < path.length; i++) {\n        var node = path[i];\n        if (getTreeScope(node) === relativeTargetTree) return node;\n      }\n      return path[path.length - 1];\n    }\n    function getTreeScopeAncestors(treeScope) {\n      var ancestors = [];\n      for (;treeScope; treeScope = treeScope.parent) {\n        ancestors.push(treeScope);\n      }\n      return ancestors;\n    }\n    function lowestCommonInclusiveAncestor(tsA, tsB) {\n      var ancestorsA = getTreeScopeAncestors(tsA);\n      var ancestorsB = getTreeScopeAncestors(tsB);\n      var result = null;\n      while (ancestorsA.length > 0 && ancestorsB.length > 0) {\n        var a = ancestorsA.pop();\n        var b = ancestorsB.pop();\n        if (a === b) result = a; else break;\n      }\n      return result;\n    }\n    function getTreeScopeRoot(ts) {\n      if (!ts.parent) return ts;\n      return getTreeScopeRoot(ts.parent);\n    }\n    function relatedTargetResolution(event, currentTarget, relatedTarget) {\n      if (currentTarget instanceof wrappers.Window) currentTarget = currentTarget.document;\n      var currentTargetTree = getTreeScope(currentTarget);\n      var relatedTargetTree = getTreeScope(relatedTarget);\n      var relatedTargetEventPath = getEventPath(relatedTarget, event);\n      var lowestCommonAncestorTree;\n      var lowestCommonAncestorTree = lowestCommonInclusiveAncestor(currentTargetTree, relatedTargetTree);\n      if (!lowestCommonAncestorTree) lowestCommonAncestorTree = relatedTargetTree.root;\n      for (var commonAncestorTree = lowestCommonAncestorTree; commonAncestorTree; commonAncestorTree = commonAncestorTree.parent) {\n        var adjustedRelatedTarget;\n        for (var i = 0; i < relatedTargetEventPath.length; i++) {\n          var node = relatedTargetEventPath[i];\n          if (getTreeScope(node) === commonAncestorTree) return node;\n        }\n      }\n      return null;\n    }\n    function inSameTree(a, b) {\n      return getTreeScope(a) === getTreeScope(b);\n    }\n    var NONE = 0;\n    var CAPTURING_PHASE = 1;\n    var AT_TARGET = 2;\n    var BUBBLING_PHASE = 3;\n    var pendingError;\n    function dispatchOriginalEvent(originalEvent) {\n      if (handledEventsTable.get(originalEvent)) return;\n      handledEventsTable.set(originalEvent, true);\n      dispatchEvent(wrap(originalEvent), wrap(originalEvent.target));\n      if (pendingError) {\n        var err = pendingError;\n        pendingError = null;\n        throw err;\n      }\n    }\n    function isLoadLikeEvent(event) {\n      switch (event.type) {\n       case \"load\":\n       case \"beforeunload\":\n       case \"unload\":\n        return true;\n      }\n      return false;\n    }\n    function dispatchEvent(event, originalWrapperTarget) {\n      if (currentlyDispatchingEvents.get(event)) throw new Error(\"InvalidStateError\");\n      currentlyDispatchingEvents.set(event, true);\n      scope.renderAllPending();\n      var eventPath;\n      var overrideTarget;\n      var win;\n      if (isLoadLikeEvent(event) && !event.bubbles) {\n        var doc = originalWrapperTarget;\n        if (doc instanceof wrappers.Document && (win = doc.defaultView)) {\n          overrideTarget = doc;\n          eventPath = [];\n        }\n      }\n      if (!eventPath) {\n        if (originalWrapperTarget instanceof wrappers.Window) {\n          win = originalWrapperTarget;\n          eventPath = [];\n        } else {\n          eventPath = getEventPath(originalWrapperTarget, event);\n          if (!isLoadLikeEvent(event)) {\n            var doc = eventPath[eventPath.length - 1];\n            if (doc instanceof wrappers.Document) win = doc.defaultView;\n          }\n        }\n      }\n      eventPathTable.set(event, eventPath);\n      if (dispatchCapturing(event, eventPath, win, overrideTarget)) {\n        if (dispatchAtTarget(event, eventPath, win, overrideTarget)) {\n          dispatchBubbling(event, eventPath, win, overrideTarget);\n        }\n      }\n      eventPhaseTable.set(event, NONE);\n      currentTargetTable.delete(event, null);\n      currentlyDispatchingEvents.delete(event);\n      return event.defaultPrevented;\n    }\n    function dispatchCapturing(event, eventPath, win, overrideTarget) {\n      var phase = CAPTURING_PHASE;\n      if (win) {\n        if (!invoke(win, event, phase, eventPath, overrideTarget)) return false;\n      }\n      for (var i = eventPath.length - 1; i > 0; i--) {\n        if (!invoke(eventPath[i], event, phase, eventPath, overrideTarget)) return false;\n      }\n      return true;\n    }\n    function dispatchAtTarget(event, eventPath, win, overrideTarget) {\n      var phase = AT_TARGET;\n      var currentTarget = eventPath[0] || win;\n      return invoke(currentTarget, event, phase, eventPath, overrideTarget);\n    }\n    function dispatchBubbling(event, eventPath, win, overrideTarget) {\n      var phase = BUBBLING_PHASE;\n      for (var i = 1; i < eventPath.length; i++) {\n        if (!invoke(eventPath[i], event, phase, eventPath, overrideTarget)) return;\n      }\n      if (win && eventPath.length > 0) {\n        invoke(win, event, phase, eventPath, overrideTarget);\n      }\n    }\n    function invoke(currentTarget, event, phase, eventPath, overrideTarget) {\n      var listeners = listenersTable.get(currentTarget);\n      if (!listeners) return true;\n      var target = overrideTarget || eventRetargetting(eventPath, currentTarget);\n      if (target === currentTarget) {\n        if (phase === CAPTURING_PHASE) return true;\n        if (phase === BUBBLING_PHASE) phase = AT_TARGET;\n      } else if (phase === BUBBLING_PHASE && !event.bubbles) {\n        return true;\n      }\n      if (\"relatedTarget\" in event) {\n        var originalEvent = unwrap(event);\n        var unwrappedRelatedTarget = originalEvent.relatedTarget;\n        if (unwrappedRelatedTarget) {\n          if (unwrappedRelatedTarget instanceof Object && unwrappedRelatedTarget.addEventListener) {\n            var relatedTarget = wrap(unwrappedRelatedTarget);\n            var adjusted = relatedTargetResolution(event, currentTarget, relatedTarget);\n            if (adjusted === target) return true;\n          } else {\n            adjusted = null;\n          }\n          relatedTargetTable.set(event, adjusted);\n        }\n      }\n      eventPhaseTable.set(event, phase);\n      var type = event.type;\n      var anyRemoved = false;\n      targetTable.set(event, target);\n      currentTargetTable.set(event, currentTarget);\n      listeners.depth++;\n      for (var i = 0, len = listeners.length; i < len; i++) {\n        var listener = listeners[i];\n        if (listener.removed) {\n          anyRemoved = true;\n          continue;\n        }\n        if (listener.type !== type || !listener.capture && phase === CAPTURING_PHASE || listener.capture && phase === BUBBLING_PHASE) {\n          continue;\n        }\n        try {\n          if (typeof listener.handler === \"function\") listener.handler.call(currentTarget, event); else listener.handler.handleEvent(event);\n          if (stopImmediatePropagationTable.get(event)) return false;\n        } catch (ex) {\n          if (!pendingError) pendingError = ex;\n        }\n      }\n      listeners.depth--;\n      if (anyRemoved && listeners.depth === 0) {\n        var copy = listeners.slice();\n        listeners.length = 0;\n        for (var i = 0; i < copy.length; i++) {\n          if (!copy[i].removed) listeners.push(copy[i]);\n        }\n      }\n      return !stopPropagationTable.get(event);\n    }\n    function Listener(type, handler, capture) {\n      this.type = type;\n      this.handler = handler;\n      this.capture = Boolean(capture);\n    }\n    Listener.prototype = {\n      equals: function(that) {\n        return this.handler === that.handler && this.type === that.type && this.capture === that.capture;\n      },\n      get removed() {\n        return this.handler === null;\n      },\n      remove: function() {\n        this.handler = null;\n      }\n    };\n    var OriginalEvent = window.Event;\n    OriginalEvent.prototype.polymerBlackList_ = {\n      returnValue: true,\n      keyLocation: true\n    };\n    function Event(type, options) {\n      if (type instanceof OriginalEvent) {\n        var impl = type;\n        if (!OriginalBeforeUnloadEvent && impl.type === \"beforeunload\" && !(this instanceof BeforeUnloadEvent)) {\n          return new BeforeUnloadEvent(impl);\n        }\n        setWrapper(impl, this);\n      } else {\n        return wrap(constructEvent(OriginalEvent, \"Event\", type, options));\n      }\n    }\n    Event.prototype = {\n      get target() {\n        return targetTable.get(this);\n      },\n      get currentTarget() {\n        return currentTargetTable.get(this);\n      },\n      get eventPhase() {\n        return eventPhaseTable.get(this);\n      },\n      get path() {\n        var eventPath = eventPathTable.get(this);\n        if (!eventPath) return [];\n        return eventPath.slice();\n      },\n      stopPropagation: function() {\n        stopPropagationTable.set(this, true);\n      },\n      stopImmediatePropagation: function() {\n        stopPropagationTable.set(this, true);\n        stopImmediatePropagationTable.set(this, true);\n      }\n    };\n    registerWrapper(OriginalEvent, Event, document.createEvent(\"Event\"));\n    function unwrapOptions(options) {\n      if (!options || !options.relatedTarget) return options;\n      return Object.create(options, {\n        relatedTarget: {\n          value: unwrap(options.relatedTarget)\n        }\n      });\n    }\n    function registerGenericEvent(name, SuperEvent, prototype) {\n      var OriginalEvent = window[name];\n      var GenericEvent = function(type, options) {\n        if (type instanceof OriginalEvent) setWrapper(type, this); else return wrap(constructEvent(OriginalEvent, name, type, options));\n      };\n      GenericEvent.prototype = Object.create(SuperEvent.prototype);\n      if (prototype) mixin(GenericEvent.prototype, prototype);\n      if (OriginalEvent) {\n        try {\n          registerWrapper(OriginalEvent, GenericEvent, new OriginalEvent(\"temp\"));\n        } catch (ex) {\n          registerWrapper(OriginalEvent, GenericEvent, document.createEvent(name));\n        }\n      }\n      return GenericEvent;\n    }\n    var UIEvent = registerGenericEvent(\"UIEvent\", Event);\n    var CustomEvent = registerGenericEvent(\"CustomEvent\", Event);\n    var relatedTargetProto = {\n      get relatedTarget() {\n        var relatedTarget = relatedTargetTable.get(this);\n        if (relatedTarget !== undefined) return relatedTarget;\n        return wrap(unwrap(this).relatedTarget);\n      }\n    };\n    function getInitFunction(name, relatedTargetIndex) {\n      return function() {\n        arguments[relatedTargetIndex] = unwrap(arguments[relatedTargetIndex]);\n        var impl = unwrap(this);\n        impl[name].apply(impl, arguments);\n      };\n    }\n    var mouseEventProto = mixin({\n      initMouseEvent: getInitFunction(\"initMouseEvent\", 14)\n    }, relatedTargetProto);\n    var focusEventProto = mixin({\n      initFocusEvent: getInitFunction(\"initFocusEvent\", 5)\n    }, relatedTargetProto);\n    var MouseEvent = registerGenericEvent(\"MouseEvent\", UIEvent, mouseEventProto);\n    var FocusEvent = registerGenericEvent(\"FocusEvent\", UIEvent, focusEventProto);\n    var defaultInitDicts = Object.create(null);\n    var supportsEventConstructors = function() {\n      try {\n        new window.FocusEvent(\"focus\");\n      } catch (ex) {\n        return false;\n      }\n      return true;\n    }();\n    function constructEvent(OriginalEvent, name, type, options) {\n      if (supportsEventConstructors) return new OriginalEvent(type, unwrapOptions(options));\n      var event = unwrap(document.createEvent(name));\n      var defaultDict = defaultInitDicts[name];\n      var args = [ type ];\n      Object.keys(defaultDict).forEach(function(key) {\n        var v = options != null && key in options ? options[key] : defaultDict[key];\n        if (key === \"relatedTarget\") v = unwrap(v);\n        args.push(v);\n      });\n      event[\"init\" + name].apply(event, args);\n      return event;\n    }\n    if (!supportsEventConstructors) {\n      var configureEventConstructor = function(name, initDict, superName) {\n        if (superName) {\n          var superDict = defaultInitDicts[superName];\n          initDict = mixin(mixin({}, superDict), initDict);\n        }\n        defaultInitDicts[name] = initDict;\n      };\n      configureEventConstructor(\"Event\", {\n        bubbles: false,\n        cancelable: false\n      });\n      configureEventConstructor(\"CustomEvent\", {\n        detail: null\n      }, \"Event\");\n      configureEventConstructor(\"UIEvent\", {\n        view: null,\n        detail: 0\n      }, \"Event\");\n      configureEventConstructor(\"MouseEvent\", {\n        screenX: 0,\n        screenY: 0,\n        clientX: 0,\n        clientY: 0,\n        ctrlKey: false,\n        altKey: false,\n        shiftKey: false,\n        metaKey: false,\n        button: 0,\n        relatedTarget: null\n      }, \"UIEvent\");\n      configureEventConstructor(\"FocusEvent\", {\n        relatedTarget: null\n      }, \"UIEvent\");\n    }\n    var OriginalBeforeUnloadEvent = window.BeforeUnloadEvent;\n    function BeforeUnloadEvent(impl) {\n      Event.call(this, impl);\n    }\n    BeforeUnloadEvent.prototype = Object.create(Event.prototype);\n    mixin(BeforeUnloadEvent.prototype, {\n      get returnValue() {\n        return unsafeUnwrap(this).returnValue;\n      },\n      set returnValue(v) {\n        unsafeUnwrap(this).returnValue = v;\n      }\n    });\n    if (OriginalBeforeUnloadEvent) registerWrapper(OriginalBeforeUnloadEvent, BeforeUnloadEvent);\n    function isValidListener(fun) {\n      if (typeof fun === \"function\") return true;\n      return fun && fun.handleEvent;\n    }\n    function isMutationEvent(type) {\n      switch (type) {\n       case \"DOMAttrModified\":\n       case \"DOMAttributeNameChanged\":\n       case \"DOMCharacterDataModified\":\n       case \"DOMElementNameChanged\":\n       case \"DOMNodeInserted\":\n       case \"DOMNodeInsertedIntoDocument\":\n       case \"DOMNodeRemoved\":\n       case \"DOMNodeRemovedFromDocument\":\n       case \"DOMSubtreeModified\":\n        return true;\n      }\n      return false;\n    }\n    var OriginalEventTarget = window.EventTarget;\n    function EventTarget(impl) {\n      setWrapper(impl, this);\n    }\n    var methodNames = [ \"addEventListener\", \"removeEventListener\", \"dispatchEvent\" ];\n    [ Node, Window ].forEach(function(constructor) {\n      var p = constructor.prototype;\n      methodNames.forEach(function(name) {\n        Object.defineProperty(p, name + \"_\", {\n          value: p[name]\n        });\n      });\n    });\n    function getTargetToListenAt(wrapper) {\n      if (wrapper instanceof wrappers.ShadowRoot) wrapper = wrapper.host;\n      return unwrap(wrapper);\n    }\n    EventTarget.prototype = {\n      addEventListener: function(type, fun, capture) {\n        if (!isValidListener(fun) || isMutationEvent(type)) return;\n        var listener = new Listener(type, fun, capture);\n        var listeners = listenersTable.get(this);\n        if (!listeners) {\n          listeners = [];\n          listeners.depth = 0;\n          listenersTable.set(this, listeners);\n        } else {\n          for (var i = 0; i < listeners.length; i++) {\n            if (listener.equals(listeners[i])) return;\n          }\n        }\n        listeners.push(listener);\n        var target = getTargetToListenAt(this);\n        target.addEventListener_(type, dispatchOriginalEvent, true);\n      },\n      removeEventListener: function(type, fun, capture) {\n        capture = Boolean(capture);\n        var listeners = listenersTable.get(this);\n        if (!listeners) return;\n        var count = 0, found = false;\n        for (var i = 0; i < listeners.length; i++) {\n          if (listeners[i].type === type && listeners[i].capture === capture) {\n            count++;\n            if (listeners[i].handler === fun) {\n              found = true;\n              listeners[i].remove();\n            }\n          }\n        }\n        if (found && count === 1) {\n          var target = getTargetToListenAt(this);\n          target.removeEventListener_(type, dispatchOriginalEvent, true);\n        }\n      },\n      dispatchEvent: function(event) {\n        var nativeEvent = unwrap(event);\n        var eventType = nativeEvent.type;\n        handledEventsTable.set(nativeEvent, false);\n        scope.renderAllPending();\n        var tempListener;\n        if (!hasListenerInAncestors(this, eventType)) {\n          tempListener = function() {};\n          this.addEventListener(eventType, tempListener, true);\n        }\n        try {\n          return unwrap(this).dispatchEvent_(nativeEvent);\n        } finally {\n          if (tempListener) this.removeEventListener(eventType, tempListener, true);\n        }\n      }\n    };\n    function hasListener(node, type) {\n      var listeners = listenersTable.get(node);\n      if (listeners) {\n        for (var i = 0; i < listeners.length; i++) {\n          if (!listeners[i].removed && listeners[i].type === type) return true;\n        }\n      }\n      return false;\n    }\n    function hasListenerInAncestors(target, type) {\n      for (var node = unwrap(target); node; node = node.parentNode) {\n        if (hasListener(wrap(node), type)) return true;\n      }\n      return false;\n    }\n    if (OriginalEventTarget) registerWrapper(OriginalEventTarget, EventTarget);\n    function wrapEventTargetMethods(constructors) {\n      forwardMethodsToWrapper(constructors, methodNames);\n    }\n    var originalElementFromPoint = document.elementFromPoint;\n    function elementFromPoint(self, document, x, y) {\n      scope.renderAllPending();\n      var element = wrap(originalElementFromPoint.call(unsafeUnwrap(document), x, y));\n      if (!element) return null;\n      var path = getEventPath(element, null);\n      var idx = path.lastIndexOf(self);\n      if (idx == -1) return null; else path = path.slice(0, idx);\n      return eventRetargetting(path, self);\n    }\n    function getEventHandlerGetter(name) {\n      return function() {\n        var inlineEventHandlers = eventHandlersTable.get(this);\n        return inlineEventHandlers && inlineEventHandlers[name] && inlineEventHandlers[name].value || null;\n      };\n    }\n    function getEventHandlerSetter(name) {\n      var eventType = name.slice(2);\n      return function(value) {\n        var inlineEventHandlers = eventHandlersTable.get(this);\n        if (!inlineEventHandlers) {\n          inlineEventHandlers = Object.create(null);\n          eventHandlersTable.set(this, inlineEventHandlers);\n        }\n        var old = inlineEventHandlers[name];\n        if (old) this.removeEventListener(eventType, old.wrapped, false);\n        if (typeof value === \"function\") {\n          var wrapped = function(e) {\n            var rv = value.call(this, e);\n            if (rv === false) e.preventDefault(); else if (name === \"onbeforeunload\" && typeof rv === \"string\") e.returnValue = rv;\n          };\n          this.addEventListener(eventType, wrapped, false);\n          inlineEventHandlers[name] = {\n            value: value,\n            wrapped: wrapped\n          };\n        }\n      };\n    }\n    scope.elementFromPoint = elementFromPoint;\n    scope.getEventHandlerGetter = getEventHandlerGetter;\n    scope.getEventHandlerSetter = getEventHandlerSetter;\n    scope.wrapEventTargetMethods = wrapEventTargetMethods;\n    scope.wrappers.BeforeUnloadEvent = BeforeUnloadEvent;\n    scope.wrappers.CustomEvent = CustomEvent;\n    scope.wrappers.Event = Event;\n    scope.wrappers.EventTarget = EventTarget;\n    scope.wrappers.FocusEvent = FocusEvent;\n    scope.wrappers.MouseEvent = MouseEvent;\n    scope.wrappers.UIEvent = UIEvent;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var UIEvent = scope.wrappers.UIEvent;\n    var mixin = scope.mixin;\n    var registerWrapper = scope.registerWrapper;\n    var setWrapper = scope.setWrapper;\n    var unsafeUnwrap = scope.unsafeUnwrap;\n    var wrap = scope.wrap;\n    var OriginalTouchEvent = window.TouchEvent;\n    if (!OriginalTouchEvent) return;\n    var nativeEvent;\n    try {\n      nativeEvent = document.createEvent(\"TouchEvent\");\n    } catch (ex) {\n      return;\n    }\n    var nonEnumDescriptor = {\n      enumerable: false\n    };\n    function nonEnum(obj, prop) {\n      Object.defineProperty(obj, prop, nonEnumDescriptor);\n    }\n    function Touch(impl) {\n      setWrapper(impl, this);\n    }\n    Touch.prototype = {\n      get target() {\n        return wrap(unsafeUnwrap(this).target);\n      }\n    };\n    var descr = {\n      configurable: true,\n      enumerable: true,\n      get: null\n    };\n    [ \"clientX\", \"clientY\", \"screenX\", \"screenY\", \"pageX\", \"pageY\", \"identifier\", \"webkitRadiusX\", \"webkitRadiusY\", \"webkitRotationAngle\", \"webkitForce\" ].forEach(function(name) {\n      descr.get = function() {\n        return unsafeUnwrap(this)[name];\n      };\n      Object.defineProperty(Touch.prototype, name, descr);\n    });\n    function TouchList() {\n      this.length = 0;\n      nonEnum(this, \"length\");\n    }\n    TouchList.prototype = {\n      item: function(index) {\n        return this[index];\n      }\n    };\n    function wrapTouchList(nativeTouchList) {\n      var list = new TouchList();\n      for (var i = 0; i < nativeTouchList.length; i++) {\n        list[i] = new Touch(nativeTouchList[i]);\n      }\n      list.length = i;\n      return list;\n    }\n    function TouchEvent(impl) {\n      UIEvent.call(this, impl);\n    }\n    TouchEvent.prototype = Object.create(UIEvent.prototype);\n    mixin(TouchEvent.prototype, {\n      get touches() {\n        return wrapTouchList(unsafeUnwrap(this).touches);\n      },\n      get targetTouches() {\n        return wrapTouchList(unsafeUnwrap(this).targetTouches);\n      },\n      get changedTouches() {\n        return wrapTouchList(unsafeUnwrap(this).changedTouches);\n      },\n      initTouchEvent: function() {\n        throw new Error(\"Not implemented\");\n      }\n    });\n    registerWrapper(OriginalTouchEvent, TouchEvent, nativeEvent);\n    scope.wrappers.Touch = Touch;\n    scope.wrappers.TouchEvent = TouchEvent;\n    scope.wrappers.TouchList = TouchList;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var unsafeUnwrap = scope.unsafeUnwrap;\n    var wrap = scope.wrap;\n    var nonEnumDescriptor = {\n      enumerable: false\n    };\n    function nonEnum(obj, prop) {\n      Object.defineProperty(obj, prop, nonEnumDescriptor);\n    }\n    function NodeList() {\n      this.length = 0;\n      nonEnum(this, \"length\");\n    }\n    NodeList.prototype = {\n      item: function(index) {\n        return this[index];\n      }\n    };\n    nonEnum(NodeList.prototype, \"item\");\n    function wrapNodeList(list) {\n      if (list == null) return list;\n      var wrapperList = new NodeList();\n      for (var i = 0, length = list.length; i < length; i++) {\n        wrapperList[i] = wrap(list[i]);\n      }\n      wrapperList.length = length;\n      return wrapperList;\n    }\n    function addWrapNodeListMethod(wrapperConstructor, name) {\n      wrapperConstructor.prototype[name] = function() {\n        return wrapNodeList(unsafeUnwrap(this)[name].apply(unsafeUnwrap(this), arguments));\n      };\n    }\n    scope.wrappers.NodeList = NodeList;\n    scope.addWrapNodeListMethod = addWrapNodeListMethod;\n    scope.wrapNodeList = wrapNodeList;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    scope.wrapHTMLCollection = scope.wrapNodeList;\n    scope.wrappers.HTMLCollection = scope.wrappers.NodeList;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var EventTarget = scope.wrappers.EventTarget;\n    var NodeList = scope.wrappers.NodeList;\n    var TreeScope = scope.TreeScope;\n    var assert = scope.assert;\n    var defineWrapGetter = scope.defineWrapGetter;\n    var enqueueMutation = scope.enqueueMutation;\n    var getTreeScope = scope.getTreeScope;\n    var isWrapper = scope.isWrapper;\n    var mixin = scope.mixin;\n    var registerTransientObservers = scope.registerTransientObservers;\n    var registerWrapper = scope.registerWrapper;\n    var setTreeScope = scope.setTreeScope;\n    var unsafeUnwrap = scope.unsafeUnwrap;\n    var unwrap = scope.unwrap;\n    var unwrapIfNeeded = scope.unwrapIfNeeded;\n    var wrap = scope.wrap;\n    var wrapIfNeeded = scope.wrapIfNeeded;\n    var wrappers = scope.wrappers;\n    function assertIsNodeWrapper(node) {\n      assert(node instanceof Node);\n    }\n    function createOneElementNodeList(node) {\n      var nodes = new NodeList();\n      nodes[0] = node;\n      nodes.length = 1;\n      return nodes;\n    }\n    var surpressMutations = false;\n    function enqueueRemovalForInsertedNodes(node, parent, nodes) {\n      enqueueMutation(parent, \"childList\", {\n        removedNodes: nodes,\n        previousSibling: node.previousSibling,\n        nextSibling: node.nextSibling\n      });\n    }\n    function enqueueRemovalForInsertedDocumentFragment(df, nodes) {\n      enqueueMutation(df, \"childList\", {\n        removedNodes: nodes\n      });\n    }\n    function collectNodes(node, parentNode, previousNode, nextNode) {\n      if (node instanceof DocumentFragment) {\n        var nodes = collectNodesForDocumentFragment(node);\n        surpressMutations = true;\n        for (var i = nodes.length - 1; i >= 0; i--) {\n          node.removeChild(nodes[i]);\n          nodes[i].parentNode_ = parentNode;\n        }\n        surpressMutations = false;\n        for (var i = 0; i < nodes.length; i++) {\n          nodes[i].previousSibling_ = nodes[i - 1] || previousNode;\n          nodes[i].nextSibling_ = nodes[i + 1] || nextNode;\n        }\n        if (previousNode) previousNode.nextSibling_ = nodes[0];\n        if (nextNode) nextNode.previousSibling_ = nodes[nodes.length - 1];\n        return nodes;\n      }\n      var nodes = createOneElementNodeList(node);\n      var oldParent = node.parentNode;\n      if (oldParent) {\n        oldParent.removeChild(node);\n      }\n      node.parentNode_ = parentNode;\n      node.previousSibling_ = previousNode;\n      node.nextSibling_ = nextNode;\n      if (previousNode) previousNode.nextSibling_ = node;\n      if (nextNode) nextNode.previousSibling_ = node;\n      return nodes;\n    }\n    function collectNodesNative(node) {\n      if (node instanceof DocumentFragment) return collectNodesForDocumentFragment(node);\n      var nodes = createOneElementNodeList(node);\n      var oldParent = node.parentNode;\n      if (oldParent) enqueueRemovalForInsertedNodes(node, oldParent, nodes);\n      return nodes;\n    }\n    function collectNodesForDocumentFragment(node) {\n      var nodes = new NodeList();\n      var i = 0;\n      for (var child = node.firstChild; child; child = child.nextSibling) {\n        nodes[i++] = child;\n      }\n      nodes.length = i;\n      enqueueRemovalForInsertedDocumentFragment(node, nodes);\n      return nodes;\n    }\n    function snapshotNodeList(nodeList) {\n      return nodeList;\n    }\n    function nodeWasAdded(node, treeScope) {\n      setTreeScope(node, treeScope);\n      node.nodeIsInserted_();\n    }\n    function nodesWereAdded(nodes, parent) {\n      var treeScope = getTreeScope(parent);\n      for (var i = 0; i < nodes.length; i++) {\n        nodeWasAdded(nodes[i], treeScope);\n      }\n    }\n    function nodeWasRemoved(node) {\n      setTreeScope(node, new TreeScope(node, null));\n    }\n    function nodesWereRemoved(nodes) {\n      for (var i = 0; i < nodes.length; i++) {\n        nodeWasRemoved(nodes[i]);\n      }\n    }\n    function ensureSameOwnerDocument(parent, child) {\n      var ownerDoc = parent.nodeType === Node.DOCUMENT_NODE ? parent : parent.ownerDocument;\n      if (ownerDoc !== child.ownerDocument) ownerDoc.adoptNode(child);\n    }\n    function adoptNodesIfNeeded(owner, nodes) {\n      if (!nodes.length) return;\n      var ownerDoc = owner.ownerDocument;\n      if (ownerDoc === nodes[0].ownerDocument) return;\n      for (var i = 0; i < nodes.length; i++) {\n        scope.adoptNodeNoRemove(nodes[i], ownerDoc);\n      }\n    }\n    function unwrapNodesForInsertion(owner, nodes) {\n      adoptNodesIfNeeded(owner, nodes);\n      var length = nodes.length;\n      if (length === 1) return unwrap(nodes[0]);\n      var df = unwrap(owner.ownerDocument.createDocumentFragment());\n      for (var i = 0; i < length; i++) {\n        df.appendChild(unwrap(nodes[i]));\n      }\n      return df;\n    }\n    function clearChildNodes(wrapper) {\n      if (wrapper.firstChild_ !== undefined) {\n        var child = wrapper.firstChild_;\n        while (child) {\n          var tmp = child;\n          child = child.nextSibling_;\n          tmp.parentNode_ = tmp.previousSibling_ = tmp.nextSibling_ = undefined;\n        }\n      }\n      wrapper.firstChild_ = wrapper.lastChild_ = undefined;\n    }\n    function removeAllChildNodes(wrapper) {\n      if (wrapper.invalidateShadowRenderer()) {\n        var childWrapper = wrapper.firstChild;\n        while (childWrapper) {\n          assert(childWrapper.parentNode === wrapper);\n          var nextSibling = childWrapper.nextSibling;\n          var childNode = unwrap(childWrapper);\n          var parentNode = childNode.parentNode;\n          if (parentNode) originalRemoveChild.call(parentNode, childNode);\n          childWrapper.previousSibling_ = childWrapper.nextSibling_ = childWrapper.parentNode_ = null;\n          childWrapper = nextSibling;\n        }\n        wrapper.firstChild_ = wrapper.lastChild_ = null;\n      } else {\n        var node = unwrap(wrapper);\n        var child = node.firstChild;\n        var nextSibling;\n        while (child) {\n          nextSibling = child.nextSibling;\n          originalRemoveChild.call(node, child);\n          child = nextSibling;\n        }\n      }\n    }\n    function invalidateParent(node) {\n      var p = node.parentNode;\n      return p && p.invalidateShadowRenderer();\n    }\n    function cleanupNodes(nodes) {\n      for (var i = 0, n; i < nodes.length; i++) {\n        n = nodes[i];\n        n.parentNode.removeChild(n);\n      }\n    }\n    var originalImportNode = document.importNode;\n    var originalCloneNode = window.Node.prototype.cloneNode;\n    function cloneNode(node, deep, opt_doc) {\n      var clone;\n      if (opt_doc) clone = wrap(originalImportNode.call(opt_doc, unsafeUnwrap(node), false)); else clone = wrap(originalCloneNode.call(unsafeUnwrap(node), false));\n      if (deep) {\n        for (var child = node.firstChild; child; child = child.nextSibling) {\n          clone.appendChild(cloneNode(child, true, opt_doc));\n        }\n        if (node instanceof wrappers.HTMLTemplateElement) {\n          var cloneContent = clone.content;\n          for (var child = node.content.firstChild; child; child = child.nextSibling) {\n            cloneContent.appendChild(cloneNode(child, true, opt_doc));\n          }\n        }\n      }\n      return clone;\n    }\n    function contains(self, child) {\n      if (!child || getTreeScope(self) !== getTreeScope(child)) return false;\n      for (var node = child; node; node = node.parentNode) {\n        if (node === self) return true;\n      }\n      return false;\n    }\n    var OriginalNode = window.Node;\n    function Node(original) {\n      assert(original instanceof OriginalNode);\n      EventTarget.call(this, original);\n      this.parentNode_ = undefined;\n      this.firstChild_ = undefined;\n      this.lastChild_ = undefined;\n      this.nextSibling_ = undefined;\n      this.previousSibling_ = undefined;\n      this.treeScope_ = undefined;\n    }\n    var OriginalDocumentFragment = window.DocumentFragment;\n    var originalAppendChild = OriginalNode.prototype.appendChild;\n    var originalCompareDocumentPosition = OriginalNode.prototype.compareDocumentPosition;\n    var originalIsEqualNode = OriginalNode.prototype.isEqualNode;\n    var originalInsertBefore = OriginalNode.prototype.insertBefore;\n    var originalRemoveChild = OriginalNode.prototype.removeChild;\n    var originalReplaceChild = OriginalNode.prototype.replaceChild;\n    var isIe = /Trident|Edge/.test(navigator.userAgent);\n    var removeChildOriginalHelper = isIe ? function(parent, child) {\n      try {\n        originalRemoveChild.call(parent, child);\n      } catch (ex) {\n        if (!(parent instanceof OriginalDocumentFragment)) throw ex;\n      }\n    } : function(parent, child) {\n      originalRemoveChild.call(parent, child);\n    };\n    Node.prototype = Object.create(EventTarget.prototype);\n    mixin(Node.prototype, {\n      appendChild: function(childWrapper) {\n        return this.insertBefore(childWrapper, null);\n      },\n      insertBefore: function(childWrapper, refWrapper) {\n        assertIsNodeWrapper(childWrapper);\n        var refNode;\n        if (refWrapper) {\n          if (isWrapper(refWrapper)) {\n            refNode = unwrap(refWrapper);\n          } else {\n            refNode = refWrapper;\n            refWrapper = wrap(refNode);\n          }\n        } else {\n          refWrapper = null;\n          refNode = null;\n        }\n        refWrapper && assert(refWrapper.parentNode === this);\n        var nodes;\n        var previousNode = refWrapper ? refWrapper.previousSibling : this.lastChild;\n        var useNative = !this.invalidateShadowRenderer() && !invalidateParent(childWrapper);\n        if (useNative) nodes = collectNodesNative(childWrapper); else nodes = collectNodes(childWrapper, this, previousNode, refWrapper);\n        if (useNative) {\n          ensureSameOwnerDocument(this, childWrapper);\n          clearChildNodes(this);\n          originalInsertBefore.call(unsafeUnwrap(this), unwrap(childWrapper), refNode);\n        } else {\n          if (!previousNode) this.firstChild_ = nodes[0];\n          if (!refWrapper) {\n            this.lastChild_ = nodes[nodes.length - 1];\n            if (this.firstChild_ === undefined) this.firstChild_ = this.firstChild;\n          }\n          var parentNode = refNode ? refNode.parentNode : unsafeUnwrap(this);\n          if (parentNode) {\n            originalInsertBefore.call(parentNode, unwrapNodesForInsertion(this, nodes), refNode);\n          } else {\n            adoptNodesIfNeeded(this, nodes);\n          }\n        }\n        enqueueMutation(this, \"childList\", {\n          addedNodes: nodes,\n          nextSibling: refWrapper,\n          previousSibling: previousNode\n        });\n        nodesWereAdded(nodes, this);\n        return childWrapper;\n      },\n      removeChild: function(childWrapper) {\n        assertIsNodeWrapper(childWrapper);\n        if (childWrapper.parentNode !== this) {\n          var found = false;\n          var childNodes = this.childNodes;\n          for (var ieChild = this.firstChild; ieChild; ieChild = ieChild.nextSibling) {\n            if (ieChild === childWrapper) {\n              found = true;\n              break;\n            }\n          }\n          if (!found) {\n            throw new Error(\"NotFoundError\");\n          }\n        }\n        var childNode = unwrap(childWrapper);\n        var childWrapperNextSibling = childWrapper.nextSibling;\n        var childWrapperPreviousSibling = childWrapper.previousSibling;\n        if (this.invalidateShadowRenderer()) {\n          var thisFirstChild = this.firstChild;\n          var thisLastChild = this.lastChild;\n          var parentNode = childNode.parentNode;\n          if (parentNode) removeChildOriginalHelper(parentNode, childNode);\n          if (thisFirstChild === childWrapper) this.firstChild_ = childWrapperNextSibling;\n          if (thisLastChild === childWrapper) this.lastChild_ = childWrapperPreviousSibling;\n          if (childWrapperPreviousSibling) childWrapperPreviousSibling.nextSibling_ = childWrapperNextSibling;\n          if (childWrapperNextSibling) {\n            childWrapperNextSibling.previousSibling_ = childWrapperPreviousSibling;\n          }\n          childWrapper.previousSibling_ = childWrapper.nextSibling_ = childWrapper.parentNode_ = undefined;\n        } else {\n          clearChildNodes(this);\n          removeChildOriginalHelper(unsafeUnwrap(this), childNode);\n        }\n        if (!surpressMutations) {\n          enqueueMutation(this, \"childList\", {\n            removedNodes: createOneElementNodeList(childWrapper),\n            nextSibling: childWrapperNextSibling,\n            previousSibling: childWrapperPreviousSibling\n          });\n        }\n        registerTransientObservers(this, childWrapper);\n        return childWrapper;\n      },\n      replaceChild: function(newChildWrapper, oldChildWrapper) {\n        assertIsNodeWrapper(newChildWrapper);\n        var oldChildNode;\n        if (isWrapper(oldChildWrapper)) {\n          oldChildNode = unwrap(oldChildWrapper);\n        } else {\n          oldChildNode = oldChildWrapper;\n          oldChildWrapper = wrap(oldChildNode);\n        }\n        if (oldChildWrapper.parentNode !== this) {\n          throw new Error(\"NotFoundError\");\n        }\n        var nextNode = oldChildWrapper.nextSibling;\n        var previousNode = oldChildWrapper.previousSibling;\n        var nodes;\n        var useNative = !this.invalidateShadowRenderer() && !invalidateParent(newChildWrapper);\n        if (useNative) {\n          nodes = collectNodesNative(newChildWrapper);\n        } else {\n          if (nextNode === newChildWrapper) nextNode = newChildWrapper.nextSibling;\n          nodes = collectNodes(newChildWrapper, this, previousNode, nextNode);\n        }\n        if (!useNative) {\n          if (this.firstChild === oldChildWrapper) this.firstChild_ = nodes[0];\n          if (this.lastChild === oldChildWrapper) this.lastChild_ = nodes[nodes.length - 1];\n          oldChildWrapper.previousSibling_ = oldChildWrapper.nextSibling_ = oldChildWrapper.parentNode_ = undefined;\n          if (oldChildNode.parentNode) {\n            originalReplaceChild.call(oldChildNode.parentNode, unwrapNodesForInsertion(this, nodes), oldChildNode);\n          }\n        } else {\n          ensureSameOwnerDocument(this, newChildWrapper);\n          clearChildNodes(this);\n          originalReplaceChild.call(unsafeUnwrap(this), unwrap(newChildWrapper), oldChildNode);\n        }\n        enqueueMutation(this, \"childList\", {\n          addedNodes: nodes,\n          removedNodes: createOneElementNodeList(oldChildWrapper),\n          nextSibling: nextNode,\n          previousSibling: previousNode\n        });\n        nodeWasRemoved(oldChildWrapper);\n        nodesWereAdded(nodes, this);\n        return oldChildWrapper;\n      },\n      nodeIsInserted_: function() {\n        for (var child = this.firstChild; child; child = child.nextSibling) {\n          child.nodeIsInserted_();\n        }\n      },\n      hasChildNodes: function() {\n        return this.firstChild !== null;\n      },\n      get parentNode() {\n        return this.parentNode_ !== undefined ? this.parentNode_ : wrap(unsafeUnwrap(this).parentNode);\n      },\n      get firstChild() {\n        return this.firstChild_ !== undefined ? this.firstChild_ : wrap(unsafeUnwrap(this).firstChild);\n      },\n      get lastChild() {\n        return this.lastChild_ !== undefined ? this.lastChild_ : wrap(unsafeUnwrap(this).lastChild);\n      },\n      get nextSibling() {\n        return this.nextSibling_ !== undefined ? this.nextSibling_ : wrap(unsafeUnwrap(this).nextSibling);\n      },\n      get previousSibling() {\n        return this.previousSibling_ !== undefined ? this.previousSibling_ : wrap(unsafeUnwrap(this).previousSibling);\n      },\n      get parentElement() {\n        var p = this.parentNode;\n        while (p && p.nodeType !== Node.ELEMENT_NODE) {\n          p = p.parentNode;\n        }\n        return p;\n      },\n      get textContent() {\n        var s = \"\";\n        for (var child = this.firstChild; child; child = child.nextSibling) {\n          if (child.nodeType != Node.COMMENT_NODE) {\n            s += child.textContent;\n          }\n        }\n        return s;\n      },\n      set textContent(textContent) {\n        if (textContent == null) textContent = \"\";\n        var removedNodes = snapshotNodeList(this.childNodes);\n        if (this.invalidateShadowRenderer()) {\n          removeAllChildNodes(this);\n          if (textContent !== \"\") {\n            var textNode = unsafeUnwrap(this).ownerDocument.createTextNode(textContent);\n            this.appendChild(textNode);\n          }\n        } else {\n          clearChildNodes(this);\n          unsafeUnwrap(this).textContent = textContent;\n        }\n        var addedNodes = snapshotNodeList(this.childNodes);\n        enqueueMutation(this, \"childList\", {\n          addedNodes: addedNodes,\n          removedNodes: removedNodes\n        });\n        nodesWereRemoved(removedNodes);\n        nodesWereAdded(addedNodes, this);\n      },\n      get childNodes() {\n        var wrapperList = new NodeList();\n        var i = 0;\n        for (var child = this.firstChild; child; child = child.nextSibling) {\n          wrapperList[i++] = child;\n        }\n        wrapperList.length = i;\n        return wrapperList;\n      },\n      cloneNode: function(deep) {\n        return cloneNode(this, deep);\n      },\n      contains: function(child) {\n        return contains(this, wrapIfNeeded(child));\n      },\n      compareDocumentPosition: function(otherNode) {\n        return originalCompareDocumentPosition.call(unsafeUnwrap(this), unwrapIfNeeded(otherNode));\n      },\n      isEqualNode: function(otherNode) {\n        return originalIsEqualNode.call(unsafeUnwrap(this), unwrapIfNeeded(otherNode));\n      },\n      normalize: function() {\n        var nodes = snapshotNodeList(this.childNodes);\n        var remNodes = [];\n        var s = \"\";\n        var modNode;\n        for (var i = 0, n; i < nodes.length; i++) {\n          n = nodes[i];\n          if (n.nodeType === Node.TEXT_NODE) {\n            if (!modNode && !n.data.length) this.removeChild(n); else if (!modNode) modNode = n; else {\n              s += n.data;\n              remNodes.push(n);\n            }\n          } else {\n            if (modNode && remNodes.length) {\n              modNode.data += s;\n              cleanupNodes(remNodes);\n            }\n            remNodes = [];\n            s = \"\";\n            modNode = null;\n            if (n.childNodes.length) n.normalize();\n          }\n        }\n        if (modNode && remNodes.length) {\n          modNode.data += s;\n          cleanupNodes(remNodes);\n        }\n      }\n    });\n    defineWrapGetter(Node, \"ownerDocument\");\n    registerWrapper(OriginalNode, Node, document.createDocumentFragment());\n    delete Node.prototype.querySelector;\n    delete Node.prototype.querySelectorAll;\n    Node.prototype = mixin(Object.create(EventTarget.prototype), Node.prototype);\n    scope.cloneNode = cloneNode;\n    scope.nodeWasAdded = nodeWasAdded;\n    scope.nodeWasRemoved = nodeWasRemoved;\n    scope.nodesWereAdded = nodesWereAdded;\n    scope.nodesWereRemoved = nodesWereRemoved;\n    scope.originalInsertBefore = originalInsertBefore;\n    scope.originalRemoveChild = originalRemoveChild;\n    scope.snapshotNodeList = snapshotNodeList;\n    scope.wrappers.Node = Node;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var HTMLCollection = scope.wrappers.HTMLCollection;\n    var NodeList = scope.wrappers.NodeList;\n    var getTreeScope = scope.getTreeScope;\n    var unsafeUnwrap = scope.unsafeUnwrap;\n    var wrap = scope.wrap;\n    var originalDocumentQuerySelector = document.querySelector;\n    var originalElementQuerySelector = document.documentElement.querySelector;\n    var originalDocumentQuerySelectorAll = document.querySelectorAll;\n    var originalElementQuerySelectorAll = document.documentElement.querySelectorAll;\n    var originalDocumentGetElementsByTagName = document.getElementsByTagName;\n    var originalElementGetElementsByTagName = document.documentElement.getElementsByTagName;\n    var originalDocumentGetElementsByTagNameNS = document.getElementsByTagNameNS;\n    var originalElementGetElementsByTagNameNS = document.documentElement.getElementsByTagNameNS;\n    var OriginalElement = window.Element;\n    var OriginalDocument = window.HTMLDocument || window.Document;\n    function filterNodeList(list, index, result, deep) {\n      var wrappedItem = null;\n      var root = null;\n      for (var i = 0, length = list.length; i < length; i++) {\n        wrappedItem = wrap(list[i]);\n        if (!deep && (root = getTreeScope(wrappedItem).root)) {\n          if (root instanceof scope.wrappers.ShadowRoot) {\n            continue;\n          }\n        }\n        result[index++] = wrappedItem;\n      }\n      return index;\n    }\n    function shimSelector(selector) {\n      return String(selector).replace(/\\/deep\\/|::shadow|>>>/g, \" \");\n    }\n    function shimMatchesSelector(selector) {\n      return String(selector).replace(/:host\\(([^\\s]+)\\)/g, \"$1\").replace(/([^\\s]):host/g, \"$1\").replace(\":host\", \"*\").replace(/\\^|\\/shadow\\/|\\/shadow-deep\\/|::shadow|\\/deep\\/|::content|>>>/g, \" \");\n    }\n    function findOne(node, selector) {\n      var m, el = node.firstElementChild;\n      while (el) {\n        if (el.matches(selector)) return el;\n        m = findOne(el, selector);\n        if (m) return m;\n        el = el.nextElementSibling;\n      }\n      return null;\n    }\n    function matchesSelector(el, selector) {\n      return el.matches(selector);\n    }\n    var XHTML_NS = \"http://www.w3.org/1999/xhtml\";\n    function matchesTagName(el, localName, localNameLowerCase) {\n      var ln = el.localName;\n      return ln === localName || ln === localNameLowerCase && el.namespaceURI === XHTML_NS;\n    }\n    function matchesEveryThing() {\n      return true;\n    }\n    function matchesLocalNameOnly(el, ns, localName) {\n      return el.localName === localName;\n    }\n    function matchesNameSpace(el, ns) {\n      return el.namespaceURI === ns;\n    }\n    function matchesLocalNameNS(el, ns, localName) {\n      return el.namespaceURI === ns && el.localName === localName;\n    }\n    function findElements(node, index, result, p, arg0, arg1) {\n      var el = node.firstElementChild;\n      while (el) {\n        if (p(el, arg0, arg1)) result[index++] = el;\n        index = findElements(el, index, result, p, arg0, arg1);\n        el = el.nextElementSibling;\n      }\n      return index;\n    }\n    function querySelectorAllFiltered(p, index, result, selector, deep) {\n      var target = unsafeUnwrap(this);\n      var list;\n      var root = getTreeScope(this).root;\n      if (root instanceof scope.wrappers.ShadowRoot) {\n        return findElements(this, index, result, p, selector, null);\n      } else if (target instanceof OriginalElement) {\n        list = originalElementQuerySelectorAll.call(target, selector);\n      } else if (target instanceof OriginalDocument) {\n        list = originalDocumentQuerySelectorAll.call(target, selector);\n      } else {\n        return findElements(this, index, result, p, selector, null);\n      }\n      return filterNodeList(list, index, result, deep);\n    }\n    var SelectorsInterface = {\n      querySelector: function(selector) {\n        var shimmed = shimSelector(selector);\n        var deep = shimmed !== selector;\n        selector = shimmed;\n        var target = unsafeUnwrap(this);\n        var wrappedItem;\n        var root = getTreeScope(this).root;\n        if (root instanceof scope.wrappers.ShadowRoot) {\n          return findOne(this, selector);\n        } else if (target instanceof OriginalElement) {\n          wrappedItem = wrap(originalElementQuerySelector.call(target, selector));\n        } else if (target instanceof OriginalDocument) {\n          wrappedItem = wrap(originalDocumentQuerySelector.call(target, selector));\n        } else {\n          return findOne(this, selector);\n        }\n        if (!wrappedItem) {\n          return wrappedItem;\n        } else if (!deep && (root = getTreeScope(wrappedItem).root)) {\n          if (root instanceof scope.wrappers.ShadowRoot) {\n            return findOne(this, selector);\n          }\n        }\n        return wrappedItem;\n      },\n      querySelectorAll: function(selector) {\n        var shimmed = shimSelector(selector);\n        var deep = shimmed !== selector;\n        selector = shimmed;\n        var result = new NodeList();\n        result.length = querySelectorAllFiltered.call(this, matchesSelector, 0, result, selector, deep);\n        return result;\n      }\n    };\n    var MatchesInterface = {\n      matches: function(selector) {\n        selector = shimMatchesSelector(selector);\n        return scope.originalMatches.call(unsafeUnwrap(this), selector);\n      }\n    };\n    function getElementsByTagNameFiltered(p, index, result, localName, lowercase) {\n      var target = unsafeUnwrap(this);\n      var list;\n      var root = getTreeScope(this).root;\n      if (root instanceof scope.wrappers.ShadowRoot) {\n        return findElements(this, index, result, p, localName, lowercase);\n      } else if (target instanceof OriginalElement) {\n        list = originalElementGetElementsByTagName.call(target, localName, lowercase);\n      } else if (target instanceof OriginalDocument) {\n        list = originalDocumentGetElementsByTagName.call(target, localName, lowercase);\n      } else {\n        return findElements(this, index, result, p, localName, lowercase);\n      }\n      return filterNodeList(list, index, result, false);\n    }\n    function getElementsByTagNameNSFiltered(p, index, result, ns, localName) {\n      var target = unsafeUnwrap(this);\n      var list;\n      var root = getTreeScope(this).root;\n      if (root instanceof scope.wrappers.ShadowRoot) {\n        return findElements(this, index, result, p, ns, localName);\n      } else if (target instanceof OriginalElement) {\n        list = originalElementGetElementsByTagNameNS.call(target, ns, localName);\n      } else if (target instanceof OriginalDocument) {\n        list = originalDocumentGetElementsByTagNameNS.call(target, ns, localName);\n      } else {\n        return findElements(this, index, result, p, ns, localName);\n      }\n      return filterNodeList(list, index, result, false);\n    }\n    var GetElementsByInterface = {\n      getElementsByTagName: function(localName) {\n        var result = new HTMLCollection();\n        var match = localName === \"*\" ? matchesEveryThing : matchesTagName;\n        result.length = getElementsByTagNameFiltered.call(this, match, 0, result, localName, localName.toLowerCase());\n        return result;\n      },\n      getElementsByClassName: function(className) {\n        return this.querySelectorAll(\".\" + className);\n      },\n      getElementsByTagNameNS: function(ns, localName) {\n        var result = new HTMLCollection();\n        var match = null;\n        if (ns === \"*\") {\n          match = localName === \"*\" ? matchesEveryThing : matchesLocalNameOnly;\n        } else {\n          match = localName === \"*\" ? matchesNameSpace : matchesLocalNameNS;\n        }\n        result.length = getElementsByTagNameNSFiltered.call(this, match, 0, result, ns || null, localName);\n        return result;\n      }\n    };\n    scope.GetElementsByInterface = GetElementsByInterface;\n    scope.SelectorsInterface = SelectorsInterface;\n    scope.MatchesInterface = MatchesInterface;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var NodeList = scope.wrappers.NodeList;\n    function forwardElement(node) {\n      while (node && node.nodeType !== Node.ELEMENT_NODE) {\n        node = node.nextSibling;\n      }\n      return node;\n    }\n    function backwardsElement(node) {\n      while (node && node.nodeType !== Node.ELEMENT_NODE) {\n        node = node.previousSibling;\n      }\n      return node;\n    }\n    var ParentNodeInterface = {\n      get firstElementChild() {\n        return forwardElement(this.firstChild);\n      },\n      get lastElementChild() {\n        return backwardsElement(this.lastChild);\n      },\n      get childElementCount() {\n        var count = 0;\n        for (var child = this.firstElementChild; child; child = child.nextElementSibling) {\n          count++;\n        }\n        return count;\n      },\n      get children() {\n        var wrapperList = new NodeList();\n        var i = 0;\n        for (var child = this.firstElementChild; child; child = child.nextElementSibling) {\n          wrapperList[i++] = child;\n        }\n        wrapperList.length = i;\n        return wrapperList;\n      },\n      remove: function() {\n        var p = this.parentNode;\n        if (p) p.removeChild(this);\n      }\n    };\n    var ChildNodeInterface = {\n      get nextElementSibling() {\n        return forwardElement(this.nextSibling);\n      },\n      get previousElementSibling() {\n        return backwardsElement(this.previousSibling);\n      }\n    };\n    var NonElementParentNodeInterface = {\n      getElementById: function(id) {\n        if (/[ \\t\\n\\r\\f]/.test(id)) return null;\n        return this.querySelector('[id=\"' + id + '\"]');\n      }\n    };\n    scope.ChildNodeInterface = ChildNodeInterface;\n    scope.NonElementParentNodeInterface = NonElementParentNodeInterface;\n    scope.ParentNodeInterface = ParentNodeInterface;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var ChildNodeInterface = scope.ChildNodeInterface;\n    var Node = scope.wrappers.Node;\n    var enqueueMutation = scope.enqueueMutation;\n    var mixin = scope.mixin;\n    var registerWrapper = scope.registerWrapper;\n    var unsafeUnwrap = scope.unsafeUnwrap;\n    var OriginalCharacterData = window.CharacterData;\n    function CharacterData(node) {\n      Node.call(this, node);\n    }\n    CharacterData.prototype = Object.create(Node.prototype);\n    mixin(CharacterData.prototype, {\n      get nodeValue() {\n        return this.data;\n      },\n      set nodeValue(data) {\n        this.data = data;\n      },\n      get textContent() {\n        return this.data;\n      },\n      set textContent(value) {\n        this.data = value;\n      },\n      get data() {\n        return unsafeUnwrap(this).data;\n      },\n      set data(value) {\n        var oldValue = unsafeUnwrap(this).data;\n        enqueueMutation(this, \"characterData\", {\n          oldValue: oldValue\n        });\n        unsafeUnwrap(this).data = value;\n      }\n    });\n    mixin(CharacterData.prototype, ChildNodeInterface);\n    registerWrapper(OriginalCharacterData, CharacterData, document.createTextNode(\"\"));\n    scope.wrappers.CharacterData = CharacterData;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var CharacterData = scope.wrappers.CharacterData;\n    var enqueueMutation = scope.enqueueMutation;\n    var mixin = scope.mixin;\n    var registerWrapper = scope.registerWrapper;\n    function toUInt32(x) {\n      return x >>> 0;\n    }\n    var OriginalText = window.Text;\n    function Text(node) {\n      CharacterData.call(this, node);\n    }\n    Text.prototype = Object.create(CharacterData.prototype);\n    mixin(Text.prototype, {\n      splitText: function(offset) {\n        offset = toUInt32(offset);\n        var s = this.data;\n        if (offset > s.length) throw new Error(\"IndexSizeError\");\n        var head = s.slice(0, offset);\n        var tail = s.slice(offset);\n        this.data = head;\n        var newTextNode = this.ownerDocument.createTextNode(tail);\n        if (this.parentNode) this.parentNode.insertBefore(newTextNode, this.nextSibling);\n        return newTextNode;\n      }\n    });\n    registerWrapper(OriginalText, Text, document.createTextNode(\"\"));\n    scope.wrappers.Text = Text;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    if (!window.DOMTokenList) {\n      console.warn(\"Missing DOMTokenList prototype, please include a \" + \"compatible classList polyfill such as http://goo.gl/uTcepH.\");\n      return;\n    }\n    var unsafeUnwrap = scope.unsafeUnwrap;\n    var enqueueMutation = scope.enqueueMutation;\n    function getClass(el) {\n      return unsafeUnwrap(el).getAttribute(\"class\");\n    }\n    function enqueueClassAttributeChange(el, oldValue) {\n      enqueueMutation(el, \"attributes\", {\n        name: \"class\",\n        namespace: null,\n        oldValue: oldValue\n      });\n    }\n    function invalidateClass(el) {\n      scope.invalidateRendererBasedOnAttribute(el, \"class\");\n    }\n    function changeClass(tokenList, method, args) {\n      var ownerElement = tokenList.ownerElement_;\n      if (ownerElement == null) {\n        return method.apply(tokenList, args);\n      }\n      var oldValue = getClass(ownerElement);\n      var retv = method.apply(tokenList, args);\n      if (getClass(ownerElement) !== oldValue) {\n        enqueueClassAttributeChange(ownerElement, oldValue);\n        invalidateClass(ownerElement);\n      }\n      return retv;\n    }\n    var oldAdd = DOMTokenList.prototype.add;\n    DOMTokenList.prototype.add = function() {\n      changeClass(this, oldAdd, arguments);\n    };\n    var oldRemove = DOMTokenList.prototype.remove;\n    DOMTokenList.prototype.remove = function() {\n      changeClass(this, oldRemove, arguments);\n    };\n    var oldToggle = DOMTokenList.prototype.toggle;\n    DOMTokenList.prototype.toggle = function() {\n      return changeClass(this, oldToggle, arguments);\n    };\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var ChildNodeInterface = scope.ChildNodeInterface;\n    var GetElementsByInterface = scope.GetElementsByInterface;\n    var Node = scope.wrappers.Node;\n    var ParentNodeInterface = scope.ParentNodeInterface;\n    var SelectorsInterface = scope.SelectorsInterface;\n    var MatchesInterface = scope.MatchesInterface;\n    var addWrapNodeListMethod = scope.addWrapNodeListMethod;\n    var enqueueMutation = scope.enqueueMutation;\n    var mixin = scope.mixin;\n    var oneOf = scope.oneOf;\n    var registerWrapper = scope.registerWrapper;\n    var unsafeUnwrap = scope.unsafeUnwrap;\n    var wrappers = scope.wrappers;\n    var OriginalElement = window.Element;\n    var matchesNames = [ \"matches\", \"mozMatchesSelector\", \"msMatchesSelector\", \"webkitMatchesSelector\" ].filter(function(name) {\n      return OriginalElement.prototype[name];\n    });\n    var matchesName = matchesNames[0];\n    var originalMatches = OriginalElement.prototype[matchesName];\n    function invalidateRendererBasedOnAttribute(element, name) {\n      var p = element.parentNode;\n      if (!p || !p.shadowRoot) return;\n      var renderer = scope.getRendererForHost(p);\n      if (renderer.dependsOnAttribute(name)) renderer.invalidate();\n    }\n    function enqueAttributeChange(element, name, oldValue) {\n      enqueueMutation(element, \"attributes\", {\n        name: name,\n        namespace: null,\n        oldValue: oldValue\n      });\n    }\n    var classListTable = new WeakMap();\n    function Element(node) {\n      Node.call(this, node);\n    }\n    Element.prototype = Object.create(Node.prototype);\n    mixin(Element.prototype, {\n      createShadowRoot: function() {\n        var newShadowRoot = new wrappers.ShadowRoot(this);\n        unsafeUnwrap(this).polymerShadowRoot_ = newShadowRoot;\n        var renderer = scope.getRendererForHost(this);\n        renderer.invalidate();\n        return newShadowRoot;\n      },\n      get shadowRoot() {\n        return unsafeUnwrap(this).polymerShadowRoot_ || null;\n      },\n      setAttribute: function(name, value) {\n        var oldValue = unsafeUnwrap(this).getAttribute(name);\n        unsafeUnwrap(this).setAttribute(name, value);\n        enqueAttributeChange(this, name, oldValue);\n        invalidateRendererBasedOnAttribute(this, name);\n      },\n      removeAttribute: function(name) {\n        var oldValue = unsafeUnwrap(this).getAttribute(name);\n        unsafeUnwrap(this).removeAttribute(name);\n        enqueAttributeChange(this, name, oldValue);\n        invalidateRendererBasedOnAttribute(this, name);\n      },\n      get classList() {\n        var list = classListTable.get(this);\n        if (!list) {\n          list = unsafeUnwrap(this).classList;\n          if (!list) return;\n          list.ownerElement_ = this;\n          classListTable.set(this, list);\n        }\n        return list;\n      },\n      get className() {\n        return unsafeUnwrap(this).className;\n      },\n      set className(v) {\n        this.setAttribute(\"class\", v);\n      },\n      get id() {\n        return unsafeUnwrap(this).id;\n      },\n      set id(v) {\n        this.setAttribute(\"id\", v);\n      }\n    });\n    matchesNames.forEach(function(name) {\n      if (name !== \"matches\") {\n        Element.prototype[name] = function(selector) {\n          return this.matches(selector);\n        };\n      }\n    });\n    if (OriginalElement.prototype.webkitCreateShadowRoot) {\n      Element.prototype.webkitCreateShadowRoot = Element.prototype.createShadowRoot;\n    }\n    mixin(Element.prototype, ChildNodeInterface);\n    mixin(Element.prototype, GetElementsByInterface);\n    mixin(Element.prototype, ParentNodeInterface);\n    mixin(Element.prototype, SelectorsInterface);\n    mixin(Element.prototype, MatchesInterface);\n    registerWrapper(OriginalElement, Element, document.createElementNS(null, \"x\"));\n    scope.invalidateRendererBasedOnAttribute = invalidateRendererBasedOnAttribute;\n    scope.matchesNames = matchesNames;\n    scope.originalMatches = originalMatches;\n    scope.wrappers.Element = Element;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var Element = scope.wrappers.Element;\n    var defineGetter = scope.defineGetter;\n    var enqueueMutation = scope.enqueueMutation;\n    var mixin = scope.mixin;\n    var nodesWereAdded = scope.nodesWereAdded;\n    var nodesWereRemoved = scope.nodesWereRemoved;\n    var registerWrapper = scope.registerWrapper;\n    var snapshotNodeList = scope.snapshotNodeList;\n    var unsafeUnwrap = scope.unsafeUnwrap;\n    var unwrap = scope.unwrap;\n    var wrap = scope.wrap;\n    var wrappers = scope.wrappers;\n    var escapeAttrRegExp = /[&\\u00A0\"]/g;\n    var escapeDataRegExp = /[&\\u00A0<>]/g;\n    function escapeReplace(c) {\n      switch (c) {\n       case \"&\":\n        return \"&amp;\";\n\n       case \"<\":\n        return \"&lt;\";\n\n       case \">\":\n        return \"&gt;\";\n\n       case '\"':\n        return \"&quot;\";\n\n       case \" \":\n        return \"&nbsp;\";\n      }\n    }\n    function escapeAttr(s) {\n      return s.replace(escapeAttrRegExp, escapeReplace);\n    }\n    function escapeData(s) {\n      return s.replace(escapeDataRegExp, escapeReplace);\n    }\n    function makeSet(arr) {\n      var set = {};\n      for (var i = 0; i < arr.length; i++) {\n        set[arr[i]] = true;\n      }\n      return set;\n    }\n    var voidElements = makeSet([ \"area\", \"base\", \"br\", \"col\", \"command\", \"embed\", \"hr\", \"img\", \"input\", \"keygen\", \"link\", \"meta\", \"param\", \"source\", \"track\", \"wbr\" ]);\n    var plaintextParents = makeSet([ \"style\", \"script\", \"xmp\", \"iframe\", \"noembed\", \"noframes\", \"plaintext\", \"noscript\" ]);\n    var XHTML_NS = \"http://www.w3.org/1999/xhtml\";\n    function needsSelfClosingSlash(node) {\n      if (node.namespaceURI !== XHTML_NS) return true;\n      var doctype = node.ownerDocument.doctype;\n      return doctype && doctype.publicId && doctype.systemId;\n    }\n    function getOuterHTML(node, parentNode) {\n      switch (node.nodeType) {\n       case Node.ELEMENT_NODE:\n        var tagName = node.tagName.toLowerCase();\n        var s = \"<\" + tagName;\n        var attrs = node.attributes;\n        for (var i = 0, attr; attr = attrs[i]; i++) {\n          s += \" \" + attr.name + '=\"' + escapeAttr(attr.value) + '\"';\n        }\n        if (voidElements[tagName]) {\n          if (needsSelfClosingSlash(node)) s += \"/\";\n          return s + \">\";\n        }\n        return s + \">\" + getInnerHTML(node) + \"</\" + tagName + \">\";\n\n       case Node.TEXT_NODE:\n        var data = node.data;\n        if (parentNode && plaintextParents[parentNode.localName]) return data;\n        return escapeData(data);\n\n       case Node.COMMENT_NODE:\n        return \"<!--\" + node.data + \"-->\";\n\n       default:\n        console.error(node);\n        throw new Error(\"not implemented\");\n      }\n    }\n    function getInnerHTML(node) {\n      if (node instanceof wrappers.HTMLTemplateElement) node = node.content;\n      var s = \"\";\n      for (var child = node.firstChild; child; child = child.nextSibling) {\n        s += getOuterHTML(child, node);\n      }\n      return s;\n    }\n    function setInnerHTML(node, value, opt_tagName) {\n      var tagName = opt_tagName || \"div\";\n      node.textContent = \"\";\n      var tempElement = unwrap(node.ownerDocument.createElement(tagName));\n      tempElement.innerHTML = value;\n      var firstChild;\n      while (firstChild = tempElement.firstChild) {\n        node.appendChild(wrap(firstChild));\n      }\n    }\n    var oldIe = /MSIE/.test(navigator.userAgent);\n    var OriginalHTMLElement = window.HTMLElement;\n    var OriginalHTMLTemplateElement = window.HTMLTemplateElement;\n    function HTMLElement(node) {\n      Element.call(this, node);\n    }\n    HTMLElement.prototype = Object.create(Element.prototype);\n    mixin(HTMLElement.prototype, {\n      get innerHTML() {\n        return getInnerHTML(this);\n      },\n      set innerHTML(value) {\n        if (oldIe && plaintextParents[this.localName]) {\n          this.textContent = value;\n          return;\n        }\n        var removedNodes = snapshotNodeList(this.childNodes);\n        if (this.invalidateShadowRenderer()) {\n          if (this instanceof wrappers.HTMLTemplateElement) setInnerHTML(this.content, value); else setInnerHTML(this, value, this.tagName);\n        } else if (!OriginalHTMLTemplateElement && this instanceof wrappers.HTMLTemplateElement) {\n          setInnerHTML(this.content, value);\n        } else {\n          unsafeUnwrap(this).innerHTML = value;\n        }\n        var addedNodes = snapshotNodeList(this.childNodes);\n        enqueueMutation(this, \"childList\", {\n          addedNodes: addedNodes,\n          removedNodes: removedNodes\n        });\n        nodesWereRemoved(removedNodes);\n        nodesWereAdded(addedNodes, this);\n      },\n      get outerHTML() {\n        return getOuterHTML(this, this.parentNode);\n      },\n      set outerHTML(value) {\n        var p = this.parentNode;\n        if (p) {\n          p.invalidateShadowRenderer();\n          var df = frag(p, value);\n          p.replaceChild(df, this);\n        }\n      },\n      insertAdjacentHTML: function(position, text) {\n        var contextElement, refNode;\n        switch (String(position).toLowerCase()) {\n         case \"beforebegin\":\n          contextElement = this.parentNode;\n          refNode = this;\n          break;\n\n         case \"afterend\":\n          contextElement = this.parentNode;\n          refNode = this.nextSibling;\n          break;\n\n         case \"afterbegin\":\n          contextElement = this;\n          refNode = this.firstChild;\n          break;\n\n         case \"beforeend\":\n          contextElement = this;\n          refNode = null;\n          break;\n\n         default:\n          return;\n        }\n        var df = frag(contextElement, text);\n        contextElement.insertBefore(df, refNode);\n      },\n      get hidden() {\n        return this.hasAttribute(\"hidden\");\n      },\n      set hidden(v) {\n        if (v) {\n          this.setAttribute(\"hidden\", \"\");\n        } else {\n          this.removeAttribute(\"hidden\");\n        }\n      }\n    });\n    function frag(contextElement, html) {\n      var p = unwrap(contextElement.cloneNode(false));\n      p.innerHTML = html;\n      var df = unwrap(document.createDocumentFragment());\n      var c;\n      while (c = p.firstChild) {\n        df.appendChild(c);\n      }\n      return wrap(df);\n    }\n    function getter(name) {\n      return function() {\n        scope.renderAllPending();\n        return unsafeUnwrap(this)[name];\n      };\n    }\n    function getterRequiresRendering(name) {\n      defineGetter(HTMLElement, name, getter(name));\n    }\n    [ \"clientHeight\", \"clientLeft\", \"clientTop\", \"clientWidth\", \"offsetHeight\", \"offsetLeft\", \"offsetTop\", \"offsetWidth\", \"scrollHeight\", \"scrollWidth\" ].forEach(getterRequiresRendering);\n    function getterAndSetterRequiresRendering(name) {\n      Object.defineProperty(HTMLElement.prototype, name, {\n        get: getter(name),\n        set: function(v) {\n          scope.renderAllPending();\n          unsafeUnwrap(this)[name] = v;\n        },\n        configurable: true,\n        enumerable: true\n      });\n    }\n    [ \"scrollLeft\", \"scrollTop\" ].forEach(getterAndSetterRequiresRendering);\n    function methodRequiresRendering(name) {\n      Object.defineProperty(HTMLElement.prototype, name, {\n        value: function() {\n          scope.renderAllPending();\n          return unsafeUnwrap(this)[name].apply(unsafeUnwrap(this), arguments);\n        },\n        configurable: true,\n        enumerable: true\n      });\n    }\n    [ \"getBoundingClientRect\", \"getClientRects\", \"scrollIntoView\" ].forEach(methodRequiresRendering);\n    registerWrapper(OriginalHTMLElement, HTMLElement, document.createElement(\"b\"));\n    scope.wrappers.HTMLElement = HTMLElement;\n    scope.getInnerHTML = getInnerHTML;\n    scope.setInnerHTML = setInnerHTML;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var HTMLElement = scope.wrappers.HTMLElement;\n    var mixin = scope.mixin;\n    var registerWrapper = scope.registerWrapper;\n    var unsafeUnwrap = scope.unsafeUnwrap;\n    var wrap = scope.wrap;\n    var OriginalHTMLCanvasElement = window.HTMLCanvasElement;\n    function HTMLCanvasElement(node) {\n      HTMLElement.call(this, node);\n    }\n    HTMLCanvasElement.prototype = Object.create(HTMLElement.prototype);\n    mixin(HTMLCanvasElement.prototype, {\n      getContext: function() {\n        var context = unsafeUnwrap(this).getContext.apply(unsafeUnwrap(this), arguments);\n        return context && wrap(context);\n      }\n    });\n    registerWrapper(OriginalHTMLCanvasElement, HTMLCanvasElement, document.createElement(\"canvas\"));\n    scope.wrappers.HTMLCanvasElement = HTMLCanvasElement;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var HTMLElement = scope.wrappers.HTMLElement;\n    var mixin = scope.mixin;\n    var registerWrapper = scope.registerWrapper;\n    var OriginalHTMLContentElement = window.HTMLContentElement;\n    function HTMLContentElement(node) {\n      HTMLElement.call(this, node);\n    }\n    HTMLContentElement.prototype = Object.create(HTMLElement.prototype);\n    mixin(HTMLContentElement.prototype, {\n      constructor: HTMLContentElement,\n      get select() {\n        return this.getAttribute(\"select\");\n      },\n      set select(value) {\n        this.setAttribute(\"select\", value);\n      },\n      setAttribute: function(n, v) {\n        HTMLElement.prototype.setAttribute.call(this, n, v);\n        if (String(n).toLowerCase() === \"select\") this.invalidateShadowRenderer(true);\n      }\n    });\n    if (OriginalHTMLContentElement) registerWrapper(OriginalHTMLContentElement, HTMLContentElement);\n    scope.wrappers.HTMLContentElement = HTMLContentElement;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var HTMLElement = scope.wrappers.HTMLElement;\n    var mixin = scope.mixin;\n    var registerWrapper = scope.registerWrapper;\n    var wrapHTMLCollection = scope.wrapHTMLCollection;\n    var unwrap = scope.unwrap;\n    var OriginalHTMLFormElement = window.HTMLFormElement;\n    function HTMLFormElement(node) {\n      HTMLElement.call(this, node);\n    }\n    HTMLFormElement.prototype = Object.create(HTMLElement.prototype);\n    mixin(HTMLFormElement.prototype, {\n      get elements() {\n        return wrapHTMLCollection(unwrap(this).elements);\n      }\n    });\n    registerWrapper(OriginalHTMLFormElement, HTMLFormElement, document.createElement(\"form\"));\n    scope.wrappers.HTMLFormElement = HTMLFormElement;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var HTMLElement = scope.wrappers.HTMLElement;\n    var registerWrapper = scope.registerWrapper;\n    var unwrap = scope.unwrap;\n    var rewrap = scope.rewrap;\n    var OriginalHTMLImageElement = window.HTMLImageElement;\n    function HTMLImageElement(node) {\n      HTMLElement.call(this, node);\n    }\n    HTMLImageElement.prototype = Object.create(HTMLElement.prototype);\n    registerWrapper(OriginalHTMLImageElement, HTMLImageElement, document.createElement(\"img\"));\n    function Image(width, height) {\n      if (!(this instanceof Image)) {\n        throw new TypeError(\"DOM object constructor cannot be called as a function.\");\n      }\n      var node = unwrap(document.createElement(\"img\"));\n      HTMLElement.call(this, node);\n      rewrap(node, this);\n      if (width !== undefined) node.width = width;\n      if (height !== undefined) node.height = height;\n    }\n    Image.prototype = HTMLImageElement.prototype;\n    scope.wrappers.HTMLImageElement = HTMLImageElement;\n    scope.wrappers.Image = Image;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var HTMLElement = scope.wrappers.HTMLElement;\n    var mixin = scope.mixin;\n    var NodeList = scope.wrappers.NodeList;\n    var registerWrapper = scope.registerWrapper;\n    var OriginalHTMLShadowElement = window.HTMLShadowElement;\n    function HTMLShadowElement(node) {\n      HTMLElement.call(this, node);\n    }\n    HTMLShadowElement.prototype = Object.create(HTMLElement.prototype);\n    HTMLShadowElement.prototype.constructor = HTMLShadowElement;\n    if (OriginalHTMLShadowElement) registerWrapper(OriginalHTMLShadowElement, HTMLShadowElement);\n    scope.wrappers.HTMLShadowElement = HTMLShadowElement;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var HTMLElement = scope.wrappers.HTMLElement;\n    var mixin = scope.mixin;\n    var registerWrapper = scope.registerWrapper;\n    var unsafeUnwrap = scope.unsafeUnwrap;\n    var unwrap = scope.unwrap;\n    var wrap = scope.wrap;\n    var contentTable = new WeakMap();\n    var templateContentsOwnerTable = new WeakMap();\n    function getTemplateContentsOwner(doc) {\n      if (!doc.defaultView) return doc;\n      var d = templateContentsOwnerTable.get(doc);\n      if (!d) {\n        d = doc.implementation.createHTMLDocument(\"\");\n        while (d.lastChild) {\n          d.removeChild(d.lastChild);\n        }\n        templateContentsOwnerTable.set(doc, d);\n      }\n      return d;\n    }\n    function extractContent(templateElement) {\n      var doc = getTemplateContentsOwner(templateElement.ownerDocument);\n      var df = unwrap(doc.createDocumentFragment());\n      var child;\n      while (child = templateElement.firstChild) {\n        df.appendChild(child);\n      }\n      return df;\n    }\n    var OriginalHTMLTemplateElement = window.HTMLTemplateElement;\n    function HTMLTemplateElement(node) {\n      HTMLElement.call(this, node);\n      if (!OriginalHTMLTemplateElement) {\n        var content = extractContent(node);\n        contentTable.set(this, wrap(content));\n      }\n    }\n    HTMLTemplateElement.prototype = Object.create(HTMLElement.prototype);\n    mixin(HTMLTemplateElement.prototype, {\n      constructor: HTMLTemplateElement,\n      get content() {\n        if (OriginalHTMLTemplateElement) return wrap(unsafeUnwrap(this).content);\n        return contentTable.get(this);\n      }\n    });\n    if (OriginalHTMLTemplateElement) registerWrapper(OriginalHTMLTemplateElement, HTMLTemplateElement);\n    scope.wrappers.HTMLTemplateElement = HTMLTemplateElement;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var HTMLElement = scope.wrappers.HTMLElement;\n    var registerWrapper = scope.registerWrapper;\n    var OriginalHTMLMediaElement = window.HTMLMediaElement;\n    if (!OriginalHTMLMediaElement) return;\n    function HTMLMediaElement(node) {\n      HTMLElement.call(this, node);\n    }\n    HTMLMediaElement.prototype = Object.create(HTMLElement.prototype);\n    registerWrapper(OriginalHTMLMediaElement, HTMLMediaElement, document.createElement(\"audio\"));\n    scope.wrappers.HTMLMediaElement = HTMLMediaElement;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var HTMLMediaElement = scope.wrappers.HTMLMediaElement;\n    var registerWrapper = scope.registerWrapper;\n    var unwrap = scope.unwrap;\n    var rewrap = scope.rewrap;\n    var OriginalHTMLAudioElement = window.HTMLAudioElement;\n    if (!OriginalHTMLAudioElement) return;\n    function HTMLAudioElement(node) {\n      HTMLMediaElement.call(this, node);\n    }\n    HTMLAudioElement.prototype = Object.create(HTMLMediaElement.prototype);\n    registerWrapper(OriginalHTMLAudioElement, HTMLAudioElement, document.createElement(\"audio\"));\n    function Audio(src) {\n      if (!(this instanceof Audio)) {\n        throw new TypeError(\"DOM object constructor cannot be called as a function.\");\n      }\n      var node = unwrap(document.createElement(\"audio\"));\n      HTMLMediaElement.call(this, node);\n      rewrap(node, this);\n      node.setAttribute(\"preload\", \"auto\");\n      if (src !== undefined) node.setAttribute(\"src\", src);\n    }\n    Audio.prototype = HTMLAudioElement.prototype;\n    scope.wrappers.HTMLAudioElement = HTMLAudioElement;\n    scope.wrappers.Audio = Audio;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var HTMLElement = scope.wrappers.HTMLElement;\n    var mixin = scope.mixin;\n    var registerWrapper = scope.registerWrapper;\n    var rewrap = scope.rewrap;\n    var unwrap = scope.unwrap;\n    var wrap = scope.wrap;\n    var OriginalHTMLOptionElement = window.HTMLOptionElement;\n    function trimText(s) {\n      return s.replace(/\\s+/g, \" \").trim();\n    }\n    function HTMLOptionElement(node) {\n      HTMLElement.call(this, node);\n    }\n    HTMLOptionElement.prototype = Object.create(HTMLElement.prototype);\n    mixin(HTMLOptionElement.prototype, {\n      get text() {\n        return trimText(this.textContent);\n      },\n      set text(value) {\n        this.textContent = trimText(String(value));\n      },\n      get form() {\n        return wrap(unwrap(this).form);\n      }\n    });\n    registerWrapper(OriginalHTMLOptionElement, HTMLOptionElement, document.createElement(\"option\"));\n    function Option(text, value, defaultSelected, selected) {\n      if (!(this instanceof Option)) {\n        throw new TypeError(\"DOM object constructor cannot be called as a function.\");\n      }\n      var node = unwrap(document.createElement(\"option\"));\n      HTMLElement.call(this, node);\n      rewrap(node, this);\n      if (text !== undefined) node.text = text;\n      if (value !== undefined) node.setAttribute(\"value\", value);\n      if (defaultSelected === true) node.setAttribute(\"selected\", \"\");\n      node.selected = selected === true;\n    }\n    Option.prototype = HTMLOptionElement.prototype;\n    scope.wrappers.HTMLOptionElement = HTMLOptionElement;\n    scope.wrappers.Option = Option;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var HTMLElement = scope.wrappers.HTMLElement;\n    var mixin = scope.mixin;\n    var registerWrapper = scope.registerWrapper;\n    var unwrap = scope.unwrap;\n    var wrap = scope.wrap;\n    var OriginalHTMLSelectElement = window.HTMLSelectElement;\n    function HTMLSelectElement(node) {\n      HTMLElement.call(this, node);\n    }\n    HTMLSelectElement.prototype = Object.create(HTMLElement.prototype);\n    mixin(HTMLSelectElement.prototype, {\n      add: function(element, before) {\n        if (typeof before === \"object\") before = unwrap(before);\n        unwrap(this).add(unwrap(element), before);\n      },\n      remove: function(indexOrNode) {\n        if (indexOrNode === undefined) {\n          HTMLElement.prototype.remove.call(this);\n          return;\n        }\n        if (typeof indexOrNode === \"object\") indexOrNode = unwrap(indexOrNode);\n        unwrap(this).remove(indexOrNode);\n      },\n      get form() {\n        return wrap(unwrap(this).form);\n      }\n    });\n    registerWrapper(OriginalHTMLSelectElement, HTMLSelectElement, document.createElement(\"select\"));\n    scope.wrappers.HTMLSelectElement = HTMLSelectElement;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var HTMLElement = scope.wrappers.HTMLElement;\n    var mixin = scope.mixin;\n    var registerWrapper = scope.registerWrapper;\n    var unwrap = scope.unwrap;\n    var wrap = scope.wrap;\n    var wrapHTMLCollection = scope.wrapHTMLCollection;\n    var OriginalHTMLTableElement = window.HTMLTableElement;\n    function HTMLTableElement(node) {\n      HTMLElement.call(this, node);\n    }\n    HTMLTableElement.prototype = Object.create(HTMLElement.prototype);\n    mixin(HTMLTableElement.prototype, {\n      get caption() {\n        return wrap(unwrap(this).caption);\n      },\n      createCaption: function() {\n        return wrap(unwrap(this).createCaption());\n      },\n      get tHead() {\n        return wrap(unwrap(this).tHead);\n      },\n      createTHead: function() {\n        return wrap(unwrap(this).createTHead());\n      },\n      createTFoot: function() {\n        return wrap(unwrap(this).createTFoot());\n      },\n      get tFoot() {\n        return wrap(unwrap(this).tFoot);\n      },\n      get tBodies() {\n        return wrapHTMLCollection(unwrap(this).tBodies);\n      },\n      createTBody: function() {\n        return wrap(unwrap(this).createTBody());\n      },\n      get rows() {\n        return wrapHTMLCollection(unwrap(this).rows);\n      },\n      insertRow: function(index) {\n        return wrap(unwrap(this).insertRow(index));\n      }\n    });\n    registerWrapper(OriginalHTMLTableElement, HTMLTableElement, document.createElement(\"table\"));\n    scope.wrappers.HTMLTableElement = HTMLTableElement;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var HTMLElement = scope.wrappers.HTMLElement;\n    var mixin = scope.mixin;\n    var registerWrapper = scope.registerWrapper;\n    var wrapHTMLCollection = scope.wrapHTMLCollection;\n    var unwrap = scope.unwrap;\n    var wrap = scope.wrap;\n    var OriginalHTMLTableSectionElement = window.HTMLTableSectionElement;\n    function HTMLTableSectionElement(node) {\n      HTMLElement.call(this, node);\n    }\n    HTMLTableSectionElement.prototype = Object.create(HTMLElement.prototype);\n    mixin(HTMLTableSectionElement.prototype, {\n      constructor: HTMLTableSectionElement,\n      get rows() {\n        return wrapHTMLCollection(unwrap(this).rows);\n      },\n      insertRow: function(index) {\n        return wrap(unwrap(this).insertRow(index));\n      }\n    });\n    registerWrapper(OriginalHTMLTableSectionElement, HTMLTableSectionElement, document.createElement(\"thead\"));\n    scope.wrappers.HTMLTableSectionElement = HTMLTableSectionElement;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var HTMLElement = scope.wrappers.HTMLElement;\n    var mixin = scope.mixin;\n    var registerWrapper = scope.registerWrapper;\n    var wrapHTMLCollection = scope.wrapHTMLCollection;\n    var unwrap = scope.unwrap;\n    var wrap = scope.wrap;\n    var OriginalHTMLTableRowElement = window.HTMLTableRowElement;\n    function HTMLTableRowElement(node) {\n      HTMLElement.call(this, node);\n    }\n    HTMLTableRowElement.prototype = Object.create(HTMLElement.prototype);\n    mixin(HTMLTableRowElement.prototype, {\n      get cells() {\n        return wrapHTMLCollection(unwrap(this).cells);\n      },\n      insertCell: function(index) {\n        return wrap(unwrap(this).insertCell(index));\n      }\n    });\n    registerWrapper(OriginalHTMLTableRowElement, HTMLTableRowElement, document.createElement(\"tr\"));\n    scope.wrappers.HTMLTableRowElement = HTMLTableRowElement;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var HTMLContentElement = scope.wrappers.HTMLContentElement;\n    var HTMLElement = scope.wrappers.HTMLElement;\n    var HTMLShadowElement = scope.wrappers.HTMLShadowElement;\n    var HTMLTemplateElement = scope.wrappers.HTMLTemplateElement;\n    var mixin = scope.mixin;\n    var registerWrapper = scope.registerWrapper;\n    var OriginalHTMLUnknownElement = window.HTMLUnknownElement;\n    function HTMLUnknownElement(node) {\n      switch (node.localName) {\n       case \"content\":\n        return new HTMLContentElement(node);\n\n       case \"shadow\":\n        return new HTMLShadowElement(node);\n\n       case \"template\":\n        return new HTMLTemplateElement(node);\n      }\n      HTMLElement.call(this, node);\n    }\n    HTMLUnknownElement.prototype = Object.create(HTMLElement.prototype);\n    registerWrapper(OriginalHTMLUnknownElement, HTMLUnknownElement);\n    scope.wrappers.HTMLUnknownElement = HTMLUnknownElement;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var Element = scope.wrappers.Element;\n    var HTMLElement = scope.wrappers.HTMLElement;\n    var registerObject = scope.registerObject;\n    var defineWrapGetter = scope.defineWrapGetter;\n    var SVG_NS = \"http://www.w3.org/2000/svg\";\n    var svgTitleElement = document.createElementNS(SVG_NS, \"title\");\n    var SVGTitleElement = registerObject(svgTitleElement);\n    var SVGElement = Object.getPrototypeOf(SVGTitleElement.prototype).constructor;\n    if (!(\"classList\" in svgTitleElement)) {\n      var descr = Object.getOwnPropertyDescriptor(Element.prototype, \"classList\");\n      Object.defineProperty(HTMLElement.prototype, \"classList\", descr);\n      delete Element.prototype.classList;\n    }\n    defineWrapGetter(SVGElement, \"ownerSVGElement\");\n    scope.wrappers.SVGElement = SVGElement;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var mixin = scope.mixin;\n    var registerWrapper = scope.registerWrapper;\n    var unwrap = scope.unwrap;\n    var wrap = scope.wrap;\n    var OriginalSVGUseElement = window.SVGUseElement;\n    var SVG_NS = \"http://www.w3.org/2000/svg\";\n    var gWrapper = wrap(document.createElementNS(SVG_NS, \"g\"));\n    var useElement = document.createElementNS(SVG_NS, \"use\");\n    var SVGGElement = gWrapper.constructor;\n    var parentInterfacePrototype = Object.getPrototypeOf(SVGGElement.prototype);\n    var parentInterface = parentInterfacePrototype.constructor;\n    function SVGUseElement(impl) {\n      parentInterface.call(this, impl);\n    }\n    SVGUseElement.prototype = Object.create(parentInterfacePrototype);\n    if (\"instanceRoot\" in useElement) {\n      mixin(SVGUseElement.prototype, {\n        get instanceRoot() {\n          return wrap(unwrap(this).instanceRoot);\n        },\n        get animatedInstanceRoot() {\n          return wrap(unwrap(this).animatedInstanceRoot);\n        }\n      });\n    }\n    registerWrapper(OriginalSVGUseElement, SVGUseElement, useElement);\n    scope.wrappers.SVGUseElement = SVGUseElement;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var EventTarget = scope.wrappers.EventTarget;\n    var mixin = scope.mixin;\n    var registerWrapper = scope.registerWrapper;\n    var unsafeUnwrap = scope.unsafeUnwrap;\n    var wrap = scope.wrap;\n    var OriginalSVGElementInstance = window.SVGElementInstance;\n    if (!OriginalSVGElementInstance) return;\n    function SVGElementInstance(impl) {\n      EventTarget.call(this, impl);\n    }\n    SVGElementInstance.prototype = Object.create(EventTarget.prototype);\n    mixin(SVGElementInstance.prototype, {\n      get correspondingElement() {\n        return wrap(unsafeUnwrap(this).correspondingElement);\n      },\n      get correspondingUseElement() {\n        return wrap(unsafeUnwrap(this).correspondingUseElement);\n      },\n      get parentNode() {\n        return wrap(unsafeUnwrap(this).parentNode);\n      },\n      get childNodes() {\n        throw new Error(\"Not implemented\");\n      },\n      get firstChild() {\n        return wrap(unsafeUnwrap(this).firstChild);\n      },\n      get lastChild() {\n        return wrap(unsafeUnwrap(this).lastChild);\n      },\n      get previousSibling() {\n        return wrap(unsafeUnwrap(this).previousSibling);\n      },\n      get nextSibling() {\n        return wrap(unsafeUnwrap(this).nextSibling);\n      }\n    });\n    registerWrapper(OriginalSVGElementInstance, SVGElementInstance);\n    scope.wrappers.SVGElementInstance = SVGElementInstance;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var mixin = scope.mixin;\n    var registerWrapper = scope.registerWrapper;\n    var setWrapper = scope.setWrapper;\n    var unsafeUnwrap = scope.unsafeUnwrap;\n    var unwrap = scope.unwrap;\n    var unwrapIfNeeded = scope.unwrapIfNeeded;\n    var wrap = scope.wrap;\n    var OriginalCanvasRenderingContext2D = window.CanvasRenderingContext2D;\n    function CanvasRenderingContext2D(impl) {\n      setWrapper(impl, this);\n    }\n    mixin(CanvasRenderingContext2D.prototype, {\n      get canvas() {\n        return wrap(unsafeUnwrap(this).canvas);\n      },\n      drawImage: function() {\n        arguments[0] = unwrapIfNeeded(arguments[0]);\n        unsafeUnwrap(this).drawImage.apply(unsafeUnwrap(this), arguments);\n      },\n      createPattern: function() {\n        arguments[0] = unwrap(arguments[0]);\n        return unsafeUnwrap(this).createPattern.apply(unsafeUnwrap(this), arguments);\n      }\n    });\n    registerWrapper(OriginalCanvasRenderingContext2D, CanvasRenderingContext2D, document.createElement(\"canvas\").getContext(\"2d\"));\n    scope.wrappers.CanvasRenderingContext2D = CanvasRenderingContext2D;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var mixin = scope.mixin;\n    var registerWrapper = scope.registerWrapper;\n    var setWrapper = scope.setWrapper;\n    var unsafeUnwrap = scope.unsafeUnwrap;\n    var unwrapIfNeeded = scope.unwrapIfNeeded;\n    var wrap = scope.wrap;\n    var OriginalWebGLRenderingContext = window.WebGLRenderingContext;\n    if (!OriginalWebGLRenderingContext) return;\n    function WebGLRenderingContext(impl) {\n      setWrapper(impl, this);\n    }\n    mixin(WebGLRenderingContext.prototype, {\n      get canvas() {\n        return wrap(unsafeUnwrap(this).canvas);\n      },\n      texImage2D: function() {\n        arguments[5] = unwrapIfNeeded(arguments[5]);\n        unsafeUnwrap(this).texImage2D.apply(unsafeUnwrap(this), arguments);\n      },\n      texSubImage2D: function() {\n        arguments[6] = unwrapIfNeeded(arguments[6]);\n        unsafeUnwrap(this).texSubImage2D.apply(unsafeUnwrap(this), arguments);\n      }\n    });\n    var instanceProperties = /WebKit/.test(navigator.userAgent) ? {\n      drawingBufferHeight: null,\n      drawingBufferWidth: null\n    } : {};\n    registerWrapper(OriginalWebGLRenderingContext, WebGLRenderingContext, instanceProperties);\n    scope.wrappers.WebGLRenderingContext = WebGLRenderingContext;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var GetElementsByInterface = scope.GetElementsByInterface;\n    var NonElementParentNodeInterface = scope.NonElementParentNodeInterface;\n    var ParentNodeInterface = scope.ParentNodeInterface;\n    var SelectorsInterface = scope.SelectorsInterface;\n    var mixin = scope.mixin;\n    var registerObject = scope.registerObject;\n    var DocumentFragment = registerObject(document.createDocumentFragment());\n    mixin(DocumentFragment.prototype, ParentNodeInterface);\n    mixin(DocumentFragment.prototype, SelectorsInterface);\n    mixin(DocumentFragment.prototype, GetElementsByInterface);\n    mixin(DocumentFragment.prototype, NonElementParentNodeInterface);\n    var Comment = registerObject(document.createComment(\"\"));\n    scope.wrappers.Comment = Comment;\n    scope.wrappers.DocumentFragment = DocumentFragment;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var DocumentFragment = scope.wrappers.DocumentFragment;\n    var TreeScope = scope.TreeScope;\n    var elementFromPoint = scope.elementFromPoint;\n    var getInnerHTML = scope.getInnerHTML;\n    var getTreeScope = scope.getTreeScope;\n    var mixin = scope.mixin;\n    var rewrap = scope.rewrap;\n    var setInnerHTML = scope.setInnerHTML;\n    var unsafeUnwrap = scope.unsafeUnwrap;\n    var unwrap = scope.unwrap;\n    var shadowHostTable = new WeakMap();\n    var nextOlderShadowTreeTable = new WeakMap();\n    function ShadowRoot(hostWrapper) {\n      var node = unwrap(unsafeUnwrap(hostWrapper).ownerDocument.createDocumentFragment());\n      DocumentFragment.call(this, node);\n      rewrap(node, this);\n      var oldShadowRoot = hostWrapper.shadowRoot;\n      nextOlderShadowTreeTable.set(this, oldShadowRoot);\n      this.treeScope_ = new TreeScope(this, getTreeScope(oldShadowRoot || hostWrapper));\n      shadowHostTable.set(this, hostWrapper);\n    }\n    ShadowRoot.prototype = Object.create(DocumentFragment.prototype);\n    mixin(ShadowRoot.prototype, {\n      constructor: ShadowRoot,\n      get innerHTML() {\n        return getInnerHTML(this);\n      },\n      set innerHTML(value) {\n        setInnerHTML(this, value);\n        this.invalidateShadowRenderer();\n      },\n      get olderShadowRoot() {\n        return nextOlderShadowTreeTable.get(this) || null;\n      },\n      get host() {\n        return shadowHostTable.get(this) || null;\n      },\n      invalidateShadowRenderer: function() {\n        return shadowHostTable.get(this).invalidateShadowRenderer();\n      },\n      elementFromPoint: function(x, y) {\n        return elementFromPoint(this, this.ownerDocument, x, y);\n      }\n    });\n    scope.wrappers.ShadowRoot = ShadowRoot;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var registerWrapper = scope.registerWrapper;\n    var setWrapper = scope.setWrapper;\n    var unsafeUnwrap = scope.unsafeUnwrap;\n    var unwrap = scope.unwrap;\n    var unwrapIfNeeded = scope.unwrapIfNeeded;\n    var wrap = scope.wrap;\n    var getTreeScope = scope.getTreeScope;\n    var OriginalRange = window.Range;\n    var ShadowRoot = scope.wrappers.ShadowRoot;\n    function getHost(node) {\n      var root = getTreeScope(node).root;\n      if (root instanceof ShadowRoot) {\n        return root.host;\n      }\n      return null;\n    }\n    function hostNodeToShadowNode(refNode, offset) {\n      if (refNode.shadowRoot) {\n        offset = Math.min(refNode.childNodes.length - 1, offset);\n        var child = refNode.childNodes[offset];\n        if (child) {\n          var insertionPoint = scope.getDestinationInsertionPoints(child);\n          if (insertionPoint.length > 0) {\n            var parentNode = insertionPoint[0].parentNode;\n            if (parentNode.nodeType == Node.ELEMENT_NODE) {\n              refNode = parentNode;\n            }\n          }\n        }\n      }\n      return refNode;\n    }\n    function shadowNodeToHostNode(node) {\n      node = wrap(node);\n      return getHost(node) || node;\n    }\n    function Range(impl) {\n      setWrapper(impl, this);\n    }\n    Range.prototype = {\n      get startContainer() {\n        return shadowNodeToHostNode(unsafeUnwrap(this).startContainer);\n      },\n      get endContainer() {\n        return shadowNodeToHostNode(unsafeUnwrap(this).endContainer);\n      },\n      get commonAncestorContainer() {\n        return shadowNodeToHostNode(unsafeUnwrap(this).commonAncestorContainer);\n      },\n      setStart: function(refNode, offset) {\n        refNode = hostNodeToShadowNode(refNode, offset);\n        unsafeUnwrap(this).setStart(unwrapIfNeeded(refNode), offset);\n      },\n      setEnd: function(refNode, offset) {\n        refNode = hostNodeToShadowNode(refNode, offset);\n        unsafeUnwrap(this).setEnd(unwrapIfNeeded(refNode), offset);\n      },\n      setStartBefore: function(refNode) {\n        unsafeUnwrap(this).setStartBefore(unwrapIfNeeded(refNode));\n      },\n      setStartAfter: function(refNode) {\n        unsafeUnwrap(this).setStartAfter(unwrapIfNeeded(refNode));\n      },\n      setEndBefore: function(refNode) {\n        unsafeUnwrap(this).setEndBefore(unwrapIfNeeded(refNode));\n      },\n      setEndAfter: function(refNode) {\n        unsafeUnwrap(this).setEndAfter(unwrapIfNeeded(refNode));\n      },\n      selectNode: function(refNode) {\n        unsafeUnwrap(this).selectNode(unwrapIfNeeded(refNode));\n      },\n      selectNodeContents: function(refNode) {\n        unsafeUnwrap(this).selectNodeContents(unwrapIfNeeded(refNode));\n      },\n      compareBoundaryPoints: function(how, sourceRange) {\n        return unsafeUnwrap(this).compareBoundaryPoints(how, unwrap(sourceRange));\n      },\n      extractContents: function() {\n        return wrap(unsafeUnwrap(this).extractContents());\n      },\n      cloneContents: function() {\n        return wrap(unsafeUnwrap(this).cloneContents());\n      },\n      insertNode: function(node) {\n        unsafeUnwrap(this).insertNode(unwrapIfNeeded(node));\n      },\n      surroundContents: function(newParent) {\n        unsafeUnwrap(this).surroundContents(unwrapIfNeeded(newParent));\n      },\n      cloneRange: function() {\n        return wrap(unsafeUnwrap(this).cloneRange());\n      },\n      isPointInRange: function(node, offset) {\n        return unsafeUnwrap(this).isPointInRange(unwrapIfNeeded(node), offset);\n      },\n      comparePoint: function(node, offset) {\n        return unsafeUnwrap(this).comparePoint(unwrapIfNeeded(node), offset);\n      },\n      intersectsNode: function(node) {\n        return unsafeUnwrap(this).intersectsNode(unwrapIfNeeded(node));\n      },\n      toString: function() {\n        return unsafeUnwrap(this).toString();\n      }\n    };\n    if (OriginalRange.prototype.createContextualFragment) {\n      Range.prototype.createContextualFragment = function(html) {\n        return wrap(unsafeUnwrap(this).createContextualFragment(html));\n      };\n    }\n    registerWrapper(window.Range, Range, document.createRange());\n    scope.wrappers.Range = Range;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var Element = scope.wrappers.Element;\n    var HTMLContentElement = scope.wrappers.HTMLContentElement;\n    var HTMLShadowElement = scope.wrappers.HTMLShadowElement;\n    var Node = scope.wrappers.Node;\n    var ShadowRoot = scope.wrappers.ShadowRoot;\n    var assert = scope.assert;\n    var getTreeScope = scope.getTreeScope;\n    var mixin = scope.mixin;\n    var oneOf = scope.oneOf;\n    var unsafeUnwrap = scope.unsafeUnwrap;\n    var unwrap = scope.unwrap;\n    var wrap = scope.wrap;\n    var ArraySplice = scope.ArraySplice;\n    function updateWrapperUpAndSideways(wrapper) {\n      wrapper.previousSibling_ = wrapper.previousSibling;\n      wrapper.nextSibling_ = wrapper.nextSibling;\n      wrapper.parentNode_ = wrapper.parentNode;\n    }\n    function updateWrapperDown(wrapper) {\n      wrapper.firstChild_ = wrapper.firstChild;\n      wrapper.lastChild_ = wrapper.lastChild;\n    }\n    function updateAllChildNodes(parentNodeWrapper) {\n      assert(parentNodeWrapper instanceof Node);\n      for (var childWrapper = parentNodeWrapper.firstChild; childWrapper; childWrapper = childWrapper.nextSibling) {\n        updateWrapperUpAndSideways(childWrapper);\n      }\n      updateWrapperDown(parentNodeWrapper);\n    }\n    function insertBefore(parentNodeWrapper, newChildWrapper, refChildWrapper) {\n      var parentNode = unwrap(parentNodeWrapper);\n      var newChild = unwrap(newChildWrapper);\n      var refChild = refChildWrapper ? unwrap(refChildWrapper) : null;\n      remove(newChildWrapper);\n      updateWrapperUpAndSideways(newChildWrapper);\n      if (!refChildWrapper) {\n        parentNodeWrapper.lastChild_ = parentNodeWrapper.lastChild;\n        if (parentNodeWrapper.lastChild === parentNodeWrapper.firstChild) parentNodeWrapper.firstChild_ = parentNodeWrapper.firstChild;\n        var lastChildWrapper = wrap(parentNode.lastChild);\n        if (lastChildWrapper) lastChildWrapper.nextSibling_ = lastChildWrapper.nextSibling;\n      } else {\n        if (parentNodeWrapper.firstChild === refChildWrapper) parentNodeWrapper.firstChild_ = refChildWrapper;\n        refChildWrapper.previousSibling_ = refChildWrapper.previousSibling;\n      }\n      scope.originalInsertBefore.call(parentNode, newChild, refChild);\n    }\n    function remove(nodeWrapper) {\n      var node = unwrap(nodeWrapper);\n      var parentNode = node.parentNode;\n      if (!parentNode) return;\n      var parentNodeWrapper = wrap(parentNode);\n      updateWrapperUpAndSideways(nodeWrapper);\n      if (nodeWrapper.previousSibling) nodeWrapper.previousSibling.nextSibling_ = nodeWrapper;\n      if (nodeWrapper.nextSibling) nodeWrapper.nextSibling.previousSibling_ = nodeWrapper;\n      if (parentNodeWrapper.lastChild === nodeWrapper) parentNodeWrapper.lastChild_ = nodeWrapper;\n      if (parentNodeWrapper.firstChild === nodeWrapper) parentNodeWrapper.firstChild_ = nodeWrapper;\n      scope.originalRemoveChild.call(parentNode, node);\n    }\n    var distributedNodesTable = new WeakMap();\n    var destinationInsertionPointsTable = new WeakMap();\n    var rendererForHostTable = new WeakMap();\n    function resetDistributedNodes(insertionPoint) {\n      distributedNodesTable.set(insertionPoint, []);\n    }\n    function getDistributedNodes(insertionPoint) {\n      var rv = distributedNodesTable.get(insertionPoint);\n      if (!rv) distributedNodesTable.set(insertionPoint, rv = []);\n      return rv;\n    }\n    function getChildNodesSnapshot(node) {\n      var result = [], i = 0;\n      for (var child = node.firstChild; child; child = child.nextSibling) {\n        result[i++] = child;\n      }\n      return result;\n    }\n    var request = oneOf(window, [ \"requestAnimationFrame\", \"mozRequestAnimationFrame\", \"webkitRequestAnimationFrame\", \"setTimeout\" ]);\n    var pendingDirtyRenderers = [];\n    var renderTimer;\n    function renderAllPending() {\n      for (var i = 0; i < pendingDirtyRenderers.length; i++) {\n        var renderer = pendingDirtyRenderers[i];\n        var parentRenderer = renderer.parentRenderer;\n        if (parentRenderer && parentRenderer.dirty) continue;\n        renderer.render();\n      }\n      pendingDirtyRenderers = [];\n    }\n    function handleRequestAnimationFrame() {\n      renderTimer = null;\n      renderAllPending();\n    }\n    function getRendererForHost(host) {\n      var renderer = rendererForHostTable.get(host);\n      if (!renderer) {\n        renderer = new ShadowRenderer(host);\n        rendererForHostTable.set(host, renderer);\n      }\n      return renderer;\n    }\n    function getShadowRootAncestor(node) {\n      var root = getTreeScope(node).root;\n      if (root instanceof ShadowRoot) return root;\n      return null;\n    }\n    function getRendererForShadowRoot(shadowRoot) {\n      return getRendererForHost(shadowRoot.host);\n    }\n    var spliceDiff = new ArraySplice();\n    spliceDiff.equals = function(renderNode, rawNode) {\n      return unwrap(renderNode.node) === rawNode;\n    };\n    function RenderNode(node) {\n      this.skip = false;\n      this.node = node;\n      this.childNodes = [];\n    }\n    RenderNode.prototype = {\n      append: function(node) {\n        var rv = new RenderNode(node);\n        this.childNodes.push(rv);\n        return rv;\n      },\n      sync: function(opt_added) {\n        if (this.skip) return;\n        var nodeWrapper = this.node;\n        var newChildren = this.childNodes;\n        var oldChildren = getChildNodesSnapshot(unwrap(nodeWrapper));\n        var added = opt_added || new WeakMap();\n        var splices = spliceDiff.calculateSplices(newChildren, oldChildren);\n        var newIndex = 0, oldIndex = 0;\n        var lastIndex = 0;\n        for (var i = 0; i < splices.length; i++) {\n          var splice = splices[i];\n          for (;lastIndex < splice.index; lastIndex++) {\n            oldIndex++;\n            newChildren[newIndex++].sync(added);\n          }\n          var removedCount = splice.removed.length;\n          for (var j = 0; j < removedCount; j++) {\n            var wrapper = wrap(oldChildren[oldIndex++]);\n            if (!added.get(wrapper)) remove(wrapper);\n          }\n          var addedCount = splice.addedCount;\n          var refNode = oldChildren[oldIndex] && wrap(oldChildren[oldIndex]);\n          for (var j = 0; j < addedCount; j++) {\n            var newChildRenderNode = newChildren[newIndex++];\n            var newChildWrapper = newChildRenderNode.node;\n            insertBefore(nodeWrapper, newChildWrapper, refNode);\n            added.set(newChildWrapper, true);\n            newChildRenderNode.sync(added);\n          }\n          lastIndex += addedCount;\n        }\n        for (var i = lastIndex; i < newChildren.length; i++) {\n          newChildren[i].sync(added);\n        }\n      }\n    };\n    function ShadowRenderer(host) {\n      this.host = host;\n      this.dirty = false;\n      this.invalidateAttributes();\n      this.associateNode(host);\n    }\n    ShadowRenderer.prototype = {\n      render: function(opt_renderNode) {\n        if (!this.dirty) return;\n        this.invalidateAttributes();\n        var host = this.host;\n        this.distribution(host);\n        var renderNode = opt_renderNode || new RenderNode(host);\n        this.buildRenderTree(renderNode, host);\n        var topMostRenderer = !opt_renderNode;\n        if (topMostRenderer) renderNode.sync();\n        this.dirty = false;\n      },\n      get parentRenderer() {\n        return getTreeScope(this.host).renderer;\n      },\n      invalidate: function() {\n        if (!this.dirty) {\n          this.dirty = true;\n          var parentRenderer = this.parentRenderer;\n          if (parentRenderer) parentRenderer.invalidate();\n          pendingDirtyRenderers.push(this);\n          if (renderTimer) return;\n          renderTimer = window[request](handleRequestAnimationFrame, 0);\n        }\n      },\n      distribution: function(root) {\n        this.resetAllSubtrees(root);\n        this.distributionResolution(root);\n      },\n      resetAll: function(node) {\n        if (isInsertionPoint(node)) resetDistributedNodes(node); else resetDestinationInsertionPoints(node);\n        this.resetAllSubtrees(node);\n      },\n      resetAllSubtrees: function(node) {\n        for (var child = node.firstChild; child; child = child.nextSibling) {\n          this.resetAll(child);\n        }\n        if (node.shadowRoot) this.resetAll(node.shadowRoot);\n        if (node.olderShadowRoot) this.resetAll(node.olderShadowRoot);\n      },\n      distributionResolution: function(node) {\n        if (isShadowHost(node)) {\n          var shadowHost = node;\n          var pool = poolPopulation(shadowHost);\n          var shadowTrees = getShadowTrees(shadowHost);\n          for (var i = 0; i < shadowTrees.length; i++) {\n            this.poolDistribution(shadowTrees[i], pool);\n          }\n          for (var i = shadowTrees.length - 1; i >= 0; i--) {\n            var shadowTree = shadowTrees[i];\n            var shadow = getShadowInsertionPoint(shadowTree);\n            if (shadow) {\n              var olderShadowRoot = shadowTree.olderShadowRoot;\n              if (olderShadowRoot) {\n                pool = poolPopulation(olderShadowRoot);\n              }\n              for (var j = 0; j < pool.length; j++) {\n                destributeNodeInto(pool[j], shadow);\n              }\n            }\n            this.distributionResolution(shadowTree);\n          }\n        }\n        for (var child = node.firstChild; child; child = child.nextSibling) {\n          this.distributionResolution(child);\n        }\n      },\n      poolDistribution: function(node, pool) {\n        if (node instanceof HTMLShadowElement) return;\n        if (node instanceof HTMLContentElement) {\n          var content = node;\n          this.updateDependentAttributes(content.getAttribute(\"select\"));\n          var anyDistributed = false;\n          for (var i = 0; i < pool.length; i++) {\n            var node = pool[i];\n            if (!node) continue;\n            if (matches(node, content)) {\n              destributeNodeInto(node, content);\n              pool[i] = undefined;\n              anyDistributed = true;\n            }\n          }\n          if (!anyDistributed) {\n            for (var child = content.firstChild; child; child = child.nextSibling) {\n              destributeNodeInto(child, content);\n            }\n          }\n          return;\n        }\n        for (var child = node.firstChild; child; child = child.nextSibling) {\n          this.poolDistribution(child, pool);\n        }\n      },\n      buildRenderTree: function(renderNode, node) {\n        var children = this.compose(node);\n        for (var i = 0; i < children.length; i++) {\n          var child = children[i];\n          var childRenderNode = renderNode.append(child);\n          this.buildRenderTree(childRenderNode, child);\n        }\n        if (isShadowHost(node)) {\n          var renderer = getRendererForHost(node);\n          renderer.dirty = false;\n        }\n      },\n      compose: function(node) {\n        var children = [];\n        var p = node.shadowRoot || node;\n        for (var child = p.firstChild; child; child = child.nextSibling) {\n          if (isInsertionPoint(child)) {\n            this.associateNode(p);\n            var distributedNodes = getDistributedNodes(child);\n            for (var j = 0; j < distributedNodes.length; j++) {\n              var distributedNode = distributedNodes[j];\n              if (isFinalDestination(child, distributedNode)) children.push(distributedNode);\n            }\n          } else {\n            children.push(child);\n          }\n        }\n        return children;\n      },\n      invalidateAttributes: function() {\n        this.attributes = Object.create(null);\n      },\n      updateDependentAttributes: function(selector) {\n        if (!selector) return;\n        var attributes = this.attributes;\n        if (/\\.\\w+/.test(selector)) attributes[\"class\"] = true;\n        if (/#\\w+/.test(selector)) attributes[\"id\"] = true;\n        selector.replace(/\\[\\s*([^\\s=\\|~\\]]+)/g, function(_, name) {\n          attributes[name] = true;\n        });\n      },\n      dependsOnAttribute: function(name) {\n        return this.attributes[name];\n      },\n      associateNode: function(node) {\n        unsafeUnwrap(node).polymerShadowRenderer_ = this;\n      }\n    };\n    function poolPopulation(node) {\n      var pool = [];\n      for (var child = node.firstChild; child; child = child.nextSibling) {\n        if (isInsertionPoint(child)) {\n          pool.push.apply(pool, getDistributedNodes(child));\n        } else {\n          pool.push(child);\n        }\n      }\n      return pool;\n    }\n    function getShadowInsertionPoint(node) {\n      if (node instanceof HTMLShadowElement) return node;\n      if (node instanceof HTMLContentElement) return null;\n      for (var child = node.firstChild; child; child = child.nextSibling) {\n        var res = getShadowInsertionPoint(child);\n        if (res) return res;\n      }\n      return null;\n    }\n    function destributeNodeInto(child, insertionPoint) {\n      getDistributedNodes(insertionPoint).push(child);\n      var points = destinationInsertionPointsTable.get(child);\n      if (!points) destinationInsertionPointsTable.set(child, [ insertionPoint ]); else points.push(insertionPoint);\n    }\n    function getDestinationInsertionPoints(node) {\n      return destinationInsertionPointsTable.get(node);\n    }\n    function resetDestinationInsertionPoints(node) {\n      destinationInsertionPointsTable.set(node, undefined);\n    }\n    var selectorStartCharRe = /^(:not\\()?[*.#[a-zA-Z_|]/;\n    function matches(node, contentElement) {\n      var select = contentElement.getAttribute(\"select\");\n      if (!select) return true;\n      select = select.trim();\n      if (!select) return true;\n      if (!(node instanceof Element)) return false;\n      if (!selectorStartCharRe.test(select)) return false;\n      try {\n        return node.matches(select);\n      } catch (ex) {\n        return false;\n      }\n    }\n    function isFinalDestination(insertionPoint, node) {\n      var points = getDestinationInsertionPoints(node);\n      return points && points[points.length - 1] === insertionPoint;\n    }\n    function isInsertionPoint(node) {\n      return node instanceof HTMLContentElement || node instanceof HTMLShadowElement;\n    }\n    function isShadowHost(shadowHost) {\n      return shadowHost.shadowRoot;\n    }\n    function getShadowTrees(host) {\n      var trees = [];\n      for (var tree = host.shadowRoot; tree; tree = tree.olderShadowRoot) {\n        trees.push(tree);\n      }\n      return trees;\n    }\n    function render(host) {\n      new ShadowRenderer(host).render();\n    }\n    Node.prototype.invalidateShadowRenderer = function(force) {\n      var renderer = unsafeUnwrap(this).polymerShadowRenderer_;\n      if (renderer) {\n        renderer.invalidate();\n        return true;\n      }\n      return false;\n    };\n    HTMLContentElement.prototype.getDistributedNodes = HTMLShadowElement.prototype.getDistributedNodes = function() {\n      renderAllPending();\n      return getDistributedNodes(this);\n    };\n    Element.prototype.getDestinationInsertionPoints = function() {\n      renderAllPending();\n      return getDestinationInsertionPoints(this) || [];\n    };\n    HTMLContentElement.prototype.nodeIsInserted_ = HTMLShadowElement.prototype.nodeIsInserted_ = function() {\n      this.invalidateShadowRenderer();\n      var shadowRoot = getShadowRootAncestor(this);\n      var renderer;\n      if (shadowRoot) renderer = getRendererForShadowRoot(shadowRoot);\n      unsafeUnwrap(this).polymerShadowRenderer_ = renderer;\n      if (renderer) renderer.invalidate();\n    };\n    scope.getRendererForHost = getRendererForHost;\n    scope.getShadowTrees = getShadowTrees;\n    scope.renderAllPending = renderAllPending;\n    scope.getDestinationInsertionPoints = getDestinationInsertionPoints;\n    scope.visual = {\n      insertBefore: insertBefore,\n      remove: remove\n    };\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var HTMLElement = scope.wrappers.HTMLElement;\n    var assert = scope.assert;\n    var mixin = scope.mixin;\n    var registerWrapper = scope.registerWrapper;\n    var unwrap = scope.unwrap;\n    var wrap = scope.wrap;\n    var elementsWithFormProperty = [ \"HTMLButtonElement\", \"HTMLFieldSetElement\", \"HTMLInputElement\", \"HTMLKeygenElement\", \"HTMLLabelElement\", \"HTMLLegendElement\", \"HTMLObjectElement\", \"HTMLOutputElement\", \"HTMLTextAreaElement\" ];\n    function createWrapperConstructor(name) {\n      if (!window[name]) return;\n      assert(!scope.wrappers[name]);\n      var GeneratedWrapper = function(node) {\n        HTMLElement.call(this, node);\n      };\n      GeneratedWrapper.prototype = Object.create(HTMLElement.prototype);\n      mixin(GeneratedWrapper.prototype, {\n        get form() {\n          return wrap(unwrap(this).form);\n        }\n      });\n      registerWrapper(window[name], GeneratedWrapper, document.createElement(name.slice(4, -7)));\n      scope.wrappers[name] = GeneratedWrapper;\n    }\n    elementsWithFormProperty.forEach(createWrapperConstructor);\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var registerWrapper = scope.registerWrapper;\n    var setWrapper = scope.setWrapper;\n    var unsafeUnwrap = scope.unsafeUnwrap;\n    var unwrap = scope.unwrap;\n    var unwrapIfNeeded = scope.unwrapIfNeeded;\n    var wrap = scope.wrap;\n    var OriginalSelection = window.Selection;\n    function Selection(impl) {\n      setWrapper(impl, this);\n    }\n    Selection.prototype = {\n      get anchorNode() {\n        return wrap(unsafeUnwrap(this).anchorNode);\n      },\n      get focusNode() {\n        return wrap(unsafeUnwrap(this).focusNode);\n      },\n      addRange: function(range) {\n        unsafeUnwrap(this).addRange(unwrapIfNeeded(range));\n      },\n      collapse: function(node, index) {\n        unsafeUnwrap(this).collapse(unwrapIfNeeded(node), index);\n      },\n      containsNode: function(node, allowPartial) {\n        return unsafeUnwrap(this).containsNode(unwrapIfNeeded(node), allowPartial);\n      },\n      getRangeAt: function(index) {\n        return wrap(unsafeUnwrap(this).getRangeAt(index));\n      },\n      removeRange: function(range) {\n        unsafeUnwrap(this).removeRange(unwrap(range));\n      },\n      selectAllChildren: function(node) {\n        unsafeUnwrap(this).selectAllChildren(unwrapIfNeeded(node));\n      },\n      toString: function() {\n        return unsafeUnwrap(this).toString();\n      }\n    };\n    if (OriginalSelection.prototype.extend) {\n      Selection.prototype.extend = function(node, offset) {\n        unsafeUnwrap(this).extend(unwrapIfNeeded(node), offset);\n      };\n    }\n    registerWrapper(window.Selection, Selection, window.getSelection());\n    scope.wrappers.Selection = Selection;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var registerWrapper = scope.registerWrapper;\n    var setWrapper = scope.setWrapper;\n    var unsafeUnwrap = scope.unsafeUnwrap;\n    var unwrapIfNeeded = scope.unwrapIfNeeded;\n    var wrap = scope.wrap;\n    var OriginalTreeWalker = window.TreeWalker;\n    function TreeWalker(impl) {\n      setWrapper(impl, this);\n    }\n    TreeWalker.prototype = {\n      get root() {\n        return wrap(unsafeUnwrap(this).root);\n      },\n      get currentNode() {\n        return wrap(unsafeUnwrap(this).currentNode);\n      },\n      set currentNode(node) {\n        unsafeUnwrap(this).currentNode = unwrapIfNeeded(node);\n      },\n      get filter() {\n        return unsafeUnwrap(this).filter;\n      },\n      parentNode: function() {\n        return wrap(unsafeUnwrap(this).parentNode());\n      },\n      firstChild: function() {\n        return wrap(unsafeUnwrap(this).firstChild());\n      },\n      lastChild: function() {\n        return wrap(unsafeUnwrap(this).lastChild());\n      },\n      previousSibling: function() {\n        return wrap(unsafeUnwrap(this).previousSibling());\n      },\n      previousNode: function() {\n        return wrap(unsafeUnwrap(this).previousNode());\n      },\n      nextNode: function() {\n        return wrap(unsafeUnwrap(this).nextNode());\n      }\n    };\n    registerWrapper(OriginalTreeWalker, TreeWalker);\n    scope.wrappers.TreeWalker = TreeWalker;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var GetElementsByInterface = scope.GetElementsByInterface;\n    var Node = scope.wrappers.Node;\n    var ParentNodeInterface = scope.ParentNodeInterface;\n    var NonElementParentNodeInterface = scope.NonElementParentNodeInterface;\n    var Selection = scope.wrappers.Selection;\n    var SelectorsInterface = scope.SelectorsInterface;\n    var ShadowRoot = scope.wrappers.ShadowRoot;\n    var TreeScope = scope.TreeScope;\n    var cloneNode = scope.cloneNode;\n    var defineWrapGetter = scope.defineWrapGetter;\n    var elementFromPoint = scope.elementFromPoint;\n    var forwardMethodsToWrapper = scope.forwardMethodsToWrapper;\n    var matchesNames = scope.matchesNames;\n    var mixin = scope.mixin;\n    var registerWrapper = scope.registerWrapper;\n    var renderAllPending = scope.renderAllPending;\n    var rewrap = scope.rewrap;\n    var setWrapper = scope.setWrapper;\n    var unsafeUnwrap = scope.unsafeUnwrap;\n    var unwrap = scope.unwrap;\n    var wrap = scope.wrap;\n    var wrapEventTargetMethods = scope.wrapEventTargetMethods;\n    var wrapNodeList = scope.wrapNodeList;\n    var implementationTable = new WeakMap();\n    function Document(node) {\n      Node.call(this, node);\n      this.treeScope_ = new TreeScope(this, null);\n    }\n    Document.prototype = Object.create(Node.prototype);\n    defineWrapGetter(Document, \"documentElement\");\n    defineWrapGetter(Document, \"body\");\n    defineWrapGetter(Document, \"head\");\n    function wrapMethod(name) {\n      var original = document[name];\n      Document.prototype[name] = function() {\n        return wrap(original.apply(unsafeUnwrap(this), arguments));\n      };\n    }\n    [ \"createComment\", \"createDocumentFragment\", \"createElement\", \"createElementNS\", \"createEvent\", \"createEventNS\", \"createRange\", \"createTextNode\" ].forEach(wrapMethod);\n    var originalAdoptNode = document.adoptNode;\n    function adoptNodeNoRemove(node, doc) {\n      originalAdoptNode.call(unsafeUnwrap(doc), unwrap(node));\n      adoptSubtree(node, doc);\n    }\n    function adoptSubtree(node, doc) {\n      if (node.shadowRoot) doc.adoptNode(node.shadowRoot);\n      if (node instanceof ShadowRoot) adoptOlderShadowRoots(node, doc);\n      for (var child = node.firstChild; child; child = child.nextSibling) {\n        adoptSubtree(child, doc);\n      }\n    }\n    function adoptOlderShadowRoots(shadowRoot, doc) {\n      var oldShadowRoot = shadowRoot.olderShadowRoot;\n      if (oldShadowRoot) doc.adoptNode(oldShadowRoot);\n    }\n    var originalGetSelection = document.getSelection;\n    mixin(Document.prototype, {\n      adoptNode: function(node) {\n        if (node.parentNode) node.parentNode.removeChild(node);\n        adoptNodeNoRemove(node, this);\n        return node;\n      },\n      elementFromPoint: function(x, y) {\n        return elementFromPoint(this, this, x, y);\n      },\n      importNode: function(node, deep) {\n        return cloneNode(node, deep, unsafeUnwrap(this));\n      },\n      getSelection: function() {\n        renderAllPending();\n        return new Selection(originalGetSelection.call(unwrap(this)));\n      },\n      getElementsByName: function(name) {\n        return SelectorsInterface.querySelectorAll.call(this, \"[name=\" + JSON.stringify(String(name)) + \"]\");\n      }\n    });\n    var originalCreateTreeWalker = document.createTreeWalker;\n    var TreeWalkerWrapper = scope.wrappers.TreeWalker;\n    Document.prototype.createTreeWalker = function(root, whatToShow, filter, expandEntityReferences) {\n      var newFilter = null;\n      if (filter) {\n        if (filter.acceptNode && typeof filter.acceptNode === \"function\") {\n          newFilter = {\n            acceptNode: function(node) {\n              return filter.acceptNode(wrap(node));\n            }\n          };\n        } else if (typeof filter === \"function\") {\n          newFilter = function(node) {\n            return filter(wrap(node));\n          };\n        }\n      }\n      return new TreeWalkerWrapper(originalCreateTreeWalker.call(unwrap(this), unwrap(root), whatToShow, newFilter, expandEntityReferences));\n    };\n    if (document.registerElement) {\n      var originalRegisterElement = document.registerElement;\n      Document.prototype.registerElement = function(tagName, object) {\n        var prototype, extendsOption;\n        if (object !== undefined) {\n          prototype = object.prototype;\n          extendsOption = object.extends;\n        }\n        if (!prototype) prototype = Object.create(HTMLElement.prototype);\n        if (scope.nativePrototypeTable.get(prototype)) {\n          throw new Error(\"NotSupportedError\");\n        }\n        var proto = Object.getPrototypeOf(prototype);\n        var nativePrototype;\n        var prototypes = [];\n        while (proto) {\n          nativePrototype = scope.nativePrototypeTable.get(proto);\n          if (nativePrototype) break;\n          prototypes.push(proto);\n          proto = Object.getPrototypeOf(proto);\n        }\n        if (!nativePrototype) {\n          throw new Error(\"NotSupportedError\");\n        }\n        var newPrototype = Object.create(nativePrototype);\n        for (var i = prototypes.length - 1; i >= 0; i--) {\n          newPrototype = Object.create(newPrototype);\n        }\n        [ \"createdCallback\", \"attachedCallback\", \"detachedCallback\", \"attributeChangedCallback\" ].forEach(function(name) {\n          var f = prototype[name];\n          if (!f) return;\n          newPrototype[name] = function() {\n            if (!(wrap(this) instanceof CustomElementConstructor)) {\n              rewrap(this);\n            }\n            f.apply(wrap(this), arguments);\n          };\n        });\n        var p = {\n          prototype: newPrototype\n        };\n        if (extendsOption) p.extends = extendsOption;\n        function CustomElementConstructor(node) {\n          if (!node) {\n            if (extendsOption) {\n              return document.createElement(extendsOption, tagName);\n            } else {\n              return document.createElement(tagName);\n            }\n          }\n          setWrapper(node, this);\n        }\n        CustomElementConstructor.prototype = prototype;\n        CustomElementConstructor.prototype.constructor = CustomElementConstructor;\n        scope.constructorTable.set(newPrototype, CustomElementConstructor);\n        scope.nativePrototypeTable.set(prototype, newPrototype);\n        var nativeConstructor = originalRegisterElement.call(unwrap(this), tagName, p);\n        return CustomElementConstructor;\n      };\n      forwardMethodsToWrapper([ window.HTMLDocument || window.Document ], [ \"registerElement\" ]);\n    }\n    forwardMethodsToWrapper([ window.HTMLBodyElement, window.HTMLDocument || window.Document, window.HTMLHeadElement, window.HTMLHtmlElement ], [ \"appendChild\", \"compareDocumentPosition\", \"contains\", \"getElementsByClassName\", \"getElementsByTagName\", \"getElementsByTagNameNS\", \"insertBefore\", \"querySelector\", \"querySelectorAll\", \"removeChild\", \"replaceChild\" ]);\n    forwardMethodsToWrapper([ window.HTMLBodyElement, window.HTMLHeadElement, window.HTMLHtmlElement ], matchesNames);\n    forwardMethodsToWrapper([ window.HTMLDocument || window.Document ], [ \"adoptNode\", \"importNode\", \"contains\", \"createComment\", \"createDocumentFragment\", \"createElement\", \"createElementNS\", \"createEvent\", \"createEventNS\", \"createRange\", \"createTextNode\", \"createTreeWalker\", \"elementFromPoint\", \"getElementById\", \"getElementsByName\", \"getSelection\" ]);\n    mixin(Document.prototype, GetElementsByInterface);\n    mixin(Document.prototype, ParentNodeInterface);\n    mixin(Document.prototype, SelectorsInterface);\n    mixin(Document.prototype, NonElementParentNodeInterface);\n    mixin(Document.prototype, {\n      get implementation() {\n        var implementation = implementationTable.get(this);\n        if (implementation) return implementation;\n        implementation = new DOMImplementation(unwrap(this).implementation);\n        implementationTable.set(this, implementation);\n        return implementation;\n      },\n      get defaultView() {\n        return wrap(unwrap(this).defaultView);\n      }\n    });\n    registerWrapper(window.Document, Document, document.implementation.createHTMLDocument(\"\"));\n    if (window.HTMLDocument) registerWrapper(window.HTMLDocument, Document);\n    wrapEventTargetMethods([ window.HTMLBodyElement, window.HTMLDocument || window.Document, window.HTMLHeadElement ]);\n    function DOMImplementation(impl) {\n      setWrapper(impl, this);\n    }\n    var originalCreateDocument = document.implementation.createDocument;\n    DOMImplementation.prototype.createDocument = function() {\n      arguments[2] = unwrap(arguments[2]);\n      return wrap(originalCreateDocument.apply(unsafeUnwrap(this), arguments));\n    };\n    function wrapImplMethod(constructor, name) {\n      var original = document.implementation[name];\n      constructor.prototype[name] = function() {\n        return wrap(original.apply(unsafeUnwrap(this), arguments));\n      };\n    }\n    function forwardImplMethod(constructor, name) {\n      var original = document.implementation[name];\n      constructor.prototype[name] = function() {\n        return original.apply(unsafeUnwrap(this), arguments);\n      };\n    }\n    wrapImplMethod(DOMImplementation, \"createDocumentType\");\n    wrapImplMethod(DOMImplementation, \"createHTMLDocument\");\n    forwardImplMethod(DOMImplementation, \"hasFeature\");\n    registerWrapper(window.DOMImplementation, DOMImplementation);\n    forwardMethodsToWrapper([ window.DOMImplementation ], [ \"createDocument\", \"createDocumentType\", \"createHTMLDocument\", \"hasFeature\" ]);\n    scope.adoptNodeNoRemove = adoptNodeNoRemove;\n    scope.wrappers.DOMImplementation = DOMImplementation;\n    scope.wrappers.Document = Document;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var EventTarget = scope.wrappers.EventTarget;\n    var Selection = scope.wrappers.Selection;\n    var mixin = scope.mixin;\n    var registerWrapper = scope.registerWrapper;\n    var renderAllPending = scope.renderAllPending;\n    var unwrap = scope.unwrap;\n    var unwrapIfNeeded = scope.unwrapIfNeeded;\n    var wrap = scope.wrap;\n    var OriginalWindow = window.Window;\n    var originalGetComputedStyle = window.getComputedStyle;\n    var originalGetDefaultComputedStyle = window.getDefaultComputedStyle;\n    var originalGetSelection = window.getSelection;\n    function Window(impl) {\n      EventTarget.call(this, impl);\n    }\n    Window.prototype = Object.create(EventTarget.prototype);\n    OriginalWindow.prototype.getComputedStyle = function(el, pseudo) {\n      return wrap(this || window).getComputedStyle(unwrapIfNeeded(el), pseudo);\n    };\n    if (originalGetDefaultComputedStyle) {\n      OriginalWindow.prototype.getDefaultComputedStyle = function(el, pseudo) {\n        return wrap(this || window).getDefaultComputedStyle(unwrapIfNeeded(el), pseudo);\n      };\n    }\n    OriginalWindow.prototype.getSelection = function() {\n      return wrap(this || window).getSelection();\n    };\n    delete window.getComputedStyle;\n    delete window.getDefaultComputedStyle;\n    delete window.getSelection;\n    [ \"addEventListener\", \"removeEventListener\", \"dispatchEvent\" ].forEach(function(name) {\n      OriginalWindow.prototype[name] = function() {\n        var w = wrap(this || window);\n        return w[name].apply(w, arguments);\n      };\n      delete window[name];\n    });\n    mixin(Window.prototype, {\n      getComputedStyle: function(el, pseudo) {\n        renderAllPending();\n        return originalGetComputedStyle.call(unwrap(this), unwrapIfNeeded(el), pseudo);\n      },\n      getSelection: function() {\n        renderAllPending();\n        return new Selection(originalGetSelection.call(unwrap(this)));\n      },\n      get document() {\n        return wrap(unwrap(this).document);\n      }\n    });\n    if (originalGetDefaultComputedStyle) {\n      Window.prototype.getDefaultComputedStyle = function(el, pseudo) {\n        renderAllPending();\n        return originalGetDefaultComputedStyle.call(unwrap(this), unwrapIfNeeded(el), pseudo);\n      };\n    }\n    registerWrapper(OriginalWindow, Window, window);\n    scope.wrappers.Window = Window;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var unwrap = scope.unwrap;\n    var OriginalDataTransfer = window.DataTransfer || window.Clipboard;\n    var OriginalDataTransferSetDragImage = OriginalDataTransfer.prototype.setDragImage;\n    if (OriginalDataTransferSetDragImage) {\n      OriginalDataTransfer.prototype.setDragImage = function(image, x, y) {\n        OriginalDataTransferSetDragImage.call(this, unwrap(image), x, y);\n      };\n    }\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var registerWrapper = scope.registerWrapper;\n    var setWrapper = scope.setWrapper;\n    var unwrap = scope.unwrap;\n    var OriginalFormData = window.FormData;\n    if (!OriginalFormData) return;\n    function FormData(formElement) {\n      var impl;\n      if (formElement instanceof OriginalFormData) {\n        impl = formElement;\n      } else {\n        impl = new OriginalFormData(formElement && unwrap(formElement));\n      }\n      setWrapper(impl, this);\n    }\n    registerWrapper(OriginalFormData, FormData, new OriginalFormData());\n    scope.wrappers.FormData = FormData;\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var unwrapIfNeeded = scope.unwrapIfNeeded;\n    var originalSend = XMLHttpRequest.prototype.send;\n    XMLHttpRequest.prototype.send = function(obj) {\n      return originalSend.call(this, unwrapIfNeeded(obj));\n    };\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    \"use strict\";\n    var isWrapperFor = scope.isWrapperFor;\n    var elements = {\n      a: \"HTMLAnchorElement\",\n      area: \"HTMLAreaElement\",\n      audio: \"HTMLAudioElement\",\n      base: \"HTMLBaseElement\",\n      body: \"HTMLBodyElement\",\n      br: \"HTMLBRElement\",\n      button: \"HTMLButtonElement\",\n      canvas: \"HTMLCanvasElement\",\n      caption: \"HTMLTableCaptionElement\",\n      col: \"HTMLTableColElement\",\n      content: \"HTMLContentElement\",\n      data: \"HTMLDataElement\",\n      datalist: \"HTMLDataListElement\",\n      del: \"HTMLModElement\",\n      dir: \"HTMLDirectoryElement\",\n      div: \"HTMLDivElement\",\n      dl: \"HTMLDListElement\",\n      embed: \"HTMLEmbedElement\",\n      fieldset: \"HTMLFieldSetElement\",\n      font: \"HTMLFontElement\",\n      form: \"HTMLFormElement\",\n      frame: \"HTMLFrameElement\",\n      frameset: \"HTMLFrameSetElement\",\n      h1: \"HTMLHeadingElement\",\n      head: \"HTMLHeadElement\",\n      hr: \"HTMLHRElement\",\n      html: \"HTMLHtmlElement\",\n      iframe: \"HTMLIFrameElement\",\n      img: \"HTMLImageElement\",\n      input: \"HTMLInputElement\",\n      keygen: \"HTMLKeygenElement\",\n      label: \"HTMLLabelElement\",\n      legend: \"HTMLLegendElement\",\n      li: \"HTMLLIElement\",\n      link: \"HTMLLinkElement\",\n      map: \"HTMLMapElement\",\n      marquee: \"HTMLMarqueeElement\",\n      menu: \"HTMLMenuElement\",\n      menuitem: \"HTMLMenuItemElement\",\n      meta: \"HTMLMetaElement\",\n      meter: \"HTMLMeterElement\",\n      object: \"HTMLObjectElement\",\n      ol: \"HTMLOListElement\",\n      optgroup: \"HTMLOptGroupElement\",\n      option: \"HTMLOptionElement\",\n      output: \"HTMLOutputElement\",\n      p: \"HTMLParagraphElement\",\n      param: \"HTMLParamElement\",\n      pre: \"HTMLPreElement\",\n      progress: \"HTMLProgressElement\",\n      q: \"HTMLQuoteElement\",\n      script: \"HTMLScriptElement\",\n      select: \"HTMLSelectElement\",\n      shadow: \"HTMLShadowElement\",\n      source: \"HTMLSourceElement\",\n      span: \"HTMLSpanElement\",\n      style: \"HTMLStyleElement\",\n      table: \"HTMLTableElement\",\n      tbody: \"HTMLTableSectionElement\",\n      template: \"HTMLTemplateElement\",\n      textarea: \"HTMLTextAreaElement\",\n      thead: \"HTMLTableSectionElement\",\n      time: \"HTMLTimeElement\",\n      title: \"HTMLTitleElement\",\n      tr: \"HTMLTableRowElement\",\n      track: \"HTMLTrackElement\",\n      ul: \"HTMLUListElement\",\n      video: \"HTMLVideoElement\"\n    };\n    function overrideConstructor(tagName) {\n      var nativeConstructorName = elements[tagName];\n      var nativeConstructor = window[nativeConstructorName];\n      if (!nativeConstructor) return;\n      var element = document.createElement(tagName);\n      var wrapperConstructor = element.constructor;\n      window[nativeConstructorName] = wrapperConstructor;\n    }\n    Object.keys(elements).forEach(overrideConstructor);\n    Object.getOwnPropertyNames(scope.wrappers).forEach(function(name) {\n      window[name] = scope.wrappers[name];\n    });\n  })(window.ShadowDOMPolyfill);\n  (function(scope) {\n    var ShadowCSS = {\n      strictStyling: false,\n      registry: {},\n      shimStyling: function(root, name, extendsName) {\n        var scopeStyles = this.prepareRoot(root, name, extendsName);\n        var typeExtension = this.isTypeExtension(extendsName);\n        var scopeSelector = this.makeScopeSelector(name, typeExtension);\n        var cssText = stylesToCssText(scopeStyles, true);\n        cssText = this.scopeCssText(cssText, scopeSelector);\n        if (root) {\n          root.shimmedStyle = cssText;\n        }\n        this.addCssToDocument(cssText, name);\n      },\n      shimStyle: function(style, selector) {\n        return this.shimCssText(style.textContent, selector);\n      },\n      shimCssText: function(cssText, selector) {\n        cssText = this.insertDirectives(cssText);\n        return this.scopeCssText(cssText, selector);\n      },\n      makeScopeSelector: function(name, typeExtension) {\n        if (name) {\n          return typeExtension ? \"[is=\" + name + \"]\" : name;\n        }\n        return \"\";\n      },\n      isTypeExtension: function(extendsName) {\n        return extendsName && extendsName.indexOf(\"-\") < 0;\n      },\n      prepareRoot: function(root, name, extendsName) {\n        var def = this.registerRoot(root, name, extendsName);\n        this.replaceTextInStyles(def.rootStyles, this.insertDirectives);\n        this.removeStyles(root, def.rootStyles);\n        if (this.strictStyling) {\n          this.applyScopeToContent(root, name);\n        }\n        return def.scopeStyles;\n      },\n      removeStyles: function(root, styles) {\n        for (var i = 0, l = styles.length, s; i < l && (s = styles[i]); i++) {\n          s.parentNode.removeChild(s);\n        }\n      },\n      registerRoot: function(root, name, extendsName) {\n        var def = this.registry[name] = {\n          root: root,\n          name: name,\n          extendsName: extendsName\n        };\n        var styles = this.findStyles(root);\n        def.rootStyles = styles;\n        def.scopeStyles = def.rootStyles;\n        var extendee = this.registry[def.extendsName];\n        if (extendee) {\n          def.scopeStyles = extendee.scopeStyles.concat(def.scopeStyles);\n        }\n        return def;\n      },\n      findStyles: function(root) {\n        if (!root) {\n          return [];\n        }\n        var styles = root.querySelectorAll(\"style\");\n        return Array.prototype.filter.call(styles, function(s) {\n          return !s.hasAttribute(NO_SHIM_ATTRIBUTE);\n        });\n      },\n      applyScopeToContent: function(root, name) {\n        if (root) {\n          Array.prototype.forEach.call(root.querySelectorAll(\"*\"), function(node) {\n            node.setAttribute(name, \"\");\n          });\n          Array.prototype.forEach.call(root.querySelectorAll(\"template\"), function(template) {\n            this.applyScopeToContent(template.content, name);\n          }, this);\n        }\n      },\n      insertDirectives: function(cssText) {\n        cssText = this.insertPolyfillDirectivesInCssText(cssText);\n        return this.insertPolyfillRulesInCssText(cssText);\n      },\n      insertPolyfillDirectivesInCssText: function(cssText) {\n        cssText = cssText.replace(cssCommentNextSelectorRe, function(match, p1) {\n          return p1.slice(0, -2) + \"{\";\n        });\n        return cssText.replace(cssContentNextSelectorRe, function(match, p1) {\n          return p1 + \" {\";\n        });\n      },\n      insertPolyfillRulesInCssText: function(cssText) {\n        cssText = cssText.replace(cssCommentRuleRe, function(match, p1) {\n          return p1.slice(0, -1);\n        });\n        return cssText.replace(cssContentRuleRe, function(match, p1, p2, p3) {\n          var rule = match.replace(p1, \"\").replace(p2, \"\");\n          return p3 + rule;\n        });\n      },\n      scopeCssText: function(cssText, scopeSelector) {\n        var unscoped = this.extractUnscopedRulesFromCssText(cssText);\n        cssText = this.insertPolyfillHostInCssText(cssText);\n        cssText = this.convertColonHost(cssText);\n        cssText = this.convertColonHostContext(cssText);\n        cssText = this.convertShadowDOMSelectors(cssText);\n        if (scopeSelector) {\n          var self = this, cssText;\n          withCssRules(cssText, function(rules) {\n            cssText = self.scopeRules(rules, scopeSelector);\n          });\n        }\n        cssText = cssText + \"\\n\" + unscoped;\n        return cssText.trim();\n      },\n      extractUnscopedRulesFromCssText: function(cssText) {\n        var r = \"\", m;\n        while (m = cssCommentUnscopedRuleRe.exec(cssText)) {\n          r += m[1].slice(0, -1) + \"\\n\\n\";\n        }\n        while (m = cssContentUnscopedRuleRe.exec(cssText)) {\n          r += m[0].replace(m[2], \"\").replace(m[1], m[3]) + \"\\n\\n\";\n        }\n        return r;\n      },\n      convertColonHost: function(cssText) {\n        return this.convertColonRule(cssText, cssColonHostRe, this.colonHostPartReplacer);\n      },\n      convertColonHostContext: function(cssText) {\n        return this.convertColonRule(cssText, cssColonHostContextRe, this.colonHostContextPartReplacer);\n      },\n      convertColonRule: function(cssText, regExp, partReplacer) {\n        return cssText.replace(regExp, function(m, p1, p2, p3) {\n          p1 = polyfillHostNoCombinator;\n          if (p2) {\n            var parts = p2.split(\",\"), r = [];\n            for (var i = 0, l = parts.length, p; i < l && (p = parts[i]); i++) {\n              p = p.trim();\n              r.push(partReplacer(p1, p, p3));\n            }\n            return r.join(\",\");\n          } else {\n            return p1 + p3;\n          }\n        });\n      },\n      colonHostContextPartReplacer: function(host, part, suffix) {\n        if (part.match(polyfillHost)) {\n          return this.colonHostPartReplacer(host, part, suffix);\n        } else {\n          return host + part + suffix + \", \" + part + \" \" + host + suffix;\n        }\n      },\n      colonHostPartReplacer: function(host, part, suffix) {\n        return host + part.replace(polyfillHost, \"\") + suffix;\n      },\n      convertShadowDOMSelectors: function(cssText) {\n        for (var i = 0; i < shadowDOMSelectorsRe.length; i++) {\n          cssText = cssText.replace(shadowDOMSelectorsRe[i], \" \");\n        }\n        return cssText;\n      },\n      scopeRules: function(cssRules, scopeSelector) {\n        var cssText = \"\";\n        if (cssRules) {\n          Array.prototype.forEach.call(cssRules, function(rule) {\n            if (rule.selectorText && (rule.style && rule.style.cssText !== undefined)) {\n              cssText += this.scopeSelector(rule.selectorText, scopeSelector, this.strictStyling) + \" {\\n\t\";\n              cssText += this.propertiesFromRule(rule) + \"\\n}\\n\\n\";\n            } else if (rule.type === CSSRule.MEDIA_RULE) {\n              cssText += \"@media \" + rule.media.mediaText + \" {\\n\";\n              cssText += this.scopeRules(rule.cssRules, scopeSelector);\n              cssText += \"\\n}\\n\\n\";\n            } else {\n              try {\n                if (rule.cssText) {\n                  cssText += rule.cssText + \"\\n\\n\";\n                }\n              } catch (x) {\n                if (rule.type === CSSRule.KEYFRAMES_RULE && rule.cssRules) {\n                  cssText += this.ieSafeCssTextFromKeyFrameRule(rule);\n                }\n              }\n            }\n          }, this);\n        }\n        return cssText;\n      },\n      ieSafeCssTextFromKeyFrameRule: function(rule) {\n        var cssText = \"@keyframes \" + rule.name + \" {\";\n        Array.prototype.forEach.call(rule.cssRules, function(rule) {\n          cssText += \" \" + rule.keyText + \" {\" + rule.style.cssText + \"}\";\n        });\n        cssText += \" }\";\n        return cssText;\n      },\n      scopeSelector: function(selector, scopeSelector, strict) {\n        var r = [], parts = selector.split(\",\");\n        parts.forEach(function(p) {\n          p = p.trim();\n          if (this.selectorNeedsScoping(p, scopeSelector)) {\n            p = strict && !p.match(polyfillHostNoCombinator) ? this.applyStrictSelectorScope(p, scopeSelector) : this.applySelectorScope(p, scopeSelector);\n          }\n          r.push(p);\n        }, this);\n        return r.join(\", \");\n      },\n      selectorNeedsScoping: function(selector, scopeSelector) {\n        if (Array.isArray(scopeSelector)) {\n          return true;\n        }\n        var re = this.makeScopeMatcher(scopeSelector);\n        return !selector.match(re);\n      },\n      makeScopeMatcher: function(scopeSelector) {\n        scopeSelector = scopeSelector.replace(/\\[/g, \"\\\\[\").replace(/\\]/g, \"\\\\]\");\n        return new RegExp(\"^(\" + scopeSelector + \")\" + selectorReSuffix, \"m\");\n      },\n      applySelectorScope: function(selector, selectorScope) {\n        return Array.isArray(selectorScope) ? this.applySelectorScopeList(selector, selectorScope) : this.applySimpleSelectorScope(selector, selectorScope);\n      },\n      applySelectorScopeList: function(selector, scopeSelectorList) {\n        var r = [];\n        for (var i = 0, s; s = scopeSelectorList[i]; i++) {\n          r.push(this.applySimpleSelectorScope(selector, s));\n        }\n        return r.join(\", \");\n      },\n      applySimpleSelectorScope: function(selector, scopeSelector) {\n        if (selector.match(polyfillHostRe)) {\n          selector = selector.replace(polyfillHostNoCombinator, scopeSelector);\n          return selector.replace(polyfillHostRe, scopeSelector + \" \");\n        } else {\n          return scopeSelector + \" \" + selector;\n        }\n      },\n      applyStrictSelectorScope: function(selector, scopeSelector) {\n        scopeSelector = scopeSelector.replace(/\\[is=([^\\]]*)\\]/g, \"$1\");\n        var splits = [ \" \", \">\", \"+\", \"~\" ], scoped = selector, attrName = \"[\" + scopeSelector + \"]\";\n        splits.forEach(function(sep) {\n          var parts = scoped.split(sep);\n          scoped = parts.map(function(p) {\n            var t = p.trim().replace(polyfillHostRe, \"\");\n            if (t && splits.indexOf(t) < 0 && t.indexOf(attrName) < 0) {\n              p = t.replace(/([^:]*)(:*)(.*)/, \"$1\" + attrName + \"$2$3\");\n            }\n            return p;\n          }).join(sep);\n        });\n        return scoped;\n      },\n      insertPolyfillHostInCssText: function(selector) {\n        return selector.replace(colonHostContextRe, polyfillHostContext).replace(colonHostRe, polyfillHost);\n      },\n      propertiesFromRule: function(rule) {\n        var cssText = rule.style.cssText;\n        if (rule.style.content && !rule.style.content.match(/['\"]+|attr/)) {\n          cssText = cssText.replace(/content:[^;]*;/g, \"content: '\" + rule.style.content + \"';\");\n        }\n        var style = rule.style;\n        for (var i in style) {\n          if (style[i] === \"initial\") {\n            cssText += i + \": initial; \";\n          }\n        }\n        return cssText;\n      },\n      replaceTextInStyles: function(styles, action) {\n        if (styles && action) {\n          if (!(styles instanceof Array)) {\n            styles = [ styles ];\n          }\n          Array.prototype.forEach.call(styles, function(s) {\n            s.textContent = action.call(this, s.textContent);\n          }, this);\n        }\n      },\n      addCssToDocument: function(cssText, name) {\n        if (cssText.match(\"@import\")) {\n          addOwnSheet(cssText, name);\n        } else {\n          addCssToDocument(cssText);\n        }\n      }\n    };\n    var selectorRe = /([^{]*)({[\\s\\S]*?})/gim, cssCommentRe = /\\/\\*[^*]*\\*+([^/*][^*]*\\*+)*\\//gim, cssCommentNextSelectorRe = /\\/\\*\\s*@polyfill ([^*]*\\*+([^/*][^*]*\\*+)*\\/)([^{]*?){/gim, cssContentNextSelectorRe = /polyfill-next-selector[^}]*content\\:[\\s]*?['\"](.*?)['\"][;\\s]*}([^{]*?){/gim, cssCommentRuleRe = /\\/\\*\\s@polyfill-rule([^*]*\\*+([^/*][^*]*\\*+)*)\\//gim, cssContentRuleRe = /(polyfill-rule)[^}]*(content\\:[\\s]*['\"](.*?)['\"])[;\\s]*[^}]*}/gim, cssCommentUnscopedRuleRe = /\\/\\*\\s@polyfill-unscoped-rule([^*]*\\*+([^/*][^*]*\\*+)*)\\//gim, cssContentUnscopedRuleRe = /(polyfill-unscoped-rule)[^}]*(content\\:[\\s]*['\"](.*?)['\"])[;\\s]*[^}]*}/gim, cssPseudoRe = /::(x-[^\\s{,(]*)/gim, cssPartRe = /::part\\(([^)]*)\\)/gim, polyfillHost = \"-shadowcsshost\", polyfillHostContext = \"-shadowcsscontext\", parenSuffix = \")(?:\\\\((\" + \"(?:\\\\([^)(]*\\\\)|[^)(]*)+?\" + \")\\\\))?([^,{]*)\";\n    var cssColonHostRe = new RegExp(\"(\" + polyfillHost + parenSuffix, \"gim\"), cssColonHostContextRe = new RegExp(\"(\" + polyfillHostContext + parenSuffix, \"gim\"), selectorReSuffix = \"([>\\\\s~+[.,{:][\\\\s\\\\S]*)?$\", colonHostRe = /\\:host/gim, colonHostContextRe = /\\:host-context/gim, polyfillHostNoCombinator = polyfillHost + \"-no-combinator\", polyfillHostRe = new RegExp(polyfillHost, \"gim\"), polyfillHostContextRe = new RegExp(polyfillHostContext, \"gim\"), shadowDOMSelectorsRe = [ />>>/g, /::shadow/g, /::content/g, /\\/deep\\//g, /\\/shadow\\//g, /\\/shadow-deep\\//g, /\\^\\^/g, /\\^/g ];\n    function stylesToCssText(styles, preserveComments) {\n      var cssText = \"\";\n      Array.prototype.forEach.call(styles, function(s) {\n        cssText += s.textContent + \"\\n\\n\";\n      });\n      if (!preserveComments) {\n        cssText = cssText.replace(cssCommentRe, \"\");\n      }\n      return cssText;\n    }\n    function cssTextToStyle(cssText) {\n      var style = document.createElement(\"style\");\n      style.textContent = cssText;\n      return style;\n    }\n    function cssToRules(cssText) {\n      var style = cssTextToStyle(cssText);\n      document.head.appendChild(style);\n      var rules = [];\n      if (style.sheet) {\n        try {\n          rules = style.sheet.cssRules;\n        } catch (e) {}\n      } else {\n        console.warn(\"sheet not found\", style);\n      }\n      style.parentNode.removeChild(style);\n      return rules;\n    }\n    var frame = document.createElement(\"iframe\");\n    frame.style.display = \"none\";\n    function initFrame() {\n      frame.initialized = true;\n      document.body.appendChild(frame);\n      var doc = frame.contentDocument;\n      var base = doc.createElement(\"base\");\n      base.href = document.baseURI;\n      doc.head.appendChild(base);\n    }\n    function inFrame(fn) {\n      if (!frame.initialized) {\n        initFrame();\n      }\n      document.body.appendChild(frame);\n      fn(frame.contentDocument);\n      document.body.removeChild(frame);\n    }\n    var isChrome = navigator.userAgent.match(\"Chrome\");\n    function withCssRules(cssText, callback) {\n      if (!callback) {\n        return;\n      }\n      var rules;\n      if (cssText.match(\"@import\") && isChrome) {\n        var style = cssTextToStyle(cssText);\n        inFrame(function(doc) {\n          doc.head.appendChild(style.impl);\n          rules = Array.prototype.slice.call(style.sheet.cssRules, 0);\n          callback(rules);\n        });\n      } else {\n        rules = cssToRules(cssText);\n        callback(rules);\n      }\n    }\n    function rulesToCss(cssRules) {\n      for (var i = 0, css = []; i < cssRules.length; i++) {\n        css.push(cssRules[i].cssText);\n      }\n      return css.join(\"\\n\\n\");\n    }\n    function addCssToDocument(cssText) {\n      if (cssText) {\n        getSheet().appendChild(document.createTextNode(cssText));\n      }\n    }\n    function addOwnSheet(cssText, name) {\n      var style = cssTextToStyle(cssText);\n      style.setAttribute(name, \"\");\n      style.setAttribute(SHIMMED_ATTRIBUTE, \"\");\n      document.head.appendChild(style);\n    }\n    var SHIM_ATTRIBUTE = \"shim-shadowdom\";\n    var SHIMMED_ATTRIBUTE = \"shim-shadowdom-css\";\n    var NO_SHIM_ATTRIBUTE = \"no-shim\";\n    var sheet;\n    function getSheet() {\n      if (!sheet) {\n        sheet = document.createElement(\"style\");\n        sheet.setAttribute(SHIMMED_ATTRIBUTE, \"\");\n        sheet[SHIMMED_ATTRIBUTE] = true;\n      }\n      return sheet;\n    }\n    if (window.ShadowDOMPolyfill) {\n      addCssToDocument(\"style { display: none !important; }\\n\");\n      var doc = ShadowDOMPolyfill.wrap(document);\n      var head = doc.querySelector(\"head\");\n      head.insertBefore(getSheet(), head.childNodes[0]);\n      document.addEventListener(\"DOMContentLoaded\", function() {\n        var urlResolver = scope.urlResolver;\n        if (window.HTMLImports && !HTMLImports.useNative) {\n          var SHIM_SHEET_SELECTOR = \"link[rel=stylesheet]\" + \"[\" + SHIM_ATTRIBUTE + \"]\";\n          var SHIM_STYLE_SELECTOR = \"style[\" + SHIM_ATTRIBUTE + \"]\";\n          HTMLImports.importer.documentPreloadSelectors += \",\" + SHIM_SHEET_SELECTOR;\n          HTMLImports.importer.importsPreloadSelectors += \",\" + SHIM_SHEET_SELECTOR;\n          HTMLImports.parser.documentSelectors = [ HTMLImports.parser.documentSelectors, SHIM_SHEET_SELECTOR, SHIM_STYLE_SELECTOR ].join(\",\");\n          var originalParseGeneric = HTMLImports.parser.parseGeneric;\n          HTMLImports.parser.parseGeneric = function(elt) {\n            if (elt[SHIMMED_ATTRIBUTE]) {\n              return;\n            }\n            var style = elt.__importElement || elt;\n            if (!style.hasAttribute(SHIM_ATTRIBUTE)) {\n              originalParseGeneric.call(this, elt);\n              return;\n            }\n            if (elt.__resource) {\n              style = elt.ownerDocument.createElement(\"style\");\n              style.textContent = elt.__resource;\n            }\n            HTMLImports.path.resolveUrlsInStyle(style, elt.href);\n            style.textContent = ShadowCSS.shimStyle(style);\n            style.removeAttribute(SHIM_ATTRIBUTE, \"\");\n            style.setAttribute(SHIMMED_ATTRIBUTE, \"\");\n            style[SHIMMED_ATTRIBUTE] = true;\n            if (style.parentNode !== head) {\n              if (elt.parentNode === head) {\n                head.replaceChild(style, elt);\n              } else {\n                this.addElementToDocument(style);\n              }\n            }\n            style.__importParsed = true;\n            this.markParsingComplete(elt);\n            this.parseNext();\n          };\n          var hasResource = HTMLImports.parser.hasResource;\n          HTMLImports.parser.hasResource = function(node) {\n            if (node.localName === \"link\" && node.rel === \"stylesheet\" && node.hasAttribute(SHIM_ATTRIBUTE)) {\n              return node.__resource;\n            } else {\n              return hasResource.call(this, node);\n            }\n          };\n        }\n      });\n    }\n    scope.ShadowCSS = ShadowCSS;\n  })(window.WebComponents);\n}\n\n(function(scope) {\n  if (window.ShadowDOMPolyfill) {\n    window.wrap = ShadowDOMPolyfill.wrapIfNeeded;\n    window.unwrap = ShadowDOMPolyfill.unwrapIfNeeded;\n  } else {\n    window.wrap = window.unwrap = function(n) {\n      return n;\n    };\n  }\n})(window.WebComponents);\n\n(function(scope) {\n  \"use strict\";\n  var hasWorkingUrl = false;\n  if (!scope.forceJURL) {\n    try {\n      var u = new URL(\"b\", \"http://a\");\n      u.pathname = \"c%20d\";\n      hasWorkingUrl = u.href === \"http://a/c%20d\";\n    } catch (e) {}\n  }\n  if (hasWorkingUrl) return;\n  var relative = Object.create(null);\n  relative[\"ftp\"] = 21;\n  relative[\"file\"] = 0;\n  relative[\"gopher\"] = 70;\n  relative[\"http\"] = 80;\n  relative[\"https\"] = 443;\n  relative[\"ws\"] = 80;\n  relative[\"wss\"] = 443;\n  var relativePathDotMapping = Object.create(null);\n  relativePathDotMapping[\"%2e\"] = \".\";\n  relativePathDotMapping[\".%2e\"] = \"..\";\n  relativePathDotMapping[\"%2e.\"] = \"..\";\n  relativePathDotMapping[\"%2e%2e\"] = \"..\";\n  function isRelativeScheme(scheme) {\n    return relative[scheme] !== undefined;\n  }\n  function invalid() {\n    clear.call(this);\n    this._isInvalid = true;\n  }\n  function IDNAToASCII(h) {\n    if (\"\" == h) {\n      invalid.call(this);\n    }\n    return h.toLowerCase();\n  }\n  function percentEscape(c) {\n    var unicode = c.charCodeAt(0);\n    if (unicode > 32 && unicode < 127 && [ 34, 35, 60, 62, 63, 96 ].indexOf(unicode) == -1) {\n      return c;\n    }\n    return encodeURIComponent(c);\n  }\n  function percentEscapeQuery(c) {\n    var unicode = c.charCodeAt(0);\n    if (unicode > 32 && unicode < 127 && [ 34, 35, 60, 62, 96 ].indexOf(unicode) == -1) {\n      return c;\n    }\n    return encodeURIComponent(c);\n  }\n  var EOF = undefined, ALPHA = /[a-zA-Z]/, ALPHANUMERIC = /[a-zA-Z0-9\\+\\-\\.]/;\n  function parse(input, stateOverride, base) {\n    function err(message) {\n      errors.push(message);\n    }\n    var state = stateOverride || \"scheme start\", cursor = 0, buffer = \"\", seenAt = false, seenBracket = false, errors = [];\n    loop: while ((input[cursor - 1] != EOF || cursor == 0) && !this._isInvalid) {\n      var c = input[cursor];\n      switch (state) {\n       case \"scheme start\":\n        if (c && ALPHA.test(c)) {\n          buffer += c.toLowerCase();\n          state = \"scheme\";\n        } else if (!stateOverride) {\n          buffer = \"\";\n          state = \"no scheme\";\n          continue;\n        } else {\n          err(\"Invalid scheme.\");\n          break loop;\n        }\n        break;\n\n       case \"scheme\":\n        if (c && ALPHANUMERIC.test(c)) {\n          buffer += c.toLowerCase();\n        } else if (\":\" == c) {\n          this._scheme = buffer;\n          buffer = \"\";\n          if (stateOverride) {\n            break loop;\n          }\n          if (isRelativeScheme(this._scheme)) {\n            this._isRelative = true;\n          }\n          if (\"file\" == this._scheme) {\n            state = \"relative\";\n          } else if (this._isRelative && base && base._scheme == this._scheme) {\n            state = \"relative or authority\";\n          } else if (this._isRelative) {\n            state = \"authority first slash\";\n          } else {\n            state = \"scheme data\";\n          }\n        } else if (!stateOverride) {\n          buffer = \"\";\n          cursor = 0;\n          state = \"no scheme\";\n          continue;\n        } else if (EOF == c) {\n          break loop;\n        } else {\n          err(\"Code point not allowed in scheme: \" + c);\n          break loop;\n        }\n        break;\n\n       case \"scheme data\":\n        if (\"?\" == c) {\n          query = \"?\";\n          state = \"query\";\n        } else if (\"#\" == c) {\n          this._fragment = \"#\";\n          state = \"fragment\";\n        } else {\n          if (EOF != c && \"\t\" != c && \"\\n\" != c && \"\\r\" != c) {\n            this._schemeData += percentEscape(c);\n          }\n        }\n        break;\n\n       case \"no scheme\":\n        if (!base || !isRelativeScheme(base._scheme)) {\n          err(\"Missing scheme.\");\n          invalid.call(this);\n        } else {\n          state = \"relative\";\n          continue;\n        }\n        break;\n\n       case \"relative or authority\":\n        if (\"/\" == c && \"/\" == input[cursor + 1]) {\n          state = \"authority ignore slashes\";\n        } else {\n          err(\"Expected /, got: \" + c);\n          state = \"relative\";\n          continue;\n        }\n        break;\n\n       case \"relative\":\n        this._isRelative = true;\n        if (\"file\" != this._scheme) this._scheme = base._scheme;\n        if (EOF == c) {\n          this._host = base._host;\n          this._port = base._port;\n          this._path = base._path.slice();\n          this._query = base._query;\n          break loop;\n        } else if (\"/\" == c || \"\\\\\" == c) {\n          if (\"\\\\\" == c) err(\"\\\\ is an invalid code point.\");\n          state = \"relative slash\";\n        } else if (\"?\" == c) {\n          this._host = base._host;\n          this._port = base._port;\n          this._path = base._path.slice();\n          this._query = \"?\";\n          state = \"query\";\n        } else if (\"#\" == c) {\n          this._host = base._host;\n          this._port = base._port;\n          this._path = base._path.slice();\n          this._query = base._query;\n          this._fragment = \"#\";\n          state = \"fragment\";\n        } else {\n          var nextC = input[cursor + 1];\n          var nextNextC = input[cursor + 2];\n          if (\"file\" != this._scheme || !ALPHA.test(c) || nextC != \":\" && nextC != \"|\" || EOF != nextNextC && \"/\" != nextNextC && \"\\\\\" != nextNextC && \"?\" != nextNextC && \"#\" != nextNextC) {\n            this._host = base._host;\n            this._port = base._port;\n            this._path = base._path.slice();\n            this._path.pop();\n          }\n          state = \"relative path\";\n          continue;\n        }\n        break;\n\n       case \"relative slash\":\n        if (\"/\" == c || \"\\\\\" == c) {\n          if (\"\\\\\" == c) {\n            err(\"\\\\ is an invalid code point.\");\n          }\n          if (\"file\" == this._scheme) {\n            state = \"file host\";\n          } else {\n            state = \"authority ignore slashes\";\n          }\n        } else {\n          if (\"file\" != this._scheme) {\n            this._host = base._host;\n            this._port = base._port;\n          }\n          state = \"relative path\";\n          continue;\n        }\n        break;\n\n       case \"authority first slash\":\n        if (\"/\" == c) {\n          state = \"authority second slash\";\n        } else {\n          err(\"Expected '/', got: \" + c);\n          state = \"authority ignore slashes\";\n          continue;\n        }\n        break;\n\n       case \"authority second slash\":\n        state = \"authority ignore slashes\";\n        if (\"/\" != c) {\n          err(\"Expected '/', got: \" + c);\n          continue;\n        }\n        break;\n\n       case \"authority ignore slashes\":\n        if (\"/\" != c && \"\\\\\" != c) {\n          state = \"authority\";\n          continue;\n        } else {\n          err(\"Expected authority, got: \" + c);\n        }\n        break;\n\n       case \"authority\":\n        if (\"@\" == c) {\n          if (seenAt) {\n            err(\"@ already seen.\");\n            buffer += \"%40\";\n          }\n          seenAt = true;\n          for (var i = 0; i < buffer.length; i++) {\n            var cp = buffer[i];\n            if (\"\t\" == cp || \"\\n\" == cp || \"\\r\" == cp) {\n              err(\"Invalid whitespace in authority.\");\n              continue;\n            }\n            if (\":\" == cp && null === this._password) {\n              this._password = \"\";\n              continue;\n            }\n            var tempC = percentEscape(cp);\n            null !== this._password ? this._password += tempC : this._username += tempC;\n          }\n          buffer = \"\";\n        } else if (EOF == c || \"/\" == c || \"\\\\\" == c || \"?\" == c || \"#\" == c) {\n          cursor -= buffer.length;\n          buffer = \"\";\n          state = \"host\";\n          continue;\n        } else {\n          buffer += c;\n        }\n        break;\n\n       case \"file host\":\n        if (EOF == c || \"/\" == c || \"\\\\\" == c || \"?\" == c || \"#\" == c) {\n          if (buffer.length == 2 && ALPHA.test(buffer[0]) && (buffer[1] == \":\" || buffer[1] == \"|\")) {\n            state = \"relative path\";\n          } else if (buffer.length == 0) {\n            state = \"relative path start\";\n          } else {\n            this._host = IDNAToASCII.call(this, buffer);\n            buffer = \"\";\n            state = \"relative path start\";\n          }\n          continue;\n        } else if (\"\t\" == c || \"\\n\" == c || \"\\r\" == c) {\n          err(\"Invalid whitespace in file host.\");\n        } else {\n          buffer += c;\n        }\n        break;\n\n       case \"host\":\n       case \"hostname\":\n        if (\":\" == c && !seenBracket) {\n          this._host = IDNAToASCII.call(this, buffer);\n          buffer = \"\";\n          state = \"port\";\n          if (\"hostname\" == stateOverride) {\n            break loop;\n          }\n        } else if (EOF == c || \"/\" == c || \"\\\\\" == c || \"?\" == c || \"#\" == c) {\n          this._host = IDNAToASCII.call(this, buffer);\n          buffer = \"\";\n          state = \"relative path start\";\n          if (stateOverride) {\n            break loop;\n          }\n          continue;\n        } else if (\"\t\" != c && \"\\n\" != c && \"\\r\" != c) {\n          if (\"[\" == c) {\n            seenBracket = true;\n          } else if (\"]\" == c) {\n            seenBracket = false;\n          }\n          buffer += c;\n        } else {\n          err(\"Invalid code point in host/hostname: \" + c);\n        }\n        break;\n\n       case \"port\":\n        if (/[0-9]/.test(c)) {\n          buffer += c;\n        } else if (EOF == c || \"/\" == c || \"\\\\\" == c || \"?\" == c || \"#\" == c || stateOverride) {\n          if (\"\" != buffer) {\n            var temp = parseInt(buffer, 10);\n            if (temp != relative[this._scheme]) {\n              this._port = temp + \"\";\n            }\n            buffer = \"\";\n          }\n          if (stateOverride) {\n            break loop;\n          }\n          state = \"relative path start\";\n          continue;\n        } else if (\"\t\" == c || \"\\n\" == c || \"\\r\" == c) {\n          err(\"Invalid code point in port: \" + c);\n        } else {\n          invalid.call(this);\n        }\n        break;\n\n       case \"relative path start\":\n        if (\"\\\\\" == c) err(\"'\\\\' not allowed in path.\");\n        state = \"relative path\";\n        if (\"/\" != c && \"\\\\\" != c) {\n          continue;\n        }\n        break;\n\n       case \"relative path\":\n        if (EOF == c || \"/\" == c || \"\\\\\" == c || !stateOverride && (\"?\" == c || \"#\" == c)) {\n          if (\"\\\\\" == c) {\n            err(\"\\\\ not allowed in relative path.\");\n          }\n          var tmp;\n          if (tmp = relativePathDotMapping[buffer.toLowerCase()]) {\n            buffer = tmp;\n          }\n          if (\"..\" == buffer) {\n            this._path.pop();\n            if (\"/\" != c && \"\\\\\" != c) {\n              this._path.push(\"\");\n            }\n          } else if (\".\" == buffer && \"/\" != c && \"\\\\\" != c) {\n            this._path.push(\"\");\n          } else if (\".\" != buffer) {\n            if (\"file\" == this._scheme && this._path.length == 0 && buffer.length == 2 && ALPHA.test(buffer[0]) && buffer[1] == \"|\") {\n              buffer = buffer[0] + \":\";\n            }\n            this._path.push(buffer);\n          }\n          buffer = \"\";\n          if (\"?\" == c) {\n            this._query = \"?\";\n            state = \"query\";\n          } else if (\"#\" == c) {\n            this._fragment = \"#\";\n            state = \"fragment\";\n          }\n        } else if (\"\t\" != c && \"\\n\" != c && \"\\r\" != c) {\n          buffer += percentEscape(c);\n        }\n        break;\n\n       case \"query\":\n        if (!stateOverride && \"#\" == c) {\n          this._fragment = \"#\";\n          state = \"fragment\";\n        } else if (EOF != c && \"\t\" != c && \"\\n\" != c && \"\\r\" != c) {\n          this._query += percentEscapeQuery(c);\n        }\n        break;\n\n       case \"fragment\":\n        if (EOF != c && \"\t\" != c && \"\\n\" != c && \"\\r\" != c) {\n          this._fragment += c;\n        }\n        break;\n      }\n      cursor++;\n    }\n  }\n  function clear() {\n    this._scheme = \"\";\n    this._schemeData = \"\";\n    this._username = \"\";\n    this._password = null;\n    this._host = \"\";\n    this._port = \"\";\n    this._path = [];\n    this._query = \"\";\n    this._fragment = \"\";\n    this._isInvalid = false;\n    this._isRelative = false;\n  }\n  function jURL(url, base) {\n    if (base !== undefined && !(base instanceof jURL)) base = new jURL(String(base));\n    this._url = url;\n    clear.call(this);\n    var input = url.replace(/^[ \\t\\r\\n\\f]+|[ \\t\\r\\n\\f]+$/g, \"\");\n    parse.call(this, input, null, base);\n  }\n  jURL.prototype = {\n    toString: function() {\n      return this.href;\n    },\n    get href() {\n      if (this._isInvalid) return this._url;\n      var authority = \"\";\n      if (\"\" != this._username || null != this._password) {\n        authority = this._username + (null != this._password ? \":\" + this._password : \"\") + \"@\";\n      }\n      return this.protocol + (this._isRelative ? \"//\" + authority + this.host : \"\") + this.pathname + this._query + this._fragment;\n    },\n    set href(href) {\n      clear.call(this);\n      parse.call(this, href);\n    },\n    get protocol() {\n      return this._scheme + \":\";\n    },\n    set protocol(protocol) {\n      if (this._isInvalid) return;\n      parse.call(this, protocol + \":\", \"scheme start\");\n    },\n    get host() {\n      return this._isInvalid ? \"\" : this._port ? this._host + \":\" + this._port : this._host;\n    },\n    set host(host) {\n      if (this._isInvalid || !this._isRelative) return;\n      parse.call(this, host, \"host\");\n    },\n    get hostname() {\n      return this._host;\n    },\n    set hostname(hostname) {\n      if (this._isInvalid || !this._isRelative) return;\n      parse.call(this, hostname, \"hostname\");\n    },\n    get port() {\n      return this._port;\n    },\n    set port(port) {\n      if (this._isInvalid || !this._isRelative) return;\n      parse.call(this, port, \"port\");\n    },\n    get pathname() {\n      return this._isInvalid ? \"\" : this._isRelative ? \"/\" + this._path.join(\"/\") : this._schemeData;\n    },\n    set pathname(pathname) {\n      if (this._isInvalid || !this._isRelative) return;\n      this._path = [];\n      parse.call(this, pathname, \"relative path start\");\n    },\n    get search() {\n      return this._isInvalid || !this._query || \"?\" == this._query ? \"\" : this._query;\n    },\n    set search(search) {\n      if (this._isInvalid || !this._isRelative) return;\n      this._query = \"?\";\n      if (\"?\" == search[0]) search = search.slice(1);\n      parse.call(this, search, \"query\");\n    },\n    get hash() {\n      return this._isInvalid || !this._fragment || \"#\" == this._fragment ? \"\" : this._fragment;\n    },\n    set hash(hash) {\n      if (this._isInvalid) return;\n      this._fragment = \"#\";\n      if (\"#\" == hash[0]) hash = hash.slice(1);\n      parse.call(this, hash, \"fragment\");\n    },\n    get origin() {\n      var host;\n      if (this._isInvalid || !this._scheme) {\n        return \"\";\n      }\n      switch (this._scheme) {\n       case \"data\":\n       case \"file\":\n       case \"javascript\":\n       case \"mailto\":\n        return \"null\";\n      }\n      host = this.host;\n      if (!host) {\n        return \"\";\n      }\n      return this._scheme + \"://\" + host;\n    }\n  };\n  var OriginalURL = scope.URL;\n  if (OriginalURL) {\n    jURL.createObjectURL = function(blob) {\n      return OriginalURL.createObjectURL.apply(OriginalURL, arguments);\n    };\n    jURL.revokeObjectURL = function(url) {\n      OriginalURL.revokeObjectURL(url);\n    };\n  }\n  scope.URL = jURL;\n})(this);\n\n(function(global) {\n  var registrationsTable = new WeakMap();\n  var setImmediate;\n  if (/Trident|Edge/.test(navigator.userAgent)) {\n    setImmediate = setTimeout;\n  } else if (window.setImmediate) {\n    setImmediate = window.setImmediate;\n  } else {\n    var setImmediateQueue = [];\n    var sentinel = String(Math.random());\n    window.addEventListener(\"message\", function(e) {\n      if (e.data === sentinel) {\n        var queue = setImmediateQueue;\n        setImmediateQueue = [];\n        queue.forEach(function(func) {\n          func();\n        });\n      }\n    });\n    setImmediate = function(func) {\n      setImmediateQueue.push(func);\n      window.postMessage(sentinel, \"*\");\n    };\n  }\n  var isScheduled = false;\n  var scheduledObservers = [];\n  function scheduleCallback(observer) {\n    scheduledObservers.push(observer);\n    if (!isScheduled) {\n      isScheduled = true;\n      setImmediate(dispatchCallbacks);\n    }\n  }\n  function wrapIfNeeded(node) {\n    return window.ShadowDOMPolyfill && window.ShadowDOMPolyfill.wrapIfNeeded(node) || node;\n  }\n  function dispatchCallbacks() {\n    isScheduled = false;\n    var observers = scheduledObservers;\n    scheduledObservers = [];\n    observers.sort(function(o1, o2) {\n      return o1.uid_ - o2.uid_;\n    });\n    var anyNonEmpty = false;\n    observers.forEach(function(observer) {\n      var queue = observer.takeRecords();\n      removeTransientObserversFor(observer);\n      if (queue.length) {\n        observer.callback_(queue, observer);\n        anyNonEmpty = true;\n      }\n    });\n    if (anyNonEmpty) dispatchCallbacks();\n  }\n  function removeTransientObserversFor(observer) {\n    observer.nodes_.forEach(function(node) {\n      var registrations = registrationsTable.get(node);\n      if (!registrations) return;\n      registrations.forEach(function(registration) {\n        if (registration.observer === observer) registration.removeTransientObservers();\n      });\n    });\n  }\n  function forEachAncestorAndObserverEnqueueRecord(target, callback) {\n    for (var node = target; node; node = node.parentNode) {\n      var registrations = registrationsTable.get(node);\n      if (registrations) {\n        for (var j = 0; j < registrations.length; j++) {\n          var registration = registrations[j];\n          var options = registration.options;\n          if (node !== target && !options.subtree) continue;\n          var record = callback(options);\n          if (record) registration.enqueue(record);\n        }\n      }\n    }\n  }\n  var uidCounter = 0;\n  function JsMutationObserver(callback) {\n    this.callback_ = callback;\n    this.nodes_ = [];\n    this.records_ = [];\n    this.uid_ = ++uidCounter;\n  }\n  JsMutationObserver.prototype = {\n    observe: function(target, options) {\n      target = wrapIfNeeded(target);\n      if (!options.childList && !options.attributes && !options.characterData || options.attributeOldValue && !options.attributes || options.attributeFilter && options.attributeFilter.length && !options.attributes || options.characterDataOldValue && !options.characterData) {\n        throw new SyntaxError();\n      }\n      var registrations = registrationsTable.get(target);\n      if (!registrations) registrationsTable.set(target, registrations = []);\n      var registration;\n      for (var i = 0; i < registrations.length; i++) {\n        if (registrations[i].observer === this) {\n          registration = registrations[i];\n          registration.removeListeners();\n          registration.options = options;\n          break;\n        }\n      }\n      if (!registration) {\n        registration = new Registration(this, target, options);\n        registrations.push(registration);\n        this.nodes_.push(target);\n      }\n      registration.addListeners();\n    },\n    disconnect: function() {\n      this.nodes_.forEach(function(node) {\n        var registrations = registrationsTable.get(node);\n        for (var i = 0; i < registrations.length; i++) {\n          var registration = registrations[i];\n          if (registration.observer === this) {\n            registration.removeListeners();\n            registrations.splice(i, 1);\n            break;\n          }\n        }\n      }, this);\n      this.records_ = [];\n    },\n    takeRecords: function() {\n      var copyOfRecords = this.records_;\n      this.records_ = [];\n      return copyOfRecords;\n    }\n  };\n  function MutationRecord(type, target) {\n    this.type = type;\n    this.target = target;\n    this.addedNodes = [];\n    this.removedNodes = [];\n    this.previousSibling = null;\n    this.nextSibling = null;\n    this.attributeName = null;\n    this.attributeNamespace = null;\n    this.oldValue = null;\n  }\n  function copyMutationRecord(original) {\n    var record = new MutationRecord(original.type, original.target);\n    record.addedNodes = original.addedNodes.slice();\n    record.removedNodes = original.removedNodes.slice();\n    record.previousSibling = original.previousSibling;\n    record.nextSibling = original.nextSibling;\n    record.attributeName = original.attributeName;\n    record.attributeNamespace = original.attributeNamespace;\n    record.oldValue = original.oldValue;\n    return record;\n  }\n  var currentRecord, recordWithOldValue;\n  function getRecord(type, target) {\n    return currentRecord = new MutationRecord(type, target);\n  }\n  function getRecordWithOldValue(oldValue) {\n    if (recordWithOldValue) return recordWithOldValue;\n    recordWithOldValue = copyMutationRecord(currentRecord);\n    recordWithOldValue.oldValue = oldValue;\n    return recordWithOldValue;\n  }\n  function clearRecords() {\n    currentRecord = recordWithOldValue = undefined;\n  }\n  function recordRepresentsCurrentMutation(record) {\n    return record === recordWithOldValue || record === currentRecord;\n  }\n  function selectRecord(lastRecord, newRecord) {\n    if (lastRecord === newRecord) return lastRecord;\n    if (recordWithOldValue && recordRepresentsCurrentMutation(lastRecord)) return recordWithOldValue;\n    return null;\n  }\n  function Registration(observer, target, options) {\n    this.observer = observer;\n    this.target = target;\n    this.options = options;\n    this.transientObservedNodes = [];\n  }\n  Registration.prototype = {\n    enqueue: function(record) {\n      var records = this.observer.records_;\n      var length = records.length;\n      if (records.length > 0) {\n        var lastRecord = records[length - 1];\n        var recordToReplaceLast = selectRecord(lastRecord, record);\n        if (recordToReplaceLast) {\n          records[length - 1] = recordToReplaceLast;\n          return;\n        }\n      } else {\n        scheduleCallback(this.observer);\n      }\n      records[length] = record;\n    },\n    addListeners: function() {\n      this.addListeners_(this.target);\n    },\n    addListeners_: function(node) {\n      var options = this.options;\n      if (options.attributes) node.addEventListener(\"DOMAttrModified\", this, true);\n      if (options.characterData) node.addEventListener(\"DOMCharacterDataModified\", this, true);\n      if (options.childList) node.addEventListener(\"DOMNodeInserted\", this, true);\n      if (options.childList || options.subtree) node.addEventListener(\"DOMNodeRemoved\", this, true);\n    },\n    removeListeners: function() {\n      this.removeListeners_(this.target);\n    },\n    removeListeners_: function(node) {\n      var options = this.options;\n      if (options.attributes) node.removeEventListener(\"DOMAttrModified\", this, true);\n      if (options.characterData) node.removeEventListener(\"DOMCharacterDataModified\", this, true);\n      if (options.childList) node.removeEventListener(\"DOMNodeInserted\", this, true);\n      if (options.childList || options.subtree) node.removeEventListener(\"DOMNodeRemoved\", this, true);\n    },\n    addTransientObserver: function(node) {\n      if (node === this.target) return;\n      this.addListeners_(node);\n      this.transientObservedNodes.push(node);\n      var registrations = registrationsTable.get(node);\n      if (!registrations) registrationsTable.set(node, registrations = []);\n      registrations.push(this);\n    },\n    removeTransientObservers: function() {\n      var transientObservedNodes = this.transientObservedNodes;\n      this.transientObservedNodes = [];\n      transientObservedNodes.forEach(function(node) {\n        this.removeListeners_(node);\n        var registrations = registrationsTable.get(node);\n        for (var i = 0; i < registrations.length; i++) {\n          if (registrations[i] === this) {\n            registrations.splice(i, 1);\n            break;\n          }\n        }\n      }, this);\n    },\n    handleEvent: function(e) {\n      e.stopImmediatePropagation();\n      switch (e.type) {\n       case \"DOMAttrModified\":\n        var name = e.attrName;\n        var namespace = e.relatedNode.namespaceURI;\n        var target = e.target;\n        var record = new getRecord(\"attributes\", target);\n        record.attributeName = name;\n        record.attributeNamespace = namespace;\n        var oldValue = e.attrChange === MutationEvent.ADDITION ? null : e.prevValue;\n        forEachAncestorAndObserverEnqueueRecord(target, function(options) {\n          if (!options.attributes) return;\n          if (options.attributeFilter && options.attributeFilter.length && options.attributeFilter.indexOf(name) === -1 && options.attributeFilter.indexOf(namespace) === -1) {\n            return;\n          }\n          if (options.attributeOldValue) return getRecordWithOldValue(oldValue);\n          return record;\n        });\n        break;\n\n       case \"DOMCharacterDataModified\":\n        var target = e.target;\n        var record = getRecord(\"characterData\", target);\n        var oldValue = e.prevValue;\n        forEachAncestorAndObserverEnqueueRecord(target, function(options) {\n          if (!options.characterData) return;\n          if (options.characterDataOldValue) return getRecordWithOldValue(oldValue);\n          return record;\n        });\n        break;\n\n       case \"DOMNodeRemoved\":\n        this.addTransientObserver(e.target);\n\n       case \"DOMNodeInserted\":\n        var changedNode = e.target;\n        var addedNodes, removedNodes;\n        if (e.type === \"DOMNodeInserted\") {\n          addedNodes = [ changedNode ];\n          removedNodes = [];\n        } else {\n          addedNodes = [];\n          removedNodes = [ changedNode ];\n        }\n        var previousSibling = changedNode.previousSibling;\n        var nextSibling = changedNode.nextSibling;\n        var record = getRecord(\"childList\", e.target.parentNode);\n        record.addedNodes = addedNodes;\n        record.removedNodes = removedNodes;\n        record.previousSibling = previousSibling;\n        record.nextSibling = nextSibling;\n        forEachAncestorAndObserverEnqueueRecord(e.relatedNode, function(options) {\n          if (!options.childList) return;\n          return record;\n        });\n      }\n      clearRecords();\n    }\n  };\n  global.JsMutationObserver = JsMutationObserver;\n  if (!global.MutationObserver) global.MutationObserver = JsMutationObserver;\n})(this);\n\nwindow.HTMLImports = window.HTMLImports || {\n  flags: {}\n};\n\n(function(scope) {\n  var IMPORT_LINK_TYPE = \"import\";\n  var useNative = Boolean(IMPORT_LINK_TYPE in document.createElement(\"link\"));\n  var hasShadowDOMPolyfill = Boolean(window.ShadowDOMPolyfill);\n  var wrap = function(node) {\n    return hasShadowDOMPolyfill ? ShadowDOMPolyfill.wrapIfNeeded(node) : node;\n  };\n  var rootDocument = wrap(document);\n  var currentScriptDescriptor = {\n    get: function() {\n      var script = HTMLImports.currentScript || document.currentScript || (document.readyState !== \"complete\" ? document.scripts[document.scripts.length - 1] : null);\n      return wrap(script);\n    },\n    configurable: true\n  };\n  Object.defineProperty(document, \"_currentScript\", currentScriptDescriptor);\n  Object.defineProperty(rootDocument, \"_currentScript\", currentScriptDescriptor);\n  var isIE = /Trident|Edge/.test(navigator.userAgent);\n  function whenReady(callback, doc) {\n    doc = doc || rootDocument;\n    whenDocumentReady(function() {\n      watchImportsLoad(callback, doc);\n    }, doc);\n  }\n  var requiredReadyState = isIE ? \"complete\" : \"interactive\";\n  var READY_EVENT = \"readystatechange\";\n  function isDocumentReady(doc) {\n    return doc.readyState === \"complete\" || doc.readyState === requiredReadyState;\n  }\n  function whenDocumentReady(callback, doc) {\n    if (!isDocumentReady(doc)) {\n      var checkReady = function() {\n        if (doc.readyState === \"complete\" || doc.readyState === requiredReadyState) {\n          doc.removeEventListener(READY_EVENT, checkReady);\n          whenDocumentReady(callback, doc);\n        }\n      };\n      doc.addEventListener(READY_EVENT, checkReady);\n    } else if (callback) {\n      callback();\n    }\n  }\n  function markTargetLoaded(event) {\n    event.target.__loaded = true;\n  }\n  function watchImportsLoad(callback, doc) {\n    var imports = doc.querySelectorAll(\"link[rel=import]\");\n    var parsedCount = 0, importCount = imports.length, newImports = [], errorImports = [];\n    function checkDone() {\n      if (parsedCount == importCount && callback) {\n        callback({\n          allImports: imports,\n          loadedImports: newImports,\n          errorImports: errorImports\n        });\n      }\n    }\n    function loadedImport(e) {\n      markTargetLoaded(e);\n      newImports.push(this);\n      parsedCount++;\n      checkDone();\n    }\n    function errorLoadingImport(e) {\n      errorImports.push(this);\n      parsedCount++;\n      checkDone();\n    }\n    if (importCount) {\n      for (var i = 0, imp; i < importCount && (imp = imports[i]); i++) {\n        if (isImportLoaded(imp)) {\n          parsedCount++;\n          checkDone();\n        } else {\n          imp.addEventListener(\"load\", loadedImport);\n          imp.addEventListener(\"error\", errorLoadingImport);\n        }\n      }\n    } else {\n      checkDone();\n    }\n  }\n  function isImportLoaded(link) {\n    return useNative ? link.__loaded || link.import && link.import.readyState !== \"loading\" : link.__importParsed;\n  }\n  if (useNative) {\n    new MutationObserver(function(mxns) {\n      for (var i = 0, l = mxns.length, m; i < l && (m = mxns[i]); i++) {\n        if (m.addedNodes) {\n          handleImports(m.addedNodes);\n        }\n      }\n    }).observe(document.head, {\n      childList: true\n    });\n    function handleImports(nodes) {\n      for (var i = 0, l = nodes.length, n; i < l && (n = nodes[i]); i++) {\n        if (isImport(n)) {\n          handleImport(n);\n        }\n      }\n    }\n    function isImport(element) {\n      return element.localName === \"link\" && element.rel === \"import\";\n    }\n    function handleImport(element) {\n      var loaded = element.import;\n      if (loaded) {\n        markTargetLoaded({\n          target: element\n        });\n      } else {\n        element.addEventListener(\"load\", markTargetLoaded);\n        element.addEventListener(\"error\", markTargetLoaded);\n      }\n    }\n    (function() {\n      if (document.readyState === \"loading\") {\n        var imports = document.querySelectorAll(\"link[rel=import]\");\n        for (var i = 0, l = imports.length, imp; i < l && (imp = imports[i]); i++) {\n          handleImport(imp);\n        }\n      }\n    })();\n  }\n  whenReady(function(detail) {\n    HTMLImports.ready = true;\n    HTMLImports.readyTime = new Date().getTime();\n    var evt = rootDocument.createEvent(\"CustomEvent\");\n    evt.initCustomEvent(\"HTMLImportsLoaded\", true, true, detail);\n    rootDocument.dispatchEvent(evt);\n  });\n  scope.IMPORT_LINK_TYPE = IMPORT_LINK_TYPE;\n  scope.useNative = useNative;\n  scope.rootDocument = rootDocument;\n  scope.whenReady = whenReady;\n  scope.isIE = isIE;\n})(HTMLImports);\n\n(function(scope) {\n  var modules = [];\n  var addModule = function(module) {\n    modules.push(module);\n  };\n  var initializeModules = function() {\n    modules.forEach(function(module) {\n      module(scope);\n    });\n  };\n  scope.addModule = addModule;\n  scope.initializeModules = initializeModules;\n})(HTMLImports);\n\nHTMLImports.addModule(function(scope) {\n  var CSS_URL_REGEXP = /(url\\()([^)]*)(\\))/g;\n  var CSS_IMPORT_REGEXP = /(@import[\\s]+(?!url\\())([^;]*)(;)/g;\n  var path = {\n    resolveUrlsInStyle: function(style, linkUrl) {\n      var doc = style.ownerDocument;\n      var resolver = doc.createElement(\"a\");\n      style.textContent = this.resolveUrlsInCssText(style.textContent, linkUrl, resolver);\n      return style;\n    },\n    resolveUrlsInCssText: function(cssText, linkUrl, urlObj) {\n      var r = this.replaceUrls(cssText, urlObj, linkUrl, CSS_URL_REGEXP);\n      r = this.replaceUrls(r, urlObj, linkUrl, CSS_IMPORT_REGEXP);\n      return r;\n    },\n    replaceUrls: function(text, urlObj, linkUrl, regexp) {\n      return text.replace(regexp, function(m, pre, url, post) {\n        var urlPath = url.replace(/[\"']/g, \"\");\n        if (linkUrl) {\n          urlPath = new URL(urlPath, linkUrl).href;\n        }\n        urlObj.href = urlPath;\n        urlPath = urlObj.href;\n        return pre + \"'\" + urlPath + \"'\" + post;\n      });\n    }\n  };\n  scope.path = path;\n});\n\nHTMLImports.addModule(function(scope) {\n  var xhr = {\n    async: true,\n    ok: function(request) {\n      return request.status >= 200 && request.status < 300 || request.status === 304 || request.status === 0;\n    },\n    load: function(url, next, nextContext) {\n      var request = new XMLHttpRequest();\n      if (scope.flags.debug || scope.flags.bust) {\n        url += \"?\" + Math.random();\n      }\n      request.open(\"GET\", url, xhr.async);\n      request.addEventListener(\"readystatechange\", function(e) {\n        if (request.readyState === 4) {\n          var locationHeader = request.getResponseHeader(\"Location\");\n          var redirectedUrl = null;\n          if (locationHeader) {\n            var redirectedUrl = locationHeader.substr(0, 1) === \"/\" ? location.origin + locationHeader : locationHeader;\n          }\n          next.call(nextContext, !xhr.ok(request) && request, request.response || request.responseText, redirectedUrl);\n        }\n      });\n      request.send();\n      return request;\n    },\n    loadDocument: function(url, next, nextContext) {\n      this.load(url, next, nextContext).responseType = \"document\";\n    }\n  };\n  scope.xhr = xhr;\n});\n\nHTMLImports.addModule(function(scope) {\n  var xhr = scope.xhr;\n  var flags = scope.flags;\n  var Loader = function(onLoad, onComplete) {\n    this.cache = {};\n    this.onload = onLoad;\n    this.oncomplete = onComplete;\n    this.inflight = 0;\n    this.pending = {};\n  };\n  Loader.prototype = {\n    addNodes: function(nodes) {\n      this.inflight += nodes.length;\n      for (var i = 0, l = nodes.length, n; i < l && (n = nodes[i]); i++) {\n        this.require(n);\n      }\n      this.checkDone();\n    },\n    addNode: function(node) {\n      this.inflight++;\n      this.require(node);\n      this.checkDone();\n    },\n    require: function(elt) {\n      var url = elt.src || elt.href;\n      elt.__nodeUrl = url;\n      if (!this.dedupe(url, elt)) {\n        this.fetch(url, elt);\n      }\n    },\n    dedupe: function(url, elt) {\n      if (this.pending[url]) {\n        this.pending[url].push(elt);\n        return true;\n      }\n      var resource;\n      if (this.cache[url]) {\n        this.onload(url, elt, this.cache[url]);\n        this.tail();\n        return true;\n      }\n      this.pending[url] = [ elt ];\n      return false;\n    },\n    fetch: function(url, elt) {\n      flags.load && console.log(\"fetch\", url, elt);\n      if (!url) {\n        setTimeout(function() {\n          this.receive(url, elt, {\n            error: \"href must be specified\"\n          }, null);\n        }.bind(this), 0);\n      } else if (url.match(/^data:/)) {\n        var pieces = url.split(\",\");\n        var header = pieces[0];\n        var body = pieces[1];\n        if (header.indexOf(\";base64\") > -1) {\n          body = atob(body);\n        } else {\n          body = decodeURIComponent(body);\n        }\n        setTimeout(function() {\n          this.receive(url, elt, null, body);\n        }.bind(this), 0);\n      } else {\n        var receiveXhr = function(err, resource, redirectedUrl) {\n          this.receive(url, elt, err, resource, redirectedUrl);\n        }.bind(this);\n        xhr.load(url, receiveXhr);\n      }\n    },\n    receive: function(url, elt, err, resource, redirectedUrl) {\n      this.cache[url] = resource;\n      var $p = this.pending[url];\n      for (var i = 0, l = $p.length, p; i < l && (p = $p[i]); i++) {\n        this.onload(url, p, resource, err, redirectedUrl);\n        this.tail();\n      }\n      this.pending[url] = null;\n    },\n    tail: function() {\n      --this.inflight;\n      this.checkDone();\n    },\n    checkDone: function() {\n      if (!this.inflight) {\n        this.oncomplete();\n      }\n    }\n  };\n  scope.Loader = Loader;\n});\n\nHTMLImports.addModule(function(scope) {\n  var Observer = function(addCallback) {\n    this.addCallback = addCallback;\n    this.mo = new MutationObserver(this.handler.bind(this));\n  };\n  Observer.prototype = {\n    handler: function(mutations) {\n      for (var i = 0, l = mutations.length, m; i < l && (m = mutations[i]); i++) {\n        if (m.type === \"childList\" && m.addedNodes.length) {\n          this.addedNodes(m.addedNodes);\n        }\n      }\n    },\n    addedNodes: function(nodes) {\n      if (this.addCallback) {\n        this.addCallback(nodes);\n      }\n      for (var i = 0, l = nodes.length, n, loading; i < l && (n = nodes[i]); i++) {\n        if (n.children && n.children.length) {\n          this.addedNodes(n.children);\n        }\n      }\n    },\n    observe: function(root) {\n      this.mo.observe(root, {\n        childList: true,\n        subtree: true\n      });\n    }\n  };\n  scope.Observer = Observer;\n});\n\nHTMLImports.addModule(function(scope) {\n  var path = scope.path;\n  var rootDocument = scope.rootDocument;\n  var flags = scope.flags;\n  var isIE = scope.isIE;\n  var IMPORT_LINK_TYPE = scope.IMPORT_LINK_TYPE;\n  var IMPORT_SELECTOR = \"link[rel=\" + IMPORT_LINK_TYPE + \"]\";\n  var importParser = {\n    documentSelectors: IMPORT_SELECTOR,\n    importsSelectors: [ IMPORT_SELECTOR, \"link[rel=stylesheet]\", \"style\", \"script:not([type])\", 'script[type=\"text/javascript\"]' ].join(\",\"),\n    map: {\n      link: \"parseLink\",\n      script: \"parseScript\",\n      style: \"parseStyle\"\n    },\n    dynamicElements: [],\n    parseNext: function() {\n      var next = this.nextToParse();\n      if (next) {\n        this.parse(next);\n      }\n    },\n    parse: function(elt) {\n      if (this.isParsed(elt)) {\n        flags.parse && console.log(\"[%s] is already parsed\", elt.localName);\n        return;\n      }\n      var fn = this[this.map[elt.localName]];\n      if (fn) {\n        this.markParsing(elt);\n        fn.call(this, elt);\n      }\n    },\n    parseDynamic: function(elt, quiet) {\n      this.dynamicElements.push(elt);\n      if (!quiet) {\n        this.parseNext();\n      }\n    },\n    markParsing: function(elt) {\n      flags.parse && console.log(\"parsing\", elt);\n      this.parsingElement = elt;\n    },\n    markParsingComplete: function(elt) {\n      elt.__importParsed = true;\n      this.markDynamicParsingComplete(elt);\n      if (elt.__importElement) {\n        elt.__importElement.__importParsed = true;\n        this.markDynamicParsingComplete(elt.__importElement);\n      }\n      this.parsingElement = null;\n      flags.parse && console.log(\"completed\", elt);\n    },\n    markDynamicParsingComplete: function(elt) {\n      var i = this.dynamicElements.indexOf(elt);\n      if (i >= 0) {\n        this.dynamicElements.splice(i, 1);\n      }\n    },\n    parseImport: function(elt) {\n      if (HTMLImports.__importsParsingHook) {\n        HTMLImports.__importsParsingHook(elt);\n      }\n      if (elt.import) {\n        elt.import.__importParsed = true;\n      }\n      this.markParsingComplete(elt);\n      if (elt.__resource && !elt.__error) {\n        elt.dispatchEvent(new CustomEvent(\"load\", {\n          bubbles: false\n        }));\n      } else {\n        elt.dispatchEvent(new CustomEvent(\"error\", {\n          bubbles: false\n        }));\n      }\n      if (elt.__pending) {\n        var fn;\n        while (elt.__pending.length) {\n          fn = elt.__pending.shift();\n          if (fn) {\n            fn({\n              target: elt\n            });\n          }\n        }\n      }\n      this.parseNext();\n    },\n    parseLink: function(linkElt) {\n      if (nodeIsImport(linkElt)) {\n        this.parseImport(linkElt);\n      } else {\n        linkElt.href = linkElt.href;\n        this.parseGeneric(linkElt);\n      }\n    },\n    parseStyle: function(elt) {\n      var src = elt;\n      elt = cloneStyle(elt);\n      src.__appliedElement = elt;\n      elt.__importElement = src;\n      this.parseGeneric(elt);\n    },\n    parseGeneric: function(elt) {\n      this.trackElement(elt);\n      this.addElementToDocument(elt);\n    },\n    rootImportForElement: function(elt) {\n      var n = elt;\n      while (n.ownerDocument.__importLink) {\n        n = n.ownerDocument.__importLink;\n      }\n      return n;\n    },\n    addElementToDocument: function(elt) {\n      var port = this.rootImportForElement(elt.__importElement || elt);\n      port.parentNode.insertBefore(elt, port);\n    },\n    trackElement: function(elt, callback) {\n      var self = this;\n      var done = function(e) {\n        if (callback) {\n          callback(e);\n        }\n        self.markParsingComplete(elt);\n        self.parseNext();\n      };\n      elt.addEventListener(\"load\", done);\n      elt.addEventListener(\"error\", done);\n      if (isIE && elt.localName === \"style\") {\n        var fakeLoad = false;\n        if (elt.textContent.indexOf(\"@import\") == -1) {\n          fakeLoad = true;\n        } else if (elt.sheet) {\n          fakeLoad = true;\n          var csr = elt.sheet.cssRules;\n          var len = csr ? csr.length : 0;\n          for (var i = 0, r; i < len && (r = csr[i]); i++) {\n            if (r.type === CSSRule.IMPORT_RULE) {\n              fakeLoad = fakeLoad && Boolean(r.styleSheet);\n            }\n          }\n        }\n        if (fakeLoad) {\n          elt.dispatchEvent(new CustomEvent(\"load\", {\n            bubbles: false\n          }));\n        }\n      }\n    },\n    parseScript: function(scriptElt) {\n      var script = document.createElement(\"script\");\n      script.__importElement = scriptElt;\n      script.src = scriptElt.src ? scriptElt.src : generateScriptDataUrl(scriptElt);\n      scope.currentScript = scriptElt;\n      this.trackElement(script, function(e) {\n        script.parentNode.removeChild(script);\n        scope.currentScript = null;\n      });\n      this.addElementToDocument(script);\n    },\n    nextToParse: function() {\n      this._mayParse = [];\n      return !this.parsingElement && (this.nextToParseInDoc(rootDocument) || this.nextToParseDynamic());\n    },\n    nextToParseInDoc: function(doc, link) {\n      if (doc && this._mayParse.indexOf(doc) < 0) {\n        this._mayParse.push(doc);\n        var nodes = doc.querySelectorAll(this.parseSelectorsForNode(doc));\n        for (var i = 0, l = nodes.length, p = 0, n; i < l && (n = nodes[i]); i++) {\n          if (!this.isParsed(n)) {\n            if (this.hasResource(n)) {\n              return nodeIsImport(n) ? this.nextToParseInDoc(n.import, n) : n;\n            } else {\n              return;\n            }\n          }\n        }\n      }\n      return link;\n    },\n    nextToParseDynamic: function() {\n      return this.dynamicElements[0];\n    },\n    parseSelectorsForNode: function(node) {\n      var doc = node.ownerDocument || node;\n      return doc === rootDocument ? this.documentSelectors : this.importsSelectors;\n    },\n    isParsed: function(node) {\n      return node.__importParsed;\n    },\n    needsDynamicParsing: function(elt) {\n      return this.dynamicElements.indexOf(elt) >= 0;\n    },\n    hasResource: function(node) {\n      if (nodeIsImport(node) && node.import === undefined) {\n        return false;\n      }\n      return true;\n    }\n  };\n  function nodeIsImport(elt) {\n    return elt.localName === \"link\" && elt.rel === IMPORT_LINK_TYPE;\n  }\n  function generateScriptDataUrl(script) {\n    var scriptContent = generateScriptContent(script);\n    return \"data:text/javascript;charset=utf-8,\" + encodeURIComponent(scriptContent);\n  }\n  function generateScriptContent(script) {\n    return script.textContent + generateSourceMapHint(script);\n  }\n  function generateSourceMapHint(script) {\n    var owner = script.ownerDocument;\n    owner.__importedScripts = owner.__importedScripts || 0;\n    var moniker = script.ownerDocument.baseURI;\n    var num = owner.__importedScripts ? \"-\" + owner.__importedScripts : \"\";\n    owner.__importedScripts++;\n    return \"\\n//# sourceURL=\" + moniker + num + \".js\\n\";\n  }\n  function cloneStyle(style) {\n    var clone = style.ownerDocument.createElement(\"style\");\n    clone.textContent = style.textContent;\n    path.resolveUrlsInStyle(clone);\n    return clone;\n  }\n  scope.parser = importParser;\n  scope.IMPORT_SELECTOR = IMPORT_SELECTOR;\n});\n\nHTMLImports.addModule(function(scope) {\n  var flags = scope.flags;\n  var IMPORT_LINK_TYPE = scope.IMPORT_LINK_TYPE;\n  var IMPORT_SELECTOR = scope.IMPORT_SELECTOR;\n  var rootDocument = scope.rootDocument;\n  var Loader = scope.Loader;\n  var Observer = scope.Observer;\n  var parser = scope.parser;\n  var importer = {\n    documents: {},\n    documentPreloadSelectors: IMPORT_SELECTOR,\n    importsPreloadSelectors: [ IMPORT_SELECTOR ].join(\",\"),\n    loadNode: function(node) {\n      importLoader.addNode(node);\n    },\n    loadSubtree: function(parent) {\n      var nodes = this.marshalNodes(parent);\n      importLoader.addNodes(nodes);\n    },\n    marshalNodes: function(parent) {\n      return parent.querySelectorAll(this.loadSelectorsForNode(parent));\n    },\n    loadSelectorsForNode: function(node) {\n      var doc = node.ownerDocument || node;\n      return doc === rootDocument ? this.documentPreloadSelectors : this.importsPreloadSelectors;\n    },\n    loaded: function(url, elt, resource, err, redirectedUrl) {\n      flags.load && console.log(\"loaded\", url, elt);\n      elt.__resource = resource;\n      elt.__error = err;\n      if (isImportLink(elt)) {\n        var doc = this.documents[url];\n        if (doc === undefined) {\n          doc = err ? null : makeDocument(resource, redirectedUrl || url);\n          if (doc) {\n            doc.__importLink = elt;\n            this.bootDocument(doc);\n          }\n          this.documents[url] = doc;\n        }\n        elt.import = doc;\n      }\n      parser.parseNext();\n    },\n    bootDocument: function(doc) {\n      this.loadSubtree(doc);\n      this.observer.observe(doc);\n      parser.parseNext();\n    },\n    loadedAll: function() {\n      parser.parseNext();\n    }\n  };\n  var importLoader = new Loader(importer.loaded.bind(importer), importer.loadedAll.bind(importer));\n  importer.observer = new Observer();\n  function isImportLink(elt) {\n    return isLinkRel(elt, IMPORT_LINK_TYPE);\n  }\n  function isLinkRel(elt, rel) {\n    return elt.localName === \"link\" && elt.getAttribute(\"rel\") === rel;\n  }\n  function hasBaseURIAccessor(doc) {\n    return !!Object.getOwnPropertyDescriptor(doc, \"baseURI\");\n  }\n  function makeDocument(resource, url) {\n    var doc = document.implementation.createHTMLDocument(IMPORT_LINK_TYPE);\n    doc._URL = url;\n    var base = doc.createElement(\"base\");\n    base.setAttribute(\"href\", url);\n    if (!doc.baseURI && !hasBaseURIAccessor(doc)) {\n      Object.defineProperty(doc, \"baseURI\", {\n        value: url\n      });\n    }\n    var meta = doc.createElement(\"meta\");\n    meta.setAttribute(\"charset\", \"utf-8\");\n    doc.head.appendChild(meta);\n    doc.head.appendChild(base);\n    doc.body.innerHTML = resource;\n    if (window.HTMLTemplateElement && HTMLTemplateElement.bootstrap) {\n      HTMLTemplateElement.bootstrap(doc);\n    }\n    return doc;\n  }\n  if (!document.baseURI) {\n    var baseURIDescriptor = {\n      get: function() {\n        var base = document.querySelector(\"base\");\n        return base ? base.href : window.location.href;\n      },\n      configurable: true\n    };\n    Object.defineProperty(document, \"baseURI\", baseURIDescriptor);\n    Object.defineProperty(rootDocument, \"baseURI\", baseURIDescriptor);\n  }\n  scope.importer = importer;\n  scope.importLoader = importLoader;\n});\n\nHTMLImports.addModule(function(scope) {\n  var parser = scope.parser;\n  var importer = scope.importer;\n  var dynamic = {\n    added: function(nodes) {\n      var owner, parsed, loading;\n      for (var i = 0, l = nodes.length, n; i < l && (n = nodes[i]); i++) {\n        if (!owner) {\n          owner = n.ownerDocument;\n          parsed = parser.isParsed(owner);\n        }\n        loading = this.shouldLoadNode(n);\n        if (loading) {\n          importer.loadNode(n);\n        }\n        if (this.shouldParseNode(n) && parsed) {\n          parser.parseDynamic(n, loading);\n        }\n      }\n    },\n    shouldLoadNode: function(node) {\n      return node.nodeType === 1 && matches.call(node, importer.loadSelectorsForNode(node));\n    },\n    shouldParseNode: function(node) {\n      return node.nodeType === 1 && matches.call(node, parser.parseSelectorsForNode(node));\n    }\n  };\n  importer.observer.addCallback = dynamic.added.bind(dynamic);\n  var matches = HTMLElement.prototype.matches || HTMLElement.prototype.matchesSelector || HTMLElement.prototype.webkitMatchesSelector || HTMLElement.prototype.mozMatchesSelector || HTMLElement.prototype.msMatchesSelector;\n});\n\n(function(scope) {\n  var initializeModules = scope.initializeModules;\n  var isIE = scope.isIE;\n  if (scope.useNative) {\n    return;\n  }\n  if (isIE && typeof window.CustomEvent !== \"function\") {\n    window.CustomEvent = function(inType, params) {\n      params = params || {};\n      var e = document.createEvent(\"CustomEvent\");\n      e.initCustomEvent(inType, Boolean(params.bubbles), Boolean(params.cancelable), params.detail);\n      return e;\n    };\n    window.CustomEvent.prototype = window.Event.prototype;\n  }\n  initializeModules();\n  var rootDocument = scope.rootDocument;\n  function bootstrap() {\n    HTMLImports.importer.bootDocument(rootDocument);\n  }\n  if (document.readyState === \"complete\" || document.readyState === \"interactive\" && !window.attachEvent) {\n    bootstrap();\n  } else {\n    document.addEventListener(\"DOMContentLoaded\", bootstrap);\n  }\n})(HTMLImports);\n\nwindow.CustomElements = window.CustomElements || {\n  flags: {}\n};\n\n(function(scope) {\n  var flags = scope.flags;\n  var modules = [];\n  var addModule = function(module) {\n    modules.push(module);\n  };\n  var initializeModules = function() {\n    modules.forEach(function(module) {\n      module(scope);\n    });\n  };\n  scope.addModule = addModule;\n  scope.initializeModules = initializeModules;\n  scope.hasNative = Boolean(document.registerElement);\n  scope.useNative = !flags.register && scope.hasNative && !window.ShadowDOMPolyfill && (!window.HTMLImports || HTMLImports.useNative);\n})(CustomElements);\n\nCustomElements.addModule(function(scope) {\n  var IMPORT_LINK_TYPE = window.HTMLImports ? HTMLImports.IMPORT_LINK_TYPE : \"none\";\n  function forSubtree(node, cb) {\n    findAllElements(node, function(e) {\n      if (cb(e)) {\n        return true;\n      }\n      forRoots(e, cb);\n    });\n    forRoots(node, cb);\n  }\n  function findAllElements(node, find, data) {\n    var e = node.firstElementChild;\n    if (!e) {\n      e = node.firstChild;\n      while (e && e.nodeType !== Node.ELEMENT_NODE) {\n        e = e.nextSibling;\n      }\n    }\n    while (e) {\n      if (find(e, data) !== true) {\n        findAllElements(e, find, data);\n      }\n      e = e.nextElementSibling;\n    }\n    return null;\n  }\n  function forRoots(node, cb) {\n    var root = node.shadowRoot;\n    while (root) {\n      forSubtree(root, cb);\n      root = root.olderShadowRoot;\n    }\n  }\n  function forDocumentTree(doc, cb) {\n    _forDocumentTree(doc, cb, []);\n  }\n  function _forDocumentTree(doc, cb, processingDocuments) {\n    doc = wrap(doc);\n    if (processingDocuments.indexOf(doc) >= 0) {\n      return;\n    }\n    processingDocuments.push(doc);\n    var imports = doc.querySelectorAll(\"link[rel=\" + IMPORT_LINK_TYPE + \"]\");\n    for (var i = 0, l = imports.length, n; i < l && (n = imports[i]); i++) {\n      if (n.import) {\n        _forDocumentTree(n.import, cb, processingDocuments);\n      }\n    }\n    cb(doc);\n  }\n  scope.forDocumentTree = forDocumentTree;\n  scope.forSubtree = forSubtree;\n});\n\nCustomElements.addModule(function(scope) {\n  var flags = scope.flags;\n  var forSubtree = scope.forSubtree;\n  var forDocumentTree = scope.forDocumentTree;\n  function addedNode(node) {\n    return added(node) || addedSubtree(node);\n  }\n  function added(node) {\n    if (scope.upgrade(node)) {\n      return true;\n    }\n    attached(node);\n  }\n  function addedSubtree(node) {\n    forSubtree(node, function(e) {\n      if (added(e)) {\n        return true;\n      }\n    });\n  }\n  function attachedNode(node) {\n    attached(node);\n    if (inDocument(node)) {\n      forSubtree(node, function(e) {\n        attached(e);\n      });\n    }\n  }\n  var hasPolyfillMutations = !window.MutationObserver || window.MutationObserver === window.JsMutationObserver;\n  scope.hasPolyfillMutations = hasPolyfillMutations;\n  var isPendingMutations = false;\n  var pendingMutations = [];\n  function deferMutation(fn) {\n    pendingMutations.push(fn);\n    if (!isPendingMutations) {\n      isPendingMutations = true;\n      setTimeout(takeMutations);\n    }\n  }\n  function takeMutations() {\n    isPendingMutations = false;\n    var $p = pendingMutations;\n    for (var i = 0, l = $p.length, p; i < l && (p = $p[i]); i++) {\n      p();\n    }\n    pendingMutations = [];\n  }\n  function attached(element) {\n    if (hasPolyfillMutations) {\n      deferMutation(function() {\n        _attached(element);\n      });\n    } else {\n      _attached(element);\n    }\n  }\n  function _attached(element) {\n    if (element.__upgraded__ && (element.attachedCallback || element.detachedCallback)) {\n      if (!element.__attached && inDocument(element)) {\n        element.__attached = true;\n        if (element.attachedCallback) {\n          element.attachedCallback();\n        }\n      }\n    }\n  }\n  function detachedNode(node) {\n    detached(node);\n    forSubtree(node, function(e) {\n      detached(e);\n    });\n  }\n  function detached(element) {\n    if (hasPolyfillMutations) {\n      deferMutation(function() {\n        _detached(element);\n      });\n    } else {\n      _detached(element);\n    }\n  }\n  function _detached(element) {\n    if (element.__upgraded__ && (element.attachedCallback || element.detachedCallback)) {\n      if (element.__attached && !inDocument(element)) {\n        element.__attached = false;\n        if (element.detachedCallback) {\n          element.detachedCallback();\n        }\n      }\n    }\n  }\n  function inDocument(element) {\n    var p = element;\n    var doc = wrap(document);\n    while (p) {\n      if (p == doc) {\n        return true;\n      }\n      p = p.parentNode || p.nodeType === Node.DOCUMENT_FRAGMENT_NODE && p.host;\n    }\n  }\n  function watchShadow(node) {\n    if (node.shadowRoot && !node.shadowRoot.__watched) {\n      flags.dom && console.log(\"watching shadow-root for: \", node.localName);\n      var root = node.shadowRoot;\n      while (root) {\n        observe(root);\n        root = root.olderShadowRoot;\n      }\n    }\n  }\n  function handler(mutations) {\n    if (flags.dom) {\n      var mx = mutations[0];\n      if (mx && mx.type === \"childList\" && mx.addedNodes) {\n        if (mx.addedNodes) {\n          var d = mx.addedNodes[0];\n          while (d && d !== document && !d.host) {\n            d = d.parentNode;\n          }\n          var u = d && (d.URL || d._URL || d.host && d.host.localName) || \"\";\n          u = u.split(\"/?\").shift().split(\"/\").pop();\n        }\n      }\n      console.group(\"mutations (%d) [%s]\", mutations.length, u || \"\");\n    }\n    mutations.forEach(function(mx) {\n      if (mx.type === \"childList\") {\n        forEach(mx.addedNodes, function(n) {\n          if (!n.localName) {\n            return;\n          }\n          addedNode(n);\n        });\n        forEach(mx.removedNodes, function(n) {\n          if (!n.localName) {\n            return;\n          }\n          detachedNode(n);\n        });\n      }\n    });\n    flags.dom && console.groupEnd();\n  }\n  function takeRecords(node) {\n    node = wrap(node);\n    if (!node) {\n      node = wrap(document);\n    }\n    while (node.parentNode) {\n      node = node.parentNode;\n    }\n    var observer = node.__observer;\n    if (observer) {\n      handler(observer.takeRecords());\n      takeMutations();\n    }\n  }\n  var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);\n  function observe(inRoot) {\n    if (inRoot.__observer) {\n      return;\n    }\n    var observer = new MutationObserver(handler);\n    observer.observe(inRoot, {\n      childList: true,\n      subtree: true\n    });\n    inRoot.__observer = observer;\n  }\n  function upgradeDocument(doc) {\n    doc = wrap(doc);\n    flags.dom && console.group(\"upgradeDocument: \", doc.baseURI.split(\"/\").pop());\n    addedNode(doc);\n    observe(doc);\n    flags.dom && console.groupEnd();\n  }\n  function upgradeDocumentTree(doc) {\n    forDocumentTree(doc, upgradeDocument);\n  }\n  var originalCreateShadowRoot = Element.prototype.createShadowRoot;\n  if (originalCreateShadowRoot) {\n    Element.prototype.createShadowRoot = function() {\n      var root = originalCreateShadowRoot.call(this);\n      CustomElements.watchShadow(this);\n      return root;\n    };\n  }\n  scope.watchShadow = watchShadow;\n  scope.upgradeDocumentTree = upgradeDocumentTree;\n  scope.upgradeSubtree = addedSubtree;\n  scope.upgradeAll = addedNode;\n  scope.attachedNode = attachedNode;\n  scope.takeRecords = takeRecords;\n});\n\nCustomElements.addModule(function(scope) {\n  var flags = scope.flags;\n  function upgrade(node) {\n    if (!node.__upgraded__ && node.nodeType === Node.ELEMENT_NODE) {\n      var is = node.getAttribute(\"is\");\n      var definition = scope.getRegisteredDefinition(is || node.localName);\n      if (definition) {\n        if (is && definition.tag == node.localName) {\n          return upgradeWithDefinition(node, definition);\n        } else if (!is && !definition.extends) {\n          return upgradeWithDefinition(node, definition);\n        }\n      }\n    }\n  }\n  function upgradeWithDefinition(element, definition) {\n    flags.upgrade && console.group(\"upgrade:\", element.localName);\n    if (definition.is) {\n      element.setAttribute(\"is\", definition.is);\n    }\n    implementPrototype(element, definition);\n    element.__upgraded__ = true;\n    created(element);\n    scope.attachedNode(element);\n    scope.upgradeSubtree(element);\n    flags.upgrade && console.groupEnd();\n    return element;\n  }\n  function implementPrototype(element, definition) {\n    if (Object.__proto__) {\n      element.__proto__ = definition.prototype;\n    } else {\n      customMixin(element, definition.prototype, definition.native);\n      element.__proto__ = definition.prototype;\n    }\n  }\n  function customMixin(inTarget, inSrc, inNative) {\n    var used = {};\n    var p = inSrc;\n    while (p !== inNative && p !== HTMLElement.prototype) {\n      var keys = Object.getOwnPropertyNames(p);\n      for (var i = 0, k; k = keys[i]; i++) {\n        if (!used[k]) {\n          Object.defineProperty(inTarget, k, Object.getOwnPropertyDescriptor(p, k));\n          used[k] = 1;\n        }\n      }\n      p = Object.getPrototypeOf(p);\n    }\n  }\n  function created(element) {\n    if (element.createdCallback) {\n      element.createdCallback();\n    }\n  }\n  scope.upgrade = upgrade;\n  scope.upgradeWithDefinition = upgradeWithDefinition;\n  scope.implementPrototype = implementPrototype;\n});\n\nCustomElements.addModule(function(scope) {\n  var isIE11OrOlder = scope.isIE11OrOlder;\n  var upgradeDocumentTree = scope.upgradeDocumentTree;\n  var upgradeAll = scope.upgradeAll;\n  var upgradeWithDefinition = scope.upgradeWithDefinition;\n  var implementPrototype = scope.implementPrototype;\n  var useNative = scope.useNative;\n  function register(name, options) {\n    var definition = options || {};\n    if (!name) {\n      throw new Error(\"document.registerElement: first argument `name` must not be empty\");\n    }\n    if (name.indexOf(\"-\") < 0) {\n      throw new Error(\"document.registerElement: first argument ('name') must contain a dash ('-'). Argument provided was '\" + String(name) + \"'.\");\n    }\n    if (isReservedTag(name)) {\n      throw new Error(\"Failed to execute 'registerElement' on 'Document': Registration failed for type '\" + String(name) + \"'. The type name is invalid.\");\n    }\n    if (getRegisteredDefinition(name)) {\n      throw new Error(\"DuplicateDefinitionError: a type with name '\" + String(name) + \"' is already registered\");\n    }\n    if (!definition.prototype) {\n      definition.prototype = Object.create(HTMLElement.prototype);\n    }\n    definition.__name = name.toLowerCase();\n    definition.lifecycle = definition.lifecycle || {};\n    definition.ancestry = ancestry(definition.extends);\n    resolveTagName(definition);\n    resolvePrototypeChain(definition);\n    overrideAttributeApi(definition.prototype);\n    registerDefinition(definition.__name, definition);\n    definition.ctor = generateConstructor(definition);\n    definition.ctor.prototype = definition.prototype;\n    definition.prototype.constructor = definition.ctor;\n    if (scope.ready) {\n      upgradeDocumentTree(document);\n    }\n    return definition.ctor;\n  }\n  function overrideAttributeApi(prototype) {\n    if (prototype.setAttribute._polyfilled) {\n      return;\n    }\n    var setAttribute = prototype.setAttribute;\n    prototype.setAttribute = function(name, value) {\n      changeAttribute.call(this, name, value, setAttribute);\n    };\n    var removeAttribute = prototype.removeAttribute;\n    prototype.removeAttribute = function(name) {\n      changeAttribute.call(this, name, null, removeAttribute);\n    };\n    prototype.setAttribute._polyfilled = true;\n  }\n  function changeAttribute(name, value, operation) {\n    name = name.toLowerCase();\n    var oldValue = this.getAttribute(name);\n    operation.apply(this, arguments);\n    var newValue = this.getAttribute(name);\n    if (this.attributeChangedCallback && newValue !== oldValue) {\n      this.attributeChangedCallback(name, oldValue, newValue);\n    }\n  }\n  function isReservedTag(name) {\n    for (var i = 0; i < reservedTagList.length; i++) {\n      if (name === reservedTagList[i]) {\n        return true;\n      }\n    }\n  }\n  var reservedTagList = [ \"annotation-xml\", \"color-profile\", \"font-face\", \"font-face-src\", \"font-face-uri\", \"font-face-format\", \"font-face-name\", \"missing-glyph\" ];\n  function ancestry(extnds) {\n    var extendee = getRegisteredDefinition(extnds);\n    if (extendee) {\n      return ancestry(extendee.extends).concat([ extendee ]);\n    }\n    return [];\n  }\n  function resolveTagName(definition) {\n    var baseTag = definition.extends;\n    for (var i = 0, a; a = definition.ancestry[i]; i++) {\n      baseTag = a.is && a.tag;\n    }\n    definition.tag = baseTag || definition.__name;\n    if (baseTag) {\n      definition.is = definition.__name;\n    }\n  }\n  function resolvePrototypeChain(definition) {\n    if (!Object.__proto__) {\n      var nativePrototype = HTMLElement.prototype;\n      if (definition.is) {\n        var inst = document.createElement(definition.tag);\n        var expectedPrototype = Object.getPrototypeOf(inst);\n        if (expectedPrototype === definition.prototype) {\n          nativePrototype = expectedPrototype;\n        }\n      }\n      var proto = definition.prototype, ancestor;\n      while (proto && proto !== nativePrototype) {\n        ancestor = Object.getPrototypeOf(proto);\n        proto.__proto__ = ancestor;\n        proto = ancestor;\n      }\n      definition.native = nativePrototype;\n    }\n  }\n  function instantiate(definition) {\n    return upgradeWithDefinition(domCreateElement(definition.tag), definition);\n  }\n  var registry = {};\n  function getRegisteredDefinition(name) {\n    if (name) {\n      return registry[name.toLowerCase()];\n    }\n  }\n  function registerDefinition(name, definition) {\n    registry[name] = definition;\n  }\n  function generateConstructor(definition) {\n    return function() {\n      return instantiate(definition);\n    };\n  }\n  var HTML_NAMESPACE = \"http://www.w3.org/1999/xhtml\";\n  function createElementNS(namespace, tag, typeExtension) {\n    if (namespace === HTML_NAMESPACE) {\n      return createElement(tag, typeExtension);\n    } else {\n      return domCreateElementNS(namespace, tag);\n    }\n  }\n  function createElement(tag, typeExtension) {\n    var definition = getRegisteredDefinition(typeExtension || tag);\n    if (definition) {\n      if (tag == definition.tag && typeExtension == definition.is) {\n        return new definition.ctor();\n      }\n      if (!typeExtension && !definition.is) {\n        return new definition.ctor();\n      }\n    }\n    var element;\n    if (typeExtension) {\n      element = createElement(tag);\n      element.setAttribute(\"is\", typeExtension);\n      return element;\n    }\n    element = domCreateElement(tag);\n    if (tag.indexOf(\"-\") >= 0) {\n      implementPrototype(element, HTMLElement);\n    }\n    return element;\n  }\n  var domCreateElement = document.createElement.bind(document);\n  var domCreateElementNS = document.createElementNS.bind(document);\n  var isInstance;\n  if (!Object.__proto__ && !useNative) {\n    isInstance = function(obj, ctor) {\n      var p = obj;\n      while (p) {\n        if (p === ctor.prototype) {\n          return true;\n        }\n        p = p.__proto__;\n      }\n      return false;\n    };\n  } else {\n    isInstance = function(obj, base) {\n      return obj instanceof base;\n    };\n  }\n  function wrapDomMethodToForceUpgrade(obj, methodName) {\n    var orig = obj[methodName];\n    obj[methodName] = function() {\n      var n = orig.apply(this, arguments);\n      upgradeAll(n);\n      return n;\n    };\n  }\n  wrapDomMethodToForceUpgrade(Node.prototype, \"cloneNode\");\n  wrapDomMethodToForceUpgrade(document, \"importNode\");\n  if (isIE11OrOlder) {\n    (function() {\n      var importNode = document.importNode;\n      document.importNode = function() {\n        var n = importNode.apply(document, arguments);\n        if (n.nodeType == n.DOCUMENT_FRAGMENT_NODE) {\n          var f = document.createDocumentFragment();\n          f.appendChild(n);\n          return f;\n        } else {\n          return n;\n        }\n      };\n    })();\n  }\n  document.registerElement = register;\n  document.createElement = createElement;\n  document.createElementNS = createElementNS;\n  scope.registry = registry;\n  scope.instanceof = isInstance;\n  scope.reservedTagList = reservedTagList;\n  scope.getRegisteredDefinition = getRegisteredDefinition;\n  document.register = document.registerElement;\n});\n\n(function(scope) {\n  var useNative = scope.useNative;\n  var initializeModules = scope.initializeModules;\n  var isIE11OrOlder = /Trident/.test(navigator.userAgent);\n  if (useNative) {\n    var nop = function() {};\n    scope.watchShadow = nop;\n    scope.upgrade = nop;\n    scope.upgradeAll = nop;\n    scope.upgradeDocumentTree = nop;\n    scope.upgradeSubtree = nop;\n    scope.takeRecords = nop;\n    scope.instanceof = function(obj, base) {\n      return obj instanceof base;\n    };\n  } else {\n    initializeModules();\n  }\n  var upgradeDocumentTree = scope.upgradeDocumentTree;\n  if (!window.wrap) {\n    if (window.ShadowDOMPolyfill) {\n      window.wrap = ShadowDOMPolyfill.wrapIfNeeded;\n      window.unwrap = ShadowDOMPolyfill.unwrapIfNeeded;\n    } else {\n      window.wrap = window.unwrap = function(node) {\n        return node;\n      };\n    }\n  }\n  function bootstrap() {\n    upgradeDocumentTree(wrap(document));\n    if (window.HTMLImports) {\n      HTMLImports.__importsParsingHook = function(elt) {\n        upgradeDocumentTree(wrap(elt.import));\n      };\n    }\n    CustomElements.ready = true;\n    setTimeout(function() {\n      CustomElements.readyTime = Date.now();\n      if (window.HTMLImports) {\n        CustomElements.elapsed = CustomElements.readyTime - HTMLImports.readyTime;\n      }\n      document.dispatchEvent(new CustomEvent(\"WebComponentsReady\", {\n        bubbles: true\n      }));\n    });\n  }\n  if (isIE11OrOlder && typeof window.CustomEvent !== \"function\") {\n    window.CustomEvent = function(inType, params) {\n      params = params || {};\n      var e = document.createEvent(\"CustomEvent\");\n      e.initCustomEvent(inType, Boolean(params.bubbles), Boolean(params.cancelable), params.detail);\n      return e;\n    };\n    window.CustomEvent.prototype = window.Event.prototype;\n  }\n  if (document.readyState === \"complete\" || scope.flags.eager) {\n    bootstrap();\n  } else if (document.readyState === \"interactive\" && !window.attachEvent && (!window.HTMLImports || window.HTMLImports.ready)) {\n    bootstrap();\n  } else {\n    var loadEvent = window.HTMLImports && !HTMLImports.ready ? \"HTMLImportsLoaded\" : \"DOMContentLoaded\";\n    window.addEventListener(loadEvent, bootstrap);\n  }\n  scope.isIE11OrOlder = isIE11OrOlder;\n})(window.CustomElements);\n\n(function(scope) {\n  if (!Function.prototype.bind) {\n    Function.prototype.bind = function(scope) {\n      var self = this;\n      var args = Array.prototype.slice.call(arguments, 1);\n      return function() {\n        var args2 = args.slice();\n        args2.push.apply(args2, arguments);\n        return self.apply(scope, args2);\n      };\n    };\n  }\n})(window.WebComponents);\n\n(function(scope) {\n  \"use strict\";\n  if (!window.performance) {\n    var start = Date.now();\n    window.performance = {\n      now: function() {\n        return Date.now() - start;\n      }\n    };\n  }\n  if (!window.requestAnimationFrame) {\n    window.requestAnimationFrame = function() {\n      var nativeRaf = window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame;\n      return nativeRaf ? function(callback) {\n        return nativeRaf(function() {\n          callback(performance.now());\n        });\n      } : function(callback) {\n        return window.setTimeout(callback, 1e3 / 60);\n      };\n    }();\n  }\n  if (!window.cancelAnimationFrame) {\n    window.cancelAnimationFrame = function() {\n      return window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || function(id) {\n        clearTimeout(id);\n      };\n    }();\n  }\n  var elementDeclarations = [];\n  var polymerStub = function(name, dictionary) {\n    if (typeof name !== \"string\" && arguments.length === 1) {\n      Array.prototype.push.call(arguments, document._currentScript);\n    }\n    elementDeclarations.push(arguments);\n  };\n  window.Polymer = polymerStub;\n  scope.consumeDeclarations = function(callback) {\n    scope.consumeDeclarations = function() {\n      throw \"Possible attempt to load Polymer twice\";\n    };\n    if (callback) {\n      callback(elementDeclarations);\n    }\n    elementDeclarations = null;\n  };\n  function installPolymerWarning() {\n    if (window.Polymer === polymerStub) {\n      window.Polymer = function() {\n        throw new Error(\"You tried to use polymer without loading it first. To \" + 'load polymer, <link rel=\"import\" href=\"' + 'components/polymer/polymer.html\">');\n      };\n    }\n  }\n  if (HTMLImports.useNative) {\n    installPolymerWarning();\n  } else {\n    addEventListener(\"DOMContentLoaded\", installPolymerWarning);\n  }\n})(window.WebComponents);\n\n(function(scope) {\n  var style = document.createElement(\"style\");\n  style.textContent = \"\" + \"body {\" + \"transition: opacity ease-in 0.2s;\" + \" } \\n\" + \"body[unresolved] {\" + \"opacity: 0; display: block; overflow: hidden; position: relative;\" + \" } \\n\";\n  var head = document.querySelector(\"head\");\n  head.insertBefore(style, head.firstChild);\n})(window.WebComponents);\n\n(function(scope) {\n  window.Platform = scope;\n})(window.WebComponents);"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/css-patterns-input-label-pairs/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <meta charset=\"UTF-8\">\n    <title>CSS Patterns</title>\n</head>\n<body>\n    <!-- Exercise instructions: This exercise will introduce you\n         to various CSS patterns.\n\n         1. Write CSS for the below label + input pair component.\n            Style the component so that label/input are on the\n            right and left of a centered axis:\n\n                    label \\ input (info)\n              other label \\ another input (info)\n               last label \\ last input (info)\n\n            Each label should be bold.  Each (info) should be in italics.\n\n         2. For each following components, implement each with one of\n         the following CSS patterns:\n              a. OOCSS\n              b. BEM\n              c. SMACSS\n\n         4. Add a required (*) modifier to each of the components.\n         5. Compare/contrast each of these implementations.  Which one\n            do you prefer?\n     -->\n    <div class=\"oocss\">\n        <label for=\"name\">Name:</label>\n        <input id=\"name\" type=\"text\" name=\"textfield\">\n        <span> (First and Last)</span>\n    </div>\n    <div class=\"bem\">\n        <label for=\"phone\">Phone:</label>\n        <input id=\"phone\" type=\"text\" name=\"textfield\">\n        <span> (123-456-7890)</span>\n    </div>\n    <div class=\"atomic-css\">\n        <label for=\"dob\">DOB:</label>\n        <input id=\"dob\" type=\"text\" name=\"textfield\">\n        <span> (01/01/1900)</span>\n    </div>\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/css-patterns-media-object/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <meta charset=\"UTF-8\">\n    <title>CSS Patterns: Media Object</title>\n    <style>\n        .media {\n            max-width: 1080px;\n        }\n\n        .media .img {\n            float: left;\n            margin-right: 10px;\n        }\n\n        .media .imgExt {\n            float: right;\n            margin-left: 10px;\n        }\n\n        .media .imgExt img {\n            display: block;\n        }\n\n        .media .img img {\n            display: block;\n        }\n    </style>\n</head>\n<body>\n<!-- Exercise instructions: This exercise will deep-dive into one type\n     CSS pattern.\n\n          a. OOCSS\n -->\n<section class=\"media\">\n    <div class=\"img\">\n        <img src=\"http://lorempixel.com/100/100/abstract/1\" alt=\"Picture\"/>\n    </div>\n\n    <p><span>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Autem dolorem explicabo, in incidunt laudantium maxime pariatur possimus qui quisquam repellendus sequi sit tempore ut voluptate voluptatum. Id maxime non quibusdam?</span><span>Dignissimos distinctio exercitationem, expedita incidunt labore libero maxime, nihil omnis quibusdam quos repellendus, rerum saepe sapiente similique suscipit tempora tempore ullam ut vel vitae! Beatae consequatur molestiae nostrum perferendis repellat?</span><span>Animi assumenda blanditiis, consectetur corporis ea eveniet fugiat fugit illum, ipsa maiores neque nulla porro provident quasi quia quisquam repellendus sapiente, sed tempora vel vero voluptas voluptates? Beatae, officia, perspiciatis.</span></p>\n</section>\n<section class=\"media\">\n    <div class=\"img\">\n        <img src=\"http://lorempixel.com/100/100/abstract/2\" alt=\"Picture\"/>\n    </div>\n\n    <p><span>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Autem dolorem explicabo, in incidunt laudantium maxime pariatur possimus qui quisquam repellendus sequi sit tempore ut voluptate voluptatum. Id maxime non quibusdam?</span></p>\n    <section class=\"media\">\n        <div class=\"img\">\n            <img src=\"http://lorempixel.com/100/100/abstract/4\" alt=\"Picture\"/>\n        </div>\n\n        <p><span>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Autem dolorem explicabo, in incidunt laudantium maxime pariatur possimus qui quisquam repellendus sequi sit tempore ut voluptate voluptatum. Id maxime non quibusdam?</span><span>Dignissimos distinctio exercitationem, expedita incidunt labore libero maxime, nihil omnis quibusdam quos repellendus, rerum saepe sapiente similique suscipit tempora tempore ullam ut vel vitae! Beatae consequatur molestiae nostrum perferendis repellat?</span><span>Animi assumenda blanditiis, consectetur corporis ea eveniet fugiat fugit illum, ipsa maiores neque nulla porro provident quasi quia quisquam repellendus sapiente, sed tempora vel vero voluptas voluptates? Beatae, officia, perspiciatis.</span></p>\n    </section>\n\n</section>\n<section class=\"media\">\n    <div class=\"imgExt\">\n        <img src=\"http://lorempixel.com/100/100/abstract/3\" alt=\"Picture\"/>\n    </div>\n\n    <p><span>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Autem dolorem explicabo, in incidunt laudantium maxime pariatur possimus qui quisquam repellendus sequi sit tempore ut voluptate voluptatum. Id maxime non quibusdam?</span><span>Dignissimos distinctio exercitationem, expedita incidunt labore libero maxime, nihil omnis quibusdam quos repellendus, rerum saepe sapiente similique suscipit tempora tempore ullam ut vel vitae! Beatae consequatur molestiae nostrum perferendis repellat?</span><span>Animi assumenda blanditiis, consectetur corporis ea eveniet fugiat fugit illum, ipsa maiores neque nulla porro provident quasi quia quisquam repellendus sapiente, sed tempora vel vero voluptas voluptates? Beatae, officia, perspiciatis.</span></p>\n</section>\n\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/css-patterns-tabs/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <meta charset=\"UTF-8\">\n    <title>CSS Patterns: Tabs</title>\n</head>\n<body>\n<!-- Exercise instructions: This exercise will deep-dive into one type\n     CSS pattern.\n\n     1. Copy your 'tabs' component from the 'general-components' exercise.\n\n     2. Rewrite the CSS  with one of\n     the following CSS patterns:\n          a. OOCSS\n          b. BEM\n          c. SMACSS\n\n     4. Be sure to add a modifier for the selected tab and for\n        the hover state of the inactive tabs.\n     5. Try and nest a tab component within one of the tabs.  Does it work?\n -->\n\n\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/general-components/hello-badge/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <meta charset=\"UTF-8\">\n    <title>Componentization: Hello Badge</title>\n    <link rel=\"stylesheet\" href=\"styles.css\"/>\n</head>\n<body>\n<!-- Start HTML Content -->\n\n<!-- Exercise instructions: Create a hello badge.  Because this is a \"component\", be sure it has\n     its own CSS / JS files included -->\n<section class=\"badge\">\n    <h1>Hello</h1>\n    <h2>My name is:</h2>\n    <div class=\"content\">\n        <h3>Daniel</h3>\n    </div>\n</section>\n<!-- End HTML Content -->\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/general-components/hello-badge/styles.css",
    "content": "* {\n    padding: 0;\n    margin: 0;\n}\n\n.badge {\n    border-radius: 15px;\n    background-color: lightcoral;\n    color: white;\n    text-align: center;\n    display: inline-block;\n    padding: 5px\n}\n\nh1, h2 {\n    padding: 2px;\n}\n\n.content {\n    background-color: white;\n    width: 500px;\n    height: 200px;\n    margin-bottom: 20px;\n    font-size: 60px;\n    color: black;\n    font-family: cursive;\n}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/general-components/readme.md",
    "content": "## Hello Badge\n\nExpected result:\n\n![Hello Badge](hello-badge/result.png)\n\n## Waiting Spinner\n\nUse CSS3 animation to rotate an image or shape of your choice to show that a process on the page is in progress.\n\n## Tabs\n\nCreate a simple tabs component, where there are a set of tabs and related panels. Clicking a tab opens the related panel."
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/general-components/tabs/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <meta charset=\"UTF-8\">\n    <title>Componentization: Tabs</title>\n</head>\n<body>\n<!-- Start HTML Content -->\n\n<!-- Exercise instructions: Create a tabs component.  Because this is a \"component\", be sure it has\n     its own CSS / JS files included -->\n\n<!-- End HTML Content -->\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/general-components/waiting-spinner/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <meta charset=\"UTF-8\">\n    <title>Componentization: Waiting Spinner</title>\n    <link rel=\"stylesheet\" href=\"styles.css\"/>\n</head>\n<body>\n<!-- Start HTML Content -->\n    <p>Testing the <span class=\"spinner\">Loading</span> screen</p>\n    <!-- Exercise instructions: Create a waiting spinner.  Because this is a \"component\", be sure it has\n         its own CSS / JS files included -->\n\n<!-- End HTML Content -->\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/general-components/waiting-spinner/styles.css",
    "content": ".spinner {\n    display: inline;\n    animation: spin 1s linear infinite;\n}\n\n@keyframes spin {\n    from {\n        transform: rotate(0deg);\n    }\n\n    to {\n        transform: rotate(360deg);\n    }\n}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/hello-web-components/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <meta charset=\"UTF-8\">\n    <title>My first web component</title>\n    <link rel=\"import\" href=\"my-first-web-component/my-first-web-component.html\">\n    <style>\n        /*Style your component element here*/\n        my-badge::shadow .badge {\n            background-color: forestgreen;\n        }\n    </style>\n</head>\n<body>\n<!-- Start HTML Content -->\n    <!-- Create your first web component!  Add the tag and some content here -->\n    <my-badge>Daniel</my-badge>\n<!-- End HTML Content -->\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/hello-web-components/my-first-web-component/my-first-web-component.html",
    "content": "<template id=\"template\">\n    <style>\n        /* Add some styles here */\n        * {\n            padding: 0;\n            margin: 0;\n        }\n\n        .badge {\n            border-radius: 15px;\n            background-color: lightcoral;\n            color: white;\n            text-align: center;\n            display: inline-block;\n            padding: 5px\n        }\n\n        h1, h2 {\n            padding: 2px;\n        }\n\n        .content {\n            background-color: white;\n            width: 500px;\n            height: 200px;\n            margin-bottom: 20px;\n            font-size: 60px;\n            color: black;\n            font-family: cursive;\n        }\n    </style>\n    <!-- Add HTML for your component here.\n    Try adding <content></content> to project from the light DOM -->\n    <section class=\"badge\">\n        <h1>Hello</h1>\n        <h2>My name is:</h2>\n        <div class=\"content\">\n            <h3><content></content></h3>\n        </div>\n    </section>\n</template>\n<script>\n    var createElement = function(tagName, templateId, basePrototype) {\n        basePrototype = basePrototype || HTMLElement.prototype;\n        var template = document.currentScript.ownerDocument.getElementById(templateId).content;\n        var customElementPrototype = Object.create(basePrototype);\n        customElementPrototype.createdCallback = function() {\n            var shadowRoot = this.createShadowRoot();\n            var clone = document.importNode(template, true);\n            shadowRoot.appendChild(clone);\n        };\n        return document.registerElement(tagName, {\n            prototype: customElementPrototype\n        });\n    };\n    // Initialize your component here with the above function!\n    createElement('my-badge', 'template');\n</script>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/intro-shadow-dom/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <meta charset=\"UTF-8\">\n    <title>Intro to the Shadow DOM</title>\n    <style>p { color: red;}</style>\n</head>\n<body>\n\n<div class=\"light\">\n    <p>Hello, World.</p>\n</div>\n<div class=\"shadow\">\n    <p>This shouldn't be visible.</p>\n</div>\n\n<!-- Exercise instructions: This exercise will introduce the Shadow DOM\n\n     1. Select the element with class 'shadow'.  Create a instance\n     of the shadow DOM that will attach to that element with\n     `element.createShadowRoot()`\n\n     2. Add a paragraph element to that shadow root.\n     3. Add a style element to the shadow root.  Confirm that style scoping is working.\n\n -->\n<script>\n    var shadowNodes = document.querySelectorAll('.shadow');\n    for (var i = 0; i < shadowNodes.length; i++) {\n        var shadowNode = shadowNodes[i];\n        var shadowRoot = shadowNode.createShadowRoot();\n        shadowRoot.innerHTML = '<style>p {color: lawngreen;}</style>';\n        shadowRoot.innerHTML += '<p>This is green!!</p>';\n    }\n</script>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/nesting-components/accordion_component/script.js",
    "content": "var accordions = Array.prototype.slice.call(document.querySelectorAll('.accordion-component'));\naccordions.forEach(function (accordion) {\n    var sections = Array.prototype.slice.call(accordion.querySelectorAll('.section'));\n    sections.forEach(function (section) {\n        var content = section.querySelector('.content');\n        section.querySelector('h2').addEventListener('click', function () {\n            content.classList.toggle('closed');\n        });\n    });\n});"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/nesting-components/accordion_component/styles.css",
    "content": ".accordion .content {\n  overflow-y: hidden;\n}\n.closed {\n  max-height: 0;\n  visibility: hidden;\n}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/nesting-components/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <meta charset=\"UTF-8\">\n    <title>Componentization</title>\n    <link rel=\"stylesheet\" href=\"accordion_component/styles.css\" type=\"text/css\"/>\n</head>\n<body>\n<!-- Start HTML Content -->\n\n<!-- Exercise instructions: Debug this \"leaky\" accordion component -->\n\n<div class=\"accordion-component\">\n    <div class=\"section\">\n        <h2>Title</h2>\n\n        <div class=\"content closed\">\n            Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci amet, commodi consequatur cupiditate\n            deserunt dicta dignissimos esse eveniet mollitia neque nisi nobis non porro, quisquam ratione unde, vitae\n            voluptas voluptatem?\n\n            <div class=\"section\">\n                <h2>Title</h2>\n\n                <div class=\"content closed\">\n                    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci amet, commodi consequatur cupiditate\n                    deserunt dicta dignissimos esse eveniet mollitia neque nisi nobis non porro, quisquam ratione unde,\n                    vitae voluptas voluptatem?\n                </div>\n            </div>\n        </div>\n    </div>\n\n    <div class=\"section\">\n        <h2>Title</h2>\n\n        <div class=\"content closed\">\n            Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci amet, commodi consequatur cupiditate\n            deserunt dicta dignissimos esse eveniet mollitia neque nisi nobis non porro, quisquam ratione unde, vitae\n            voluptas voluptatem?\n\n            <div class=\"section\">\n                <h2>Title</h2>\n\n                <div class=\"content closed\">\n                    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci amet, commodi consequatur cupiditate\n                    deserunt dicta dignissimos esse eveniet mollitia neque nisi nobis non porro, quisquam ratione unde,\n                    vitae voluptas voluptatem?\n                </div>\n            </div>\n        </div>\n    </div>\n    <script src=\"accordion_component/script.js\"></script>\n</div>\n\n<!-- End HTML Content -->\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/progress-bar-component/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <meta charset=\"UTF-8\">\n    <title>Progress Bar Component</title>\n</head>\n<body>\n<!-- Exercise instructions: This exercise will introduce shadow DOM CSS\n\n     1. Override the color of the progress bar.  Try #3787FF, #FFCA6A, #9B6EFF or another color.\n        Use ::shadow.\n     2. Refactor above style to use /deep/ combinator.\n     3. Override the color of the label.  Notice that it is in a shadow root within a shadow root.\n        Use ::shadow, not /deep/.\n     4. Increase width of progress bar from 45%.  Notice the CSS specificity required.\n -->\n<style>\n    /* Add styles here */\n</style>\n\n<div id=\"progress-bar\"></div>\n<script src=\"script.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/progress-bar-component/script.js",
    "content": "(function() {\n  var progressBarShadowRoot = document.getElementById('progress-bar').createShadowRoot();\n  progressBarShadowRoot.innerHTML += '<style>.total {max-width: 100%; border: 1px solid rgba(39,41,45,.20); border-radius: .25em; background: rgba(211, 211, 211, 0.24); padding: .25em; height: 1.8em;} .bar {background-color: #8de674; height: 1.75em;}</style>';\n  progressBarShadowRoot.innerHTML += '<div class=\"total\"><div class=\"bar\" style=\"width: 45%;\"></div></div><div id=\"label\"></div>';\n  var labelShadowRoot = progressBarShadowRoot.getElementById('label').createShadowRoot();\n  labelShadowRoot.innerHTML += '<style>.label { width: 100%; text-align: center; }</style>';\n  labelShadowRoot.innerHTML += '<div class=\"label\">45% Complete</div>';\n}());"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/styleguide/components/accordion.html",
    "content": "<template id=\"template\">\n    <style>\n        ::content .item {\n            border: 1px solid black;\n        }\n\n        ::content .item .body {\n            height: 0;\n            transition: height 500ms;\n            overflow: hidden;\n        }\n    </style>\n    <div class=\"items\">\n        <content></content>\n    </div>\n</template>\n<script src=\"../createElement.js\"></script>\n<script>\n    function mouseEnter(e) {\n        expandElement(e.target.querySelector('.body'));\n    }\n\n    function mouseLeave(e) {\n        collapseElement(e.target.querySelector('.body'));\n    }\n\n    function expandParent(element) {\n        if (element.parentNode.classList.contains('item')\n                && element.parentNode.parentNode.nodeName === 'MY-ACCORDION'\n                && element.parentNode.parentNode.parentNode.classList.contains('body')) {\n            return function() {\n                expandElement(element.parentNode.parentNode.parentNode);\n            };\n        }\n        return function() {};\n    }\n\n    function expandElement(element) {\n        element.style.height = element.scrollHeight + 'px';\n    }\n\n    function collapseElement(element) {\n        element.style.height = '';\n    }\n\n    function loader() {\n        var items = this.shadowRoot.querySelector('content').getDistributedNodes();\n        for (var i = 0; i < items.length; i++) {\n            var item = items[i];\n            if (item.nodeType === 1 && item.classList.contains('item')) {\n                item.addEventListener('mouseenter', mouseEnter);\n                item.addEventListener('mouseleave', mouseLeave);\n            }\n        }\n    }\n\n    var proto = Object.create(HTMLElement.prototype);\n    proto.createdCallback = loader;\n\n    window.MyAccordion = createElement('my-accordion', '#template', proto);\n</script>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/styleguide/components/badge.html",
    "content": "<template id=\"template\">\n    <style>\n        /* Add some styles here */\n        * {\n            padding: 0;\n            margin: 0;\n            box-sizing: border-box;\n        }\n\n        .badge {\n            border-radius: 15px;\n            background-color: lightcoral;\n            color: white;\n            text-align: center;\n            display: inline-block;\n            padding: 5px 5px 20px 5px;\n            transform: rotate(-7deg);\n            margin: 40px 20px;\n            box-shadow: -1px 1px 3px 1px black;\n        }\n\n        h1 {\n            font-size: 40px;\n        }\n\n        h2 {\n            font-size: 30px;\n        }\n\n        h1, h2 {\n            padding: 2px;\n            font-family: serif;\n        }\n\n        .content {\n            background-color: white;\n            width: 500px;\n            height: 200px;\n            overflow: hidden;\n            font-size: 80px;\n            color: black;\n            font-family: cursive;\n            display: flex;\n            justify-content: center;\n            align-items: center;\n        }\n    </style>\n    <!-- Add HTML for your component here.\n    Try adding <content></content> to project from the light DOM -->\n    <section class=\"badge\">\n        <h1>Hello</h1>\n        <h2>My name is:</h2>\n        <div class=\"content\">\n            <h3><content></content></h3>\n        </div>\n    </section>\n</template>\n<script src=\"../createElement.js\"></script>\n<script>\n    var MyBadge = createElement('my-badge', '#template');\n</script>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/styleguide/components/blink.html",
    "content": "<template id=\"template\">\n    <div id=\"showing\">\n        <content></content>\n    </div>\n</template>\n<script src=\"../createElement.js\"></script>\n<script>\n    function toggleStyle() {\n        var interval = parseInt(this.getAttribute('interval')) || 1000;\n        this.timeoutId = setTimeout(toggleStyle.bind(this), interval);\n        var item = this.shadowRoot.querySelector('#showing');\n        var styleText = this.getAttribute('styles') || 'visibility: hidden';\n        var styleLevels = styleText.split('/');\n        item.currentSetting = (item.currentSetting + 1) % (styleLevels.length + 1);\n        var detail = {newStyle: item.currentSetting ? styleLevels[item.currentSetting - 1] : ''};\n        var e = new CustomEvent('styleChanged', {detail: detail});\n        this.dispatchEvent(e);\n        var styles = item.currentSetting ? styleLevels[item.currentSetting - 1].split(',') : [];\n        clearStyle.call(this);\n        styles.forEach(function(style) {\n            var keyVal = style.split(':');\n            item.style[keyVal[0].trim()] = keyVal[1].trim();\n        });\n    }\n\n    function loader() {\n        var item = this.shadowRoot.querySelector('#showing');\n        item.currentSetting = 0;\n        var interval = parseInt(this.getAttribute('interval')) || 1000;\n        this.timeoutId = setTimeout(toggleStyle.bind(this), interval);\n    }\n\n    function cleanUp() {\n        clearTimeout(this.timeoutId);\n    }\n\n    function clearStyle() {\n        var item = this.shadowRoot.querySelector('#showing');\n        for (var key in item.style) {\n            if (item.style.hasOwnProperty(key)) {\n                item.style[key] = '';\n            }\n        }\n    }\n\n    var proto = Object.create(HTMLElement.prototype);\n    proto.createdCallback = loader;\n    proto.detachedCallback = cleanUp;\n    proto.attributeChangedCallback = clearStyle;\n    proto.stop = cleanUp;\n    proto.start = loader;\n    window.MyBlink = createElement('my-blink', '#template', proto);\n</script>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/styleguide/components/button.html",
    "content": "<template id=\"template\">\n    <style>\n        button {\n            min-width: 100px;\n            min-height: 50px;\n            border-radius: 10px;\n            background-color: cornsilk;\n            padding: 0;\n            margin: 0;\n        }\n\n        button:focus {\n            outline: 0;\n        }\n\n        ::content {\n            font-size: 20px;\n            margin: 0;\n            padding: 0;\n        }\n    </style>\n    <!-- Add HTML for your component here.\n    Try adding <content></content> to project from the light DOM -->\n    <button><content></content></button>\n</template>\n<script src=\"../createElement.js\"></script>\n<script>\n    var MyButton = createElement('my-button', '#template');\n</script>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/styleguide/components/slider.html",
    "content": "<template id=\"template\">\n    <style>\n        #slider {\n            min-width: 400px;\n            min-height: 200px;\n            overflow: hidden;\n        }\n    </style>\n    <!-- Add HTML for your component here.\n    Try adding <content></content> to project from the light DOM -->\n    <section id=\"slider\">\n        <content></content>\n    </section>\n</template>\n<script src=\"../createElement.js\"></script>\n<script>\n    function slideNext() {\n        var shadowRoot = this.shadowRoot;\n        var nodes = shadowRoot.nodesData;\n        shadowRoot.currentNode = (shadowRoot.currentNode + 1) % nodes.length;\n        for (var i = 0; i < nodes.length; i++) {\n            nodes[i].style.display = 'none';\n        }\n        nodes[shadowRoot.currentNode].style.display = '';\n    }\n\n    function loader() {\n        var shadowRoot = this.shadowRoot;\n        var nodes = shadowRoot.querySelector('content').getDistributedNodes();\n        shadowRoot.nodesData = [];\n        shadowRoot.currentNode = 0;\n        for (var i = 0; i < nodes.length; i++) {\n            var node = nodes[i];\n            if (node.nodeType === 1) {\n                shadowRoot.nodesData.push(node);\n                node.style.display = 'none';\n            }\n        }\n        var interval = this.getAttribute('interval') || 1000;\n        this.intervalId = setInterval(slideNext.bind(this), interval);\n    }\n\n    function changeInterval(name, oldVal, newVal) {\n        if (name === 'interval') {\n            clearInterval(this.intervalId);\n            this.intervalId = setInterval(slideNext.bind(this), newVal)\n        }\n    }\n\n    function deleteItem() {\n        clearInterval(this.intervalId);\n    }\n\n\n    var proto = Object.create(HTMLElement.prototype);\n    proto.createdCallback = loader;\n    proto.attributeChangedCallback = changeInterval;\n    proto.detachedCallback = deleteItem;\n    proto.slideNext = slideNext;\n    window.MySlider = createElement('my-slider', '#template', proto);\n</script>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/styleguide/components/spinner.html",
    "content": "<template id=\"template\">\n    <style>\n        /* Add some styles here */\n        .spinner {\n            display: inline;\n            animation: spinZ 1s linear infinite;\n        }\n\n        @keyframes spinX {\n            from {\n                transform: rotateX(0deg);\n            }\n\n            to {\n                transform: rotateX(360deg);\n            }\n        }\n\n        @keyframes spinY {\n            from {\n                transform: rotateY(0deg);\n            }\n\n            to {\n                transform: rotateY(360deg);\n            }\n        }\n\n        @keyframes spinZ {\n            from {\n                transform: rotate(0deg);\n            }\n\n            to {\n                transform: rotate(360deg);\n            }\n        }\n    </style>\n    <!-- Add HTML for your component here.\n    Try adding <content></content> to project from the light DOM -->\n    <span class=\"spinner\"><content></content></span>\n</template>\n<script src=\"../createElement.js\"></script>\n<script>\n    function loader() {\n        var spin = this.shadowRoot.querySelector('.spinner');\n        var speed = this.getAttribute('speed') || 1000;\n        spin.style.animationDuration = speed + 'ms';\n        var orientation = this.getAttribute('axis') || 'Z';\n        spin.style.animationName = 'spin' + orientation;\n        if (this.hasAttribute('reverse')) {\n            spin.style.animationDirection = 'reverse';\n        }\n    }\n\n    var proto = Object.create(HTMLElement.prototype);\n    proto.createdCallback = loader;\n    window.MySpinner = createElement('my-spinner', '#template', proto);\n</script>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/styleguide/createElement.js",
    "content": "function createElement(elementName, templateSelector, proto) {\n    proto = proto || HTMLElement.prototype;\n    var currentScript = document._currentScript ? document._currentScript : document.currentScript;\n    var template = currentScript.ownerDocument.querySelector(templateSelector).content;\n    var customPrototype = Object.create(proto);\n    var oldCallback = customPrototype.createdCallback;\n    customPrototype.createdCallback = function () {\n        var shadowRoot = this.createShadowRoot();\n        var clone = document.importNode(template, true);\n        shadowRoot.appendChild(clone);\n        if (oldCallback) {\n            oldCallback.call(this);\n        }\n    };\n    return document.registerElement(elementName, {prototype: customPrototype});\n}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/styleguide/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\">\n    <title>Web Components Styleguide</title>\n    <script src=\"webcomponents.min.js\"></script>\n    <!-- Bootstrap core CSS -->\n\n    <link href=\"vendor/bootstrap.min.css\" rel=\"stylesheet\">\n\n    <link href=\"vendor/docs.min.css\" rel=\"stylesheet\">\n    <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.6/styles/default.min.css\">\n    <link rel=\"import\" href=\"components/badge.html\">\n    <link rel=\"import\" href=\"components/spinner.html\">\n    <link rel=\"import\" href=\"components/button.html\">\n    <link rel=\"import\" href=\"components/slider.html\">\n    <link rel=\"import\" href=\"components/accordion.html\"/>\n    <link rel=\"import\" href=\"components/blink.html\"/>\n    <style>.navbar-brand {\n        font-size: 250%;\n        line-height: 1.2;\n        margin: 20px 0;\n    }</style>\n\n</head>\n<body>\n\n<!-- Docs master nav -->\n<header class=\"navbar navbar-static-top bs-docs-nav\" id=\"top\" role=\"banner\">\n    <div class=\"container\">\n        <div class=\"navbar-header\">\n            <a href=\"../\" class=\"navbar-brand\">My Web Components Styleguide</a>\n        </div>\n    </div>\n</header>\n\n\n<div class=\"container bs-docs-container\">\n\n    <div class=\"row\">\n        <div class=\"col-md-9\">\n            <div class=\"bs-docs-section\">\n                <!-- Component group title -->\n                <h1 id=\"first-component-group\" class=\"page-header\">Component Group</h1>\n                <!-- Description of component group -->\n                <p class=\"lead\">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium commodi fugit\n                    incidunt laborum magni maiores minima minus omnis quas, quis quo repellendus sapiente ut! Autem\n                    doloribus molestiae quasi saepe vel.</p>\n                <!-- Note callout about component group -->\n                <div class=\"bs-callout bs-callout-warning\" id=\"callout-btn-group-tooltips\">\n                    <h4>Note about component</h4>\n\n                    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium aliquam amet culpa dolores\n                        hic itaque magni minima minus mollitia nemo nulla numquam odit provident, quidem ratione rem\n                        tempora ullam vitae.</p>\n                </div>\n\n                <!-- Component title -->\n                <h2 id=\"hello-badge\">Hello Badge</h2>\n                <!-- Component description -->\n                <p>Lorem ipsum.</p>\n                <!-- Component code -->\n                <my-badge>Daniel</my-badge>\n                <!-- Component code example -->\n                <div class=\"highlight\"><code class=\"html\">\n                    <my-badge>Daniel</my-badge>\n                </code></div>\n\n                <!-- Component title -->\n                <h2 id=\"spinner\">Spinner</h2>\n                <!-- Component description -->\n                <p>Lorem ipsum.</p>\n                <!-- Component code -->\n                <my-spinner speed=\"500\">One</my-spinner>\n                <my-spinner reverse>Two</my-spinner>\n                <my-spinner axis=\"Y\">Three</my-spinner>\n                <my-spinner axis=\"Y\" reverse>Four</my-spinner>\n                <my-spinner axis=\"X\">Five</my-spinner>\n                <my-spinner axis=\"X\" reverse>Six</my-spinner>\n                <!-- Component code example -->\n                <div class=\"highlight\"><code class=\"html\">\n                    <my-spinner speed=\"500\">One</my-spinner>\n                    <my-spinner reverse>Two</my-spinner>\n                    <my-spinner axis=\"Y\">Three</my-spinner>\n                    <my-spinner axis=\"Y\" reverse>Four</my-spinner>\n                    <my-spinner axis=\"X\">Five</my-spinner>\n                    <my-spinner axis=\"X\" reverse>Six</my-spinner>\n                </code></div>\n\n                <!-- Component title -->\n                <h2 id=\"button\">Button</h2>\n                <!-- Component description -->\n                <p>Lorem ipsum.</p>\n                <!-- Component code -->\n                <my-button>Testing</my-button>\n                <!-- Component code example -->\n                <div class=\"highlight\"><code class=\"html\">\n                    <my-button>Testing</my-button>\n                </code></div>\n\n                <!-- Component title -->\n                <h2 id=\"slider\">Slider</h2>\n                <!-- Component description -->\n                <p>Lorem ipsum.</p>\n                <!-- Component code -->\n                <my-slider interval=\"2000\">\n                    <img src=\"http://lorempixel.com/200/200/abstract/1\"/>\n                    <img src=\"http://lorempixel.com/200/200/abstract/2\"/>\n                    <img src=\"http://lorempixel.com/200/200/abstract/3\"/>\n                    <img src=\"http://lorempixel.com/200/200/abstract/4\"/>\n                </my-slider>\n                <!-- Component code example -->\n                <div class=\"highlight\"><code class=\"html\">\n                    <my-slider interval=\"2000\">\n                        <img src=\"http://lorempixel.com/200/200/abstract/1\"/>\n                        <img src=\"http://lorempixel.com/200/200/abstract/2\"/>\n                        <img src=\"http://lorempixel.com/200/200/abstract/3\"/>\n                        <img src=\"http://lorempixel.com/200/200/abstract/4\"/>\n                    </my-slider>\n                </code></div>\n\n                <!-- Component title -->\n                <h2 id=\"accordion\">Accordion</h2>\n                <!-- Component description -->\n                <p>Lorem ipsum.</p>\n                <!-- Component code -->\n                <my-accordion>\n                    <div class=\"item\">\n                        <p class=\"header\">First paragraph</p>\n\n                        <p class=\"body\">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Assumenda commodi fuga\n                            pariatur. Accusantium blanditiis dolore eius veniam, veritatis vitae voluptatibus? Atque cum\n                            eum exercitationem fuga magnam modi odit praesentium repudiandae?</p>\n                    </div>\n                    <div class=\"item\">\n                        <p class=\"header\">Some text</p>\n\n                        <p class=\"body\">Laborum mollitia quas quod unde. Atque magnam magni nisi sed veritatis? Alias\n                            dolore eveniet fugit libero nesciunt nobis numquam ratione voluptatem? Expedita sequi sunt\n                            voluptatem! Consequatur est magni nihil similique!</p>\n                    </div>\n                    <div class=\"item\">\n                        <p class=\"header\">A body of characters</p>\n\n                        <p class=\"body\">Animi itaque iure maxime non perferendis quos, reprehenderit sit voluptatem.\n                            Aliquid at autem consequuntur doloremque eaque eligendi, facere fugiat fugit numquam odit\n                            officia quasi, quia quisquam reprehenderit sed totam vitae!</p>\n                    </div>\n                    <div class=\"item\">\n                        <p class=\"header\">Fancy HTML</p>\n\n                        <p class=\"body\">Adipisci, alias aspernatur distinctio esse fuga id nobis nulla placeat quis\n                            repudiandae, similique sunt voluptate. Amet eveniet iusto nihil sapiente unde? At\n                            consequuntur eveniet id necessitatibus neque sapiente, soluta voluptates.</p>\n                    </div>\n                </my-accordion>\n                <!-- Component code example -->\n                <div class=\"highlight\"><code class=\"html\">\n                    <my-accordion>\n                        <div class=\"item\">\n                            <p class=\"header\">...</p>\n\n                            <p class=\"body\">...</p>\n                        </div>\n                        <div class=\"item\">\n                            <p class=\"header\">...</p>\n\n                            <p class=\"body\">...</p>\n                        </div>\n                        <div class=\"item\">\n                            <p class=\"header\">...</p>\n\n                            <p class=\"body\">...</p>\n                        </div>\n                        <div class=\"item\">\n                            <p class=\"header\">...</p>\n\n                            <p class=\"body\">...</p>\n                        </div>\n                    </my-accordion>\n                </code></div>\n\n                <!-- Component title -->\n                <h2 id=\"blink\">Blink</h2>\n                <!-- Component description -->\n                <p>Lorem ipsum.</p>\n                <!-- Component code -->\n                <my-blink interval=\"300\" styles=\"color: red, background-color: blue / color: green, background-color: yellow\">Hello World!</my-blink>\n                <!-- Component code example -->\n                <div class=\"highlight\"><code class=\"html\">\n                    <my-blink interval=\"300\" styles=\"color: red, background-color: blue / color: green, background-color: yellow\">Hello World!</my-blink>\n                </code></div>\n\n\n            </div>\n        </div>\n\n        <div class=\"col-md-3\" role=\"complementary\">\n            <nav class=\"bs-docs-sidebar hidden-print hidden-xs hidden-sm\">\n                <ul class=\"nav bs-docs-sidenav\">\n\n\n                    <li>\n                        <a href=\"#first-component-group\">Component Group</a>\n                        <ul class=\"nav\">\n                            <li><a href=\"#hello-badge\">Hello Badge</a></li>\n                            <li><a href=\"#spinner\">Spinner</a></li>\n                            <li><a href=\"#button\">Button</a></li>\n                            <li><a href=\"#slider\">Slider</a></li>\n                            <li><a href=\"#accordion\">Accordion</a></li>\n                            <li><a href=\"#blink\">Blink</a></li>\n                        </ul>\n                    </li>\n                </ul>\n\n            </nav>\n        </div>\n\n    </div>\n</div>\n\n<!-- Footer\n================================================== -->\n<footer class=\"bs-docs-footer\" role=\"contentinfo\">\n    <div class=\"container\">\n\n\n        <p>Styleguide documentation page is forked from <a href=\"https://github.com/twbs/bootstrap/tree/gh-pages\">Twitter\n            Bootstrap</a>, licensed under <a rel=\"license\" href=\"https://github.com/twbs/bootstrap/blob/master/LICENSE\"\n                                             target=\"_blank\">MIT</a>.</p>\n\n    </div>\n</footer>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.6/highlight.min.js\"></script>\n<script>\n\n    function escapeHtml(str) {\n        var div = document.createElement('div');\n        div.appendChild(document.createTextNode(str));\n        return div.innerHTML;\n    }\n\n    var codeNodes = Array.prototype.slice.call(document.querySelectorAll('code'));\n    codeNodes.forEach(function (el) {\n        el.innerHTML = escapeHtml(el.innerHTML);\n    });\n    codeNodes.forEach(function (el) {\n        hljs.highlightBlock(el);\n    });\n</script>\n\n<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js\"></script>\n\n\n<script src=\"vendor/bootstrap.min.js\"></script>\n\n\n<script src=\"vendor/docs.min.js\"></script>\n\n\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/ui-libraries/dogo-toolkit/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <meta charset=\"UTF-8\">\n    <title>Dojo Toolkit Exercise</title>\n</head>\n<body>\n    <!-- Exercise instructions: This exercise will introduce you to Dojo Toolkit\n         1. Go to https://dojotoolkit.org/download/\n         2. Download a Dojo Toolkit\n         3. Include that library on this page\n         4. Follow Hello Dogo tutorial on https://dojotoolkit.org/documentation/tutorials/1.10/hello_dojo/\n         5. Add a widget to your page (https://dojotoolkit.org/documentation/#widgets)\n     -->\n    <h1 id=\"greeting\">Hello</h1>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week5/web-components-training-exercises/ui-libraries/jquery-ui/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <meta charset=\"UTF-8\">\n    <title>jQueryUI Exercise</title>\n</head>\n<body>\n    <!-- Exercise instructions: This exercise will introduce you to jquery UI\n         1. Go to http://jqueryui.com/download/\n         2. Download a build of jQueryUI with everything included\n         3. Include that library on this page (remember to include CSS and JS).\n         4. Create a set of tabs, one which has a button inside that opens a dialog box.\n     -->\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/1-text-editors/1-emmet.html",
    "content": ".header\n\th1.logo\n\t\ta\n\tnav.nav\n\t\tul\n\t\t\tli.nav-item\n\t\t\t\ta.nav-link\n\n.header>h1.logo>a^nav.nav>ul>li.nav-item>a.nav-link\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/1-text-editors/2-emmet.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<title>Document</title>\n</head>\n<body>\n\t<div class=\"wrap\">\n\t\t<header class=\"header\">\n\t\t\t<h1 class=\"logo\"><a href=\"#\" title=\"My Logo\">My Logo</a></h1>\n\t\t\t<nav class=\"nav\">\n\t\t\t\t<ul>\n\t\t\t\t\t<li class=\"nav-item\"><a href=\"\"></a></li>\n\t\t\t\t\t<li class=\"nav-item\"><a href=\"\"></a></li>\n\t\t\t\t\t<li class=\"nav-item\"><a href=\"\"></a></li>\n\t\t\t\t\t<li class=\"nav-item\"><a href=\"\"></a></li>\n\t\t\t\t\t<li class=\"nav-item\"><a href=\"\"></a></li>\n\t\t\t\t</ul>\n\t\t\t</nav>\n\t\t</header>\n\t\t<main class=\"content\">\n\t\t\t<div class=\"col-01\"></div>\n\t\t\t<div class=\"col-02\"></div>\n\t\t</main>\n\t\t<div class=\"footer\"><span class=\"copy\">all rights reserved</span></div>\n\t</div>\n</body>\n</html>\n\nhtml:5>.wrap>header.header>h1.logo>a[href='#' title='My Logo']{My Logo}^nav.nav>ul>(li.nav-item>a)*5^^^main.content>.col-01+.col-02^.footer>span.copy{all rights reserved}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/2-browser-devtools/zlickr/css/gallery-grid.css",
    "content": ".pure-u-1,\n.pure-u-1-1,\n.pure-u-1-2,\n.pure-u-1-3,\n.pure-u-2-3,\n.pure-u-1-6,\n.pure-u-2-6,\n.pure-u-3-6,\n.pure-u-4-6,\n.pure-u-5-6,\n.pure-u-6-6 {\n    display: inline-block;\n    *display: inline;\n    zoom: 1;\n    letter-spacing: normal;\n    word-spacing: normal;\n    vertical-align: top;\n    text-rendering: auto;\n}\n\n.pure-u-1-6 {\n    width: 16.6667%;\n    *width: 16.6357%;\n}\n\n.pure-u-1-3,\n.pure-u-2-6 {\n    width: 33.3333%;\n    *width: 33.3023%;\n}\n\n.pure-u-1-2,\n.pure-u-3-6 {\n    width: 50%;\n    *width: 49.9690%;\n}\n\n.pure-u-2-3,\n.pure-u-4-6 {\n    width: 66.6667%;\n    *width: 66.6357%;\n}\n\n.pure-u-5-6 {\n    width: 83.3333%;\n    *width: 83.3023%;\n}\n\n.pure-u-1,\n.pure-u-1-1,\n.pure-u-6-6 {\n    width: 100%;\n}\n\n@media screen and (min-width: 30em) {\n    .pure-u-med-1,\n    .pure-u-med-1-1,\n    .pure-u-med-1-2,\n    .pure-u-med-1-3,\n    .pure-u-med-2-3,\n    .pure-u-med-1-6,\n    .pure-u-med-2-6,\n    .pure-u-med-3-6,\n    .pure-u-med-4-6,\n    .pure-u-med-5-6,\n    .pure-u-med-6-6 {\n        display: inline-block;\n        *display: inline;\n        zoom: 1;\n        letter-spacing: normal;\n        word-spacing: normal;\n        vertical-align: top;\n        text-rendering: auto;\n    }\n\n    .pure-u-med-1-6 {\n        width: 16.6667%;\n        *width: 16.6357%;\n    }\n\n    .pure-u-med-1-3,\n    .pure-u-med-2-6 {\n        width: 33.3333%;\n        *width: 33.3023%;\n    }\n\n    .pure-u-med-1-2,\n    .pure-u-med-3-6 {\n        width: 50%;\n        *width: 49.9690%;\n    }\n\n    .pure-u-med-2-3,\n    .pure-u-med-4-6 {\n        width: 66.6667%;\n        *width: 66.6357%;\n    }\n\n    .pure-u-med-5-6 {\n        width: 83.3333%;\n        *width: 83.3023%;\n    }\n\n    .pure-u-med-1,\n    .pure-u-med-1-1,\n    .pure-u-med-6-6 {\n        width: 100%;\n    }\n}\n\n@media screen and (min-width: 48em) {\n    .pure-u-lrg-1,\n    .pure-u-lrg-1-1,\n    .pure-u-lrg-1-2,\n    .pure-u-lrg-1-3,\n    .pure-u-lrg-2-3,\n    .pure-u-lrg-1-6,\n    .pure-u-lrg-2-6,\n    .pure-u-lrg-3-6,\n    .pure-u-lrg-4-6,\n    .pure-u-lrg-5-6,\n    .pure-u-lrg-6-6 {\n        display: inline-block;\n        *display: inline;\n        zoom: 1;\n        letter-spacing: normal;\n        word-spacing: normal;\n        vertical-align: top;\n        text-rendering: auto;\n    }\n\n    .pure-u-lrg-1-6 {\n        width: 16.6667%;\n        *width: 16.6357%;\n    }\n\n    .pure-u-lrg-1-3,\n    .pure-u-lrg-2-6 {\n        width: 33.3333%;\n        *width: 33.3023%;\n    }\n\n    .pure-u-lrg-1-2,\n    .pure-u-lrg-3-6 {\n        width: 50%;\n        *width: 49.9690%;\n    }\n\n    .pure-u-lrg-2-3,\n    .pure-u-lrg-4-6 {\n        width: 66.6667%;\n        *width: 66.6357%;\n    }\n\n    .pure-u-lrg-5-6 {\n        width: 83.3333%;\n        *width: 83.3023%;\n    }\n\n    .pure-u-lrg-1,\n    .pure-u-lrg-1-1,\n    .pure-u-lrg-6-6 {\n        width: 100%;\n    }\n}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/2-browser-devtools/zlickr/css/gallery.css",
    "content": "body {\n    color: #666;\n}\n\nh1,h2,h3,h4,h5,h6 {\n    color: #111;\n}\n\n.l-box {\n    padding: 2em;\n}\n\n.header .pure-menu {\n    border-bottom-color: black;\n    border-radius: 0;\n}\n\n.photo-box, .text-box {\n    overflow: hidden;\n    position: relative;\n    height: 250px;\n    text-align: center;\n}\n\n.photo-box-thin {\n    height: 120px;\n}\n\n\n    .photo-box img {\n        max-width: 100%;\n        height: auto;\n        min-height: 250px;\n    }\n\n    .photo-box aside {\n        position: absolute;\n        bottom: 0;\n        right: 0;\n        padding: 1em 0.5em;\n        color: white;\n        width: 100%;\n        font-size: 80%;\n        text-align: right;\n        background: -moz-linear-gradient(top,  rgba(16,27,30,0) 0%, rgba(12,2,2,1) 90%); /* FF3.6+ */\n        background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(16,27,30,0)), color-stop(90%,rgba(12,2,2,1))); /* Chrome,Safari4+ */\n        background: -webkit-linear-gradient(top,  rgba(16,27,30,0) 0%,rgba(12,2,2,1) 90%); /* Chrome10+,Safari5.1+ */\n        background: -o-linear-gradient(top,  rgba(16,27,30,0) 0%,rgba(12,2,2,1) 90%); /* Opera 11.10+ */\n        background: -ms-linear-gradient(top,  rgba(16,27,30,0) 0%,rgba(12,2,2,1) 90%); /* IE10+ */\n        background: linear-gradient(to bottom,  rgba(16,27,30,0) 0%,rgba(12,2,2,1) 90%); /* W3C */\n        filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00101b1e', endColorstr='#0c0202',GradientType=0 ); /* IE6-9 */\n\n    }\n\n    .photo-box aside span {\n        color: #aaa;\n    }\n\n        .photo-box aside span a {\n            color: #ccc;\n            text-decoration: none;\n        }\n\n.text-box {\n    background: #2065a1;\n    color: #fcd209;\n}\n\n    .text-box-head {\n        color: #fff;\n        padding-bottom: 0.2em;\n        font-weight: 400;\n        text-transform: uppercase;\n        letter-spacing: 0.05em;\n        font-size: 24px;\n    }\n\n    .text-box-subhead {\n        font-weight: normal;\n        letter-spacing: 0.1em;\n        text-transform: uppercase;\n    }\n\n.footer {\n    background: #111;\n    color: #666;\n    text-align: center;\n    padding: 1em;\n    font-size: 80%;\n}\n\n@media (min-width: 30em) {\n    .photo-box, .text-box {\n        text-align: left;\n    }\n\n    .photo-box-thin {\n        height: 250px;\n    }\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/2-browser-devtools/zlickr/css/pure.css",
    "content": "/*!\nPure v0.4.2\nCopyright 2014 Yahoo! Inc. All rights reserved.\nLicensed under the BSD License.\nhttps://github.com/yui/pure/blob/master/LICENSE.md\n*/\n/*!\nnormalize.css v1.1.3 | MIT License | git.io/normalize\nCopyright (c) Nicolas Gallagher and Jonathan Neal\n*/\n/*! normalize.css v1.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none;height:0}[hidden]{display:none}html{font-size:100%;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}html,button,input,select,textarea{font-family:sans-serif}body{margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{font-size:2em;margin:.67em 0}h2{font-size:1.5em;margin:.83em 0}h3{font-size:1.17em;margin:1em 0}h4{font-size:1em;margin:1.33em 0}h5{font-size:.83em;margin:1.67em 0}h6{font-size:.67em;margin:2.33em 0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:1em 40px}dfn{font-style:italic}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}mark{background:#ff0;color:#000}p,pre{margin:1em 0}code,kbd,pre,samp{font-family:monospace,serif;_font-family:'courier new',monospace;font-size:1em}pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word}q{quotes:none}q:before,q:after{content:'';content:none}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,menu,ol,ul{margin:1em 0}dd{margin:0 0 0 40px}menu,ol,ul{padding:0 0 0 40px}nav ul,nav ol{list-style:none;list-style-image:none}img{border:0;-ms-interpolation-mode:bicubic}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0;white-space:normal;*margin-left:-7px}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;*overflow:visible}button[disabled],html input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0;*height:13px;*width:13px}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}[hidden]{display:none!important}.pure-g{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em;text-rendering:optimizespeed;font-family:FreeSans,Arimo,\"Droid Sans\",Helvetica,Arial,sans-serif;display:-webkit-flex;-webkit-flex-flow:row wrap;display:-ms-flexbox;-ms-flex-flow:row wrap}.opera-only :-o-prefocus,.pure-g{word-spacing:-.43em}.pure-u{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-g [class *=\"pure-u\"]{font-family:sans-serif}.pure-u-1,.pure-u-1-1,.pure-u-1-2,.pure-u-1-3,.pure-u-2-3,.pure-u-1-4,.pure-u-3-4,.pure-u-1-5,.pure-u-2-5,.pure-u-3-5,.pure-u-4-5,.pure-u-5-5,.pure-u-1-6,.pure-u-5-6,.pure-u-1-8,.pure-u-3-8,.pure-u-5-8,.pure-u-7-8,.pure-u-1-12,.pure-u-5-12,.pure-u-7-12,.pure-u-11-12,.pure-u-1-24,.pure-u-2-24,.pure-u-3-24,.pure-u-4-24,.pure-u-5-24,.pure-u-6-24,.pure-u-7-24,.pure-u-8-24,.pure-u-9-24,.pure-u-10-24,.pure-u-11-24,.pure-u-12-24,.pure-u-13-24,.pure-u-14-24,.pure-u-15-24,.pure-u-16-24,.pure-u-17-24,.pure-u-18-24,.pure-u-19-24,.pure-u-20-24,.pure-u-21-24,.pure-u-22-24,.pure-u-23-24,.pure-u-24-24{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-1-24{width:4.1667%;*width:4.1357%}.pure-u-1-12,.pure-u-2-24{width:8.3333%;*width:8.3023%}.pure-u-1-8,.pure-u-3-24{width:12.5%;*width:12.469%}.pure-u-1-6,.pure-u-4-24{width:16.6667%;*width:16.6357%}.pure-u-1-5{width:20%;*width:19.969%}.pure-u-5-24{width:20.8333%;*width:20.8023%}.pure-u-1-4,.pure-u-6-24{width:25%;*width:24.969%}.pure-u-7-24{width:29.1667%;*width:29.1357%}.pure-u-1-3,.pure-u-8-24{width:33.3333%;*width:33.3023%}.pure-u-3-8,.pure-u-9-24{width:37.5%;*width:37.469%}.pure-u-2-5{width:40%;*width:39.969%}.pure-u-5-12,.pure-u-10-24{width:41.6667%;*width:41.6357%}.pure-u-11-24{width:45.8333%;*width:45.8023%}.pure-u-1-2,.pure-u-12-24{width:50%;*width:49.969%}.pure-u-13-24{width:54.1667%;*width:54.1357%}.pure-u-7-12,.pure-u-14-24{width:58.3333%;*width:58.3023%}.pure-u-3-5{width:60%;*width:59.969%}.pure-u-5-8,.pure-u-15-24{width:62.5%;*width:62.469%}.pure-u-2-3,.pure-u-16-24{width:66.6667%;*width:66.6357%}.pure-u-17-24{width:70.8333%;*width:70.8023%}.pure-u-3-4,.pure-u-18-24{width:75%;*width:74.969%}.pure-u-19-24{width:79.1667%;*width:79.1357%}.pure-u-4-5{width:80%;*width:79.969%}.pure-u-5-6,.pure-u-20-24{width:83.3333%;*width:83.3023%}.pure-u-7-8,.pure-u-21-24{width:87.5%;*width:87.469%}.pure-u-11-12,.pure-u-22-24{width:91.6667%;*width:91.6357%}.pure-u-23-24{width:95.8333%;*width:95.8023%}.pure-u-1,.pure-u-1-1,.pure-u-5-5,.pure-u-24-24{width:100%}.pure-g-r{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em;font-family:FreeSans,Arimo,\"Droid Sans\",Helvetica,Arial,sans-serif;display:-webkit-flex;-webkit-flex-flow:row wrap;display:-ms-flexbox;-ms-flex-flow:row wrap}.opera-only :-o-prefocus,.pure-g-r{word-spacing:-.43em}.pure-g-r [class *=\"pure-u\"]{font-family:sans-serif}.pure-g-r img{max-width:100%;height:auto}@media (min-width:980px){.pure-visible-phone{display:none}.pure-visible-tablet{display:none}.pure-hidden-desktop{display:none}}@media (max-width:480px){.pure-g-r>.pure-u,.pure-g-r>[class *=\"pure-u-\"]{width:100%}}@media (max-width:767px){.pure-g-r>.pure-u,.pure-g-r>[class *=\"pure-u-\"]{width:100%}.pure-hidden-phone{display:none}.pure-visible-desktop{display:none}}@media (min-width:768px) and (max-width:979px){.pure-hidden-tablet{display:none}.pure-visible-desktop{display:none}}.pure-button{display:inline-block;*display:inline;zoom:1;line-height:normal;white-space:nowrap;vertical-align:baseline;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button{font-family:inherit;font-size:100%;*font-size:90%;*overflow:visible;padding:.5em 1em;color:#444;color:rgba(0,0,0,.8);*color:#444;border:1px solid #999;border:0 rgba(0,0,0,0);background-color:#E6E6E6;text-decoration:none;border-radius:2px}.pure-button-hover,.pure-button:hover,.pure-button:focus{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#1a000000', GradientType=0);background-image:-webkit-gradient(linear,0 0,0 100%,from(transparent),color-stop(40%,rgba(0,0,0,.05)),to(rgba(0,0,0,.1)));background-image:-webkit-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:-moz-linear-gradient(top,rgba(0,0,0,.05) 0,rgba(0,0,0,.1));background-image:-o-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1))}.pure-button:focus{outline:0}.pure-button-active,.pure-button:active{box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset}.pure-button[disabled],.pure-button-disabled,.pure-button-disabled:hover,.pure-button-disabled:focus,.pure-button-disabled:active{border:0;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);filter:alpha(opacity=40);-khtml-opacity:.4;-moz-opacity:.4;opacity:.4;cursor:not-allowed;box-shadow:none}.pure-button-hidden{display:none}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button-primary,.pure-button-selected,a.pure-button-primary,a.pure-button-selected{background-color:#0078e7;color:#fff}.pure-form input[type=text],.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=color],.pure-form select,.pure-form textarea{padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-form input:not([type]){padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-form input[type=color]{padding:.2em .5em}.pure-form input[type=text]:focus,.pure-form input[type=password]:focus,.pure-form input[type=email]:focus,.pure-form input[type=url]:focus,.pure-form input[type=date]:focus,.pure-form input[type=month]:focus,.pure-form input[type=time]:focus,.pure-form input[type=datetime]:focus,.pure-form input[type=datetime-local]:focus,.pure-form input[type=week]:focus,.pure-form input[type=number]:focus,.pure-form input[type=search]:focus,.pure-form input[type=tel]:focus,.pure-form input[type=color]:focus,.pure-form select:focus,.pure-form textarea:focus{outline:0;outline:thin dotted \\9;border-color:#129FEA}.pure-form input:not([type]):focus{outline:0;outline:thin dotted \\9;border-color:#129FEA}.pure-form input[type=file]:focus,.pure-form input[type=radio]:focus,.pure-form input[type=checkbox]:focus{outline:thin dotted #333;outline:1px auto #129FEA}.pure-form .pure-checkbox,.pure-form .pure-radio{margin:.5em 0;display:block}.pure-form input[type=text][disabled],.pure-form input[type=password][disabled],.pure-form input[type=email][disabled],.pure-form input[type=url][disabled],.pure-form input[type=date][disabled],.pure-form input[type=month][disabled],.pure-form input[type=time][disabled],.pure-form input[type=datetime][disabled],.pure-form input[type=datetime-local][disabled],.pure-form input[type=week][disabled],.pure-form input[type=number][disabled],.pure-form input[type=search][disabled],.pure-form input[type=tel][disabled],.pure-form input[type=color][disabled],.pure-form select[disabled],.pure-form textarea[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input:not([type])[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input[readonly],.pure-form select[readonly],.pure-form textarea[readonly]{background:#eee;color:#777;border-color:#ccc}.pure-form input:focus:invalid,.pure-form textarea:focus:invalid,.pure-form select:focus:invalid{color:#b94a48;border-color:#ee5f5b}.pure-form input:focus:invalid:focus,.pure-form textarea:focus:invalid:focus,.pure-form select:focus:invalid:focus{border-color:#e9322d}.pure-form input[type=file]:focus:invalid:focus,.pure-form input[type=radio]:focus:invalid:focus,.pure-form input[type=checkbox]:focus:invalid:focus{outline-color:#e9322d}.pure-form select{border:1px solid #ccc;background-color:#fff}.pure-form select[multiple]{height:auto}.pure-form label{margin:.5em 0 .2em}.pure-form fieldset{margin:0;padding:.35em 0 .75em;border:0}.pure-form legend{display:block;width:100%;padding:.3em 0;margin-bottom:.3em;color:#333;border-bottom:1px solid #e5e5e5}.pure-form-stacked input[type=text],.pure-form-stacked input[type=password],.pure-form-stacked input[type=email],.pure-form-stacked input[type=url],.pure-form-stacked input[type=date],.pure-form-stacked input[type=month],.pure-form-stacked input[type=time],.pure-form-stacked input[type=datetime],.pure-form-stacked input[type=datetime-local],.pure-form-stacked input[type=week],.pure-form-stacked input[type=number],.pure-form-stacked input[type=search],.pure-form-stacked input[type=tel],.pure-form-stacked input[type=color],.pure-form-stacked select,.pure-form-stacked label,.pure-form-stacked textarea{display:block;margin:.25em 0}.pure-form-stacked input:not([type]){display:block;margin:.25em 0}.pure-form-aligned input,.pure-form-aligned textarea,.pure-form-aligned select,.pure-form-aligned .pure-help-inline,.pure-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.pure-form-aligned textarea{vertical-align:top}.pure-form-aligned .pure-control-group{margin-bottom:.5em}.pure-form-aligned .pure-control-group label{text-align:right;display:inline-block;vertical-align:middle;width:10em;margin:0 1em 0 0}.pure-form-aligned .pure-controls{margin:1.5em 0 0 10em}.pure-form input.pure-input-rounded,.pure-form .pure-input-rounded{border-radius:2em;padding:.5em 1em}.pure-form .pure-group fieldset{margin-bottom:10px}.pure-form .pure-group input{display:block;padding:10px;margin:0;border-radius:0;position:relative;top:-1px}.pure-form .pure-group input:focus{z-index:2}.pure-form .pure-group input:first-child{top:1px;border-radius:4px 4px 0 0}.pure-form .pure-group input:last-child{top:-2px;border-radius:0 0 4px 4px}.pure-form .pure-group button{margin:.35em 0}.pure-form .pure-input-1{width:100%}.pure-form .pure-input-2-3{width:66%}.pure-form .pure-input-1-2{width:50%}.pure-form .pure-input-1-3{width:33%}.pure-form .pure-input-1-4{width:25%}.pure-form .pure-help-inline,.pure-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:.875em}.pure-form-message{display:block;color:#666;font-size:.875em}@media only screen and (max-width :480px){.pure-form button[type=submit]{margin:.7em 0 0}.pure-form input:not([type]),.pure-form input[type=text],.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=color],.pure-form label{margin-bottom:.3em;display:block}.pure-group input:not([type]),.pure-group input[type=text],.pure-group input[type=password],.pure-group input[type=email],.pure-group input[type=url],.pure-group input[type=date],.pure-group input[type=month],.pure-group input[type=time],.pure-group input[type=datetime],.pure-group input[type=datetime-local],.pure-group input[type=week],.pure-group input[type=number],.pure-group input[type=search],.pure-group input[type=tel],.pure-group input[type=color]{margin-bottom:0}.pure-form-aligned .pure-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.pure-form-aligned .pure-controls{margin:1.5em 0 0}.pure-form .pure-help-inline,.pure-form-message-inline,.pure-form-message{display:block;font-size:.75em;padding:.2em 0 .8em}}.pure-menu ul{position:absolute;visibility:hidden}.pure-menu.pure-menu-open{visibility:visible;z-index:2;width:100%}.pure-menu ul{left:-10000px;list-style:none;margin:0;padding:0;top:-10000px;z-index:1}.pure-menu>ul{position:relative}.pure-menu-open>ul{left:0;top:0;visibility:visible}.pure-menu-open>ul:focus{outline:0}.pure-menu li{position:relative}.pure-menu a,.pure-menu .pure-menu-heading{display:block;color:inherit;line-height:1.5em;padding:5px 20px;text-decoration:none;white-space:nowrap}.pure-menu.pure-menu-horizontal>.pure-menu-heading{display:inline-block;*display:inline;zoom:1;margin:0;vertical-align:middle}.pure-menu.pure-menu-horizontal>ul{display:inline-block;*display:inline;zoom:1;vertical-align:middle}.pure-menu li a{padding:5px 20px}.pure-menu-can-have-children>.pure-menu-label:after{content:'\\25B8';float:right;font-family:'Lucida Grande','Lucida Sans Unicode','DejaVu Sans',sans-serif;margin-right:-20px;margin-top:-1px}.pure-menu-can-have-children>.pure-menu-label{padding-right:30px}.pure-menu-separator{background-color:#dfdfdf;display:block;height:1px;font-size:0;margin:7px 2px;overflow:hidden}.pure-menu-hidden{display:none}.pure-menu-fixed{position:fixed;top:0;left:0;width:100%}.pure-menu-horizontal li{display:inline-block;*display:inline;zoom:1;vertical-align:middle}.pure-menu-horizontal li li{display:block}.pure-menu-horizontal>.pure-menu-children>.pure-menu-can-have-children>.pure-menu-label:after{content:\"\\25BE\"}.pure-menu-horizontal>.pure-menu-children>.pure-menu-can-have-children>.pure-menu-label{padding-right:30px}.pure-menu-horizontal li.pure-menu-separator{height:50%;width:1px;margin:0 7px}.pure-menu-horizontal li li.pure-menu-separator{height:1px;width:auto;margin:7px 2px}.pure-menu.pure-menu-open,.pure-menu.pure-menu-horizontal li .pure-menu-children{background:#fff;border:1px solid #b7b7b7}.pure-menu.pure-menu-horizontal,.pure-menu.pure-menu-horizontal .pure-menu-heading{border:0}.pure-menu a{border:1px solid transparent;border-left:0;border-right:0}.pure-menu a,.pure-menu .pure-menu-can-have-children>li:after{color:#777}.pure-menu .pure-menu-can-have-children>li:hover:after{color:#fff}.pure-menu .pure-menu-open{background:#dedede}.pure-menu li a:hover,.pure-menu li a:focus{background:#eee}.pure-menu li.pure-menu-disabled a:hover,.pure-menu li.pure-menu-disabled a:focus{background:#fff;color:#bfbfbf}.pure-menu .pure-menu-disabled>a{background-image:none;border-color:transparent;cursor:default}.pure-menu .pure-menu-disabled>a,.pure-menu .pure-menu-can-have-children.pure-menu-disabled>a:after{color:#bfbfbf}.pure-menu .pure-menu-heading{color:#565d64;text-transform:uppercase;font-size:90%;margin-top:.5em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:#dfdfdf}.pure-menu .pure-menu-selected a{color:#000}.pure-menu.pure-menu-open.pure-menu-fixed{border:0;border-bottom:1px solid #b7b7b7}.pure-paginator{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em;text-rendering:optimizespeed;list-style:none;margin:0;padding:0}.opera-only :-o-prefocus,.pure-paginator{word-spacing:-.43em}.pure-paginator li{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-paginator .pure-button{border-radius:0;padding:.8em 1.4em;vertical-align:top;height:1.1em}.pure-paginator .pure-button:focus,.pure-paginator .pure-button:active{outline-style:none}.pure-paginator .prev,.pure-paginator .next{color:#C0C1C3;text-shadow:0 -1px 0 rgba(0,0,0,.45)}.pure-paginator .prev{border-radius:2px 0 0 2px}.pure-paginator .next{border-radius:0 2px 2px 0}@media (max-width:480px){.pure-menu-horizontal{width:100%}.pure-menu-children li{display:block;border-bottom:1px solid #000}}.pure-table{border-collapse:collapse;border-spacing:0;empty-cells:show;border:1px solid #cbcbcb}.pure-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.pure-table td,.pure-table th{border-left:1px solid #cbcbcb;border-width:0 0 0 1px;font-size:inherit;margin:0;overflow:visible;padding:6px 12px}.pure-table td:first-child,.pure-table th:first-child{border-left-width:0}.pure-table thead{background:#e0e0e0;color:#000;text-align:left;vertical-align:bottom}.pure-table td{background-color:transparent}.pure-table-odd td{background-color:#f2f2f2}.pure-table-striped tr:nth-child(2n-1) td{background-color:#f2f2f2}.pure-table-bordered td{border-bottom:1px solid #cbcbcb}.pure-table-bordered tbody>tr:last-child td,.pure-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.pure-table-horizontal td,.pure-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #cbcbcb}.pure-table-horizontal tbody>tr:last-child td{border-bottom-width:0}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/2-browser-devtools/zlickr/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta name=\"description\" content=\"A layout example that shows off a responsive photo gallery.\">\n\n    <title>Zlickr</title>\n\n    <link rel=\"stylesheet\" href=\"css/pure.css\">\n    <link rel=\"stylesheet\" href=\"css/gallery-grid.css\">\n    <link rel=\"stylesheet\" href=\"css/gallery.css\">\n</head>\n<body>\n\n<div>\n    <div class=\"header\">\n        <div class=\"pure-menu pure-menu-open pure-menu-horizontal\">\n            <a class=\"pure-menu-heading\" href=\"\">Zlickr</a>\n\n            <ul>\n                <li class=\"pure-menu-selected\"><a href=\"#\">Home</a></li>\n                <li><a href=\"#\">Photos</a></li>\n                <li><a href=\"#\">About</a></li>\n            </ul>\n        </div>\n    </div>\n\n    <div class=\"pure-g\">\n        <div class=\"photo-box pure-u-1 pure-u-med-1-3 pure-u-lrg-1-4\">\n            <a href=\"http://www.dillonmcintosh.tumblr.com/\">\n                <img src=\"img/1.jpg\" alt=\"Beach\">\n            </a>\n\n            <aside class=\"photo-box-caption\">\n                <span>por <a href=\"http://www.dillonmcintosh.tumblr.com/\">Dillon McIntosh</a></span>\n            </aside>\n        </div>\n\n        <div class=\"text-box pure-u-1 pure-u-med-2-3 pure-u-lrg-3-4\">\n            <div class=\"l-box\">\n                <h1 class=\"text-box-head\">Zlickr</h1>\n                <p class=\"text-box-subhead\">Lorem ipsum dolor sit amet, consectetur adipisicing.</p>\n            </div>\n        </div>\n\n        <div class=\"photo-box pure-u-1 pure-u-med-1-2 pure-u-lrg-1-3\">\n            <a href=\"http://www.flickr.com/photos/charliefoster/\">\n                <img src=\"img/5.jpg\" alt=\"Bridge\">\n            </a>\n\n            <aside class=\"photo-box-caption\">\n                <span>\n                    por <a href=\"http://www.flickr.com/photos/charliefoster/\">Charlie Foster</a>\n                </span>\n            </aside>\n        </div>\n\n        <div class=\"photo-box photo-box-thin pure-u-1 pure-u-lrg-2-3\">\n            <a href=\"http://ngkhanhlinh.dunked.com/\">\n                <img src=\"img/6.jpg\" alt=\"Balloons\">\n            </a>\n\n            <aside class=\"photo-box-caption\">\n                <span>\n                    por <a href=\"http://ngkhanhlinh.dunked.com/\">Linh Nguyen</a>\n                </span>\n            </aside>\n        </div>\n\n        <div class=\"photo-box photo-box-thin pure-u-1 pure-u-med-2-3\">\n            <a href=\"http://twitter.com/iBoZR\">\n                <img src=\"img/7.jpg\" alt=\"Rain Drops\">\n            </a>\n\n            <aside class=\"photo-box-caption\">\n                <span>\n                    por <a href=\"http://twitter.com/iBoZR\">Thanun Buranapong</a>\n                </span>\n            </aside>\n        </div>\n\n        <div class=\"photo-box pure-u-1 pure-u-med-1-2 pure-u-lrg-1-3\">\n            <a href=\"http://ngkhanhlinh.dunked.com/\">\n                <img src=\"img/2.jpg\" alt=\"Meadow\">\n            </a>\n\n            <aside class=\"photo-box-caption\">\n                <span>\n                    por <a href=\"http://ngkhanhlinh.dunked.com/\">Linh Nguyen</a>\n                </span>\n            </aside>\n        </div>\n\n        <div class=\"photo-box pure-u-1 pure-u-med-1-2 pure-u-lrg-1-3\">\n            <a href=\"http://www.nilssonlee.se/\">\n                <img src=\"img/3.jpg\" alt=\"City\">\n            </a>\n\n            <aside class=\"photo-box-caption\">\n                <span>\n                    por <a href=\"http://www.nilssonlee.se/\">Jonas Nilsson Lee</a>\n                </span>\n            </aside>\n        </div>\n\n        <div class=\"photo-box pure-u-1 pure-u-med-1-2 pure-u-lrg-1-3\">\n            <a href=\"http://www.flickr.com/photos/rulasibai/\">\n                <img src=\"img/4.jpg\" alt=\"Flowers\">\n            </a>\n\n            <aside class=\"photo-box-caption\">\n                <span>\n                    por <a href=\"http://www.flickr.com/photos/rulasibai/\">Rula Sibai</a>\n                </span>\n            </aside>\n        </div>\n\n        <div class=\"photo-box pure-u-1 pure-u-med-1-3\">\n            <a href=\"http://www.goodfreephotos.com/\">\n                <img src=\"img/8.jpg\"\n                     alt=\"Port\">\n            </a>\n\n            <aside class=\"photo-box-caption\">\n                <span>\n                    por <a href=\"http://www.goodfreephotos.com/\">Yinan Chen</a>\n                </span>\n            </aside>\n        </div>\n\n    </div>\n\n    <div class=\"footer\">\n        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloremque, provident!\n    </div>\n</div>\n\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/2-browser-devtools/zmail/css/email.css",
    "content": "/*\n * -- BASE STYLES --\n * Most of these are inherited from Base, but I want to change a few.\n */\nbody {\n    color: #333;\n}\n\n.brand-title {\n    color: white;\n}\n\na {\n    text-decoration: none;\n    color: #49ad48;\n}\n\n\n/*\n * -- HELPER STYLES --\n * Over-riding some of the .pure-button styles to make my buttons look unique\n */\n.primary-button,\n.secondary-button {\n    -webkit-box-shadow: none;\n    -moz-box-shadow: none;\n    box-shadow: none;\n    border-radius: 20px;\n}\n.primary-button {\n    color: #fff;\n    background: #e7b320;\n    margin: 1em 0;\n}\n.secondary-button {\n    background: #fff;\n    border: 1px solid #ddd;\n    color: #666;\n    padding: 0.5em 2em;\n    font-size: 80%;\n}\n\n/*\n * -- LAYOUT STYLES --\n * This layout consists of three main elements, `#nav` (navigation bar), `#list` (email list), and `#main` (email content). All 3 elements are within `#layout`\n */\n#layout, #nav, #list, #main {\n    margin: 0;\n    padding: 0;\n}\n\n/* Make the navigation 100% width on phones */\n#nav {\n    width: 100%;\n    height: 40px;\n    position: relative;\n    background: #2065a1;\n    text-align: center;\n}\n/* Show the \"Menu\" button on phones */\n#nav .nav-menu-button {\n    display: block;\n    top: 0.5em;\n    right: 0.5em;\n    position: absolute;\n}\n\n/* When \"Menu\" is clicked, the navbar should be 80% height */\n#nav.active {\n    height: 80%;\n}\n/* Don't show the navigation items... */\n.nav-inner {\n    display: none;\n}\n\n/* ...until the \"Menu\" button is clicked */\n#nav.active .nav-inner {\n    display: block;\n    padding: 2em 0;\n}\n\n\n/*\n * -- NAV BAR STYLES --\n * Styling the default .pure-menu to look a little more unique.\n */\n#nav .pure-menu.pure-menu-open {\n    background: transparent;\n    border: none;\n    text-align: left;\n}\n    #nav .pure-menu a:hover,\n    #nav .pure-menu a:focus {\n        background: rgb(55, 60, 90);\n    }\n    #nav .pure-menu a {\n        color: #fff;\n        margin-left: 0.5em;\n    }\n    #nav .pure-menu-heading {\n        border-bottom: none;\n        font-size:110%;\n        color: #7db1df;\n    }\n\n\n/*\n * -- EMAIL STYLES --\n * Styles relevant to the email messages, labels, counts, and more.\n */\n.email-count {\n    color: #7db1df;\n}\n\n.email-label-personal,\n.email-label-work,\n.email-label-travel {\n    width: 15px;\n    height: 15px;\n    display: inline-block;\n    margin-right: 0.5em;\n    border-radius: 3px;\n}\n.email-label-personal {\n    background: #fcd209;\n}\n.email-label-work {\n    background: #e84d42;\n}\n.email-label-travel {\n    background: #4cb749;\n}\n\n\n/* Email Item Styles */\n.email-item {\n    padding: 0.9em 1em;\n    border-bottom: 1px solid #ddd;\n    border-left: 6px solid transparent;\n}\n    .email-avatar {\n        border-radius: 3px;\n        margin-right: 0.5em;\n    }\n    .email-name,\n    .email-subject {\n        margin: 0;\n    }\n    .email-name {\n        text-transform: uppercase;\n        color: #999;\n    }\n    .email-desc {\n        font-size: 80%;\n        margin: 0.4em 0;\n    }\n\n.email-item-selected {\n    background: #eee;\n}\n.email-item-unread {\n    border-left: 6px solid #49ad48;\n}\n\n/* Email Content Styles */\n.email-content-header, .email-content-body, .email-content-footer {\n    padding: 1em 2em;\n}\n    .email-content-header {\n        border-bottom: 1px solid #ddd;\n    }\n\n        .email-content-title {\n            margin: 0.5em 0 0;\n        }\n        .email-content-subtitle {\n            font-size: 1em;\n            margin: 0;\n            font-weight: normal;\n        }\n            .email-content-subtitle span {\n                color: #999;\n            }\n    .email-content-controls {\n        margin-top: 2em;\n        text-align: right;\n    }\n        .email-content-controls .secondary-button {\n            margin-bottom: 0.3em;\n        }\n\n    .email-avatar {\n        width: 40px;\n        height: 40px;\n    }\n\n\n/*\n * -- TABLET (AND UP) MEDIA QUERIES --\n * On tablets and other medium-sized devices, we want to customize some\n * of the mobile styles.\n */\n@media (min-width: 40em) {\n\n    /* Move the layout over so we can fit the nav + list in on the left */\n    #layout {\n        padding-left:500px; /* \"left col (nav + list)\" width */\n        position: relative;\n    }\n\n    /* These are position:fixed; elements that will be in the left 500px of the screen */\n    #nav, #list {\n        position: fixed;\n        top: 0;\n        bottom: 0;\n        overflow: auto;\n    }\n    #nav {\n        margin-left:-500px; /* \"left col (nav + list)\" width */\n        width:150px;\n        height: 100%;\n    }\n\n    /* Show the menu items on the larger screen */\n    .nav-inner {\n        display: block;\n        padding: 2em 0;\n    }\n\n    /* Hide the \"Menu\" button on larger screens */\n    #nav .nav-menu-button {\n        display: none;\n    }\n\n    #list {\n        margin-left: -350px;\n        width: 100%;\n        height: 33%;\n        border-bottom: 1px solid #ddd;\n    }\n\n    #main {\n        position: fixed;\n        top: 33%;\n        right: 0;\n        bottom: 0;\n        left: 150px;\n        overflow: auto;\n        width: auto; /* so that it's not 100% */\n    }\n\n}\n\n/*\n * -- DESKTOP (AND UP) MEDIA QUERIES --\n * On desktops and other large-sized devices, we want to customize some\n * of the mobile styles.\n */\n@media (min-width: 60em) {\n\n    /* This will take up the entire height, and be a little thinner */\n    #list {\n        margin-left: -350px;\n        width:350px;\n        height: 100%;\n        border-right: 1px solid #ddd;\n    }\n\n    /* This will now take up it's own column, so don't need position: fixed; */\n    #main {\n        position: static;\n        margin: 0;\n        padding: 0;\n    }\n}\n\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/2-browser-devtools/zmail/css/pure.css",
    "content": "/*!\nPure v0.4.2\nCopyright 2014 Yahoo! Inc. All rights reserved.\nLicensed under the BSD License.\nhttps://github.com/yui/pure/blob/master/LICENSE.md\n*/\n/*!\nnormalize.css v1.1.3 | MIT License | git.io/normalize\nCopyright (c) Nicolas Gallagher and Jonathan Neal\n*/\n/*! normalize.css v1.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none;height:0}[hidden]{display:none}html{font-size:100%;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}html,button,input,select,textarea{font-family:sans-serif}body{margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{font-size:2em;margin:.67em 0}h2{font-size:1.5em;margin:.83em 0}h3{font-size:1.17em;margin:1em 0}h4{font-size:1em;margin:1.33em 0}h5{font-size:.83em;margin:1.67em 0}h6{font-size:.67em;margin:2.33em 0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:1em 40px}dfn{font-style:italic}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}mark{background:#ff0;color:#000}p,pre{margin:1em 0}code,kbd,pre,samp{font-family:monospace,serif;_font-family:'courier new',monospace;font-size:1em}pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word}q{quotes:none}q:before,q:after{content:'';content:none}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,menu,ol,ul{margin:1em 0}dd{margin:0 0 0 40px}menu,ol,ul{padding:0 0 0 40px}nav ul,nav ol{list-style:none;list-style-image:none}img{border:0;-ms-interpolation-mode:bicubic}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0;white-space:normal;*margin-left:-7px}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;*overflow:visible}button[disabled],html input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0;*height:13px;*width:13px}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}[hidden]{display:none!important}.pure-g{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em;text-rendering:optimizespeed;font-family:FreeSans,Arimo,\"Droid Sans\",Helvetica,Arial,sans-serif;display:-webkit-flex;-webkit-flex-flow:row wrap;display:-ms-flexbox;-ms-flex-flow:row wrap}.opera-only :-o-prefocus,.pure-g{word-spacing:-.43em}.pure-u{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-g [class *=\"pure-u\"]{font-family:sans-serif}.pure-u-1,.pure-u-1-1,.pure-u-1-2,.pure-u-1-3,.pure-u-2-3,.pure-u-1-4,.pure-u-3-4,.pure-u-1-5,.pure-u-2-5,.pure-u-3-5,.pure-u-4-5,.pure-u-5-5,.pure-u-1-6,.pure-u-5-6,.pure-u-1-8,.pure-u-3-8,.pure-u-5-8,.pure-u-7-8,.pure-u-1-12,.pure-u-5-12,.pure-u-7-12,.pure-u-11-12,.pure-u-1-24,.pure-u-2-24,.pure-u-3-24,.pure-u-4-24,.pure-u-5-24,.pure-u-6-24,.pure-u-7-24,.pure-u-8-24,.pure-u-9-24,.pure-u-10-24,.pure-u-11-24,.pure-u-12-24,.pure-u-13-24,.pure-u-14-24,.pure-u-15-24,.pure-u-16-24,.pure-u-17-24,.pure-u-18-24,.pure-u-19-24,.pure-u-20-24,.pure-u-21-24,.pure-u-22-24,.pure-u-23-24,.pure-u-24-24{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-1-24{width:4.1667%;*width:4.1357%}.pure-u-1-12,.pure-u-2-24{width:8.3333%;*width:8.3023%}.pure-u-1-8,.pure-u-3-24{width:12.5%;*width:12.469%}.pure-u-1-6,.pure-u-4-24{width:16.6667%;*width:16.6357%}.pure-u-1-5{width:20%;*width:19.969%}.pure-u-5-24{width:20.8333%;*width:20.8023%}.pure-u-1-4,.pure-u-6-24{width:25%;*width:24.969%}.pure-u-7-24{width:29.1667%;*width:29.1357%}.pure-u-1-3,.pure-u-8-24{width:33.3333%;*width:33.3023%}.pure-u-3-8,.pure-u-9-24{width:37.5%;*width:37.469%}.pure-u-2-5{width:40%;*width:39.969%}.pure-u-5-12,.pure-u-10-24{width:41.6667%;*width:41.6357%}.pure-u-11-24{width:45.8333%;*width:45.8023%}.pure-u-1-2,.pure-u-12-24{width:50%;*width:49.969%}.pure-u-13-24{width:54.1667%;*width:54.1357%}.pure-u-7-12,.pure-u-14-24{width:58.3333%;*width:58.3023%}.pure-u-3-5{width:60%;*width:59.969%}.pure-u-5-8,.pure-u-15-24{width:62.5%;*width:62.469%}.pure-u-2-3,.pure-u-16-24{width:66.6667%;*width:66.6357%}.pure-u-17-24{width:70.8333%;*width:70.8023%}.pure-u-3-4,.pure-u-18-24{width:75%;*width:74.969%}.pure-u-19-24{width:79.1667%;*width:79.1357%}.pure-u-4-5{width:80%;*width:79.969%}.pure-u-5-6,.pure-u-20-24{width:83.3333%;*width:83.3023%}.pure-u-7-8,.pure-u-21-24{width:87.5%;*width:87.469%}.pure-u-11-12,.pure-u-22-24{width:91.6667%;*width:91.6357%}.pure-u-23-24{width:95.8333%;*width:95.8023%}.pure-u-1,.pure-u-1-1,.pure-u-5-5,.pure-u-24-24{width:100%}.pure-g-r{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em;font-family:FreeSans,Arimo,\"Droid Sans\",Helvetica,Arial,sans-serif;display:-webkit-flex;-webkit-flex-flow:row wrap;display:-ms-flexbox;-ms-flex-flow:row wrap}.opera-only :-o-prefocus,.pure-g-r{word-spacing:-.43em}.pure-g-r [class *=\"pure-u\"]{font-family:sans-serif}.pure-g-r img{max-width:100%;height:auto}@media (min-width:980px){.pure-visible-phone{display:none}.pure-visible-tablet{display:none}.pure-hidden-desktop{display:none}}@media (max-width:480px){.pure-g-r>.pure-u,.pure-g-r>[class *=\"pure-u-\"]{width:100%}}@media (max-width:767px){.pure-g-r>.pure-u,.pure-g-r>[class *=\"pure-u-\"]{width:100%}.pure-hidden-phone{display:none}.pure-visible-desktop{display:none}}@media (min-width:768px) and (max-width:979px){.pure-hidden-tablet{display:none}.pure-visible-desktop{display:none}}.pure-button{display:inline-block;*display:inline;zoom:1;line-height:normal;white-space:nowrap;vertical-align:baseline;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button{font-family:inherit;font-size:100%;*font-size:90%;*overflow:visible;padding:.5em 1em;color:#444;color:rgba(0,0,0,.8);*color:#444;border:1px solid #999;border:0 rgba(0,0,0,0);background-color:#E6E6E6;text-decoration:none;border-radius:2px}.pure-button-hover,.pure-button:hover,.pure-button:focus{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#1a000000', GradientType=0);background-image:-webkit-gradient(linear,0 0,0 100%,from(transparent),color-stop(40%,rgba(0,0,0,.05)),to(rgba(0,0,0,.1)));background-image:-webkit-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:-moz-linear-gradient(top,rgba(0,0,0,.05) 0,rgba(0,0,0,.1));background-image:-o-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1))}.pure-button:focus{outline:0}.pure-button-active,.pure-button:active{box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset}.pure-button[disabled],.pure-button-disabled,.pure-button-disabled:hover,.pure-button-disabled:focus,.pure-button-disabled:active{border:0;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);filter:alpha(opacity=40);-khtml-opacity:.4;-moz-opacity:.4;opacity:.4;cursor:not-allowed;box-shadow:none}.pure-button-hidden{display:none}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button-primary,.pure-button-selected,a.pure-button-primary,a.pure-button-selected{background-color:#0078e7;color:#fff}.pure-form input[type=text],.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=color],.pure-form select,.pure-form textarea{padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-form input:not([type]){padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-form input[type=color]{padding:.2em .5em}.pure-form input[type=text]:focus,.pure-form input[type=password]:focus,.pure-form input[type=email]:focus,.pure-form input[type=url]:focus,.pure-form input[type=date]:focus,.pure-form input[type=month]:focus,.pure-form input[type=time]:focus,.pure-form input[type=datetime]:focus,.pure-form input[type=datetime-local]:focus,.pure-form input[type=week]:focus,.pure-form input[type=number]:focus,.pure-form input[type=search]:focus,.pure-form input[type=tel]:focus,.pure-form input[type=color]:focus,.pure-form select:focus,.pure-form textarea:focus{outline:0;outline:thin dotted \\9;border-color:#129FEA}.pure-form input:not([type]):focus{outline:0;outline:thin dotted \\9;border-color:#129FEA}.pure-form input[type=file]:focus,.pure-form input[type=radio]:focus,.pure-form input[type=checkbox]:focus{outline:thin dotted #333;outline:1px auto #129FEA}.pure-form .pure-checkbox,.pure-form .pure-radio{margin:.5em 0;display:block}.pure-form input[type=text][disabled],.pure-form input[type=password][disabled],.pure-form input[type=email][disabled],.pure-form input[type=url][disabled],.pure-form input[type=date][disabled],.pure-form input[type=month][disabled],.pure-form input[type=time][disabled],.pure-form input[type=datetime][disabled],.pure-form input[type=datetime-local][disabled],.pure-form input[type=week][disabled],.pure-form input[type=number][disabled],.pure-form input[type=search][disabled],.pure-form input[type=tel][disabled],.pure-form input[type=color][disabled],.pure-form select[disabled],.pure-form textarea[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input:not([type])[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input[readonly],.pure-form select[readonly],.pure-form textarea[readonly]{background:#eee;color:#777;border-color:#ccc}.pure-form input:focus:invalid,.pure-form textarea:focus:invalid,.pure-form select:focus:invalid{color:#b94a48;border-color:#ee5f5b}.pure-form input:focus:invalid:focus,.pure-form textarea:focus:invalid:focus,.pure-form select:focus:invalid:focus{border-color:#e9322d}.pure-form input[type=file]:focus:invalid:focus,.pure-form input[type=radio]:focus:invalid:focus,.pure-form input[type=checkbox]:focus:invalid:focus{outline-color:#e9322d}.pure-form select{border:1px solid #ccc;background-color:#fff}.pure-form select[multiple]{height:auto}.pure-form label{margin:.5em 0 .2em}.pure-form fieldset{margin:0;padding:.35em 0 .75em;border:0}.pure-form legend{display:block;width:100%;padding:.3em 0;margin-bottom:.3em;color:#333;border-bottom:1px solid #e5e5e5}.pure-form-stacked input[type=text],.pure-form-stacked input[type=password],.pure-form-stacked input[type=email],.pure-form-stacked input[type=url],.pure-form-stacked input[type=date],.pure-form-stacked input[type=month],.pure-form-stacked input[type=time],.pure-form-stacked input[type=datetime],.pure-form-stacked input[type=datetime-local],.pure-form-stacked input[type=week],.pure-form-stacked input[type=number],.pure-form-stacked input[type=search],.pure-form-stacked input[type=tel],.pure-form-stacked input[type=color],.pure-form-stacked select,.pure-form-stacked label,.pure-form-stacked textarea{display:block;margin:.25em 0}.pure-form-stacked input:not([type]){display:block;margin:.25em 0}.pure-form-aligned input,.pure-form-aligned textarea,.pure-form-aligned select,.pure-form-aligned .pure-help-inline,.pure-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.pure-form-aligned textarea{vertical-align:top}.pure-form-aligned .pure-control-group{margin-bottom:.5em}.pure-form-aligned .pure-control-group label{text-align:right;display:inline-block;vertical-align:middle;width:10em;margin:0 1em 0 0}.pure-form-aligned .pure-controls{margin:1.5em 0 0 10em}.pure-form input.pure-input-rounded,.pure-form .pure-input-rounded{border-radius:2em;padding:.5em 1em}.pure-form .pure-group fieldset{margin-bottom:10px}.pure-form .pure-group input{display:block;padding:10px;margin:0;border-radius:0;position:relative;top:-1px}.pure-form .pure-group input:focus{z-index:2}.pure-form .pure-group input:first-child{top:1px;border-radius:4px 4px 0 0}.pure-form .pure-group input:last-child{top:-2px;border-radius:0 0 4px 4px}.pure-form .pure-group button{margin:.35em 0}.pure-form .pure-input-1{width:100%}.pure-form .pure-input-2-3{width:66%}.pure-form .pure-input-1-2{width:50%}.pure-form .pure-input-1-3{width:33%}.pure-form .pure-input-1-4{width:25%}.pure-form .pure-help-inline,.pure-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:.875em}.pure-form-message{display:block;color:#666;font-size:.875em}@media only screen and (max-width :480px){.pure-form button[type=submit]{margin:.7em 0 0}.pure-form input:not([type]),.pure-form input[type=text],.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=color],.pure-form label{margin-bottom:.3em;display:block}.pure-group input:not([type]),.pure-group input[type=text],.pure-group input[type=password],.pure-group input[type=email],.pure-group input[type=url],.pure-group input[type=date],.pure-group input[type=month],.pure-group input[type=time],.pure-group input[type=datetime],.pure-group input[type=datetime-local],.pure-group input[type=week],.pure-group input[type=number],.pure-group input[type=search],.pure-group input[type=tel],.pure-group input[type=color]{margin-bottom:0}.pure-form-aligned .pure-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.pure-form-aligned .pure-controls{margin:1.5em 0 0}.pure-form .pure-help-inline,.pure-form-message-inline,.pure-form-message{display:block;font-size:.75em;padding:.2em 0 .8em}}.pure-menu ul{position:absolute;visibility:hidden}.pure-menu.pure-menu-open{visibility:visible;z-index:2;width:100%}.pure-menu ul{left:-10000px;list-style:none;margin:0;padding:0;top:-10000px;z-index:1}.pure-menu>ul{position:relative}.pure-menu-open>ul{left:0;top:0;visibility:visible}.pure-menu-open>ul:focus{outline:0}.pure-menu li{position:relative}.pure-menu a,.pure-menu .pure-menu-heading{display:block;color:inherit;line-height:1.5em;padding:5px 20px;text-decoration:none;white-space:nowrap}.pure-menu.pure-menu-horizontal>.pure-menu-heading{display:inline-block;*display:inline;zoom:1;margin:0;vertical-align:middle}.pure-menu.pure-menu-horizontal>ul{display:inline-block;*display:inline;zoom:1;vertical-align:middle}.pure-menu li a{padding:5px 20px}.pure-menu-can-have-children>.pure-menu-label:after{content:'\\25B8';float:right;font-family:'Lucida Grande','Lucida Sans Unicode','DejaVu Sans',sans-serif;margin-right:-20px;margin-top:-1px}.pure-menu-can-have-children>.pure-menu-label{padding-right:30px}.pure-menu-separator{background-color:#dfdfdf;display:block;height:1px;font-size:0;margin:7px 2px;overflow:hidden}.pure-menu-hidden{display:none}.pure-menu-fixed{position:fixed;top:0;left:0;width:100%}.pure-menu-horizontal li{display:inline-block;*display:inline;zoom:1;vertical-align:middle}.pure-menu-horizontal li li{display:block}.pure-menu-horizontal>.pure-menu-children>.pure-menu-can-have-children>.pure-menu-label:after{content:\"\\25BE\"}.pure-menu-horizontal>.pure-menu-children>.pure-menu-can-have-children>.pure-menu-label{padding-right:30px}.pure-menu-horizontal li.pure-menu-separator{height:50%;width:1px;margin:0 7px}.pure-menu-horizontal li li.pure-menu-separator{height:1px;width:auto;margin:7px 2px}.pure-menu.pure-menu-open,.pure-menu.pure-menu-horizontal li .pure-menu-children{background:#fff;border:1px solid #b7b7b7}.pure-menu.pure-menu-horizontal,.pure-menu.pure-menu-horizontal .pure-menu-heading{border:0}.pure-menu a{border:1px solid transparent;border-left:0;border-right:0}.pure-menu a,.pure-menu .pure-menu-can-have-children>li:after{color:#777}.pure-menu .pure-menu-can-have-children>li:hover:after{color:#fff}.pure-menu .pure-menu-open{background:#dedede}.pure-menu li a:hover,.pure-menu li a:focus{background:#eee}.pure-menu li.pure-menu-disabled a:hover,.pure-menu li.pure-menu-disabled a:focus{background:#fff;color:#bfbfbf}.pure-menu .pure-menu-disabled>a{background-image:none;border-color:transparent;cursor:default}.pure-menu .pure-menu-disabled>a,.pure-menu .pure-menu-can-have-children.pure-menu-disabled>a:after{color:#bfbfbf}.pure-menu .pure-menu-heading{color:#565d64;text-transform:uppercase;font-size:90%;margin-top:.5em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:#dfdfdf}.pure-menu .pure-menu-selected a{color:#000}.pure-menu.pure-menu-open.pure-menu-fixed{border:0;border-bottom:1px solid #b7b7b7}.pure-paginator{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em;text-rendering:optimizespeed;list-style:none;margin:0;padding:0}.opera-only :-o-prefocus,.pure-paginator{word-spacing:-.43em}.pure-paginator li{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-paginator .pure-button{border-radius:0;padding:.8em 1.4em;vertical-align:top;height:1.1em}.pure-paginator .pure-button:focus,.pure-paginator .pure-button:active{outline-style:none}.pure-paginator .prev,.pure-paginator .next{color:#C0C1C3;text-shadow:0 -1px 0 rgba(0,0,0,.45)}.pure-paginator .prev{border-radius:2px 0 0 2px}.pure-paginator .next{border-radius:0 2px 2px 0}@media (max-width:480px){.pure-menu-horizontal{width:100%}.pure-menu-children li{display:block;border-bottom:1px solid #000}}.pure-table{border-collapse:collapse;border-spacing:0;empty-cells:show;border:1px solid #cbcbcb}.pure-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.pure-table td,.pure-table th{border-left:1px solid #cbcbcb;border-width:0 0 0 1px;font-size:inherit;margin:0;overflow:visible;padding:6px 12px}.pure-table td:first-child,.pure-table th:first-child{border-left-width:0}.pure-table thead{background:#e0e0e0;color:#000;text-align:left;vertical-align:bottom}.pure-table td{background-color:transparent}.pure-table-odd td{background-color:#f2f2f2}.pure-table-striped tr:nth-child(2n-1) td{background-color:#f2f2f2}.pure-table-bordered td{border-bottom:1px solid #cbcbcb}.pure-table-bordered tbody>tr:last-child td,.pure-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.pure-table-horizontal td,.pure-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #cbcbcb}.pure-table-horizontal tbody>tr:last-child td{border-bottom-width:0}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/2-browser-devtools/zmail/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta name=\"description\" content=\"A layout example that shows off a responsive email layout.\">\n\n    <title>Zmail Beta</title>\n\n    <link rel=\"stylesheet\" href=\"css/pure.css\">\n    <link rel=\"stylesheet\" href=\"css/email.css\">\n</head>\n<body>\n\n<div id=\"layout\" class=\"content pure-g\">\n    <div id=\"nav\" class=\"pure-u\">\n        <a href=\"#\" class=\"nav-menu-button\">Menu</a>\n\n        <div class=\"nav-inner\">\n            <h1 class=\"brand-title\">Zmail</h1>\n\n            <button class=\"primary-button pure-button\">Compose</button>\n\n            <div class=\"pure-menu pure-menu-open\">\n                <ul>\n                    <li><a href=\"#\">Inbox <span class=\"email-count\">(2)</span></a></li>\n                    <li><a href=\"#\">Important</a></li>\n                    <li><a href=\"#\">Sent</a></li>\n                    <li><a href=\"#\">Drafts</a></li>\n                    <li><a href=\"#\">Trash</a></li>\n                    <li class=\"pure-menu-heading\">Labels</li>\n                    <li><a href=\"#\"><span class=\"email-label-personal\"></span>Personal</a></li>\n                    <li><a href=\"#\"><span class=\"email-label-work\"></span>Work</a></li>\n                    <li><a href=\"#\"><span class=\"email-label-travel\"></span>Travel</a></li>\n                </ul>\n            </div>\n        </div>\n    </div>\n\n    <div id=\"list\" class=\"pure-u-1\">\n        <div class=\"email-item email-item-selected pure-g\">\n            <div class=\"pure-u\">\n                <img class=\"email-avatar\" alt=\"Zeno Rocha&#x27;s avatar\" height=\"64\" width=\"64\" src=\"../common/zeno.jpg\">\n            </div>\n\n            <div class=\"pure-u-3-4\">\n                <h5 class=\"email-name\">Zeno Rocha</h5>\n                <h4 class=\"email-subject\">Summer Bootcamp 2015</h4>\n                <p class=\"email-desc\">\n                    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Necessitatibus, sequi.\n                </p>\n            </div>\n        </div>\n\n        <div class=\"email-item email-item-unread pure-g\">\n            <div class=\"pure-u\">\n                <img class=\"email-avatar\" alt=\"Todd&#x27;s avatar\" height=\"64\" width=\"64\" src=\"../common/todd.jpg\">\n            </div>\n\n            <div class=\"pure-u-3-4\">\n                <h5 class=\"email-name\">Todd McLeod</h5>\n                <h4 class=\"email-subject\">Dinner Sunday Night?</h4>\n                <p class=\"email-desc\">\n                    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Harum nihil maxime excepturi!\n                </p>\n            </div>\n        </div>\n\n        <div class=\"email-item email-item-unread pure-g\">\n            <div class=\"pure-u\">\n                <img class=\"email-avatar\" alt=\"Todd McLeod&#x27;s avatar\" height=\"64\" width=\"64\" src=\"../common/todd.jpg\">\n            </div>\n\n            <div class=\"pure-u-3-4\">\n                <h5 class=\"email-name\">Todd McLeod</h5>\n                <h4 class=\"email-subject\">Video recording</h4>\n                <p class=\"email-desc\">\n                    Duis aute irure dolor in reprehenderit in voluptate velit essecillum dolore eu fugiat nulla.\n                </p>\n            </div>\n        </div>\n\n        <div class=\"email-item pure-g\">\n            <div class=\"pure-u\">\n                <img class=\"email-avatar\" alt=\"Andrew Rota&#x27;s avatar\" height=\"64\" width=\"64\" src=\"../common/andrew.jpg\">\n            </div>\n\n            <div class=\"pure-u-3-4\">\n                <h5 class=\"email-name\">Andrew Rota</h5>\n                <h4 class=\"email-subject\">I ♥ JS</h4>\n                <p class=\"email-desc\">\n                    Excepteur sint occaecat cupidatat non proident, sunt in culpa.\n                </p>\n            </div>\n        </div>\n\n        <div class=\"email-item pure-g\">\n            <div class=\"pure-u\">\n                <img class=\"email-avatar\" alt=\"Andrew Rota&#x27;s avatar\" height=\"64\" width=\"64\" src=\"../common/andrew.jpg\">\n            </div>\n\n            <div class=\"pure-u-3-4\">\n                <h5 class=\"email-name\">Andrew Rota</h5>\n                <h4 class=\"email-subject\">Hotels with kitchens</h4>\n                <p class=\"email-desc\">\n                    Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip.\n                </p>\n            </div>\n        </div>\n\n        <div class=\"email-item pure-g\">\n            <div class=\"pure-u\">\n                <img class=\"email-avatar\" alt=\"Yahoo! Finance&#x27;s Avatar\" height=\"64\" width=\"64\" src=\"img/yfinance-avatar.png\">\n            </div>\n\n            <div class=\"pure-u-3-4\">\n                <h5 class=\"email-name\">Yahoo! Finance</h5>\n                <h4 class=\"email-subject\">How to protect your finances from winter storms</h4>\n                <p class=\"email-desc\">\n                    Mauris tempor mi vitae sem aliquet pharetra. Fusce in dui purus, nec malesuada mauris.\n                </p>\n            </div>\n        </div>\n\n        <div class=\"email-item pure-g\">\n            <div class=\"pure-u\">\n                <img class=\"email-avatar\" alt=\"Yahoo! News&#x27; avatar\" height=\"64\" width=\"64\" src=\"img/ynews-avatar.png\">\n            </div>\n\n            <div class=\"pure-u-3-4\">\n                <h5 class=\"email-name\">Yahoo! News</h5>\n                <h4 class=\"email-subject\">Summary for April 3rd, 2015</h4>\n                <p class=\"email-desc\">\n                    Lorem ipsum dolor sit amet, consectetur.\n                </p>\n            </div>\n        </div>\n    </div>\n\n    <div id=\"main\" class=\"pure-u-1\">\n        <div class=\"email-content\">\n            <div class=\"email-content-header pure-g\">\n                <div class=\"pure-u-1-2\">\n                    <h1 class=\"email-content-title\">Summer Bootcamp 2015</h1>\n                    <p class=\"email-content-subtitle\">\n                        From <a>Zeno Rocha</a> at <span>3:56pm, May 28, 2015</span>\n                    </p>\n                </div>\n\n                <div class=\"email-content-controls pure-u-1-2\">\n                    <button class=\"secondary-button pure-button\">Reply</button>\n                    <button class=\"secondary-button pure-button\">Forward</button>\n                    <button class=\"secondary-button pure-button\">Move to</button>\n                </div>\n            </div>\n\n            <div class=\"email-content-body\">\n                <p>\n                    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n                </p>\n                <p>\n                    Duis aute irure dolor in reprehenderit in voluptate velit essecillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n                </p>\n                <p>\n                    Aliquam ac feugiat dolor. Proin mattis massa sit amet enim iaculis tincidunt. Mauris tempor mi vitae sem aliquet pharetra. Fusce in dui purus, nec malesuada mauris. Curabitur ornare arcu quis mi blandit laoreet. Vivamus imperdiet fermentum mauris, ac posuere urna tempor at. Duis pellentesque justo ac sapien aliquet egestas. Morbi enim mi, porta eget ullamcorper at, pharetra id lorem.\n                </p>\n                <p>\n                    Donec sagittis dolor ut quam pharetra pretium varius in nibh. Suspendisse potenti. Donec imperdiet, velit vel adipiscing bibendum, leo eros tristique augue, eu rutrum lacus sapien vel quam. Nam orci arcu, luctus quis vestibulum ut, ullamcorper ut enim. Morbi semper erat quis orci aliquet condimentum. Nam interdum mauris sed massa dignissim rhoncus.\n                </p>\n                <p>\n                    Regards,<br>\n                    Zeno\n                </p>\n            </div>\n        </div>\n    </div>\n</div>\n\n<script src=\"js/menu.js\"></script>\n\n<script src=\"js/spam.js\"></script>\n<script src=\"js/count.js\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/2-browser-devtools/zmail/js/count.js",
    "content": "var count = document.querySelector('.email-count');\nvar item = document.querySelectorAll('.email-item');\n\ncount.innerHTML = '(' + item.length + ')';"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/2-browser-devtools/zmail/js/menu.js",
    "content": "var menuButton = document.querySelector('.nav-menu-button'),\n\tnav        = document.querySelector('#nav');\n\nmenuButton.addEventListener('click', function (e) {\n\tdebugger;\n    nav.classList.toggle('active');\n\te.preventDefault();\n});"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/2-browser-devtools/zmail/js/spam.js",
    "content": "var template = '' +\n    '<div class=\"email-item email-item-selected pure-g\">' +\n        '<div class=\"pure-u\">' +\n            '<img class=\"email-avatar\" alt=\"Yahoo! Finance Avatar\" height=\"64\" width=\"64\" src=\"img/yfinance-avatar.png\">' +\n        '</div>' +\n\n        '<div class=\"pure-u-3-4\">' +\n            '<h5 class=\"email-name\">Yahoo! Finance</h5>' +\n            '<h4 class=\"email-subject\">How to protect your finances from winter storms</h4>' +\n            '<p class=\"email-desc\">' +\n                'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Necessitatibus, sequi.' +\n            '</p>' +\n        '</div>' +\n    '</div>';\n\n    var result = '';\n    for (var i = 0; i < 200; i++) {\n      result += template;\n    }\n\n    document.querySelector('#list').innerHTML += result;\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/2-browser-devtools/zordpress/css/blog.css",
    "content": "* {\n    -webkit-box-sizing: border-box;\n    -moz-box-sizing: border-box;\n    box-sizing: border-box;\n}\n\na {\n    text-decoration: none;\n    color: rgb(61, 146, 201);\n}\na:hover,\na:focus {\n    text-decoration: underline;\n}\n\nh3 {\n    font-weight: 100;\n}\n\n/* LAYOUT CSS */\n.pure-img-responsive {\n    max-width: 100%;\n    height: auto;\n}\n\n#layout {\n    padding: 0;\n}\n\n.header {\n    text-align: center;\n    top: auto;\n    margin: 3em auto;\n}\n\n.sidebar {\n    background: #2065a1;\n    color: #fff;\n}\n\n.brand-title,\n.brand-tagline {\n    margin: 0;\n}\n.brand-title {\n    text-transform: uppercase;\n}\n.brand-tagline {\n    font-weight: 300;\n    color: #7db1df;\n}\n\n.nav-list {\n    margin: 0;\n    padding: 0;\n    list-style: none;\n}\n.nav-item {\n    display: inline-block;\n    *display: inline;\n    zoom: 1;\n}\n.nav-item a {\n    background: transparent;\n    border: 2px solid #7db1df;\n    color: #fff;\n    margin-top: 1em;\n    letter-spacing: 0.05em;\n    text-transform: uppercase;\n    font-size: 85%;\n}\n.nav-item a:hover,\n.nav-item a:focus {\n    border: 2px solid rgb(61, 146, 201);\n    text-decoration: none;\n}\n\n.content-subhead {\n    text-transform: uppercase;\n    color: #aaa;\n    border-bottom: 1px solid #eee;\n    padding: 0.4em 0;\n    font-size: 80%;\n    font-weight: 500;\n    letter-spacing: 0.1em;\n}\n\n.content {\n    padding: 2em 1em 0;\n}\n\n.post {\n    padding-bottom: 2em;\n}\n.post-title {\n    font-size: 2em;\n    color: #222;\n    margin-bottom: 0.2em;\n}\n.post-avatar {\n    border-radius: 50px;\n    float: right;\n    margin-left: 1em;\n}\n.post-description {\n    font-family: Georgia, \"Cambria\", serif;\n    color: #444;\n    line-height: 1.8em;\n}\n.post-meta {\n    color: #999;\n    font-size: 90%;\n    margin: 0;\n}\n\n.post-category {\n    margin: 0 0.1em;\n    padding: 0.3em 1em;\n    color: #fff;\n    background: #999;\n    font-size: 80%;\n}\n    .post-category-design {\n        background: #4cb749;\n    }\n    .post-category-pure {\n        background: #fcd209;\n    }\n    .post-category-gdg {\n        background: #8156a7;\n    }\n    .post-category-ios {\n        background: #e84d42;\n    }\n\n.post-images {\n    margin: 1em 0;\n}\n.post-image-meta {\n    margin-top: -3.5em;\n    margin-left: 1em;\n    color: #fff;\n    text-shadow: 0 1px 1px #333;\n}\n\n.footer {\n    text-align: center;\n    padding: 1em 0;\n}\n.footer a {\n    color: #ccc;\n    font-size: 80%;\n}\n.footer .pure-menu a:hover,\n.footer .pure-menu a:focus {\n    background: none;\n}\n\n@media (min-width: 48em) {\n    .content {\n        padding: 2em 3em 0;\n        margin-left: 25%;\n    }\n\n    .header {\n        margin: 80% 2em 0;\n        text-align: right;\n    }\n\n    .sidebar {\n        position: fixed;\n        top: 0;\n        bottom: 0;\n    }\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/2-browser-devtools/zordpress/css/main-grid.css",
    "content": "@media screen and (min-width: 35.5em) {\n    .pure-u-sm-1,\n    .pure-u-sm-1-1,\n    .pure-u-sm-1-2,\n    .pure-u-sm-1-3,\n    .pure-u-sm-2-3,\n    .pure-u-sm-1-4,\n    .pure-u-sm-3-4,\n    .pure-u-sm-1-5,\n    .pure-u-sm-2-5,\n    .pure-u-sm-3-5,\n    .pure-u-sm-4-5,\n    .pure-u-sm-5-5,\n    .pure-u-sm-1-6,\n    .pure-u-sm-5-6,\n    .pure-u-sm-1-8,\n    .pure-u-sm-3-8,\n    .pure-u-sm-5-8,\n    .pure-u-sm-7-8,\n    .pure-u-sm-1-12,\n    .pure-u-sm-5-12,\n    .pure-u-sm-7-12,\n    .pure-u-sm-11-12,\n    .pure-u-sm-1-24,\n    .pure-u-sm-2-24,\n    .pure-u-sm-3-24,\n    .pure-u-sm-4-24,\n    .pure-u-sm-5-24,\n    .pure-u-sm-6-24,\n    .pure-u-sm-7-24,\n    .pure-u-sm-8-24,\n    .pure-u-sm-9-24,\n    .pure-u-sm-10-24,\n    .pure-u-sm-11-24,\n    .pure-u-sm-12-24,\n    .pure-u-sm-13-24,\n    .pure-u-sm-14-24,\n    .pure-u-sm-15-24,\n    .pure-u-sm-16-24,\n    .pure-u-sm-17-24,\n    .pure-u-sm-18-24,\n    .pure-u-sm-19-24,\n    .pure-u-sm-20-24,\n    .pure-u-sm-21-24,\n    .pure-u-sm-22-24,\n    .pure-u-sm-23-24,\n    .pure-u-sm-24-24 {\n        display: inline-block;\n        *display: inline;\n        zoom: 1;\n        letter-spacing: normal;\n        word-spacing: normal;\n        vertical-align: top;\n        text-rendering: auto;\n    }\n\n    .pure-u-sm-1-24 {\n        width: 4.1667%;\n        *width: 4.1357%;\n    }\n\n    .pure-u-sm-1-12,\n    .pure-u-sm-2-24 {\n        width: 8.3333%;\n        *width: 8.3023%;\n    }\n\n    .pure-u-sm-1-8,\n    .pure-u-sm-3-24 {\n        width: 12.5000%;\n        *width: 12.4690%;\n    }\n\n    .pure-u-sm-1-6,\n    .pure-u-sm-4-24 {\n        width: 16.6667%;\n        *width: 16.6357%;\n    }\n\n    .pure-u-sm-1-5 {\n        width: 20%;\n        *width: 19.9690%;\n    }\n\n    .pure-u-sm-5-24 {\n        width: 20.8333%;\n        *width: 20.8023%;\n    }\n\n    .pure-u-sm-1-4,\n    .pure-u-sm-6-24 {\n        width: 25%;\n        *width: 24.9690%;\n    }\n\n    .pure-u-sm-7-24 {\n        width: 29.1667%;\n        *width: 29.1357%;\n    }\n\n    .pure-u-sm-1-3,\n    .pure-u-sm-8-24 {\n        width: 33.3333%;\n        *width: 33.3023%;\n    }\n\n    .pure-u-sm-3-8,\n    .pure-u-sm-9-24 {\n        width: 37.5000%;\n        *width: 37.4690%;\n    }\n\n    .pure-u-sm-2-5 {\n        width: 40%;\n        *width: 39.9690%;\n    }\n\n    .pure-u-sm-5-12,\n    .pure-u-sm-10-24 {\n        width: 41.6667%;\n        *width: 41.6357%;\n    }\n\n    .pure-u-sm-11-24 {\n        width: 45.8333%;\n        *width: 45.8023%;\n    }\n\n    .pure-u-sm-1-2,\n    .pure-u-sm-12-24 {\n        width: 50%;\n        *width: 49.9690%;\n    }\n\n    .pure-u-sm-13-24 {\n        width: 54.1667%;\n        *width: 54.1357%;\n    }\n\n    .pure-u-sm-7-12,\n    .pure-u-sm-14-24 {\n        width: 58.3333%;\n        *width: 58.3023%;\n    }\n\n    .pure-u-sm-3-5 {\n        width: 60%;\n        *width: 59.9690%;\n    }\n\n    .pure-u-sm-5-8,\n    .pure-u-sm-15-24 {\n        width: 62.5000%;\n        *width: 62.4690%;\n    }\n\n    .pure-u-sm-2-3,\n    .pure-u-sm-16-24 {\n        width: 66.6667%;\n        *width: 66.6357%;\n    }\n\n    .pure-u-sm-17-24 {\n        width: 70.8333%;\n        *width: 70.8023%;\n    }\n\n    .pure-u-sm-3-4,\n    .pure-u-sm-18-24 {\n        width: 75%;\n        *width: 74.9690%;\n    }\n\n    .pure-u-sm-19-24 {\n        width: 79.1667%;\n        *width: 79.1357%;\n    }\n\n    .pure-u-sm-4-5 {\n        width: 80%;\n        *width: 79.9690%;\n    }\n\n    .pure-u-sm-5-6,\n    .pure-u-sm-20-24 {\n        width: 83.3333%;\n        *width: 83.3023%;\n    }\n\n    .pure-u-sm-7-8,\n    .pure-u-sm-21-24 {\n        width: 87.5000%;\n        *width: 87.4690%;\n    }\n\n    .pure-u-sm-11-12,\n    .pure-u-sm-22-24 {\n        width: 91.6667%;\n        *width: 91.6357%;\n    }\n\n    .pure-u-sm-23-24 {\n        width: 95.8333%;\n        *width: 95.8023%;\n    }\n\n    .pure-u-sm-1,\n    .pure-u-sm-1-1,\n    .pure-u-sm-5-5,\n    .pure-u-sm-24-24 {\n        width: 100%;\n    }\n}\n\n@media screen and (min-width: 48em) {\n    .pure-u-med-1,\n    .pure-u-med-1-1,\n    .pure-u-med-1-2,\n    .pure-u-med-1-3,\n    .pure-u-med-2-3,\n    .pure-u-med-1-4,\n    .pure-u-med-3-4,\n    .pure-u-med-1-5,\n    .pure-u-med-2-5,\n    .pure-u-med-3-5,\n    .pure-u-med-4-5,\n    .pure-u-med-5-5,\n    .pure-u-med-1-6,\n    .pure-u-med-5-6,\n    .pure-u-med-1-8,\n    .pure-u-med-3-8,\n    .pure-u-med-5-8,\n    .pure-u-med-7-8,\n    .pure-u-med-1-12,\n    .pure-u-med-5-12,\n    .pure-u-med-7-12,\n    .pure-u-med-11-12,\n    .pure-u-med-1-24,\n    .pure-u-med-2-24,\n    .pure-u-med-3-24,\n    .pure-u-med-4-24,\n    .pure-u-med-5-24,\n    .pure-u-med-6-24,\n    .pure-u-med-7-24,\n    .pure-u-med-8-24,\n    .pure-u-med-9-24,\n    .pure-u-med-10-24,\n    .pure-u-med-11-24,\n    .pure-u-med-12-24,\n    .pure-u-med-13-24,\n    .pure-u-med-14-24,\n    .pure-u-med-15-24,\n    .pure-u-med-16-24,\n    .pure-u-med-17-24,\n    .pure-u-med-18-24,\n    .pure-u-med-19-24,\n    .pure-u-med-20-24,\n    .pure-u-med-21-24,\n    .pure-u-med-22-24,\n    .pure-u-med-23-24,\n    .pure-u-med-24-24 {\n        display: inline-block;\n        *display: inline;\n        zoom: 1;\n        letter-spacing: normal;\n        word-spacing: normal;\n        vertical-align: top;\n        text-rendering: auto;\n    }\n\n    .pure-u-med-1-24 {\n        width: 4.1667%;\n        *width: 4.1357%;\n    }\n\n    .pure-u-med-1-12,\n    .pure-u-med-2-24 {\n        width: 8.3333%;\n        *width: 8.3023%;\n    }\n\n    .pure-u-med-1-8,\n    .pure-u-med-3-24 {\n        width: 12.5000%;\n        *width: 12.4690%;\n    }\n\n    .pure-u-med-1-6,\n    .pure-u-med-4-24 {\n        width: 16.6667%;\n        *width: 16.6357%;\n    }\n\n    .pure-u-med-1-5 {\n        width: 20%;\n        *width: 19.9690%;\n    }\n\n    .pure-u-med-5-24 {\n        width: 20.8333%;\n        *width: 20.8023%;\n    }\n\n    .pure-u-med-1-4,\n    .pure-u-med-6-24 {\n        width: 25%;\n        *width: 24.9690%;\n    }\n\n    .pure-u-med-7-24 {\n        width: 29.1667%;\n        *width: 29.1357%;\n    }\n\n    .pure-u-med-1-3,\n    .pure-u-med-8-24 {\n        width: 33.3333%;\n        *width: 33.3023%;\n    }\n\n    .pure-u-med-3-8,\n    .pure-u-med-9-24 {\n        width: 37.5000%;\n        *width: 37.4690%;\n    }\n\n    .pure-u-med-2-5 {\n        width: 40%;\n        *width: 39.9690%;\n    }\n\n    .pure-u-med-5-12,\n    .pure-u-med-10-24 {\n        width: 41.6667%;\n        *width: 41.6357%;\n    }\n\n    .pure-u-med-11-24 {\n        width: 45.8333%;\n        *width: 45.8023%;\n    }\n\n    .pure-u-med-1-2,\n    .pure-u-med-12-24 {\n        width: 50%;\n        *width: 49.9690%;\n    }\n\n    .pure-u-med-13-24 {\n        width: 54.1667%;\n        *width: 54.1357%;\n    }\n\n    .pure-u-med-7-12,\n    .pure-u-med-14-24 {\n        width: 58.3333%;\n        *width: 58.3023%;\n    }\n\n    .pure-u-med-3-5 {\n        width: 60%;\n        *width: 59.9690%;\n    }\n\n    .pure-u-med-5-8,\n    .pure-u-med-15-24 {\n        width: 62.5000%;\n        *width: 62.4690%;\n    }\n\n    .pure-u-med-2-3,\n    .pure-u-med-16-24 {\n        width: 66.6667%;\n        *width: 66.6357%;\n    }\n\n    .pure-u-med-17-24 {\n        width: 70.8333%;\n        *width: 70.8023%;\n    }\n\n    .pure-u-med-3-4,\n    .pure-u-med-18-24 {\n        width: 75%;\n        *width: 74.9690%;\n    }\n\n    .pure-u-med-19-24 {\n        width: 79.1667%;\n        *width: 79.1357%;\n    }\n\n    .pure-u-med-4-5 {\n        width: 80%;\n        *width: 79.9690%;\n    }\n\n    .pure-u-med-5-6,\n    .pure-u-med-20-24 {\n        width: 83.3333%;\n        *width: 83.3023%;\n    }\n\n    .pure-u-med-7-8,\n    .pure-u-med-21-24 {\n        width: 87.5000%;\n        *width: 87.4690%;\n    }\n\n    .pure-u-med-11-12,\n    .pure-u-med-22-24 {\n        width: 91.6667%;\n        *width: 91.6357%;\n    }\n\n    .pure-u-med-23-24 {\n        width: 95.8333%;\n        *width: 95.8023%;\n    }\n\n    .pure-u-med-1,\n    .pure-u-med-1-1,\n    .pure-u-med-5-5,\n    .pure-u-med-24-24 {\n        width: 100%;\n    }\n}\n\n@media screen and (min-width: 58em) {\n    .pure-u-lrg-1,\n    .pure-u-lrg-1-1,\n    .pure-u-lrg-1-2,\n    .pure-u-lrg-1-3,\n    .pure-u-lrg-2-3,\n    .pure-u-lrg-1-4,\n    .pure-u-lrg-3-4,\n    .pure-u-lrg-1-5,\n    .pure-u-lrg-2-5,\n    .pure-u-lrg-3-5,\n    .pure-u-lrg-4-5,\n    .pure-u-lrg-5-5,\n    .pure-u-lrg-1-6,\n    .pure-u-lrg-5-6,\n    .pure-u-lrg-1-8,\n    .pure-u-lrg-3-8,\n    .pure-u-lrg-5-8,\n    .pure-u-lrg-7-8,\n    .pure-u-lrg-1-12,\n    .pure-u-lrg-5-12,\n    .pure-u-lrg-7-12,\n    .pure-u-lrg-11-12,\n    .pure-u-lrg-1-24,\n    .pure-u-lrg-2-24,\n    .pure-u-lrg-3-24,\n    .pure-u-lrg-4-24,\n    .pure-u-lrg-5-24,\n    .pure-u-lrg-6-24,\n    .pure-u-lrg-7-24,\n    .pure-u-lrg-8-24,\n    .pure-u-lrg-9-24,\n    .pure-u-lrg-10-24,\n    .pure-u-lrg-11-24,\n    .pure-u-lrg-12-24,\n    .pure-u-lrg-13-24,\n    .pure-u-lrg-14-24,\n    .pure-u-lrg-15-24,\n    .pure-u-lrg-16-24,\n    .pure-u-lrg-17-24,\n    .pure-u-lrg-18-24,\n    .pure-u-lrg-19-24,\n    .pure-u-lrg-20-24,\n    .pure-u-lrg-21-24,\n    .pure-u-lrg-22-24,\n    .pure-u-lrg-23-24,\n    .pure-u-lrg-24-24 {\n        display: inline-block;\n        *display: inline;\n        zoom: 1;\n        letter-spacing: normal;\n        word-spacing: normal;\n        vertical-align: top;\n        text-rendering: auto;\n    }\n\n    .pure-u-lrg-1-24 {\n        width: 4.1667%;\n        *width: 4.1357%;\n    }\n\n    .pure-u-lrg-1-12,\n    .pure-u-lrg-2-24 {\n        width: 8.3333%;\n        *width: 8.3023%;\n    }\n\n    .pure-u-lrg-1-8,\n    .pure-u-lrg-3-24 {\n        width: 12.5000%;\n        *width: 12.4690%;\n    }\n\n    .pure-u-lrg-1-6,\n    .pure-u-lrg-4-24 {\n        width: 16.6667%;\n        *width: 16.6357%;\n    }\n\n    .pure-u-lrg-1-5 {\n        width: 20%;\n        *width: 19.9690%;\n    }\n\n    .pure-u-lrg-5-24 {\n        width: 20.8333%;\n        *width: 20.8023%;\n    }\n\n    .pure-u-lrg-1-4,\n    .pure-u-lrg-6-24 {\n        width: 25%;\n        *width: 24.9690%;\n    }\n\n    .pure-u-lrg-7-24 {\n        width: 29.1667%;\n        *width: 29.1357%;\n    }\n\n    .pure-u-lrg-1-3,\n    .pure-u-lrg-8-24 {\n        width: 33.3333%;\n        *width: 33.3023%;\n    }\n\n    .pure-u-lrg-3-8,\n    .pure-u-lrg-9-24 {\n        width: 37.5000%;\n        *width: 37.4690%;\n    }\n\n    .pure-u-lrg-2-5 {\n        width: 40%;\n        *width: 39.9690%;\n    }\n\n    .pure-u-lrg-5-12,\n    .pure-u-lrg-10-24 {\n        width: 41.6667%;\n        *width: 41.6357%;\n    }\n\n    .pure-u-lrg-11-24 {\n        width: 45.8333%;\n        *width: 45.8023%;\n    }\n\n    .pure-u-lrg-1-2,\n    .pure-u-lrg-12-24 {\n        width: 50%;\n        *width: 49.9690%;\n    }\n\n    .pure-u-lrg-13-24 {\n        width: 54.1667%;\n        *width: 54.1357%;\n    }\n\n    .pure-u-lrg-7-12,\n    .pure-u-lrg-14-24 {\n        width: 58.3333%;\n        *width: 58.3023%;\n    }\n\n    .pure-u-lrg-3-5 {\n        width: 60%;\n        *width: 59.9690%;\n    }\n\n    .pure-u-lrg-5-8,\n    .pure-u-lrg-15-24 {\n        width: 62.5000%;\n        *width: 62.4690%;\n    }\n\n    .pure-u-lrg-2-3,\n    .pure-u-lrg-16-24 {\n        width: 66.6667%;\n        *width: 66.6357%;\n    }\n\n    .pure-u-lrg-17-24 {\n        width: 70.8333%;\n        *width: 70.8023%;\n    }\n\n    .pure-u-lrg-3-4,\n    .pure-u-lrg-18-24 {\n        width: 75%;\n        *width: 74.9690%;\n    }\n\n    .pure-u-lrg-19-24 {\n        width: 79.1667%;\n        *width: 79.1357%;\n    }\n\n    .pure-u-lrg-4-5 {\n        width: 80%;\n        *width: 79.9690%;\n    }\n\n    .pure-u-lrg-5-6,\n    .pure-u-lrg-20-24 {\n        width: 83.3333%;\n        *width: 83.3023%;\n    }\n\n    .pure-u-lrg-7-8,\n    .pure-u-lrg-21-24 {\n        width: 87.5000%;\n        *width: 87.4690%;\n    }\n\n    .pure-u-lrg-11-12,\n    .pure-u-lrg-22-24 {\n        width: 91.6667%;\n        *width: 91.6357%;\n    }\n\n    .pure-u-lrg-23-24 {\n        width: 95.8333%;\n        *width: 95.8023%;\n    }\n\n    .pure-u-lrg-1,\n    .pure-u-lrg-1-1,\n    .pure-u-lrg-5-5,\n    .pure-u-lrg-24-24 {\n        width: 100%;\n    }\n}\n\n@media screen and (min-width: 75em) {\n    .pure-u-xl-1,\n    .pure-u-xl-1-1,\n    .pure-u-xl-1-2,\n    .pure-u-xl-1-3,\n    .pure-u-xl-2-3,\n    .pure-u-xl-1-4,\n    .pure-u-xl-3-4,\n    .pure-u-xl-1-5,\n    .pure-u-xl-2-5,\n    .pure-u-xl-3-5,\n    .pure-u-xl-4-5,\n    .pure-u-xl-5-5,\n    .pure-u-xl-1-6,\n    .pure-u-xl-5-6,\n    .pure-u-xl-1-8,\n    .pure-u-xl-3-8,\n    .pure-u-xl-5-8,\n    .pure-u-xl-7-8,\n    .pure-u-xl-1-12,\n    .pure-u-xl-5-12,\n    .pure-u-xl-7-12,\n    .pure-u-xl-11-12,\n    .pure-u-xl-1-24,\n    .pure-u-xl-2-24,\n    .pure-u-xl-3-24,\n    .pure-u-xl-4-24,\n    .pure-u-xl-5-24,\n    .pure-u-xl-6-24,\n    .pure-u-xl-7-24,\n    .pure-u-xl-8-24,\n    .pure-u-xl-9-24,\n    .pure-u-xl-10-24,\n    .pure-u-xl-11-24,\n    .pure-u-xl-12-24,\n    .pure-u-xl-13-24,\n    .pure-u-xl-14-24,\n    .pure-u-xl-15-24,\n    .pure-u-xl-16-24,\n    .pure-u-xl-17-24,\n    .pure-u-xl-18-24,\n    .pure-u-xl-19-24,\n    .pure-u-xl-20-24,\n    .pure-u-xl-21-24,\n    .pure-u-xl-22-24,\n    .pure-u-xl-23-24,\n    .pure-u-xl-24-24 {\n        display: inline-block;\n        *display: inline;\n        zoom: 1;\n        letter-spacing: normal;\n        word-spacing: normal;\n        vertical-align: top;\n        text-rendering: auto;\n    }\n\n    .pure-u-xl-1-24 {\n        width: 4.1667%;\n        *width: 4.1357%;\n    }\n\n    .pure-u-xl-1-12,\n    .pure-u-xl-2-24 {\n        width: 8.3333%;\n        *width: 8.3023%;\n    }\n\n    .pure-u-xl-1-8,\n    .pure-u-xl-3-24 {\n        width: 12.5000%;\n        *width: 12.4690%;\n    }\n\n    .pure-u-xl-1-6,\n    .pure-u-xl-4-24 {\n        width: 16.6667%;\n        *width: 16.6357%;\n    }\n\n    .pure-u-xl-1-5 {\n        width: 20%;\n        *width: 19.9690%;\n    }\n\n    .pure-u-xl-5-24 {\n        width: 20.8333%;\n        *width: 20.8023%;\n    }\n\n    .pure-u-xl-1-4,\n    .pure-u-xl-6-24 {\n        width: 25%;\n        *width: 24.9690%;\n    }\n\n    .pure-u-xl-7-24 {\n        width: 29.1667%;\n        *width: 29.1357%;\n    }\n\n    .pure-u-xl-1-3,\n    .pure-u-xl-8-24 {\n        width: 33.3333%;\n        *width: 33.3023%;\n    }\n\n    .pure-u-xl-3-8,\n    .pure-u-xl-9-24 {\n        width: 37.5000%;\n        *width: 37.4690%;\n    }\n\n    .pure-u-xl-2-5 {\n        width: 40%;\n        *width: 39.9690%;\n    }\n\n    .pure-u-xl-5-12,\n    .pure-u-xl-10-24 {\n        width: 41.6667%;\n        *width: 41.6357%;\n    }\n\n    .pure-u-xl-11-24 {\n        width: 45.8333%;\n        *width: 45.8023%;\n    }\n\n    .pure-u-xl-1-2,\n    .pure-u-xl-12-24 {\n        width: 50%;\n        *width: 49.9690%;\n    }\n\n    .pure-u-xl-13-24 {\n        width: 54.1667%;\n        *width: 54.1357%;\n    }\n\n    .pure-u-xl-7-12,\n    .pure-u-xl-14-24 {\n        width: 58.3333%;\n        *width: 58.3023%;\n    }\n\n    .pure-u-xl-3-5 {\n        width: 60%;\n        *width: 59.9690%;\n    }\n\n    .pure-u-xl-5-8,\n    .pure-u-xl-15-24 {\n        width: 62.5000%;\n        *width: 62.4690%;\n    }\n\n    .pure-u-xl-2-3,\n    .pure-u-xl-16-24 {\n        width: 66.6667%;\n        *width: 66.6357%;\n    }\n\n    .pure-u-xl-17-24 {\n        width: 70.8333%;\n        *width: 70.8023%;\n    }\n\n    .pure-u-xl-3-4,\n    .pure-u-xl-18-24 {\n        width: 75%;\n        *width: 74.9690%;\n    }\n\n    .pure-u-xl-19-24 {\n        width: 79.1667%;\n        *width: 79.1357%;\n    }\n\n    .pure-u-xl-4-5 {\n        width: 80%;\n        *width: 79.9690%;\n    }\n\n    .pure-u-xl-5-6,\n    .pure-u-xl-20-24 {\n        width: 83.3333%;\n        *width: 83.3023%;\n    }\n\n    .pure-u-xl-7-8,\n    .pure-u-xl-21-24 {\n        width: 87.5000%;\n        *width: 87.4690%;\n    }\n\n    .pure-u-xl-11-12,\n    .pure-u-xl-22-24 {\n        width: 91.6667%;\n        *width: 91.6357%;\n    }\n\n    .pure-u-xl-23-24 {\n        width: 95.8333%;\n        *width: 95.8023%;\n    }\n\n    .pure-u-xl-1,\n    .pure-u-xl-1-1,\n    .pure-u-xl-5-5,\n    .pure-u-xl-24-24 {\n        width: 100%;\n    }\n}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/2-browser-devtools/zordpress/css/pure.css",
    "content": "/*!\nPure v0.4.2\nCopyright 2014 Yahoo! Inc. All rights reserved.\nLicensed under the BSD License.\nhttps://github.com/yui/pure/blob/master/LICENSE.md\n*/\n/*!\nnormalize.css v1.1.3 | MIT License | git.io/normalize\nCopyright (c) Nicolas Gallagher and Jonathan Neal\n*/\n/*! normalize.css v1.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none;height:0}[hidden]{display:none}html{font-size:100%;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}html,button,input,select,textarea{font-family:sans-serif}body{margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{font-size:2em;margin:.67em 0}h2{font-size:1.5em;margin:.83em 0}h3{font-size:1.17em;margin:1em 0}h4{font-size:1em;margin:1.33em 0}h5{font-size:.83em;margin:1.67em 0}h6{font-size:.67em;margin:2.33em 0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:1em 40px}dfn{font-style:italic}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}mark{background:#ff0;color:#000}p,pre{margin:1em 0}code,kbd,pre,samp{font-family:monospace,serif;_font-family:'courier new',monospace;font-size:1em}pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word}q{quotes:none}q:before,q:after{content:'';content:none}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,menu,ol,ul{margin:1em 0}dd{margin:0 0 0 40px}menu,ol,ul{padding:0 0 0 40px}nav ul,nav ol{list-style:none;list-style-image:none}img{border:0;-ms-interpolation-mode:bicubic}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0;white-space:normal;*margin-left:-7px}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;*overflow:visible}button[disabled],html input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0;*height:13px;*width:13px}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}[hidden]{display:none!important}.pure-g{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em;text-rendering:optimizespeed;font-family:FreeSans,Arimo,\"Droid Sans\",Helvetica,Arial,sans-serif;display:-webkit-flex;-webkit-flex-flow:row wrap;display:-ms-flexbox;-ms-flex-flow:row wrap}.opera-only :-o-prefocus,.pure-g{word-spacing:-.43em}.pure-u{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-g [class *=\"pure-u\"]{font-family:sans-serif}.pure-u-1,.pure-u-1-1,.pure-u-1-2,.pure-u-1-3,.pure-u-2-3,.pure-u-1-4,.pure-u-3-4,.pure-u-1-5,.pure-u-2-5,.pure-u-3-5,.pure-u-4-5,.pure-u-5-5,.pure-u-1-6,.pure-u-5-6,.pure-u-1-8,.pure-u-3-8,.pure-u-5-8,.pure-u-7-8,.pure-u-1-12,.pure-u-5-12,.pure-u-7-12,.pure-u-11-12,.pure-u-1-24,.pure-u-2-24,.pure-u-3-24,.pure-u-4-24,.pure-u-5-24,.pure-u-6-24,.pure-u-7-24,.pure-u-8-24,.pure-u-9-24,.pure-u-10-24,.pure-u-11-24,.pure-u-12-24,.pure-u-13-24,.pure-u-14-24,.pure-u-15-24,.pure-u-16-24,.pure-u-17-24,.pure-u-18-24,.pure-u-19-24,.pure-u-20-24,.pure-u-21-24,.pure-u-22-24,.pure-u-23-24,.pure-u-24-24{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-1-24{width:4.1667%;*width:4.1357%}.pure-u-1-12,.pure-u-2-24{width:8.3333%;*width:8.3023%}.pure-u-1-8,.pure-u-3-24{width:12.5%;*width:12.469%}.pure-u-1-6,.pure-u-4-24{width:16.6667%;*width:16.6357%}.pure-u-1-5{width:20%;*width:19.969%}.pure-u-5-24{width:20.8333%;*width:20.8023%}.pure-u-1-4,.pure-u-6-24{width:25%;*width:24.969%}.pure-u-7-24{width:29.1667%;*width:29.1357%}.pure-u-1-3,.pure-u-8-24{width:33.3333%;*width:33.3023%}.pure-u-3-8,.pure-u-9-24{width:37.5%;*width:37.469%}.pure-u-2-5{width:40%;*width:39.969%}.pure-u-5-12,.pure-u-10-24{width:41.6667%;*width:41.6357%}.pure-u-11-24{width:45.8333%;*width:45.8023%}.pure-u-1-2,.pure-u-12-24{width:50%;*width:49.969%}.pure-u-13-24{width:54.1667%;*width:54.1357%}.pure-u-7-12,.pure-u-14-24{width:58.3333%;*width:58.3023%}.pure-u-3-5{width:60%;*width:59.969%}.pure-u-5-8,.pure-u-15-24{width:62.5%;*width:62.469%}.pure-u-2-3,.pure-u-16-24{width:66.6667%;*width:66.6357%}.pure-u-17-24{width:70.8333%;*width:70.8023%}.pure-u-3-4,.pure-u-18-24{width:75%;*width:74.969%}.pure-u-19-24{width:79.1667%;*width:79.1357%}.pure-u-4-5{width:80%;*width:79.969%}.pure-u-5-6,.pure-u-20-24{width:83.3333%;*width:83.3023%}.pure-u-7-8,.pure-u-21-24{width:87.5%;*width:87.469%}.pure-u-11-12,.pure-u-22-24{width:91.6667%;*width:91.6357%}.pure-u-23-24{width:95.8333%;*width:95.8023%}.pure-u-1,.pure-u-1-1,.pure-u-5-5,.pure-u-24-24{width:100%}.pure-g-r{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em;font-family:FreeSans,Arimo,\"Droid Sans\",Helvetica,Arial,sans-serif;display:-webkit-flex;-webkit-flex-flow:row wrap;display:-ms-flexbox;-ms-flex-flow:row wrap}.opera-only :-o-prefocus,.pure-g-r{word-spacing:-.43em}.pure-g-r [class *=\"pure-u\"]{font-family:sans-serif}.pure-g-r img{max-width:100%;height:auto}@media (min-width:980px){.pure-visible-phone{display:none}.pure-visible-tablet{display:none}.pure-hidden-desktop{display:none}}@media (max-width:480px){.pure-g-r>.pure-u,.pure-g-r>[class *=\"pure-u-\"]{width:100%}}@media (max-width:767px){.pure-g-r>.pure-u,.pure-g-r>[class *=\"pure-u-\"]{width:100%}.pure-hidden-phone{display:none}.pure-visible-desktop{display:none}}@media (min-width:768px) and (max-width:979px){.pure-hidden-tablet{display:none}.pure-visible-desktop{display:none}}.pure-button{display:inline-block;*display:inline;zoom:1;line-height:normal;white-space:nowrap;vertical-align:baseline;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button{font-family:inherit;font-size:100%;*font-size:90%;*overflow:visible;padding:.5em 1em;color:#444;color:rgba(0,0,0,.8);*color:#444;border:1px solid #999;border:0 rgba(0,0,0,0);background-color:#E6E6E6;text-decoration:none;border-radius:2px}.pure-button-hover,.pure-button:hover,.pure-button:focus{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#1a000000', GradientType=0);background-image:-webkit-gradient(linear,0 0,0 100%,from(transparent),color-stop(40%,rgba(0,0,0,.05)),to(rgba(0,0,0,.1)));background-image:-webkit-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:-moz-linear-gradient(top,rgba(0,0,0,.05) 0,rgba(0,0,0,.1));background-image:-o-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1))}.pure-button:focus{outline:0}.pure-button-active,.pure-button:active{box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset}.pure-button[disabled],.pure-button-disabled,.pure-button-disabled:hover,.pure-button-disabled:focus,.pure-button-disabled:active{border:0;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);filter:alpha(opacity=40);-khtml-opacity:.4;-moz-opacity:.4;opacity:.4;cursor:not-allowed;box-shadow:none}.pure-button-hidden{display:none}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button-primary,.pure-button-selected,a.pure-button-primary,a.pure-button-selected{background-color:#0078e7;color:#fff}.pure-form input[type=text],.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=color],.pure-form select,.pure-form textarea{padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-form input:not([type]){padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-form input[type=color]{padding:.2em .5em}.pure-form input[type=text]:focus,.pure-form input[type=password]:focus,.pure-form input[type=email]:focus,.pure-form input[type=url]:focus,.pure-form input[type=date]:focus,.pure-form input[type=month]:focus,.pure-form input[type=time]:focus,.pure-form input[type=datetime]:focus,.pure-form input[type=datetime-local]:focus,.pure-form input[type=week]:focus,.pure-form input[type=number]:focus,.pure-form input[type=search]:focus,.pure-form input[type=tel]:focus,.pure-form input[type=color]:focus,.pure-form select:focus,.pure-form textarea:focus{outline:0;outline:thin dotted \\9;border-color:#129FEA}.pure-form input:not([type]):focus{outline:0;outline:thin dotted \\9;border-color:#129FEA}.pure-form input[type=file]:focus,.pure-form input[type=radio]:focus,.pure-form input[type=checkbox]:focus{outline:thin dotted #333;outline:1px auto #129FEA}.pure-form .pure-checkbox,.pure-form .pure-radio{margin:.5em 0;display:block}.pure-form input[type=text][disabled],.pure-form input[type=password][disabled],.pure-form input[type=email][disabled],.pure-form input[type=url][disabled],.pure-form input[type=date][disabled],.pure-form input[type=month][disabled],.pure-form input[type=time][disabled],.pure-form input[type=datetime][disabled],.pure-form input[type=datetime-local][disabled],.pure-form input[type=week][disabled],.pure-form input[type=number][disabled],.pure-form input[type=search][disabled],.pure-form input[type=tel][disabled],.pure-form input[type=color][disabled],.pure-form select[disabled],.pure-form textarea[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input:not([type])[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input[readonly],.pure-form select[readonly],.pure-form textarea[readonly]{background:#eee;color:#777;border-color:#ccc}.pure-form input:focus:invalid,.pure-form textarea:focus:invalid,.pure-form select:focus:invalid{color:#b94a48;border-color:#ee5f5b}.pure-form input:focus:invalid:focus,.pure-form textarea:focus:invalid:focus,.pure-form select:focus:invalid:focus{border-color:#e9322d}.pure-form input[type=file]:focus:invalid:focus,.pure-form input[type=radio]:focus:invalid:focus,.pure-form input[type=checkbox]:focus:invalid:focus{outline-color:#e9322d}.pure-form select{border:1px solid #ccc;background-color:#fff}.pure-form select[multiple]{height:auto}.pure-form label{margin:.5em 0 .2em}.pure-form fieldset{margin:0;padding:.35em 0 .75em;border:0}.pure-form legend{display:block;width:100%;padding:.3em 0;margin-bottom:.3em;color:#333;border-bottom:1px solid #e5e5e5}.pure-form-stacked input[type=text],.pure-form-stacked input[type=password],.pure-form-stacked input[type=email],.pure-form-stacked input[type=url],.pure-form-stacked input[type=date],.pure-form-stacked input[type=month],.pure-form-stacked input[type=time],.pure-form-stacked input[type=datetime],.pure-form-stacked input[type=datetime-local],.pure-form-stacked input[type=week],.pure-form-stacked input[type=number],.pure-form-stacked input[type=search],.pure-form-stacked input[type=tel],.pure-form-stacked input[type=color],.pure-form-stacked select,.pure-form-stacked label,.pure-form-stacked textarea{display:block;margin:.25em 0}.pure-form-stacked input:not([type]){display:block;margin:.25em 0}.pure-form-aligned input,.pure-form-aligned textarea,.pure-form-aligned select,.pure-form-aligned .pure-help-inline,.pure-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.pure-form-aligned textarea{vertical-align:top}.pure-form-aligned .pure-control-group{margin-bottom:.5em}.pure-form-aligned .pure-control-group label{text-align:right;display:inline-block;vertical-align:middle;width:10em;margin:0 1em 0 0}.pure-form-aligned .pure-controls{margin:1.5em 0 0 10em}.pure-form input.pure-input-rounded,.pure-form .pure-input-rounded{border-radius:2em;padding:.5em 1em}.pure-form .pure-group fieldset{margin-bottom:10px}.pure-form .pure-group input{display:block;padding:10px;margin:0;border-radius:0;position:relative;top:-1px}.pure-form .pure-group input:focus{z-index:2}.pure-form .pure-group input:first-child{top:1px;border-radius:4px 4px 0 0}.pure-form .pure-group input:last-child{top:-2px;border-radius:0 0 4px 4px}.pure-form .pure-group button{margin:.35em 0}.pure-form .pure-input-1{width:100%}.pure-form .pure-input-2-3{width:66%}.pure-form .pure-input-1-2{width:50%}.pure-form .pure-input-1-3{width:33%}.pure-form .pure-input-1-4{width:25%}.pure-form .pure-help-inline,.pure-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:.875em}.pure-form-message{display:block;color:#666;font-size:.875em}@media only screen and (max-width :480px){.pure-form button[type=submit]{margin:.7em 0 0}.pure-form input:not([type]),.pure-form input[type=text],.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=color],.pure-form label{margin-bottom:.3em;display:block}.pure-group input:not([type]),.pure-group input[type=text],.pure-group input[type=password],.pure-group input[type=email],.pure-group input[type=url],.pure-group input[type=date],.pure-group input[type=month],.pure-group input[type=time],.pure-group input[type=datetime],.pure-group input[type=datetime-local],.pure-group input[type=week],.pure-group input[type=number],.pure-group input[type=search],.pure-group input[type=tel],.pure-group input[type=color]{margin-bottom:0}.pure-form-aligned .pure-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.pure-form-aligned .pure-controls{margin:1.5em 0 0}.pure-form .pure-help-inline,.pure-form-message-inline,.pure-form-message{display:block;font-size:.75em;padding:.2em 0 .8em}}.pure-menu ul{position:absolute;visibility:hidden}.pure-menu.pure-menu-open{visibility:visible;z-index:2;width:100%}.pure-menu ul{left:-10000px;list-style:none;margin:0;padding:0;top:-10000px;z-index:1}.pure-menu>ul{position:relative}.pure-menu-open>ul{left:0;top:0;visibility:visible}.pure-menu-open>ul:focus{outline:0}.pure-menu li{position:relative}.pure-menu a,.pure-menu .pure-menu-heading{display:block;color:inherit;line-height:1.5em;padding:5px 20px;text-decoration:none;white-space:nowrap}.pure-menu.pure-menu-horizontal>.pure-menu-heading{display:inline-block;*display:inline;zoom:1;margin:0;vertical-align:middle}.pure-menu.pure-menu-horizontal>ul{display:inline-block;*display:inline;zoom:1;vertical-align:middle}.pure-menu li a{padding:5px 20px}.pure-menu-can-have-children>.pure-menu-label:after{content:'\\25B8';float:right;font-family:'Lucida Grande','Lucida Sans Unicode','DejaVu Sans',sans-serif;margin-right:-20px;margin-top:-1px}.pure-menu-can-have-children>.pure-menu-label{padding-right:30px}.pure-menu-separator{background-color:#dfdfdf;display:block;height:1px;font-size:0;margin:7px 2px;overflow:hidden}.pure-menu-hidden{display:none}.pure-menu-fixed{position:fixed;top:0;left:0;width:100%}.pure-menu-horizontal li{display:inline-block;*display:inline;zoom:1;vertical-align:middle}.pure-menu-horizontal li li{display:block}.pure-menu-horizontal>.pure-menu-children>.pure-menu-can-have-children>.pure-menu-label:after{content:\"\\25BE\"}.pure-menu-horizontal>.pure-menu-children>.pure-menu-can-have-children>.pure-menu-label{padding-right:30px}.pure-menu-horizontal li.pure-menu-separator{height:50%;width:1px;margin:0 7px}.pure-menu-horizontal li li.pure-menu-separator{height:1px;width:auto;margin:7px 2px}.pure-menu.pure-menu-open,.pure-menu.pure-menu-horizontal li .pure-menu-children{background:#fff;border:1px solid #b7b7b7}.pure-menu.pure-menu-horizontal,.pure-menu.pure-menu-horizontal .pure-menu-heading{border:0}.pure-menu a{border:1px solid transparent;border-left:0;border-right:0}.pure-menu a,.pure-menu .pure-menu-can-have-children>li:after{color:#777}.pure-menu .pure-menu-can-have-children>li:hover:after{color:#fff}.pure-menu .pure-menu-open{background:#dedede}.pure-menu li a:hover,.pure-menu li a:focus{background:#eee}.pure-menu li.pure-menu-disabled a:hover,.pure-menu li.pure-menu-disabled a:focus{background:#fff;color:#bfbfbf}.pure-menu .pure-menu-disabled>a{background-image:none;border-color:transparent;cursor:default}.pure-menu .pure-menu-disabled>a,.pure-menu .pure-menu-can-have-children.pure-menu-disabled>a:after{color:#bfbfbf}.pure-menu .pure-menu-heading{color:#565d64;text-transform:uppercase;font-size:90%;margin-top:.5em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:#dfdfdf}.pure-menu .pure-menu-selected a{color:#000}.pure-menu.pure-menu-open.pure-menu-fixed{border:0;border-bottom:1px solid #b7b7b7}.pure-paginator{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em;text-rendering:optimizespeed;list-style:none;margin:0;padding:0}.opera-only :-o-prefocus,.pure-paginator{word-spacing:-.43em}.pure-paginator li{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-paginator .pure-button{border-radius:0;padding:.8em 1.4em;vertical-align:top;height:1.1em}.pure-paginator .pure-button:focus,.pure-paginator .pure-button:active{outline-style:none}.pure-paginator .prev,.pure-paginator .next{color:#C0C1C3;text-shadow:0 -1px 0 rgba(0,0,0,.45)}.pure-paginator .prev{border-radius:2px 0 0 2px}.pure-paginator .next{border-radius:0 2px 2px 0}@media (max-width:480px){.pure-menu-horizontal{width:100%}.pure-menu-children li{display:block;border-bottom:1px solid #000}}.pure-table{border-collapse:collapse;border-spacing:0;empty-cells:show;border:1px solid #cbcbcb}.pure-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.pure-table td,.pure-table th{border-left:1px solid #cbcbcb;border-width:0 0 0 1px;font-size:inherit;margin:0;overflow:visible;padding:6px 12px}.pure-table td:first-child,.pure-table th:first-child{border-left-width:0}.pure-table thead{background:#e0e0e0;color:#000;text-align:left;vertical-align:bottom}.pure-table td{background-color:transparent}.pure-table-odd td{background-color:#f2f2f2}.pure-table-striped tr:nth-child(2n-1) td{background-color:#f2f2f2}.pure-table-bordered td{border-bottom:1px solid #cbcbcb}.pure-table-bordered tbody>tr:last-child td,.pure-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.pure-table-horizontal td,.pure-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #cbcbcb}.pure-table-horizontal tbody>tr:last-child td{border-bottom-width:0}"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/2-browser-devtools/zordpress/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta name=\"description\" content=\"A layout example that shows off a blog page with a list of posts.\">\n\n    <title>Zordpress</title>\n\n    <link rel=\"stylesheet\" href=\"css/pure.css\">\n    <link rel=\"stylesheet\" href=\"css/main-grid.css\">\n    <link rel=\"stylesheet\" href=\"css/blog.css\">\n</head>\n<body>\n\n<div id=\"layout\" class=\"pure-g\">\n    <div class=\"sidebar pure-u-1 pure-u-med-1-4\">\n        <div class=\"header\">\n            <hgroup>\n                <h1 class=\"brand-title\">Zordpress</h1>\n                <h2 class=\"brand-tagline\">Lorem ipsum dolor sit</h2>\n            </hgroup>\n        </div>\n    </div>\n\n    <div class=\"content pure-u-1 pure-u-med-3-4\">\n        <div>\n            <!-- A wrapper for all the blog posts -->\n            <div class=\"posts\">\n                <h1 class=\"content-subhead\">Pinned Post</h1>\n\n                <!-- A single blog post -->\n                <section class=\"post\">\n                    <header class=\"post-header\">\n                        <img class=\"post-avatar\" alt=\"Zeno Rocha&#x27;s avatar\" height=\"48\" width=\"48\" src=\"../common/zeno.jpg\">\n\n                        <h2 class=\"post-title\">Chrome DevTools Secrets</h2>\n\n                        <p class=\"post-meta\">\n                            By <a href=\"#\" class=\"post-author\">Zeno Rocha</a> under <a class=\"post-category post-category-design\" href=\"#\">Chrome</a> <a class=\"post-category post-category-pure\" href=\"#\">DevTools</a>\n                        </p>\n                    </header>\n\n                    <div class=\"post-description\">\n                        <p id=\"my-post\">\n                            Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laborum, magnam eos rem voluptatibus recusandae odio neque voluptates perferendis quod quis odit voluptatem dolore! Accusamus, hic, officia vero animi debitis incidunt ipsum culpa doloribus recusandae fugiat in excepturi suscipit laboriosam fugit!\n                        </p>\n                    </div>\n                </section>\n            </div>\n\n            <div class=\"posts\">\n                <h1 class=\"content-subhead\">Recent Posts</h1>\n\n                <section class=\"post\">\n                    <header class=\"post-header\">\n                        <img class=\"post-avatar\" alt=\"Todd McLeod&#x27;s avatar\" height=\"48\" width=\"48\" src=\"../common/todd.jpg\">\n\n                        <h2 class=\"post-title\">Why Fresno City College rocks</h2>\n\n                        <p class=\"post-meta\">\n                            By <a class=\"post-author\" href=\"#\">Todd McLeod</a> under <a class=\"post-category post-category-opinion\" href=\"#\">Opinion</a>\n                        </p>\n                    </header>\n\n                    <div class=\"post-description\">\n                        <p>\n                            Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\n                        </p>\n                    </div>\n                </section>\n\n                <section class=\"post\">\n                    <header class=\"post-header\">\n                        <img class=\"post-avatar\" alt=\"Andrew Rota&#x27;s avatar\" height=\"48\" width=\"48\" src=\"../common/andrew.jpg\">\n\n                        <h2 class=\"post-title\">Getting started with Web Components</h2>\n\n                        <p class=\"post-meta\">\n                            By <a class=\"post-author\" href=\"#\">Andrew Rota</a> under <a class=\"post-category post-category-web\" href=\"#\">Web</a>\n                        </p>\n                    </header>\n\n                    <div class=\"post-description\">\n                        <p>\n                            Lorem ipsum dolor sit amet, consectetur adipisicing elit. Libero voluptatibus aperiam voluptatum nulla exercitationem, a porro totam magnam at esse illum, vel ea magni ex laudantium perspiciatis, tempora expedita molestiae repellendus. Consequuntur corporis ipsa tempore et vero, ipsam consectetur necessitatibus non architecto accusamus distinctio ducimus molestias quibusdam voluptate, tempora numquam.\n                        </p>\n                    </div>\n                </section>\n            </div>\n        </div>\n    </div>\n</div>\n\n<script src=\"js/save.js\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/2-browser-devtools/zordpress/js/save.js",
    "content": ""
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/3-html5/1-detection/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Document</title>\n  <style>\n    html {\n      background-color: red;\n    }\n\n    html.websqldatabase {\n      background-color: green;\n    }\n  </style>\n</head>\n<body>\n  <script src=\"modernizr.min.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/3-html5/2-structure/1-past.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n<head>\n\t<meta http-equiv=\"Content-Type\" content=\"text/html;charset=UTF-8\">\n</head>\n<body>\n\t<div class=\"wrap\">\n\t\t<div class=\"header\">\n\t\t\t<ul class=\"nav\">\n\t\t\t\t<li><a href=\"\"></a></li>\n\t\t\t\t<li><a href=\"\"></a></li>\n\t\t\t\t<li><a href=\"\"></a></li>\n\t\t\t</ul>\n\t\t</div>\n\t\t<div class=\"content\">\n\t\t\t<h2>Subtitle</h2>\n\t\t\t<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. A, ex asperiores quia veniam aperiam reprehenderit.</p>\n\t\t</div>\n\t\t<div class=\"footer\">Lorem ipsum dolor sit.</div>\n\t</div>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/3-html5/2-structure/2-today.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Document</title>\n</head>\n<body>\n  <div class=\"wrap\">\n    <header>\n      <nav>\n        <ul>\n          <li><a href=\"\"></a></li>\n          <li><a href=\"\"></a></li>\n          <li><a href=\"\"></a></li>\n        </ul>\n      </nav>\n    </header>\n    <main>\n      <h2>Subtitle</h2>\n      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. A, ex asperiores quia veniam aperiam reprehenderit.</p>\n    </main>\n    <footer>Lorem ipsum dolor sit</footer>\n  </div>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/3-html5/3-audio/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Document</title>\n</head>\n<body>\n  <audio autoplay loop controls>\n    <source src=\"zelda.ogg\" type=\"audio/ogg\">\n    <source src=\"zelda.mp3\" type=\"audio/mpeg\">\n  </audio>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/3-html5/4-video/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Document</title>\n</head>\n<body>\n  <video preload=\"auto\" controls poster=\"http://www.gravatar.com/avatar/5f57ad1c5f070528c87ecc1b0a46a5e9\">\n    <source src=\"rabbit.ogg\" type=\"video/ogg\">\n    <source src=\"rabbit.mp4\" type=\"video/mp4\">\n  </video>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/3-html5/5-input/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<meta name=\"viewport\" content=\"width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0\">\n\t<style>\n\tinput { display: block; }\n\n\tinput:invalid {\n\t\tborder-color: pink;\n\t}\n\n\tinput:valid {\n\t\tborder-color: lightgreen;\n\t}\n\t</style>\n</head>\n<body>\n\t<form>\n\t\t<label for=\"email\">Email</label>\n\t\t<input name=\"email\" type=\"email\" placeholder=\"your@email.com\" required>\n\t\t<label for=\"name\">Name</label>\n\t\t<input name=\"name\" type=\"text\" placeholder=\"John Wayne\">\n\t\t<label for=\"age\">Age</label>\n\t\t<input name=\"age\" type=\"number\" min=\"13\" max=\"120\" placeholder=\"18\">\n\t\t<label for=\"color\">Favorite Color</label>\n\t\t<input name=\"color\" type=\"color\" value=\"#0000ff\">\n\t\t<label for=\"zip\">ZIP</label>\n\t\t<input name=\"zip\" type=\"number\" max=\"99999\" min=\"10000\" placeholder=\"XXXXX\" required>\n\t\t<input type=\"submit\">\n\t</form>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/3-html5/6-mark/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n</head>\n<body>\n\t<input type=\"search\" value=\"ipsum\">\n\t<p>Lorem <mark>ipsum</mark> dolor sit amet, consectetur adipisicing elit. Repellat dolores accusantium ex deleniti perspiciatis fugit maiores reprehenderit illum quisquam ad, officia inventore hic, ratione rem unde rerum, praesentium laborum quos.</p>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/3-html5/7-progress/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n</head>\n<body>\n\t<progress></progress>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/4-js/1-jquery/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<script src=\"jquery.min.js\"></script>\n</head>\n<body>\n\t<div id=\"box\" class=\"box\" width=\"300\"></div>\n\n\t<script>\n\t// 1\n\t$(function() {\n\n\t});\n\n\tdocument.addEventListener('DOMContentLoaded', function(e) {\n\n\t});\n\n\t// 2\n\t$(\"#box\");\n\n\tdocument.querySelector('#box');\n\tdocument.getElementById('box');\n\n\t// 3\n\t$(\".box\");\n\n\tdocument.querySelectorAll('.box');\n\n\t// 4\n\t$(\"div\");\n\n\tdocument.querySelector('div');\n\tdocument.getElementsByTagName('div')\n\n\t// 5\n\t$(\".box\").get(0);\n\n\tdocument.querySelector('.box');\n\tdocument.getElementsByClassName('box');\n\n\t// 6\n\t$(document).on('click', function(event) {\n\t\tconsole.log(event);\n\t});\n\n\tdocument.addEventListener('click', function(event) {\n\t\tconsole.log(event);\n\t});\n\n\t// 7\n\t$(\"#box\").text(\"lorem\");\n\n\tdocument.querySelector('#box').textContent = 'lorem';\n\n\t// 8\n\t$(\"#box\").html(\"<p>lorem</p>\");\n\n\tdocument.querySelector('#box').innerHTML = '<p>lorem</p>';\n\n\t// 9\n\t$(\"#box\").append(\"<p>lorem</p>\");\n\n\tdocument.querySelector('#box').innerHTML += '<p>lorem</p>';\n\n\t// 10\n\t$(\"#box\").attr(\"width\");\n\n\tdocument.querySelector('#box').getAttribute('width');\n\n\t// 11\n\t$(\"#box\").attr(\"width\", \"400\");\n\n\tdocument.querySelector('#box').setAttribute('width', '400');\n\n\t// 12\n\t$(\"#box\").removeAttr(\"width\");\n\n\tdocument.querySelector('#box').removeAttribute('width');\n\n\t// 13\n\t$(\"#box\").addClass(\"selected\");\n\n\tdocument.querySelector('#box').classList.add('selected');\n\n\t// 14\n\t$(\"#box\").removeClass(\"selected\");\n\n\tdocument.querySelector('#box').classList.remove('selected');\n\n\t// 15\n\t$(\"#box\").toggleClass(\"selected\");\n\n\tdocument.querySelector('#box').classList.toggle('selected');\n\n\t// 16\n\t$(\"#box\").hasClass(\"box\");\n\n\tdocument.querySelector('#box').classList.contains('box');\n\n\t// 17\n\t$(\"#box\").css({\n\t\t\"background\": \"#F60\",\n\t\t\"height\": \"300\"\n\t});\n\n\tdocument.querySelector('#box').style.background = '#F60';\n\tdocument.querySelector('#box').style.height = '300px';\n\t</script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/4-js/2-audio/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Document</title>\n</head>\n<body>\n  <audio preload=\"auto\">\n    <source src=\"zelda.ogg\" type=\"audio/ogg\">\n    <source src=\"zelda.mp3\" type=\"audio/mpeg\">\n  </audio>\n  <button id=\"play\">Play</button>\n  <label for=\"volume\">Volume:</label>\n  <input id=\"volume\" type=\"range\" min=0 max=1 step=\"0.01\" value=\"1\">\n  <script>\n    document.querySelector('#play').addEventListener('click', function(e) {\n      if (e.target.classList.contains('playing')) {\n        document.querySelector('audio').pause();\n        e.target.textContent = 'Play';\n      }\n      else {\n        document.querySelector('audio').play();\n        e.target.textContent = 'Pause';\n      }\n      e.target.classList.toggle('playing');\n    });\n\n    document.querySelector('#volume').addEventListener('input', function(e) {\n      document.querySelector('audio').volume = e.target.value;\n    });\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/4-js/3-video/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Document</title>\n</head>\n<body>\n  <video preload=\"auto\">\n    <source src=\"rabbit.ogg\" type=\"video/ogg\">\n    <source src=\"rabbit.mp4\" type=\"video/mp4\">\n  </video>\n  <button id=\"play\">Play</button>\n  <button id=\"replay\">Replay</button>\n  <p><span id=\"currentPoint\"></span>/<span id=\"duration\"></span></p>\n  <script>\n    function updateDurations() {\n      var video = document.querySelector('video');\n      document.querySelector('#currentPoint').textContent = Math.round(video.currentTime);\n      document.querySelector('#duration').textContent = Math.round(video.duration);\n    }\n\n    document.querySelector('#play').addEventListener('click', function(e) {\n      if (e.target.classList.contains('playing')) {\n        e.target.textContent = 'Play';\n        document.querySelector('video').pause();\n      }\n      else {\n        e.target.textContent = 'Pause';\n        document.querySelector('video').play();\n      }\n\n      e.target.classList.toggle('playing');\n    });\n\n    window.addEventListener('load', updateDurations);\n\n    document.querySelector('video').addEventListener('timeupdate', updateDurations);\n\n    document.querySelector('#replay').addEventListener('click', function() {\n      var playButton = document.querySelector('#play');\n      playButton.textContent = 'Pause';\n      playButton.classList.add('playing');\n      var video = document.querySelector('video');\n      video.currentTime = 0;\n      video.play();\n    });\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/4-js/4-form/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<style>\n\t\tinput:required {\n\t\t\tborder-color: blue;\n\t\t}\n\n\t\tinput:invalid {\n\t\t\tbackground-color: pink;\n\t\t}\n\n\t\tinput:valid {\n\t\t\tbackground-color: lightgreen;\n\t\t}\n\t</style>\n</head>\n<body>\n\t<form name=\"tele\">\n\t\t<label for=\"name\">Name</label>\n\t\t<input name=\"name\" type=\"text\" placeholder=\"John Wayne\" required>\n\t\t<label for=\"phone\">Phone</label>\n\t\t<input name=\"phone\" type=\"tel\" placeholder=\"XXX-XXX-XXXX\" pattern=\"\\d{3}\\-\\d{3}\\-\\d{4}\" required>\n\t\t<input type=\"submit\" value=\"Send\">\n\t</form>\n\n\t<script>\n\t\tfunction setInvalidMessage(emptyMessage, wrongMessage) {\n\t\t\treturn function(e) {\n\t\t\t\tif (e.target.value != '') {\n\t\t\t\t\te.target.setCustomValidity(wrongMessage)\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\te.target.setCustomValidity(emptyMessage)\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tdocument.forms.tele.name.addEventListener('invalid', setInvalidMessage('You need to enter your name!'))\n\t\tdocument.forms.tele.phone.addEventListener('invalid', setInvalidMessage('You need to enter a phone number!', 'A full American phone number separated by dashes is required.'))\n\n\t\tfunction clearErrors(e) {\n\t\t\tvar regex = new RegExp(e.target.pattern);\n\t\t\tif (regex.test(e.target.value)) {\n\t\t\t\te.target.setCustomValidity('');\n\t\t\t}\n\t\t\telse {\n\t\t\t\te.target.checkValidity();\n\t\t\t}\n\t\t}\n\n\t\tdocument.forms.tele.name.addEventListener('input', clearErrors);\n\t\tdocument.forms.tele.phone.addEventListener('input', clearErrors);\n\t</script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/4-js/5-storage/local.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Document</title>\n</head>\n<body>\n  <textarea cols=\"60\" rows=\"25\"></textarea>\n\n  <script>\n    var area = document.querySelector('textarea');\n    area.value = localStorage.getItem('message') || '';\n    area.addEventListener('input', function() {\n      localStorage.setItem('message', area.value);\n    });\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/4-js/5-storage/session.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Document</title>\n</head>\n<body>\n  <label>To-Do List</label>\n  <ol contenteditable><li></li></ol>\n  <script>\n    var area = document.querySelector('ol');\n    area.innerHTML = sessionStorage.getItem('todo') || '<li></li>';\n    area.addEventListener('input', function() {\n      sessionStorage.setItem('todo', area.innerHTML);\n    });\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/4-js/6-geolocation/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Document</title>\n</head>\n<body>\n  <script>\n    if (navigator && navigator.geolocation) {\n      navigator.geolocation.getCurrentPosition(function(pos) {\n        var img = new Image();\n        img.alt = 'Map';\n        img.src = 'https://maps.googleapis.com/maps/api/staticmap?';\n        img.src += 'markers=' + pos.coords.latitude + ',' + pos.coords.longitude;\n        img.src += '&zoom=14&size=700x700';\n        document.body.appendChild(img);\n      });\n    }\n    else {\n      alert('Geolocation not available');\n    }\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/4-js/7-usermedia/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Document</title>\n</head>\n<body>\n  <video></video>\n  <script>\n    if (navigator && (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia)) {\n      navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;\n      navigator.getUserMedia({video: true},\n        function(stream) {\n          console.dir(stream);\n          var video = document.querySelector('video');\n          video.src = URL.createObjectURL(stream);\n          video.play();\n        },\n        function(err) {\n          alert(err.name);\n        });\n    }\n    else {\n      alert('User media does not work.')\n    }\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/4-js/8-dragndrop/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<style>\n\timg {\n\t\tborder: 0;\n\t\twidth: 75px;\n\t\theight: 75px;\n\t}\n\n\t.box {\n\t\tborder: 10px #CCC solid;\n\t\tpadding: 20px;\n\t\tmargin: 100px 0 0 100px;\n\t\tfloat: left;\n\t\twidth: 200px;\n\t\theight: 200px;\n\t}\n\t</style>\n</head>\n<body>\n\t<div class=\"box\">\n\t\t<img src=\"img/clubs.png\" alt=\"clubs\" id=\"clubs\" draggable>\n\t\t<img src=\"img/hearts.png\" alt=\"hearts\" id=\"hearts\" draggable>\n\t\t<img src=\"img/spades.png\" alt=\"spades\" id=\"spades\" draggable>\n\t\t<img src=\"img/diamonds.png\" alt=\"diamonds\" id=\"diamonds\" draggable>\n\t</div>\n\t<div class=\"box\"></div>\n\t<script>\n\t\tvar boxes = document.querySelectorAll('.box');\n\n\t\t// Method 1\n\t\t// var destination = null;\n\t\t// for (var i = 0; i < boxes.length; i++) {\n\t\t// \tboxes[i].addEventListener('dragend', function(e) {\n\t\t// \t\tif (destination !== null) {\n\t\t// \t\t\tvar item = e.target;\n\t\t// \t\t\tdestination.appendChild(item);\n\t\t// \t\t\tdestination = null;\n\t\t// \t\t}\n\t\t// \t});\n\t\t// \tboxes[i].addEventListener('dragenter', function(e) {\n\t\t// \t\tif (e.target.classList.contains('box')) {\n\t\t// \t\t\tdestination = e.target;\n\t\t// \t\t}\n\t\t// \t});\n\t\t// }\n\n\t\t// Method 2\n\t\tvar draggedItem\n\t\tfor (var i = 0; i < boxes.length; i++) {\n\t\t\tboxes[i].addEventListener('dragstart', function(e) {\n\t\t\t\tdraggedItem = e.target;\n\t\t\t});\n\t\t\tboxes[i].addEventListener('dragover', function(e) {\n\t\t\t\te.preventDefault();\n\t\t\t});\n\t\t\tboxes[i].addEventListener('drop', function(e) {\n\t\t\t\tvar item = e.target;\n\t\t\t\twhile (!item.classList.contains('box') && item !== document.body) {\n\t\t\t\t\titem = item.parentNode;\n\t\t\t\t}\n\t\t\t\tif (item.classList.contains('box')) {\n\t\t\t\t\titem.appendChild(draggedItem);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t</script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/4-js/9-canvas/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <style>\n    * {\n      padding: 0;\n      margin: 0;\n    }\n  </style>\n</head>\n<body>\n  <canvas width=\"800\" height=\"600\"></canvas>\n  <script>\n    function render(time) {\n      requestAnimationFrame(render);\n\n      var delta = time - lastTime;\n      lastTime = time;\n      delta = Math.min(1, delta / 1000);\n      var deltaX = 0;\n      var deltaY = 0;\n      deltaX += right ? 1 : 0;\n      deltaX -= left ? 1 : 0;\n      deltaY += down ? 1 : 0;\n      deltaY -= up ? 1 : 0;\n      xPos += deltaX * delta * 100;\n      yPos += deltaY * delta * 100;\n\n      context.fillStyle = '#ffffcc';\n      context.fillRect(0, 0, 800, 600);\n\n      context.fillStyle = 'white';\n      context.arc(xPos + 50, yPos + 50, 50, 0, Math.PI * 2, true);\n      context.fill();\n      context.stroke();\n      context.fillStyle = 'black';\n\n      context.fillStyle = 'rgba(0, 0, 0, 0.5)'\n      context.beginPath();\n      context.moveTo(xPos + 3, yPos + 35);\n      context.lineTo(xPos + 97, yPos + 35);\n      context.stroke();\n      context.moveTo(xPos + 80, yPos + 35);\n      context.lineTo(xPos + 65, yPos + 50);\n      context.lineTo(xPos + 52, yPos + 35);\n      context.moveTo(xPos + 48, yPos + 35);\n      context.lineTo(xPos + 35, yPos + 50);\n      context.lineTo(xPos + 20, yPos + 35);\n      context.fill();\n      context.fillStyle = 'black';\n\n      context.beginPath();\n      context.arc(xPos + 35, yPos + 40, 10, 0, Math.PI * 2);\n      context.stroke();\n      context.beginPath();\n      context.arc(xPos + 65, yPos + 40, 10, 0, Math.PI * 2);\n      context.stroke();\n\n      var xEyePos = deltaX != 0 && deltaY != 0 ? deltaX * .7 : deltaX\n      var yEyePos = deltaX != 0 && deltaY != 0 ? deltaY * .7 : deltaY\n      context.beginPath();\n      context.arc(xPos + 35 + xEyePos * 5, yPos + 40 + yEyePos * 5, 3, 0, Math.PI * 2);\n      context.fill();\n      context.beginPath();\n      context.arc(xPos + 65 + xEyePos * 5, yPos + 40 + yEyePos * 5, 3, 0, Math.PI * 2);\n      context.fill();\n\n      context.beginPath();\n      context.arc(xPos + 50, yPos + 50, 30, Math.PI * 5 / 6, Math.PI / 6, true);\n      context.stroke();\n      context.beginPath();\n      for (var i = 0; i < hair.length; i++) {\n        context.moveTo(xPos + i + 1, yPos - Math.sqrt(2500 - (i - 49) * (i - 49)) + 50);\n        context.lineTo(xPos + i + 1, yPos - Math.sqrt(2500 - (i - 49) * (i - 49)) + hair[i] + 50);\n      }\n      context.stroke();\n    }\n\n    var canvas = document.querySelector('canvas');\n    var context = canvas.getContext('2d');\n    var xPos = 10;\n    var yPos = 10;\n    var left = false;\n    var right = false;\n    var up = false;\n    var down = false;\n    var lastTime = 0;\n    var hair = [];\n    for (var i = 0; i < 98; i++) {\n      hair.push(Math.random() * 15 + 10);\n    }\n\n    window.addEventListener('keydown', function(e) {\n      switch (e.keyIdentifier) {\n        case 'Up':\n          up = true;\n          break;\n        case 'Down':\n          down = true;\n          break;\n        case 'Left':\n          left = true;\n          break;\n        case 'Right':\n          right = true;\n          break;\n      }\n    });\n\n    window.addEventListener('keyup', function(e) {\n      switch (e.keyIdentifier) {\n        case 'Up':\n          up = false;\n          break;\n        case 'Down':\n          down = false;\n          break;\n        case 'Left':\n          left = false;\n          break;\n        case 'Right':\n          right = false;\n          break;\n      }\n    });\n\n    render(0);\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/5-web-components/0-proto/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<title>Document</title>\n</head>\n<body>\n\t<script>\n\tfunction Animal(name, age, brothers, sisters, sad) {\n\t\tthis.name = name;\n\t\tthis.age = age;\n\t\tthis.brothers = brothers;\n\t\tthis.sisters = sisters;\n\t\tthis.sad = sad;\n\t}\n\n\tAnimal.prototype.isSad = function() {\n\t\tif (this.sad) {\n\t\t\treturn 'Ohh :(';\n\t\t}\n\t\telse {\n\t\t\treturn 'Yay!';\n\t\t}\n\t};\n\n\tfunction Cow(bell) {\n\t\tthis.bell = bell;\n\t}\n\tvar cow = new Animal(\"Martha\", 10, [\"John\"], null, true);\n\tvar frog = new Animal(\"Martha\", 10, [\"John\"], null, true);\n\n\tcow.hasMilk = function() {\n\t\treturn 'Yes!'\n\t};\n\t</script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/5-web-components/1-custom-elements/1-index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n</head>\n<body>\n\t<fcc-hello></fcc-hello>\n\n\t<script>\n\tvar element = Object.create(HTMLElement.prototype);\n\n\telement.attachedCallback = function() {\n\t\tthis.innerHTML = '<h1>Hello Fresno</h1>';\n\t};\n\n\tdocument.registerElement('fcc-hello', {\n\t\tprototype: element\n\t});\n\t</script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/5-web-components/1-custom-elements/2-fcc-location.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n</head>\n<body>\n\t<fcc-location></fcc-location>\n\n\t<script>\n\tvar proto = Object.create(HTMLElement.prototype);\n\n\tproto.createdCallback = function() {\n\t\tnavigator.geolocation.getCurrentPosition(function(pos) {\n\t\t\tvar image = new Image();\n\t\t\timage.alt = 'Map';\n\t\t\timage.src = 'https://maps.googleapis.com/maps/api/staticmap?';\n\t\t\timage.src += 'markers=' + pos.coords.latitude + ',' + pos.coords.longitude;\n\t\t\timage.src += '&size=700x700&zoom=16';\n\t\t\tthis.appendChild(image);\n\t\t}.bind(this));\n\t};\n\n\tdocument.registerElement('fcc-location', {prototype: proto})\n\t</script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/5-web-components/2-html-templates/1-index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n</head>\n<body>\n\t<template>\n\t\t<img src=\"1-fresno-night.jpg\" alt=\"Fresno by night\">\n\t\t<img src=\"1-fresno-day.png\" alt=\"Fresno by day\">\n\t</template>\n\n\t<script>\n\tvar template = document.querySelector('template').content;\n\tvar clone = template.cloneNode(true);\n\tconsole.log(clone);\n\t</script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/5-web-components/2-html-templates/2-fcc-logo.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n</head>\n<body>\n\t<template>\n\t\t<a href=\"http://www.fresnocitycollege.edu/\">\n\t\t\t<img src=\"http://devfest.gdgfresno.com/img/partners/fcc.jpg\" alt=\"Fresno City College\">\n\t\t</a>\n\t</template>\n\t<my-logo></my-logo>\n\n\t<script>\n\tvar proto = Object.create(HTMLElement.prototype);\n\n\tproto.createdCallback = function() {\n\t\tvar template = document.querySelector('template').content;\n\t\tthis.appendChild(template.cloneNode(true));\n\t}\n\n\tdocument.registerElement('my-logo', {prototype: proto});\n\t</script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/5-web-components/2-html-templates/3-airport.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<script src=\"https://cdn.firebase.com/js/client/2.2.7/firebase.js\"></script>\n</head>\n<body>\n\t<template>\n\t\t<li>\n\t\t\t<p>\n\t\t\t\t<strong>✈ </strong>\n\t\t\t\t<span id=\"name\"></span>\n\t\t\t\t<em>(<span id=\"city\"></span>, <span id=\"state\"></span>)</em>\n\t\t\t\t<span id=\"delay\"></span>\n\t\t\t</p>\n\t\t</li>\n\t</template>\n\n\t<h1>List of aiports</h1>\n\t<h4>Updated on: <span id=\"updated\"></span></h4>\n\t<ol id=\"airportList\"></ol>\n\n\t<script>\n\tvar ref = new Firebase('https://publicdata-airports.firebaseio.com/');\n\n\tref.on('value', function(snapshot) {\n\t\tvar airportList = document.querySelector('#airportList');\n\t\tvar template = document.querySelector('template').content;\n\t\tvar airports = snapshot.val();\n\t\tairportList.innerHTML = '';\n\t\tfor (var airportCode in airports) {\n\t\t\tif (airportCode[0] !== '_') {\n\t\t\t\tvar clone = template.cloneNode(true);\n\t\t\t\tclone.querySelector('#name').textContent = airports[airportCode].name;\n\t\t\t\tclone.querySelector('#city').textContent = airports[airportCode].city;\n\t\t\t\tclone.querySelector('#state').textContent = airports[airportCode].state;\n\t\t\t\tif (airports[airportCode].delay) {\n\t\t\t\t\tclone.querySelector('#delay').textContent = 'Delay: ' + airports[airportCode].status.avgDelay;\n\t\t\t\t}\n\t\t\t\tairportList.appendChild(clone);\n\t\t\t}\n\t\t}\n\t\tdocument.querySelector('#updated').textContent = airports._updated;\n\t});\n\t</script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/5-web-components/3-shadow-dom/1-index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<style>\n\th1 {\n\t\tcolor: blue;\n\t}\n\t</style>\n</head>\n<body>\n\t<h1>Foo</h1>\n\t<div id=\"bar\"></div>\n\n\t<script>\n\tvar shadowRoot = bar.createShadowRoot();\n\n\tshadowRoot.innerHTML = '<style>h1 {color: red;}</style><h1>Qwer</h1>';\n\t</script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/5-web-components/3-shadow-dom/2-fcc-button.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n</head>\n<body>\n\t<template>\n\t\t<style>\n\t\t\tbutton {\n\t\t\t\tposition: absolute;\n\t\t\t\ttop: calc(50% - 160px);\n\t\t\t\tleft: calc(50% - 220px);\n\t\t\t\twidth: 440px;\n\t\t\t\theight: 365px;\n\t\t\t\toutline: none;\n\t\t\t\tborder: none;\n\t\t\t\tborder-radius: 50%;\n\t\t\t\tbackground: #b3b3b3;\n\t\t\t\tbox-shadow:\n\t\t\t\t\t0 10px 0 #888888,\n\t\t\t\t\t0 20px 0 #888888,\n\t\t\t\t\t0 30px 0  #888888,\n\t\t\t\t\t-10px 40px 0 hsla(0, 0%, 0%, .2);\n\t\t\t}\n\n\t\t\tbutton:before {\n\t\t\t\tposition: absolute;\n\t\t\t\ttop: -95px;\n\t\t\t\tleft: 40px;\n\t\t\t\twidth: 360px;\n\t\t\t\theight: 305px;\n\t\t\t\tborder-radius: inherit;\n\t\t\t\tcolor: #ff6573;\n\t\t\t\tbackground-color: currentColor;\n\t\t\t\tbox-shadow:\n\t\t\t\t\t0 30px 0 #c54c57,\n\t\t\t\t\t0 60px 0 #c54c57,\n\t\t\t\t\t0 90px 0 #c54c57,\n\t\t\t\t\t0 110px 0 #c54c57,\n\t\t\t\t\t-25px 140px 0 hsla(0, 0%, 0%, .1);\n\t\t\t\tcontent: '';\n\t\t\t\ttransition: all 250ms;\n\t\t\t}\n\n\t\t\tbutton:active:before{\n\t\t\t\ttop: 0px;\n\t\t\t\tbox-shadow:\n\t\t\t\t\t0 16px #c54c57,\n\t\t\t\t\t0 16px #c54c57,\n\t\t\t\t\t0 16px #c54c57,\n\t\t\t\t\t0 16px #c54c57,\n\t\t\t\t\t-5px 20px 0 hsla(0, 0%, 0%, .1),\n\t\t\t\t\t0 16px 0 #c54c57;\n\t\t\t}\n\t\t</style>\n\n\t\t<button></button>\n\t</template>\n\n\t<fcc-button></fcc-button>\n\n\t<script>\n\tvar template = document.querySelector('template').content;\n\n\tvar proto = Object.create(HTMLElement.prototype);\n\n\tproto.createdCallback = function() {\n\t\tvar clone = template.cloneNode(true);\n\t\tvar shadow = this.createShadowRoot();\n\n\t\tshadow.appendChild(clone);\n\t};\n\n\tdocument.registerElement('fcc-button', {prototype: proto});\n\t</script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/5-web-components/4-html-imports/1-component.html",
    "content": "<p>Component</p>\n\n<style>\n  p {\n    color: blue;\n  }\n</style>\n\n<script>\n  var parent = document;\n  var component = document.currentScript.ownerDocument;\n</script>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/5-web-components/4-html-imports/1-index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<link rel=\"import\" href=\"1-component.html\">\n</head>\n<body>\n\t<p>Parent</p>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/5-web-components/4-html-imports/2-index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<link rel=\"import\" href=\"2-toc.html\">\n</head>\n<body>\n\t<h1>FAQ</h1>\n\n\t<fcc-toc></fcc-toc>\n\n  <h2 id=\"one\">What is the TEAS exam?</h2>\n\n\t<p>The Test of Essential Academic Skills (TEAS) was developed to measure basic essential skills in the academic content area domains of Reading, Mathematics, Science, and English and Language Usage. These entry level skills were deemed important for nursing program applicants by a nursing program curriculum expert. Students must earn an overall score of 62% or higher to submit an application to the Registered Nursing and LVN to RN Program. Students who earn an overall score below 62% may enroll into remediation workshops within the Health Sciences Division at FCC. Students may call the Health Sciences Division office at (559) 244-2604 and ask to speak to Stephanie Robinson for more information on the remediation workshops.</p>\n\n\t<h2 id=\"two\">How much will the TEAS exam cost me?</h2>\n\n\t<p>The cost of the TEAS exam at Fresno City College is approximately $45.00.  Students will be asked to pay the cost of the exam at the time of testing by using a major credit card or debit card only.  The remediation workshops offered within the Health Sciences Division are free of charge.</p>\n\n\t<h2 id=\"three\">What happens if I do not achieve a 62% on the TEAS V exam?</h2>\n\n\t<p>Students who did not achieve a 62% or higher on the TEAS V exam may participate in the TEAS Remediation Workshops offered within the Health Sciences Division at FCC.  Students interested in the remediation workshops can send an email to Stephanie Robinson, Director of Nursing.</p>\n\n\t<h2 id=\"four\">What do I need to take care of children in my home?</h2>\n\n\t<p>Family Child Care is the term used for child care that is provided in a home setting for three or more unrelated children. Family Child Care does require a license, which may be applied for through the Department of Social Services. A licensed family child care home may provide care for up to six children, including the provider's own children. Currently, family child care providers must complete 15 hours of child health and safety training. This requirement is fulfilled by Child Development 6, but may also be fulfilled by non-credit training offered through Red Cross or the American Heart Association.</p>\n\n\t<h2 id=\"five\">What education do I need to teach in a preschool center?</h2>\n\n\t<p>To become a fully qualified teacher in a privately operated child development program, Title 22 Licensing requires a minimum of 12 units of course work in Child Development and six months of experience working in a teaching capacity in an early childhood program.</p>\n\n\t<h2 id=\"six\">What Can I Expect From My First Appointment? </h2>\n\n\t<p>Your first appointment will last approximately one hour. Your therapist will discuss with you the reason(s) you are requesting psychological services. Your therapist will also ask you questions about your personal history, your social and intimate relationships, your educational goals, and your expectations for therapy. At the end of the appointment you and your therapist will decide how to best use the available resources. You may set up another appointment, or be referred to another resource, for example, an off-campus therapist, your physician, or community agency.</p>\n\n\t<h2 id=\"seven\">How do I get started at Fresno City College?</h2>\n\n\t<p>You need to apply for admission, which you can do on the Fresno City College website. Just go to the home page and click “Apply Online”. That will lead you to the application information screen. After reading the instructions, click “Begin Application for State Center Community College District” at the bottom of the page. You will be taken to a website called CCCApply, where you will apply. You will need to create a user profile before you can begin your application. If you have applied online in the past, you will need to log into the profile you created at that time.</p>\n\n\t<h2 id=\"eight\">What is the cancellation policy?</h2>\n\n\t<p>Cancellations received up to five (5) working days before the course start date are refundable, minus a $25 processing fee.  After that, cancellations are subject to the entire course fee.  Please note that if you don't cancel and don't attend, you are still responsible for payment.</p>\n\n\t<h2 id=\"nine\">What is the FAFSA?</h2>\n\n\t<p>It stands for Free Application for Federal Student Aid.  It is an application, not an award. It is used to determine eligibility for not only the Pell Grant, but also used by other financial aid providers to determine eligibility for other financial aid such as the Cal Grant, the Board of Governor’s Fee Waiver, federally funded loans and more.</p>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/5-web-components/4-html-imports/2-toc.html",
    "content": "<template>\n  <p><a></a></p>\n</template>\n\n<script>\n  var importee = document.currentScript.ownerDocument;\n  var proto = Object.create(HTMLElement.prototype);\n  var template = importee.querySelector('template').content;\n\n  proto.attachedCallback = function() {\n    var shadow = this.createShadowRoot();\n    var headers = document.querySelectorAll('h2');\n    for (var i = 0; i < headers.length; i++) {\n      var clone = template.cloneNode(true);\n      var anchor = clone.querySelector('a');\n      anchor.textContent = headers[i].textContent;\n      anchor.href = '#' + headers[i].id;\n      shadow.appendChild(clone);\n    }\n  };\n\n  document.registerElement('fcc-toc', {prototype: proto});\n</script>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/6-collapse/2-index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<link rel=\"import\" href=\"bower_components/iron-collapse/iron-collapse.html\">\n\t<link rel=\"import\" href=\"bower_components/paper-button/paper-button.html\">\n\t<style>\n\t\tpaper-button {\n\t\t\tdisplay: block;\n\t\t}\n\t</style>\n</head>\n<body>\n\t<h1>FAQ</h1>\n\n\t<paper-button onclick=\"document.querySelector('#one').toggle()\">What is the TEAS exam?</paper-button>\n\n\t<iron-collapse id=\"one\">The Test of Essential Academic Skills (TEAS) was developed to measure basic essential skills in the academic content area domains of Reading, Mathematics, Science, and English and Language Usage. These entry level skills were deemed important for nursing program applicants by a nursing program curriculum expert. Students must earn an overall score of 62% or higher to submit an application to the Registered Nursing and LVN to RN Program. Students who earn an overall score below 62% may enroll into remediation workshops within the Health Sciences Division at FCC. Students may call the Health Sciences Division office at (559) 244-2604 and ask to speak to Stephanie Robinson for more information on the remediation workshops.</iron-collapse>\n\n\t<paper-button onclick=\"document.querySelector('#two').toggle()\">How much will the TEAS exam cost me?</paper-button>\n\n\t<iron-collapse id=\"two\">The cost of the TEAS exam at Fresno City College is approximately $45.00.  Students will be asked to pay the cost of the exam at the time of testing by using a major credit card or debit card only.  The remediation workshops offered within the Health Sciences Division are free of charge.</iron-collapse>\n\n\t<paper-button onclick=\"document.querySelector('#three').toggle()\">What happens if I do not achieve a 62% on the TEAS V exam?</paper-button>\n\n\t<iron-collapse id=\"three\">Students who did not achieve a 62% or higher on the TEAS V exam may participate in the TEAS Remediation Workshops offered within the Health Sciences Division at FCC.  Students interested in the remediation workshops can send an email to Stephanie Robinson, Director of Nursing.</iron-collapse>\n\n\t<paper-button onclick=\"document.querySelector('#four').toggle()\">What do I need to take care of children in my home?</paper-button>\n\n\t<iron-collapse id=\"four\">Family Child Care is the term used for child care that is provided in a home setting for three or more unrelated children. Family Child Care does require a license, which may be applied for through the Department of Social Services. A licensed family child care home may provide care for up to six children, including the provider's own children. Currently, family child care providers must complete 15 hours of child health and safety training. This requirement is fulfilled by Child Development 6, but may also be fulfilled by non-credit training offered through Red Cross or the American Heart Association.</iron-collapse>\n\n\t<paper-button onclick=\"document.querySelector('#five').toggle()\">What education do I need to teach in a preschool center?</paper-button>\n\n\t<iron-collapse id=\"five\">To become a fully qualified teacher in a privately operated child development program, Title 22 Licensing requires a minimum of 12 units of course work in Child Development and six months of experience working in a teaching capacity in an early childhood program.</iron-collapse>\n\n\t<paper-button onclick=\"document.querySelector('#six').toggle()\">What Can I Expect From My First Appointment? </paper-button>\n\n\t<iron-collapse id=\"six\">Your first appointment will last approximately one hour. Your therapist will discuss with you the reason(s) you are requesting psychological services. Your therapist will also ask you questions about your personal history, your social and intimate relationships, your educational goals, and your expectations for therapy. At the end of the appointment you and your therapist will decide how to best use the available resources. You may set up another appointment, or be referred to another resource, for example, an off-campus therapist, your physician, or community agency.</iron-collapse>\n\n\t<paper-button onclick=\"document.querySelector('#seven').toggle()\">How do I get started at Fresno City College?</paper-button>\n\n\t<iron-collapse id=\"seven\">You need to apply for admission, which you can do on the Fresno City College website. Just go to the home page and click “Apply Online”. That will lead you to the application information screen. After reading the instructions, click “Begin Application for State Center Community College District” at the bottom of the page. You will be taken to a website called CCCApply, where you will apply. You will need to create a user profile before you can begin your application. If you have applied online in the past, you will need to log into the profile you created at that time.</iron-collapse>\n\n\t<paper-button onclick=\"document.querySelector('#eight').toggle()\">What is the cancellation policy?</paper-button>\n\n\t<iron-collapse id=\"eight\">Cancellations received up to five (5) working days before the course start date are refundable, minus a $25 processing fee.  After that, cancellations are subject to the entire course fee.  Please note that if you don't cancel and don't attend, you are still responsible for payment.</iron-collapse>\n\n\t<paper-button onclick=\"document.querySelector('#nine').toggle()\">What is the FAFSA?</paper-button>\n\n\t<iron-collapse id=\"nine\">It stands for Free Application for Federal Student Aid.  It is an application, not an award. It is used to determine eligibility for not only the Pell Grant, but also used by other financial aid providers to determine eligibility for other financial aid such as the Cal Grant, the Board of Governor’s Fee Waiver, federally funded loans and more.</iron-collapse>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/6-collapse/bower.json",
    "content": "{\n  \"name\": \"collapse\",\n  \"version\": \"0.0.0\",\n  \"authors\": [\n    \"Daniel Hoffmann <oralordos@gmail.com>\"\n  ],\n  \"license\": \"MIT\",\n  \"ignore\": [\n    \"**/.*\",\n    \"node_modules\",\n    \"bower_components\",\n    \"test\",\n    \"tests\"\n  ],\n  \"dependencies\": {\n    \"iron-collapse\": \"PolymerElements/iron-collapse#~1.0.2\",\n    \"paper-button\": \"PolymerElements/paper-button#~1.0.2\"\n  }\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/7-polymer/1-registering/1-index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <link rel=\"import\" href=\"1-polymer.html\">\n</head>\n<body>\n<my-element></my-element>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/7-polymer/1-registering/1-plain.html",
    "content": "<script>\n  var proto = Object.create(HTMLElement.prototype);\n  document.registerElement('my-element', {prototype: proto});\n</script>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/7-polymer/1-registering/1-polymer.html",
    "content": "<link rel=\"import\" href=\"../bower_components/polymer/polymer.html\">\n\n<script>\n  Polymer({\n    is: 'my-element'\n  })\n</script>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/7-polymer/2-lifecycle/1-index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Document</title>\n</head>\n<body>\n  <my-blink interval=\"1000\">Testing</my-blink>\n  <my-blink interval=300>Blah blah blah</my-blink>\n\n  <script>\n    var proto = Object.create(HTMLElement.prototype);\n\n    proto.toggleBlink = function() {\n      this.style.visibility = this.style.visibility === '' ? 'hidden' : '';\n    }\n\n    proto.attachedCallback = function() {\n      var interval = this.getAttribute('interval') || 500;\n      this.intervalId = setInterval(this.toggleBlink.bind(this), interval);\n    };\n\n    proto.detachedCallback = function() {\n      clearInterval(this.intervalId);\n      this.intervalId = undefined;\n    };\n\n    proto.attributeChangedCallback = function(attr, oldVal, newVal) {\n      clearInterval(this.intervalId);\n      var interval = newVal || 500;\n      this.intervalId = setInterval(this.toggleBlink.bind(this), interval);\n    };\n\n    document.registerElement('my-blink', {prototype: proto});\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/7-polymer/2-lifecycle/2-index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <link rel=\"import\" href=\"../bower_components/polymer/polymer.html\">\n</head>\n<body>\n  <my-blink interval=\"1000\">Testing</my-blink>\n  <my-blink interval=300>Blah blah blah</my-blink>\n\n  <script>\n    Polymer({\n      is: 'my-blink',\n\n      toggleBlink: function() {\n        this.style.visibility = this.style.visibility === '' ? 'hidden' : '';\n      },\n\n      attached: function() {\n        var interval = this.getAttribute('interval') || 500;\n        this.intervalId = setInterval(this.toggleBlink.bind(this), interval);\n      },\n\n      detached: function() {\n        clearInterval(this.intervalId);\n        this.intervalId = undefined;\n      },\n\n      attributeChangedCallback: function(attr, oldVal, newVal) {\n        clearInterval(this.intervalId);\n        var interval = newVal || 500;\n        this.intervalId = setInterval(this.toggleBlink.bind(this), interval);\n      }\n    });\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/7-polymer/2-lifecycle/2-plain.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n</head>\n<body>\n  <my-element blah=\"500\"></my-element>\n\n  <script>\n    var proto = Object.create(HTMLElement.prototype);\n\n    proto.createdCallback = function() {\n      console.log('created!');\n    };\n\n    proto.attachedCallback = function() {\n      console.log('attached!');\n    };\n\n    proto.detachedCallback = function() {\n      console.log('detached!');\n    };\n\n    proto.attributeChangedCallback = function(attr, oldVal, newVal) {\n      console.log('attribute: ', attr);\n      console.log('old value: ', oldVal);\n      console.log('new value: ', newVal);\n    };\n\n    document.registerElement('my-element', {prototype: proto});\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/7-polymer/2-lifecycle/2-polymer.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <link rel=\"import\" href=\"../bower_components/polymer/polymer.html\">\n</head>\n<body>\n  <my-element blah=\"500\"></my-element>\n\n  <script>\n    Polymer({\n      is: 'my-element',\n\n      created: function() {\n        console.log('created!');\n      },\n\n      attached: function() {\n        console.log('attached!');\n      },\n\n      detached: function() {\n        console.log('detached');\n      },\n\n      attributeChanged: function(attr, oldVal, newVal) {\n        console.log('attribute: ', attr);\n        console.log('old value: ', oldVal);\n        console.log('new value: ', newVal);\n      }\n    });\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/7-polymer/3-properties/1-index.html",
    "content": ""
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/7-polymer/3-properties/1-polymer.html",
    "content": ""
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/7-polymer/3-properties/2-index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <link rel=\"import\" href=\"2-polymer.html\">\n</head>\n<body>\n  <my-blink interval=\"1000\">Testing</my-blink>\n  <my-blink interval=\"300\">blah blah blah</my-blink>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/7-polymer/3-properties/2-polymer.html",
    "content": "<link rel=\"import\" href=\"../bower_components/polymer/polymer.html\">\n\n<script>\n  Polymer({\n    is: 'my-blink',\n\n    properties: {\n      interval: {\n        type: Number,\n        value: 500,\n        reflectToAttribute: true,\n        observer: '_changeInterval'\n      }\n    },\n\n    toggleBlink: function() {\n      this.style.visibility = this.style.visibility === '' ? 'hidden' : '';\n    },\n\n    detached: function() {\n      if (this.intervalId) {\n        clearInterval(this.intervalId);\n        this.intervalId = undefined;\n      }\n    },\n\n    _changeInterval: function(newVal) {\n      if (this.intervalId) {\n        clearInterval(this.intervalId);\n      }\n      this.intervalId = setInterval(this.toggleBlink.bind(this), newVal);\n      if (newVal === 0) {\n        this.interval = this.properties.interval.value;\n      }\n    }\n  })\n</script>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/7-polymer/4-local-dom/1-index.html",
    "content": ""
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/7-polymer/4-local-dom/1-polymer.html",
    "content": ""
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/7-polymer/4-local-dom/2-index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Diploma</title>\n  <link rel=\"import\" href=\"2-polymer.html\">\n</head>\n<body>\n  <fcc-diploma school=\"Fresno City College\" person=\"Daniel Hoffmann\" course=\"Summer Bootcamp\"></fcc-diploma>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/7-polymer/4-local-dom/2-polymer.html",
    "content": "<link rel=\"import\" href=\"../bower_components/polymer/polymer.html\">\n<link href='http://fonts.googleapis.com/css?family=Rochester' rel='stylesheet' type='text/css'>\n\n<dom-module id='fcc-diploma'>\n  <style>\n    :host {\n      box-sizing: border-box;\n      border: 20px solid maroon;\n      background-image: url(\"2-diploma-bg.jpg\");\n      display: inline-block;\n      text-align: center;\n      padding: 20px;\n    }\n\n    h1, h2, p {\n      font-family: 'Rochester', cursive;\n      color: maroon;\n      margin: 20px 10px;\n    }\n\n    h1 {\n      font-size : 60px;\n      margin-bottom: 30px;\n    }\n\n    h2 {\n      font-size: 50px;\n      margin-bottom: 0;\n      border-bottom: 3px solid maroon;\n    }\n\n    p {\n      font-size: 30px;\n    }\n  </style>\n\n  <template>\n    <h1>{{school}}</h1>\n    <p>Has conferred upon</p>\n    <h2>{{person}}</h2>\n    <p>having completed the prescribed studies and</p>\n    <p>satisfied the requirements for the</p>\n    <h2>{{course}}</h2>\n    <p>issued by the board of regents upon</p>\n    <p>recommendation of the faculty</p>\n  </template>\n</dom-module>\n\n<script>\n  Polymer({\n    is: 'fcc-diploma',\n\n    properties: {\n      school: String,\n      person: String,\n      course: String\n    }\n  });\n</script>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/7-polymer/5-data-binding/1-index.html",
    "content": ""
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/7-polymer/5-data-binding/1-polymer.html",
    "content": ""
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/7-polymer/5-data-binding/2-index.html",
    "content": ""
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/7-polymer/5-data-binding/2-polymer.html",
    "content": ""
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/8-bonus/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<link rel=\"import\" href=\"bower_components/paper-drawer-panel/paper-drawer-panel.html\">\n\t<link rel=\"import\" href=\"bower_components/paper-toolbar/paper-toolbar.html\">\n\t<link rel=\"import\" href=\"bower_components/paper-menu/paper-menu.html\">\n\t<link rel=\"import\" href=\"bower_components/iron-icons/iron-icons.html\">\n\t<link rel=\"import\" href=\"bower_components/paper-icon-button/paper-icon-button.html\">\n\t<link rel=\"import\" href=\"bower_components/iron-pages/iron-pages.html\">\n\t<link rel=\"import\" href=\"bower_components/paper-material/paper-material.html\">\n\t<link rel=\"import\" href=\"bower_components/paper-styles/paper-styles-classes.html\">\n\t<link rel=\"import\" href=\"bower_components/paper-input/paper-input.html\">\n\t<link rel=\"import\" href=\"bower_components/firebase-element/firebase-collection.html\">\n\t<link rel=\"import\" href=\"style.html\">\n</head>\n<body>\n\t<template is=\"dom-bind\" id=\"app\">\n\n    <paper-drawer-panel id=\"paperDrawerPanel\">\n      <paper-header-panel drawer mode=\"seam\">\n\n        <!-- Drawer Toolbar -->\n        <paper-toolbar id=\"drawerToolbar\">\n          <span class=\"paper-font-title\">Menu</span>\n        </paper-toolbar>\n\n        <!-- Drawer Content -->\n        <paper-menu class=\"list\">\n          <a href=\"/\">\n            <iron-icon icon=\"home\"></iron-icon>\n            <span>Home</span>\n          </a>\n\n          <a href=\"/users\">\n            <iron-icon icon=\"info\"></iron-icon>\n            <span>Users</span>\n          </a>\n\n          <a href=\"/contact\">\n            <iron-icon icon=\"mail\"></iron-icon>\n            <span>Contact</span>\n          </a>\n        </paper-menu>\n      </paper-header-panel>\n      <paper-header-panel main mode=\"waterfall-tall\">\n\n        <!-- Main Toolbar -->\n        <paper-toolbar id=\"mainToolbar\">\n          <paper-icon-button id=\"paperToggle\" icon=\"menu\" paper-drawer-toggle></paper-icon-button>\n          <span class=\"flex\"></span>\n\n          <!-- Toolbar icons -->\n          <paper-icon-button icon=\"refresh\"></paper-icon-button>\n          <paper-icon-button icon=\"search\"></paper-icon-button>\n\n          <!-- Application name -->\n          <div class=\"middle paper-font-display2 app-name\">Fresno City College Chat</div>\n\n          <!-- Application sub title -->\n          <div class=\"bottom title\"></div>\n\n        </paper-toolbar>\n\n        <!-- Main Content -->\n        <div class=\"content\">\n            <section>\n\t\t\t\t\t\t\t<firebase-collection data=\"{{messages}}\" location=\"https://polymer-chat-first.firebaseio.com/\"></firebase-collection>\n\t\t\t\t\t\t\t<template is=\"dom-repeat\" items=\"[[messages]]\" as=\"message\">\n\t\t\t\t\t\t\t\t<paper-material elevation=\"1\" class=\"layout horizontal\">\n\t              \t<img class=\"avatar\" src=\"[[message.avatar]]\" width=\"40\" height=\"40\">\n\t                <p class=\"flex\">[[message.message]]</p>\n\t              </paper-material>\n\t\t\t\t\t\t\t</template>\n            </section>\n        </div>\n      </paper-header-panel>\n    </paper-drawer-panel>\n\t\t<paper-input labal=\"Chat\"></paper-input>\n\t\t<script>\n\t\t\tvar input = document.querySelector('paper-input');\n\t\t\tvar firebase = document.querySelector('firebase-collection');\n\t\t\tinput.addEventListener('keydown', function(e) {\n\t\t\t\tif (e.keyIdentifier === 'Enter') {\n\t\t\t\t\tvar message = {avatar: 'http://heintendsvictory.org/wp-content/uploads/default-avatar.png', message: e.target.value};\n\t\t\t\t\tfirebase.add(message);\n\t\t\t\t\te.target.value = '';\n\t\t\t\t}\n\t\t\t});\n\t\t</script>\n  </template>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week6/8-bonus/style.html",
    "content": "<style is=\"custom-style\">\n\n\t:root {\n\t\t--dark-primary-color: #303F9F;\n\t\t--default-primary-color: #F44336;\n\t\t--light-primary-color: #C5CAE9;\n\t\t--text-primary-color: #ffffff;\n\t\t--accent-color: #FF4081;\n\t\t--primary-background-color: #c5cae9;\n\t\t--primary-text-color: #212121;\n\t\t--secondary-text-color: #727272;\n\t\t--disabled-text-color: #bdbdbd;\n\t\t--divider-color: #B6B6B6;\n\t\t--drawer-menu-color: #ffffff;\n\t\t--drawer-border-color: 1px solid #ccc;\n\t\t--drawer-toolbar-border-color: none;\n\t\t--paper-menu-background-color: #fff;\n\t\t--menu-link-color: #111111;\n\t}\n\n\t#drawerToolbar {\n\t\tcolor: var(--secondary-text-color);\n\t\tbackground-color: var(--drawer-menu-color);\n\t\tborder-bottom: var(--drawer-toolbar-border-color);\n\t}\n\n\tpaper-material {\n\t\tborder-radius: 2px;\n\t\theight: 100%;\n\t\tpadding: 16px 0 16px 0;\n\t\twidth: calc(98.66% - 16px);\n\t\tmargin: 16px auto;\n\t\tbackground: white;\n\t}\n\n\tpaper-menu iron-icon {\n\t\tmargin-right: 33px;\n\t\topacity: 0.54;\n\t}\n\n\t.paper-menu > .iron-selected {\n\t\tcolor: var(--default-primary-color);\n\t}\n\n\tpaper-menu a {\n\t\ttext-decoration: none;\n\t\tcolor: var(--menu-link-color);\n\t\tdisplay: -ms-flexbox;\n\t\tdisplay: -webkit-flex;\n\t\tdisplay: flex;\n\t\t-ms-flex-direction: row;\n\t\t-webkit-flex-direction: row;\n\t\tflex-direction: row;\n\t\t-ms-flex-align: center;\n\t\t-webkit-align-items: center;\n\t\talign-items: center;\n\t\tfont-family: 'Roboto', 'Noto', sans-serif;\n\t\t-webkit-font-smoothing: antialiased;\n\t\ttext-rendering: optimizeLegibility;\n\t\tfont-size: 14px;\n\t\tfont-weight: 400;\n\t\tline-height: 24px;\n\t\tmin-height: 48px;\n\t\tpadding: 0 16px;\n\t}\n\n\t#mainToolbar .middle {\n\t\tmargin-left: 48px;\n\t}\n\n\t#mainToolbar:not(.tall) .middle {\n\t\tfont-size: 20px;\n\t\tpadding-bottom: 0;\n\t\tmargin-left: 48px;\n\t}\n\n\t#mainToolbar .bottom {\n\t\ttransition: 0.18s opacity 0.18s ease-in;\n\t\topacity: 1;\n\t}\n\n\t#mainToolbar:not(.tall) .bottom {\n\t\ttransition: 0.18s opacity ease-in;\n\t\topacity: 0;\n\t}\n\n\t.content {\n\t\theight: 900px;\n\t}\n\n\t@media (max-width: 600px) {\n\n\t\tpaper-material {\n\t\t\t--menu-container-display: none;\n\t\t\twidth: calc(97.33% - 32px);\n\t\t\tpadding-left: 16px;\n\t\t\tpadding-right: 16px;\n\t\t}\n\n\t\t.paper-font-display1 {\n\t\t\tfont-size: 12px;\n\t\t}\n\n\t\t.app-name {\n\t\t\tfont-size: 26px;\n\t\t}\n\n\t\t#drawer .paper-toolbar {\n\t\t\tmargin-left: 16px;\n\t\t}\n\n\t\t#overlay {\n\t\t\tmin-width: 360px;\n\t\t}\n\n\t\t.bg {\n\t\t\tbackground: white;\n\t\t}\n\n\t}\n\n\t@media (min-width: 601px) {\n\n\t\tpaper-material {\n\t\t\twidth: calc(98% - 46px);\n\t\t\tmargin-bottom: 32px;\n\t\t\tpadding-left: 30px;\n\t\t\tpadding-right: 30px;\n\t\t}\n\n\t\t#drawer.paper-drawer-panel > [drawer] {\n\t\t\tborder-right: 1px solid rgba(0, 0, 0, 0.14);\n\t\t}\n\n\t\tiron-pages {\n\t\t\tpadding: 48px 62px;\n\t\t}\n\n\t}\n\n\t.avatar {\n\t\tmargin-right: 20px;\n\t}\n\n\tp {\n\t\tfont-family: 'Roboto', 'Noto', sans-serif;\n\t\tmargin: 0;\n\t}\n\n\tpaper-input {\n\t\tposition: fixed;\n\t\tbottom: 0;\n\t\tleft: 0;\n\t\tright: 0;\n\t\tbackground-color: white;\n\t\tborder: 1px solid black;\n\t\tpadding: 0 5px;\n\t}\n</style>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week7/Converter/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nconst (\n\tmiTokm  = 1.60934\n\tpToKg   = 0.453592\n\tdivider = \"+------------------------+\"\n)\n\nfunc main() {\n\tfmt.Println(\"Choose an option\")\n\tfmt.Println(\"1: Miles to Kilometers\")\n\tfmt.Println(\"2: Fahrenheit to Celsius\")\n\tfmt.Println(\"3: Pounds to Kilograms\")\n\tvar (\n\t\toption int\n\t\tnumber float64\n\t)\n\tfmt.Scanf(\"%d\", &option)\n\tfmt.Print(\"Enter a number: \")\n\tfmt.Scanf(\"%f\", &number)\n\n\tfmt.Println(divider)\n\tswitch option {\n\tcase 1:\n\t\tfmt.Printf(\"| Miles: %15.2f |\\n\", number)\n\t\tfmt.Println(divider)\n\t\tfmt.Printf(\"| Kilometers: %10.2f |\\n\", number*miTokm)\n\tcase 2:\n\t\tfmt.Printf(\"| Fahrenheit: %10.2f |\\n\", number)\n\t\tfmt.Println(divider)\n\t\tfmt.Printf(\"| Celsius: %13.2f |\\n\", (number-32)*5/9)\n\tcase 3:\n\t\tfmt.Printf(\"| Pounds: %14.2f |\\n\", number)\n\t\tfmt.Println(divider)\n\t\tfmt.Printf(\"| Kilograms: %11.2f |\\n\", number*pToKg)\n\t}\n\tfmt.Println(divider)\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week7/Hello/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(\"Hello World!\")\n\tfmt.Print(\"What is your name? \")\n\tvar myName string\n\tfmt.Scanf(\"%s\", &myName)\n\tfmt.Println(\"It is nice to meet you\", myName)\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week7/Loops/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfor i := 1; i <= 100; i++ {\n\t\tif i%15 == 0 {\n\t\t\tfmt.Println(\"FizzBuzz\")\n\t\t} else if i%3 == 0 {\n\t\t\tfmt.Println(\"Fizz\")\n\t\t} else if i%5 == 0 {\n\t\t\tfmt.Println(\"Buzz\")\n\t\t} else {\n\t\t\tfmt.Println(i)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week7/capitalize/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tif len(os.Args) < 2 {\n\t\tlog.Fatalln(\"Usage:\", os.Args[0], \"<file>\")\n\t}\n\n\tfile, err := os.Open(os.Args[1])\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer file.Close()\n\n\tscan := bufio.NewScanner(file)\n\tfor scan.Scan() {\n\t\ttext := scan.Text()\n\t\tfirst := text[0]\n\t\trest := text[1:]\n\t\tresult := strings.ToUpper(string(first)) + rest\n\t\tfmt.Println(result)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week7/capitalize/test.txt",
    "content": "this is a line\nline two\nanother line\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week7/distanceConverter/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nconst (\n\tkmToMi = 0.621371\n\tftToMi = 0.000189394\n\tmToMi  = 0.000621371\n\tmiToKm = 1.60934\n\tmiToFt = 5280\n\tmiToM  = 1609.34\n)\n\nfunc main() {\n\tif len(os.Args) < 3 {\n\t\tlog.Fatalln(\"Not enough arguments\")\n\t}\n\n\tfrom := os.Args[1]\n\tto := os.Args[2]\n\n\tvar (\n\t\tfromNum  float64\n\t\tfromType string\n\t\terr      error\n\t\tmiles    float64\n\t\tresult   float64\n\t)\n\n\tswitch {\n\tcase strings.HasSuffix(from, \"mi\"):\n\t\tfromNum, err = strconv.ParseFloat(from[:len(from)-2], 64)\n\t\tmiles = fromNum\n\t\tfromType = \"mi\"\n\tcase strings.HasSuffix(from, \"km\"):\n\t\tfromNum, err = strconv.ParseFloat(from[:len(from)-2], 64)\n\t\tmiles = fromNum * kmToMi\n\t\tfromType = \"km\"\n\tcase strings.HasSuffix(from, \"ft\"):\n\t\tfromNum, err = strconv.ParseFloat(from[:len(from)-2], 64)\n\t\tmiles = fromNum * ftToMi\n\t\tfromType = \"ft\"\n\tcase strings.HasSuffix(from, \"m\"):\n\t\tfromNum, err = strconv.ParseFloat(from[:len(from)-1], 64)\n\t\tmiles = fromNum * mToMi\n\t\tfromType = \"m\"\n\tdefault:\n\t\tlog.Fatalf(\"Unidentified type detected on: %s\\n\", from)\n\t}\n\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tswitch to {\n\tcase \"mi\":\n\t\tresult = miles\n\tcase \"km\":\n\t\tresult = miles * miToKm\n\tcase \"ft\":\n\t\tresult = miles * miToFt\n\tcase \"m\":\n\t\tresult = miles * miToM\n\tdefault:\n\t\tlog.Fatalf(\"Unidentified type detected on: %s\\n\", to)\n\t}\n\n\tfmt.Println(\"<!DOCTYPE html>\")\n\tfmt.Println(\"<html>\")\n\tfmt.Println(\"\\t<head></head>\")\n\tfmt.Println(\"\\t<body>\")\n\tswitch fromType {\n\tcase \"mi\":\n\t\tfmt.Printf(\"\\t\\tMiles: %.2f<br>\\n\", fromNum)\n\tcase \"km\":\n\t\tfmt.Printf(\"\\t\\tKilometers: %.2f<br>\\n\", fromNum)\n\tcase \"ft\":\n\t\tfmt.Printf(\"\\t\\tFeet: %.2f<br>\\n\", fromNum)\n\tcase \"m\":\n\t\tfmt.Printf(\"\\t\\tMeters: %.2f<br>\\n\", fromNum)\n\t}\n\tswitch to {\n\tcase \"mi\":\n\t\tfmt.Printf(\"\\t\\tMiles: %.2f<br>\\n\", result)\n\tcase \"km\":\n\t\tfmt.Printf(\"\\t\\tKilometers: %.2f<br>\\n\", result)\n\tcase \"ft\":\n\t\tfmt.Printf(\"\\t\\tFeet: %.2f<br>\\n\", result)\n\tcase \"m\":\n\t\tfmt.Printf(\"\\t\\tMeters: %.2f<br>\\n\", result)\n\t}\n\tfmt.Println(\"\\t</body>\")\n\tfmt.Println(\"</html>\")\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week7/findSmallest/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tx := []int{\n\t\t48, 96, 86, 68,\n\t\t57, 82, 63, 70,\n\t\t37, 34, 83, 27,\n\t\t19, 97, 9, 17,\n\t}\n\tsmallest := x[0]\n\tfor _, v := range x {\n\t\tif v < smallest {\n\t\t\tsmallest = v\n\t\t}\n\t}\n\tfmt.Println(smallest)\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week7/monuments/City_of_Champaign_GPS_Control_Points.csv",
    "content": "Station ID,Elevation in feet,Northing Y in feet,Easting X in feet,Link to PDF Diagram,Location\n1,806.4,1273972.11,994654.35,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/1.pdf,\"(40.16487373840, -88.29610594380)\"\n2,768.6,1274951.47,999932.47,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/2.pdf,\"(40.16755455110, -88.27721830670)\"\n3A,793,1271718,990184.96,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/3A.pdf,\"(40.15869004880, -88.31209961610)\"\n4,807.4,1271130.54,994685.52,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/4.pdf,\"(40.15707334710, -88.29599868850)\"\n5,764.6,1271025.83,1002608.65,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/5.pdf,\"(40.15677329990, -88.26765278800)\"\n6A,757.8,1273209.04,1005235.8,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/6A.pdf,\"(40.16276068470, -88.25824721050)\"\n7,736.5,1270845.11,1013130.63,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/7.pdf,\"(40.15624973680, -88.23000978540)\"\n7A,747.2,1270909.25,1005305.12,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/7A.pdf,\"(40.15644740380, -88.25800616410)\"\n8,799.3,1269031.75,994747.74,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/8.pdf,\"(40.15131190830, -88.29577926070)\"\n9A,732.1,1270815.88,1010500.12,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/9A.pdf,\"(40.15617751300, -88.23942081470)\"\n11,759,1268551.5,1002645.83,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/11.pdf,\"(40.14998096860, -88.26752632790)\"\n11A,814.8,1269793.89,993475.69,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/11A.pdf,\"(40.15340543810, -88.30032881320)\"\n12,743,1269197.4,1005246.22,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/12.pdf,\"(40.15174836190, -88.25822206280)\"\n13,739,1268215.15,1010544.51,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/13.pdf,\"(40.14903815310, -88.23927185470)\"\n13A,764.2,1268033.91,1000040.72,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/13A.pdf,\"(40.14856505790, -88.27684670400)\"\n15,764,1265692.39,997649.66,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/15.pdf,\"(40.14214122290, -88.28540452810)\"\n16,759.2,1266601.54,999969.26,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/16.pdf,\"(40.14463319400, -88.27710557290)\"\n18,733,1265712.06,989404.99,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/18.pdf,\"(40.14220366940, -88.31489460120)\"\n18A,744.6,1268158.14,989435.72,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/18A.pdf,\"(40.14891837200, -88.31478285760)\"\n19,734.1,1265572.5,1013102.91,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/19.pdf,\"(40.14177604530, -88.23013086410)\"\n19A,761.4,1265651.81,991263.18,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/19A.pdf,\"(40.14203702840, -88.30824815730)\"\n23,774.7,1263314.08,1005364.95,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/23.pdf,\"(40.13559782560, -88.25781520640)\"\n24,750.2,1265769.28,1005293.66,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/24.pdf,\"(40.14233774920, -88.25806274010)\"\n25,710.7,1260497.53,987032.07,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/25.pdf,\"(40.12789030690, -88.32338431640)\"\n26,752.7,1265528.84,1010670.29,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/26.pdf,\"(40.14166362200, -88.23883213010)\"\n26A,748.6,1264659.76,1009274.67,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/26A.pdf,\"(40.13928188230, -88.24382716700)\"\n26B,761.5,1260443.14,992318.4,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/26B.pdf,\"(40.12773783380, -88.30447982930)\"\n27,753.7,1260425.01,997294.29,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/27.pdf,\"(40.12768226480, -88.28668552660)\"\n28,759.1,1260239.07,1003944.63,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/28.pdf,\"(40.12715981970, -88.26290372480)\"\n28A,736,1263132.61,989463.28,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/28A.pdf,\"(40.13512279420, -88.31468804090)\"\n29,756.8,1260283.51,1008312.72,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/29.pdf,\"(40.12727125910, -88.24728293890)\"\n30,738.6,1260280.16,1013266.08,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/30.pdf,\"(40.12724754690, -88.22956932870)\"\n31,765.3,1257792.13,989482.57,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/31.pdf,\"(40.12046261710, -88.31462307010)\"\n32A,737.9,1263263.51,1010615.86,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/32A.pdf,\"(40.13544523700, -88.23903541400)\"\n34,707.6,1255202.77,986907.8,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/34.pdf,\"(40.11335566570, -88.32383074450)\"\n35,734.4,1255157.04,992345.26,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/35.pdf,\"(40.11322690520, -88.30438992850)\"\n36,746.2,1255094.2,997436.33,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/36.pdf,\"(40.11304842360, -88.28618768450)\"\n37,787.3,1254996.45,1004026.73,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/37.pdf,\"(40.11276810120, -88.26262503790)\"\n38,752.3,1260294.2,999928.94,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/38.pdf,\"(40.12731899990, -88.27726402920)\"\n38A,739.5,1255001.39,1008433.13,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/38A.pdf,\"(40.11277097280, -88.24687071100)\"\n39,778.3,1270990.67,999968.23,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/39.pdf,\"(40.15668175550, -88.27709932150)\"\n40,757.9,1260300.06,1005369.72,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/40.pdf,\"(40.12732403210, -88.25780730510)\"\n40A,747,1252930.13,989506.96,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/40A.pdf,\"(40.10711588130, -88.31453953230)\"\n41,738.1,1270895.25,1007907.63,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/41.pdf,\"(40.15640254130, -88.24869543520)\"\n44,742,1252766.34,1000081.69,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/44.pdf,\"(40.10665395570, -88.27673491670)\"\n45,762.1,1257735.72,994792.8,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/45.pdf,\"(40.12030314160, -88.29563520400)\"\n45B,767.5,1257755.36,1005320.69,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/45B.pdf,\"(40.12033868440, -88.25799035240)\"\n47,753.2,1265591.87,1007980.09,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/47.pdf,\"(40.14184409790, -88.24845432460)\"\n48,716.9,1249829.29,993022.46,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/48.pdf,\"(40.09860100000, -88.30197541630)\"\n48A,745.2,1255114.98,990084.35,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/48A.pdf,\"(40.11311318380, -88.31247351250)\"\n50,737,1249657.65,1003004.72,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/50.pdf,\"(40.09811467250, -88.26629344390)\"\n52,759.5,1249696.59,1013524.62,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/52.pdf,\"(40.09819369950, -88.22868930520)\"\n52A,777.4,1254908.35,1000107.01,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/52A.pdf,\"(40.11253396480, -88.27663951580)\"\n53,716.6,1247390.14,989568.2,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/53.pdf,\"(40.09190792960, -88.31432482960)\"\n54,778.5,1254914.88,1005304.35,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/54.pdf,\"(40.11254130400, -88.25805737780)\"\n55,716.5,1247087.72,994892.09,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/55.pdf,\"(40.09107306500, -88.29529645360)\"\n55A,739.4,1256325.7,1008471.68,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/55A.pdf,\"(40.11640624110, -88.24672827090)\"\n57,723.7,1247233.86,1000202.11,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/57.pdf,\"(40.09146644990, -88.27631709190)\"\n59,736.5,1247223.22,1005419.43,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/59.pdf,\"(40.09142656220, -88.25766932390)\"\n60,759.5,1249664.65,1005425.75,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/60.pdf,\"(40.09812855640, -88.25763931010)\"\n61,753.4,1247035.42,1010901.43,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/61.pdf,\"(40.09089657370, -88.23807624090)\"\n61A,727.7,1252594,997516.67,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/61A.pdf,\"(40.10618498090, -88.28590520870)\"\n62,708.4,1244596.07,987433,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/62.pdf,\"(40.08423886840, -88.32195781570)\"\n63,723.3,1244511.31,991716.07,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/63.pdf,\"(40.08400367730, -88.30665092110)\"\n63A,785.8,1252977.92,1003930.79,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/63A.pdf,\"(40.10722722480, -88.26297376420)\"\n64,736.7,1244425.49,997561.47,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/64.pdf,\"(40.08376139550, -88.28576066570)\"\n64A,771.7,1252961.44,1005949.74,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/64A.pdf,\"(40.10717737590, -88.25575599890)\"\n65,712.1,1249848.45,986993.39,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/65.pdf,\"(40.09865742580, -88.32352684030)\"\n66,722.3,1244439.51,1008390.47,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/66.pdf,\"(40.08377752440, -88.24705985830)\"\n67,704.9,1241891.26,989687.37,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/67.pdf,\"(40.07681275510, -88.31390317970)\"\n68,737.8,1244488.28,994925.83,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/68.pdf,\"(40.08393724700, -88.29517984450)\"\n69,746.8,1241852.02,994920.37,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/69.pdf,\"(40.07670039070, -88.29520339450)\"\n69A,720.8,1249767.28,997836.05,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/69A.pdf,\"(40.09842483920, -88.28476894840)\"\n70,725.1,1249628.7,1000184.51,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/70.pdf,\"(40.09804059730, -88.27637451760)\"\n70A,744,1241788.25,997730.5,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/70A.pdf,\"(40.07652159370, -88.28516168670)\"\n71,735.2,1242102.96,1000208.1,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/71.pdf,\"(40.07738149240, -88.27630743550)\"\n72,725.4,1244405.56,1000200.34,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/72.pdf,\"(40.08370242840, -88.27632989480)\"\n73,739.9,1242198.62,1005473.17,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/73.pdf,\"(40.07763330160, -88.25749255300)\"\n74,739.2,1244389.51,1002835.95,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/74.pdf,\"(40.08365335130, -88.26691078140)\"\n76,789.1,1265685.79,994733.94,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/76.pdf,\"(40.14212695210, -88.29583367910)\"\n77,780.8,1262801.45,994786.29,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/77.pdf,\"(40.13420909730, -88.29565080420)\"\n78,756.1,1260395.57,994787.59,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/78.pdf,\"(40.12760471280, -88.29564980240)\"\n79A,722.7,1247201.91,998094.5,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/79A.pdf,\"(40.09138220620, -88.28385020000)\"\n79B,719.3,1247219.96,996383.95,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/79B.pdf,\"(40.09143420600, -88.28996402960)\"\n80,720,1268348.44,984151.19,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/80.pdf,\"(40.14944224850, -88.33368680140)\"\n81,715.2,1265696.3,984143.4,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/81.pdf,\"(40.14216187400, -88.33371462750)\"\n82,711.4,1260496.2,984195.9,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/82.pdf,\"(40.12788708310, -88.33352680140)\"\n83,737.7,1246610.96,1008735.92,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/83.pdf,\"(40.08973748740, -88.24581765370)\"\n84,704.4,1252535.99,984283.87,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/84.pdf,\"(40.10603544710, -88.33321224890)\"\n85,704.8,1249882.4,984309.86,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/85.pdf,\"(40.09875103750, -88.33311935810)\"\n86,704.2,1247230.31,984332.82,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/86.pdf,\"(40.09147073630, -88.33303731700)\"\n87,703.8,1244576.17,984355.66,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/87.pdf,\"(40.08418479840, -88.33295572220)\"\n88,703.6,1241928.83,984372.72,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/88.pdf,\"(40.07691751810, -88.33289479920)\"\n89,698.8,1239285.25,984389.45,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/89.pdf,\"(40.06966055040, -88.33283506830)\"\n90,701.1,1239244.73,989681.97,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/90.pdf,\"(40.06954769300, -88.31392453870)\"\n91,718.2,1249780.6,994906.29,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/91.pdf,\"(40.09846532150, -88.29524157890)\"\n92,743.3,1249590.51,1011404.05,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/92.pdf,\"(40.09790909780, -88.23626982330)\"\n93,732.7,1244372.69,1005472.05,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/93.pdf,\"(40.08360139350, -88.25748993380)\"\n94,716.6,1244243.05,1010938.79,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/94.pdf,\"(40.08323107760, -88.23795340840)\"\n95,747,1260462.71,989478.72,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/95.pdf,\"(40.12779364030, -88.31463482830)\"\n96,732.6,1255076.11,994845.81,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/96.pdf,\"(40.11300216430, -88.29544970670)\"\n97,733.3,1260265.69,1010680.7,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/97.pdf,\"(40.12721573990, -88.23881491310)\"\n98,738.6,1257711.99,1013502.78,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/98.pdf,\"(40.12019690150, -88.22873367530)\"\n99,732.4,1256234.56,1013470.87,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/99.pdf,\"(40.11614130720, -88.22885398370)\"\n100,738.1,1249862.65,989575.18,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/100.pdf,\"(40.09869525750, -88.31429799050)\"\n101,722.6,1244556.99,989626.47,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/101.pdf,\"(40.08413055400, -88.31411874580)\"\n102,699.5,1239246.06,987004.47,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/102.pdf,\"(40.06955255180, -88.32349142580)\"\n118,706.5,1255124.03,984244.26,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/118.pdf,\"(40.11313990550, -88.33335385580)\"\n119,722.1,1257485.09,984210.6,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/119.pdf,\"(40.11962127080, -88.33347421540)\"\n121,713.6,1262872.63,984187.63,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/121.pdf,\"(40.13441062400, -88.33355639730)\"\n122,718.7,1265713.07,986863,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/122.pdf,\"(40.14220753280, -88.32398696990)\"\n123,749.1,1270926.62,1005274.77,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/123.pdf,\"(40.15649515660, -88.25811469210)\"\n124,747.3,1268272.12,1005305.25,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/124.pdf,\"(40.14920824810, -88.25801369650)\"\n125,734.4,1271447.3,1012974.17,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/125.pdf,\"(40.15790329740, -88.23056704500)\"\n126,754.2,1239200.32,996606.32,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/126.pdf,\"(40.06941899510, -88.28918345350)\"\n127,734.8,1239183.61,994965.67,http://www.ci.champaign.il.us/mapsetc/controlpoints/diags/127.pdf,\"(40.06937520960, -88.29504561970)\"\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week7/monuments/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n)\n\ntype monument struct {\n\tid        string\n\televation float64\n\tlocation  string\n}\n\ntype monumentInfo struct {\n\tcolumns   map[string]int\n\tmonuments []monument\n}\n\nfunc loadMonuments(rdr io.Reader) (*monumentInfo, error) {\n\tinfo := new(monumentInfo)\n\treader := csv.NewReader(rdr)\n\tfor i := 0; ; i++ {\n\t\trecord, err := reader.Read()\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif i == 0 {\n\t\t\tinfo.loadHeader(record)\n\t\t} else {\n\t\t\terr = info.parseRow(record)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t}\n\treturn info, nil\n}\n\nfunc (mi *monumentInfo) loadHeader(row []string) {\n\tmi.columns = make(map[string]int, len(row))\n\tfor i, v := range row {\n\t\tmi.columns[v] = i\n\t}\n}\n\nfunc (mi *monumentInfo) parseRow(row []string) error {\n\tinfo := mi.columns[\"Elevation in feet\"]\n\televation, err := strconv.ParseFloat(row[info], 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\tlocation := row[mi.columns[\"Location\"]]\n\tid := row[mi.columns[\"Station ID\"]]\n\tmi.monuments = append(mi.monuments, monument{\n\t\televation: elevation,\n\t\tlocation:  location,\n\t\tid:        id,\n\t})\n\treturn nil\n}\n\nfunc main() {\n\tfile, err := os.Open(\"City_of_Champaign_GPS_Control_Points.csv\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer file.Close()\n\n\tmonuments, err := loadMonuments(file)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tvar highest monument\n\tfor _, v := range monuments.monuments {\n\t\tif v.elevation > highest.elevation {\n\t\t\thighest = v\n\t\t}\n\t}\n\n\tlocation := highest.location[1 : len(highest.location)-1]\n\tlocation = strings.Replace(location, \" \", \"\", -1)\n\n\tfmt.Println(`<!DOCTYPE html>\n<html>\n  <body>\n    <img src=\"https://maps.googleapis.com/maps/api/staticmap?zoom=16&maptype=satellite&size=700x700&markers=` + location + `\">\n    <h1>Station ` + string(highest.id) + `</h1>\n    <h3>` + strconv.FormatFloat(highest.elevation, 'f', 2, 64) + `ft</h3>\n  </body>\n</html>`)\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week7/monuments/test.html",
    "content": "<!DOCTYPE html>\n<html>\n  <body>\n    <img src=\"https://maps.googleapis.com/maps/api/staticmap?zoom=16&maptype=satellite&size=700x700&markers=40.15340543810,-88.30032881320\">\n    <h1>Station 11A</h1>\n    <h3>814.80ft</h3>\n  </body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week7/my-cat/hello.txt",
    "content": "Hello World\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week7/my-cat/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc main() {\n\tif len(os.Args) < 2 {\n\t\tlog.Fatalln(\"Not enough command line arguments\")\n\t}\n\n\treaders := make([]io.Reader, len(os.Args)-1)\n\tfor i, v := range os.Args[1:] {\n\t\treadFile, err := os.Open(v)\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\t\tdefer readFile.Close()\n\t\treaders[i] = readFile\n\t}\n\trdr := io.MultiReader(readers...)\n\n\tio.Copy(os.Stdout, rdr)\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week7/my-md5/main.go",
    "content": "package main\n\nimport (\n\t\"crypto/md5\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sync\"\n)\n\nfunc walkPath(path string, info os.FileInfo, err error, wg *sync.WaitGroup) {\n\tif !info.IsDir() {\n\t\tf, err := os.Open(path)\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err.Error())\n\t\t}\n\t\tdefer f.Close()\n\t\thash := md5.New()\n\t\tio.Copy(hash, f)\n\t\tfmt.Printf(\"%x\\t%s\\n\", hash.Sum(nil), info.Name())\n\t}\n\twg.Done()\n}\n\nfunc main() {\n\tif len(os.Args) < 2 {\n\t\tlog.Fatalln(\"Please pass in a filename to calculate the md5 of\")\n\t}\n\n\tvar wg sync.WaitGroup\n\terr := filepath.Walk(os.Args[1], func(path string, info os.FileInfo, err error) error {\n\t\twg.Add(1)\n\t\tgo walkPath(path, info, err, &wg)\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\twg.Wait()\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week7/profileGenerator/main.go",
    "content": "package main\n\nimport (\n\t\"crypto/md5\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc getGravatarHash(email string) string {\n\temail = strings.TrimSpace(email)\n\temail = strings.ToLower(email)\n\n\th := md5.New()\n\tio.WriteString(h, email)\n\tfinalBytes := h.Sum(nil)\n\tfinalString := hex.EncodeToString(finalBytes)\n\treturn finalString\n}\n\nfunc main() {\n\temail := os.Args[1]\n\tgravatarHash := getGravatarHash(email)\n\tfmt.Println(`<!DOCTYPE html>\n<html>\n  <head></head>\n  <body>\n    <img src=\"http://www.gravatar.com/avatar/` + gravatarHash + `?d=monsterid&f=1\">\n  </body>\n</html>`)\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week7/rotate/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc swap(x, y *int) {\n\t*x, *y = *y, *x\n}\n\nfunc rotateLeft(xs ...*int) {\n\tif len(xs) == 0 {\n\t\treturn\n\t}\n\tfirst := *xs[0]\n\tfor i := 1; i < len(xs); i++ {\n\t\t*xs[i-1] = *xs[i]\n\t}\n\t*xs[len(xs)-1] = first\n}\n\nfunc rotateRight(xs ...*int) {\n\tif len(xs) == 0 {\n\t\treturn\n\t}\n\tlast := *xs[len(xs)-1]\n\tfor i := len(xs) - 1; i > 0; i-- {\n\t\t*xs[i] = *xs[i-1]\n\t}\n\t*xs[0] = last\n}\n\nfunc main() {\n\tx, y := 5, 10\n\tswap(&x, &y)\n\tfmt.Println(x, y)\n\ta, b, c, d, e := 1, 2, 3, 4, 5\n\trotateLeft(&a, &b, &c, &d, &e)\n\tfmt.Println(a, b, c, d, e)\n\ta, b, c, d, e = 1, 2, 3, 4, 5\n\trotateRight(&a, &b, &c, &d, &e)\n\tfmt.Println(a, b, c, d, e)\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week7/wordCount/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc count(r io.Reader) (map[string](int), string, int) {\n\tscanner := bufio.NewScanner(r)\n\tscanner.Split(bufio.ScanWords)\n\twords := map[string](int){}\n\tlargestWord := \"\"\n\tnumWords := 0\n\tfor scanner.Scan() {\n\t\twordsOrWord := strings.ToLower(scanner.Text())\n\t\twordsOrWord = strings.Replace(wordsOrWord, \"-\", \" \", -1)\n\t\twordsOrWord = strings.Replace(wordsOrWord, \"/\", \" \", -1)\n\t\twordsOrWord = strings.Replace(wordsOrWord, \"*\", \" \", -1)\n\t\twordsOrWord = strings.Replace(wordsOrWord, \".\", \" \", -1)\n\t\twordsOrWord = strings.Replace(wordsOrWord, \",\", \" \", -1)\n\t\twordsOrWord = strings.Replace(wordsOrWord, \"\\\"\", \" \", -1)\n\t\twordsOrWord = strings.Replace(wordsOrWord, \"'\", \" \", -1)\n\t\twordsOrWord = strings.Replace(wordsOrWord, \"!\", \" \", -1)\n\t\twordsOrWord = strings.Replace(wordsOrWord, \"?\", \" \", -1)\n\t\twordsOrWord = strings.Replace(wordsOrWord, \"_\", \" \", -1)\n\t\twordsOrWord = strings.Replace(wordsOrWord, \"=\", \" \", -1)\n\t\twordsOrWord = strings.Replace(wordsOrWord, \"+\", \" \", -1)\n\t\twordsOrWord = strings.Replace(wordsOrWord, \"&\", \" \", -1)\n\t\twordsOrWord = strings.Replace(wordsOrWord, \"%\", \" \", -1)\n\t\twordsOrWord = strings.Replace(wordsOrWord, \"^\", \" \", -1)\n\t\twordsOrWord = strings.Replace(wordsOrWord, \"(\", \" \", -1)\n\t\twordsOrWord = strings.Replace(wordsOrWord, \")\", \" \", -1)\n\t\twordsOrWord = strings.Replace(wordsOrWord, \"$\", \" \", -1)\n\t\twordsOrWord = strings.Replace(wordsOrWord, \"<\", \" \", -1)\n\t\twordsOrWord = strings.Replace(wordsOrWord, \">\", \" \", -1)\n\t\twordsOrWord = strings.Replace(wordsOrWord, \"{\", \" \", -1)\n\t\twordsOrWord = strings.Replace(wordsOrWord, \"}\", \" \", -1)\n\t\twordsOrWord = strings.Replace(wordsOrWord, \"[\", \" \", -1)\n\t\twordsOrWord = strings.Replace(wordsOrWord, \"]\", \" \", -1)\n\t\tfor _, word := range strings.Fields(wordsOrWord) {\n\t\t\tsize := len(word)\n\t\t\twords[word]++\n\t\t\tnumWords++\n\t\t\tif size > len(largestWord) {\n\t\t\t\tlargestWord = word\n\t\t\t}\n\t\t}\n\t}\n\treturn words, largestWord, numWords\n}\n\nfunc main() {\n\tmessage, _ := os.Open(\"moby10b.txt\")\n\twords, largestWord, numWords := count(message)\n\tfmt.Println(\"Number of the word \\\"the\\\":\", words[\"the\"])\n\tfmt.Println(\"Number of the word \\\"and\\\":\", words[\"and\"])\n\tfmt.Println(\"Number of the word \\\"whale\\\":\", words[\"whale\"])\n\tfmt.Println(\"Number of the word \\\"try\\\":\", words[\"try\"])\n\tfmt.Println(\"Number of the word \\\"succeed\\\":\", words[\"succeed\"])\n\tfmt.Printf(\"There are %d unique words in the document\\n\", len(words))\n\tfmt.Printf(\"There are %d total words in the document\\n\", numWords)\n\tfmt.Printf(\"The largest word is \\\"%s\\\", with a length of %d which appears %d times\\n\", largestWord, len(largestWord), words[largestWord])\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week7/wordCount/moby10b.txt",
    "content": "**The Project Gutenberg Etext of Moby Dick, by Herman Melville**\n#3 in our series by Herman Melville\n\nThis Project Gutenberg version of Moby Dick is based on a combination\nof the etext from the ERIS project at Virginia Tech and another from\nProject Gutenberg's archives, as compared to a public-domain hard copy.\n\nCopyright laws are changing all over the world, be sure to check\nthe copyright laws for your country before posting these files!!\n\nPlease take a look at the important information in this header.\nWe encourage you to keep this file on your own disk, keeping an\nelectronic path open for the next readers.  Do not remove this.\n\n\n**Welcome To The World of Free Plain Vanilla Electronic Texts**\n\n**Etexts Readable By Both Humans and By Computers, Since 1971**\n\n*These Etexts Prepared By Hundreds of Volunteers and Donations*\n\nInformation on contacting Project Gutenberg to get Etexts, and\nfurther information is included below.  We need your donations.\n\n\nTitle:  Moby Dick; or The Whale\n\nAuthor:  Herman Melville\n\nJune, 2001  [Etext #2701]\n\n**The Project Gutenberg Etext of Moby Dick, by Herman Melville**\n******This file should be named moby10b.txt or moby10b.zip******\n\nCorrected EDITIONS of our etexts get a new NUMBER, moby11b.txt\nVERSIONS based on separate sources get new LETTER, moby10c.txt\n\nThis etext was prepared by Daniel Lazarus and Jonesey\n\nProject Gutenberg Etexts are usually created from multiple editions,\nall of which are in the Public Domain in the United States, unless a\ncopyright notice is included.  Therefore, we usually do NOT keep any\nof these books in compliance with any particular paper edition.\n\n\nWe are now trying to release all our books one month in advance\nof the official release dates, leaving time for better editing.\n\nPlease note:  neither this list nor its contents are final till\nmidnight of the last day of the month of any such announcement.\nThe official release date of all Project Gutenberg Etexts is at\nMidnight, Central Time, of the last day of the stated month.  A\npreliminary version may often be posted for suggestion, comment\nand editing by those who wish to do so.  To be sure you have an\nup to date first edition [xxxxx10x.xxx] please check file sizes\nin the first week of the next month.  Since our ftp program has\na bug in it that scrambles the date [tried to fix and failed] a\nlook at the file size will have to do, but we will try to see a\nnew copy has at least one byte more or less.\n\n\nInformation about Project Gutenberg (one page)\n\nWe produce about two million dollars for each hour we work.  The\ntime it takes us, a rather conservative estimate, is fifty hours\nto get any etext selected, entered, proofread, edited, copyright\nsearched and analyzed, the copyright letters written, etc.  This\nprojected audience is one hundred million readers.  If our value\nper text is nominally estimated at one dollar then we produce $2\nmillion dollars per hour this year as we release thirty-six text\nfiles per month, or 432 more Etexts in 1999 for a total of 2000+\nIf these reach just 10% of the computerized population, then the\ntotal should reach over 200 billion Etexts given away this year.\n\nThe Goal of Project Gutenberg is to Give Away One Trillion Etext\nFiles by December 31, 2001.  [10,000 x 100,000,000 = 1 Trillion]\nThis is ten thousand titles each to one hundred million readers,\nwhich is only ~5% of the present number of computer users.\n\nAt our revised rates of production, we will reach only one-third\nof that goal by the end of 2001, or about 3,333 Etexts unless we\nmanage to get some real funding; currently our funding is mostly\nfrom Michael Hart's salary at Carnegie-Mellon University, and an\nassortment of sporadic gifts; this salary is only good for a few\nmore years, so we are looking for something to replace it, as we\ndon't want Project Gutenberg to be so dependent on one person.\n\nWe need your donations more than ever!\n\n\nAll donations should be made to \"Project Gutenberg/CMU\": and are\ntax deductible to the extent allowable by law.  (CMU = Carnegie-\nMellon University).\n\nFor these and other matters, please mail to:\n\nProject Gutenberg\nP. O. Box  2782\nChampaign, IL 61825\n\nWhen all other email fails. . .try our Executive Director:\nMichael S. Hart <hart@pobox.com>\nhart@pobox.com forwards to hart@prairienet.org and archive.org\nif your mail bounces from archive.org, I will still see it, if\nit bounces from prairienet.org, better resend later on. . . .\n\nWe would prefer to send you this information by email.\n\n******\n\nTo access Project Gutenberg etexts, use any Web browser\nto view http://promo.net/pg.  This site lists Etexts by\nauthor and by title, and includes information about how\nto get involved with Project Gutenberg.  You could also\ndownload our past Newsletters, or subscribe here.  This\nis one of our major sites, please email hart@pobox.com,\nfor a more complete list of our various sites.\n\nTo go directly to the etext collections, use FTP or any\nWeb browser to visit a Project Gutenberg mirror (mirror\nsites are available on 7 continents; mirrors are listed\nat http://promo.net/pg).\n\nMac users, do NOT point and click, typing works better.\n\nExample FTP session:\n\nftp sunsite.unc.edu\nlogin: anonymous\npassword: your@login\ncd pub/docs/books/gutenberg\ncd etext90 through etext99\ndir [to see files]\nget or mget [to get files. . .set bin for zip files]\nGET GUTINDEX.??  [to get a year's listing of books, e.g., GUTINDEX.99]\nGET GUTINDEX.ALL [to get a listing of ALL books]\n\n***\n\n**Information prepared by the Project Gutenberg legal advisor**\n\n(Three Pages)\n\n\n***START**THE SMALL PRINT!**FOR PUBLIC DOMAIN ETEXTS**START***\nWhy is this \"Small Print!\" statement here?  You know: lawyers.\nThey tell us you might sue us if there is something wrong with\nyour copy of this etext, even if you got it for free from\nsomeone other than us, and even if what's wrong is not our\nfault.  So, among other things, this \"Small Print!\" statement\ndisclaims most of our liability to you.  It also tells you how\nyou can distribute copies of this etext if you want to.\n\n*BEFORE!* YOU USE OR READ THIS ETEXT\nBy using or reading any part of this PROJECT GUTENBERG-tm\netext, you indicate that you understand, agree to and accept\nthis \"Small Print!\" statement.  If you do not, you can receive\na refund of the money (if any) you paid for this etext by\nsending a request within 30 days of receiving it to the person\nyou got it from.  If you received this etext on a physical\nmedium (such as a disk), you must return it with your request.\n\nABOUT PROJECT GUTENBERG-TM ETEXTS\nThis PROJECT GUTENBERG-tm etext, like most PROJECT GUTENBERG-\ntm etexts, is a \"public domain\" work distributed by Professor\nMichael S. Hart through the Project Gutenberg Association at\nCarnegie-Mellon University (the \"Project\").  Among other\nthings, this means that no one owns a United States copyright\non or for this work, so the Project (and you!) can copy and\ndistribute it in the United States without permission and\nwithout paying copyright royalties.  Special rules, set forth\nbelow, apply if you wish to copy and distribute this etext\nunder the Project's \"PROJECT GUTENBERG\" trademark.\n\nTo create these etexts, the Project expends considerable\nefforts to identify, transcribe and proofread public domain\nworks.  Despite these efforts, the Project's etexts and any\nmedium they may be on may contain \"Defects\".  Among other\nthings, Defects may take the form of incomplete, inaccurate or\ncorrupt data, transcription errors, a copyright or other\nintellectual property infringement, a defective or damaged\ndisk or other etext medium, a computer virus, or computer\ncodes that damage or cannot be read by your equipment.\n\nLIMITED WARRANTY; DISCLAIMER OF DAMAGES\nBut for the \"Right of Replacement or Refund\" described below,\n[1] the Project (and any other party you may receive this\netext from as a PROJECT GUTENBERG-tm etext) disclaims all\nliability to you for damages, costs and expenses, including\nlegal fees, and [2] YOU HAVE NO REMEDIES FOR NEGLIGENCE OR\nUNDER STRICT LIABILITY, OR FOR BREACH OF WARRANTY OR CONTRACT,\nINCLUDING BUT NOT LIMITED TO INDIRECT, CONSEQUENTIAL, PUNITIVE\nOR INCIDENTAL DAMAGES, EVEN IF YOU GIVE NOTICE OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\nIf you discover a Defect in this etext within 90 days of\nreceiving it, you can receive a refund of the money (if any)\nyou paid for it by sending an explanatory note within that\ntime to the person you received it from.  If you received it\non a physical medium, you must return it with your note, and\nsuch person may choose to alternatively give you a replacement\ncopy.  If you received it electronically, such person may\nchoose to alternatively give you a second opportunity to\nreceive it electronically.\n\nTHIS ETEXT IS OTHERWISE PROVIDED TO YOU \"AS-IS\".  NO OTHER\nWARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, ARE MADE TO YOU AS\nTO THE ETEXT OR ANY MEDIUM IT MAY BE ON, INCLUDING BUT NOT\nLIMITED TO WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A\nPARTICULAR PURPOSE.\n\nSome states do not allow disclaimers of implied warranties or\nthe exclusion or limitation of consequential damages, so the\nabove disclaimers and exclusions may not apply to you, and you\nmay have other legal rights.\n\nINDEMNITY\nYou will indemnify and hold the Project, its directors,\nofficers, members and agents harmless from all liability, cost\nand expense, including legal fees, that arise directly or\nindirectly from any of the following that you do or cause:\n[1] distribution of this etext, [2] alteration, modification,\nor addition to the etext, or [3] any Defect.\n\nDISTRIBUTION UNDER \"PROJECT GUTENBERG-tm\"\nYou may distribute copies of this etext electronically, or by\ndisk, book or any other medium if you either delete this\n\"Small Print!\" and all other references to Project Gutenberg,\nor:\n\n[1]  Only give exact copies of it.  Among other things, this\n     requires that you do not remove, alter or modify the\n     etext or this \"small print!\" statement.  You may however,\n     if you wish, distribute this etext in machine readable\n     binary, compressed, mark-up, or proprietary form,\n     including any form resulting from conversion by word pro-\n     cessing or hypertext software, but only so long as\n     *EITHER*:\n\n     [*]  The etext, when displayed, is clearly readable, and\n          does *not* contain characters other than those\n          intended by the author of the work, although tilde\n          (~), asterisk (*) and underline (_) characters may\n          be used to convey punctuation intended by the\n          author, and additional characters may be used to\n          indicate hypertext links; OR\n\n     [*]  The etext may be readily converted by the reader at\n          no expense into plain ASCII, EBCDIC or equivalent\n          form by the program that displays the etext (as is\n          the case, for instance, with most word processors);\n          OR\n\n     [*]  You provide, or agree to also provide on request at\n          no additional cost, fee or expense, a copy of the\n          etext in its original plain ASCII form (or in EBCDIC\n          or other equivalent proprietary form).\n\n[2]  Honor the etext refund and replacement provisions of this\n     \"Small Print!\" statement.\n\n[3]  Pay a trademark license fee to the Project of 20% of the\n     net profits you derive calculated using the method you\n     already use to calculate your applicable taxes.  If you\n     don't derive profits, no royalty is due.  Royalties are\n     payable to \"Project Gutenberg Association/Carnegie-Mellon\n     University\" within the 60 days following each\n     date you prepare (or were legally required to prepare)\n     your annual (or equivalent periodic) tax return.\n\nWHAT IF YOU *WANT* TO SEND MONEY EVEN IF YOU DON'T HAVE TO?\nThe Project gratefully accepts contributions in money, time,\nscanning machines, OCR software, public domain etexts, royalty\nfree copyright licenses, and every other sort of contribution\nyou can think of.  Money should be paid to \"Project Gutenberg\nAssociation / Carnegie-Mellon University\".\n\nWe are planning on making some changes in our donation structure\nin 2000, so you might want to email me, hart@pobox.com beforehand.\n\n\n\n\n*END THE SMALL PRINT! FOR PUBLIC DOMAIN ETEXTS*Ver.04.29.93*END*\n\n\n\n\n\nThis etext was prepared by Daniel Lazarus and Jonesey\n\n\n\n\n\nNotes on this etext of Moby Dick:\n\nThis text is a combination of etexts, one from the now-defunct ERIS\nproject at Virginia Tech and one from Project Gutenberg's archives.\nThe proofreaders of this version are indebted to The University of\nAdelaide Library for preserving the Virginia Tech version.  The\nresulting etext was compared with a public domain hard copy version of\nthe text.\n\nIn chapters 24, 89, and 90, we substituted a capital L for the symbol\nfor the British pound, a unit of currency.\n\n\n\n\n\nMOBY DICK; OR THE WHALE \n\nby Herman Melville\n\n\n\n\nETYMOLOGY.\n\n(Supplied by a Late Consumptive Usher to a Grammar School)\n\nThe pale Usher--threadbare in coat, heart, body, and brain; I see him\nnow.  He was ever dusting his old lexicons and grammars, with a queer\nhandkerchief, mockingly embellished with all the gay flags of all the\nknown nations of the world.  He loved to dust his old grammars; it\nsomehow mildly reminded him of his mortality.\n\n\"While you take in hand to school others, and to teach them by what\nname a whale-fish is to be called in our tongue leaving out, through\nignorance, the letter H, which almost alone maketh the signification\nof the word, you deliver that which is not true.\" --HACKLUYT\n\n\"WHALE. ... Sw. and Dan. HVAL.  This animal is named from roundness\nor rolling; for in Dan. HVALT is arched or vaulted.\" --WEBSTER'S\nDICTIONARY\n\n\"WHALE. ... It is more immediately from the Dut. and Ger. WALLEN;\nA.S. WALW-IAN, to roll, to wallow.\" --RICHARDSON'S DICTIONARY\n\nKETOS,               GREEK.\nCETUS,               LATIN.\nWHOEL,               ANGLO-SAXON.\nHVALT,               DANISH.\nWAL,                 DUTCH.\nHWAL,                SWEDISH.\nWHALE,               ICELANDIC.\nWHALE,               ENGLISH.\nBALEINE,             FRENCH.\nBALLENA,             SPANISH.\nPEKEE-NUEE-NUEE,     FEGEE.\nPEKEE-NUEE-NUEE,     ERROMANGOAN.\n\n\n\n\nEXTRACTS (Supplied by a Sub-Sub-Librarian).\n\nIt will be seen that this mere painstaking burrower and grub-worm of\na poor devil of a Sub-Sub appears to have gone through the long\nVaticans and street-stalls of the earth, picking up whatever random\nallusions to whales he could anyways find in any book whatsoever,\nsacred or profane.  Therefore you must not, in every case at least,\ntake the higgledy-piggledy whale statements, however authentic, in\nthese extracts, for veritable gospel cetology.  Far from it.  As\ntouching the ancient authors generally, as well as the poets here\nappearing, these extracts are solely valuable or entertaining, as\naffording a glancing bird's eye view of what has been promiscuously\nsaid, thought, fancied, and sung of Leviathan, by many nations and\ngenerations, including our own.\n\nSo fare thee well, poor devil of a Sub-Sub, whose commentator I am.\nThou belongest to that hopeless, sallow tribe which no wine of this\nworld will ever warm; and for whom even Pale Sherry would be too\nrosy-strong; but with whom one sometimes loves to sit, and feel\npoor-devilish, too; and grow convivial upon tears; and say to them\nbluntly, with full eyes and empty glasses, and in not altogether\nunpleasant sadness--Give it up, Sub-Subs!  For by how much the more\npains ye take to please the world, by so much the more shall ye for\never go thankless!  Would that I could clear out Hampton Court and\nthe Tuileries for ye!  But gulp down your tears and hie aloft to the\nroyal-mast with your hearts; for your friends who have gone before\nare clearing out the seven-storied heavens, and making refugees of\nlong-pampered Gabriel, Michael, and Raphael, against your coming.\nHere ye strike but splintered hearts together--there, ye shall strike\nunsplinterable glasses!\n\n\nEXTRACTS.\n\n\"And God created great whales.\" --GENESIS.\n\n\"Leviathan maketh a path to shine after him; One would think the deep\nto be hoary.\" --JOB.\n\n\"Now the Lord had prepared a great fish to swallow up Jonah.\"\n--JONAH.\n\n\"There go the ships; there is that Leviathan whom thou hast made to\nplay therein.\" --PSALMS.\n\n\"In that day, the Lord with his sore, and great, and strong sword,\nshall punish Leviathan the piercing serpent, even Leviathan that\ncrooked serpent; and he shall slay the dragon that is in the sea.\"\n--ISAIAH\n\n\"And what thing soever besides cometh within the chaos of this\nmonster's mouth, be it beast, boat, or stone, down it goes all\nincontinently that foul great swallow of his, and perisheth in the\nbottomless gulf of his paunch.\" --HOLLAND'S PLUTARCH'S MORALS.\n\n\"The Indian Sea breedeth the most and the biggest fishes that are:\namong which the Whales and Whirlpooles called Balaene, take up as\nmuch in length as four acres or arpens of land.\" --HOLLAND'S PLINY.\n\n\"Scarcely had we proceeded two days on the sea, when about sunrise a\ngreat many Whales and other monsters of the sea, appeared.  Among the\nformer, one was of a most monstrous size. ...  This came towards us,\nopen-mouthed, raising the waves on all sides, and beating the sea\nbefore him into a foam.\" --TOOKE'S LUCIAN.  \"THE TRUE HISTORY.\"\n\n\"He visited this country also with a view of catching horse-whales,\nwhich had bones of very great value for their teeth, of which he\nbrought some to the king. ...  The best whales were catched in his\nown country, of which some were forty-eight, some fifty yards long.\nHe said that he was one of six who had killed sixty in two days.\"\n--OTHER OR OCTHER'S VERBAL NARRATIVE TAKEN DOWN FROM HIS MOUTH BY\nKING ALFRED, A.D. 890.\n\n\"And whereas all the other things, whether beast or vessel, that\nenter into the dreadful gulf of this monster's (whale's) mouth, are\nimmediately lost and swallowed up, the sea-gudgeon retires into it in\ngreat security, and there sleeps.\" --MONTAIGNE.  --APOLOGY FOR\nRAIMOND SEBOND.\n\n\"Let us fly, let us fly!  Old Nick take me if is not Leviathan\ndescribed by the noble prophet Moses in the life of patient Job.\"\n--RABELAIS.\n\n\"This whale's liver was two cartloads.\" --STOWE'S ANNALS.\n\n\"The great Leviathan that maketh the seas to seethe like boiling\npan.\" --LORD BACON'S VERSION OF THE PSALMS.\n\n\"Touching that monstrous bulk of the whale or ork we have received\nnothing certain.  They grow exceeding fat, insomuch that an\nincredible quantity of oil will be extracted out of one whale.\"\n--IBID.  \"HISTORY OF LIFE AND DEATH.\"\n\n\"The sovereignest thing on earth is parmacetti for an inward bruise.\"\n--KING HENRY.\n\n\"Very like a whale.\" --HAMLET.\n\n\"Which to secure, no skill of leach's art\nMote him availle, but to returne againe\nTo his wound's worker, that with lowly dart,\nDinting his breast, had bred his restless paine,\nLike as the wounded whale to shore flies thro' the maine.\"\n--THE FAERIE QUEEN.\n\n\"Immense as whales, the motion of whose vast bodies can in a peaceful\ncalm trouble the ocean til it boil.\" --SIR WILLIAM DAVENANT.  PREFACE\nTO GONDIBERT.\n\n\"What spermacetti is, men might justly doubt, since the learned\nHosmannus in his work of thirty years, saith plainly, Nescio quid\nsit.\" --SIR T. BROWNE.  OF SPERMA CETI AND THE SPERMA CETI WHALE.\nVIDE HIS V. E.\n\n\"Like Spencer's Talus with his modern flail\nHe threatens ruin with his ponderous tail.\n...\nTheir fixed jav'lins in his side he wears,\nAnd on his back a grove of pikes appears.\" --WALLER'S BATTLE OF THE\nSUMMER ISLANDS.\n\n\"By art is created that great Leviathan, called a Commonwealth or\nState--(in Latin, Civitas) which is but an artificial man.\" --OPENING\nSENTENCE OF HOBBES'S LEVIATHAN.\n\n\"Silly Mansoul swallowed it without chewing, as if it had been a\nsprat in the mouth of a whale.\" --PILGRIM'S PROGRESS.\n\n\"That sea beast\nLeviathan, which God of all his works\nCreated hugest that swim the ocean stream.\" --PARADISE LOST.\n\n---\"There Leviathan,\nHugest of living creatures, in the deep\nStretched like a promontory sleeps or swims,\nAnd seems a moving land; and at his gills\nDraws in, and at his breath spouts out a sea.\" --IBID.\n\n\"The mighty whales which swim in a sea of water, and have a sea of\noil swimming in them.\" --FULLLER'S PROFANE AND HOLY STATE.\n\n\"So close behind some promontory lie\nThe huge Leviathan to attend their prey,\nAnd give no chance, but swallow in the fry,\nWhich through their gaping jaws mistake the way.\"\n--DRYDEN'S ANNUS MIRABILIS.\n\n\"While the whale is floating at the stern of the ship, they cut off\nhis head, and tow it with a boat as near the shore as it will come;\nbut it will be aground in twelve or thirteen feet water.\" --THOMAS\nEDGE'S TEN VOYAGES TO SPITZBERGEN, IN PURCHAS.\n\n\"In their way they saw many whales sporting in the ocean, and in\nwantonness fuzzing up the water through their pipes and vents, which\nnature has placed on their shoulders.\" --SIR T. HERBERT'S VOYAGES\nINTO ASIA AND AFRICA.  HARRIS COLL.\n\n\"Here they saw such huge troops of whales, that they were forced to\nproceed with a great deal of caution for fear they should run their\nship upon them.\" --SCHOUTEN'S SIXTH CIRCUMNAVIGATION.\n\n\"We set sail from the Elbe, wind N.E. in the ship called The\nJonas-in-the-Whale. ...  Some say the whale can't open his mouth, but\nthat is a fable. ...  They frequently climb up the masts to see\nwhether they can see a whale, for the first discoverer has a ducat\nfor his pains. ...  I was told of a whale taken near Shetland, that\nhad above a barrel of herrings in his belly. ...  One of our\nharpooneers told me that he caught once a whale in Spitzbergen that\nwas white all over.\" --A VOYAGE TO GREENLAND, A.D. 1671 HARRIS COLL.\n\n\"Several whales have come in upon this coast (Fife) Anno 1652, one\neighty feet in length of the whale-bone kind came in, which (as I was\ninformed), besides a vast quantity of oil, did afford 500 weight of\nbaleen.  The jaws of it stand for a gate in the garden of Pitferren.\"\n--SIBBALD'S FIFE AND KINROSS.\n\n\"Myself have agreed to try whether I can master and kill this\nSperma-ceti whale, for I could never hear of any of that sort that\nwas killed by any man, such is his fierceness and swiftness.\"\n--RICHARD STRAFFORD'S LETTER FROM THE BERMUDAS.  PHIL. TRANS.  A.D.\n1668.\n\n\"Whales in the sea God's voice obey.\" --N. E. PRIMER.\n\n\"We saw also abundance of large whales, there being more in those\nsouthern seas, as I may say, by a hundred to one; than we have to the\nnorthward of us.\" --CAPTAIN COWLEY'S VOYAGE ROUND THE GLOBE, A.D.\n1729.\n\n\"... and the breath of the whale is frequendy attended with such an\ninsupportable smell, as to bring on a disorder of the brain.\"\n--ULLOA'S SOUTH AMERICA.\n\n\"To fifty chosen sylphs of special note,\nWe trust the important charge, the petticoat.\nOft have we known that seven-fold fence to fail,\nTho' stuffed with hoops and armed with ribs of whale.\" --RAPE\nOF THE LOCK.\n\n\"If we compare land animals in respect to magnitude, with those that\ntake up their abode in the deep, we shall find they will appear\ncontemptible in the comparison.  The whale is doubtless the largest\nanimal in creation.\" --GOLDSMITH, NAT. HIST.\n\n\"If you should write a fable for little fishes, you would make them\nspeak like great wales.\" --GOLDSMITH TO JOHNSON.\n\n\"In the afternoon we saw what was supposed to be a rock, but it was\nfound to be a dead whale, which some Asiatics had killed, and were\nthen towing ashore.  They seemed to endeavor to conceal themselves\nbehind the whale, in order to avoid being seen by us.\" --COOK'S\nVOYAGES.\n\n\"The larger whales, they seldom venture to attack.  They stand in so\ngreat dread of some of them, that when out at sea they are afraid to\nmention even their names, and carry dung, lime-stone, juniper-wood,\nand some other articles of the same nature in their boats, in order\nto terrify and prevent their too near approach.\" --UNO VON TROIL'S\nLETTERS ON BANKS'S AND SOLANDER'S VOYAGE TO ICELAND IN 1772.\n\n\"The Spermacetti Whale found by the Nantuckois, is an active, fierce\nanimal, and requires vast address and boldness in the fishermen.\"\n--THOMAS JEFFERSON'S WHALE MEMORIAL TO THE FRENCH MINISTER IN 1778.\n\n\"And pray, sir, what in the world is equal to it?\" --EDMUND BURKE'S\nREFERENCE IN PARLIAMENT TO THE NANTUCKET WHALE-FISHERY.\n\n\"Spain--a great whale stranded on the shores of Europe.\" --EDMUND\nBURKE. (SOMEWHERE.)\n\n\"A tenth branch of the king's ordinary revenue, said to be grounded\non the consideration of his guarding and protecting the seas from\npirates and robbers, is the right to royal fish, which are whale and\nsturgeon.  And these, when either thrown ashore or caught near the\ncoast, are the property of the king.\" --BLACKSTONE.\n\n\"Soon to the sport of death the crews repair:\nRodmond unerring o'er his head suspends\nThe barbed steel, and every turn attends.\"\n--FALCONER'S SHIPWRECK.\n\n\"Bright shone the roofs, the domes, the spires,\nAnd rockets blew self driven,\nTo hang their momentary fire\nAround the vault of heaven.\n\n\"So fire with water to compare,\nThe ocean serves on high,\nUp-spouted by a whale in air,\nTo express unwieldy joy.\" --COWPER, ON THE QUEEN'S\nVISIT TO LONDON.\n\n\"Ten or fifteen gallons of blood are thrown out of the heart at a\nstroke, with immense velocity.\" --JOHN HUNTER'S ACCOUNT OF THE\nDISSECTION OF A WHALE.  (A SMALL SIZED ONE.)\n\n\"The aorta of a whale is larger in the bore than the main pipe of the\nwater-works at London Bridge, and the water roaring in its passage\nthrough that pipe is inferior in impetus and velocity to the blood\ngushing from the whale's heart.\" --PALEY'S THEOLOGY.\n\n\"The whale is a mammiferous animal without hind feet.\" --BARON\nCUVIER.\n\n\"In 40 degrees south, we saw Spermacetti Whales, but did not take any\ntill the first of May, the sea being then covered with them.\"\n--COLNETT'S VOYAGE FOR THE PURPOSE OF EXTENDING THE SPERMACETI WHALE\nFISHERY.\n\n\"In the free element beneath me swam,\nFloundered and dived, in play, in chace, in battle,\nFishes of every colour, form, and kind;\nWhich language cannot paint, and mariner\nHad never seen; from dread Leviathan\nTo insect millions peopling every wave:\nGather'd in shoals immense, like floating islands,\nLed by mysterious instincts through that waste\nAnd trackless region, though on every side\nAssaulted by voracious enemies,\nWhales, sharks, and monsters, arm'd in front or jaw,\nWith swords, saws, spiral horns, or hooked fangs.\"\n--MONTGOMERY'S WORLD BEFORE THE FLOOD.\n\n\"Io!  Paean!  Io! sing.\nTo the finny people's king.\nNot a mightier whale than this\nIn the vast Atlantic is;\nNot a fatter fish than he,\nFlounders round the Polar Sea.\" --CHARLES LAMB'S TRIUMPH OF THE\nWHALE.\n\n\"In the year 1690 some persons were on a high hill observing the\nwhales spouting and sporting with each other, when one observed:\nthere--pointing to the sea--is a green pasture where our children's\ngrand-children will go for bread.\" --OBED MACY'S HISTORY OF\nNANTUCKET.\n\n\"I built a cottage for Susan and myself and made a gateway in the\nform of a Gothic Arch, by setting up a whale's jaw bones.\"\n--HAWTHORNE'S TWICE TOLD TALES.\n\n\"She came to bespeak a monument for her first love, who had been\nkilled by a whale in the Pacific ocean, no less than forty years\nago.\" --IBID.\n\n\"No, Sir, 'tis a Right Whale,\" answered Tom; \"I saw his sprout; he\nthrew up a pair of as pretty rainbows as a Christian would wish to\nlook at.  He's a raal oil-butt, that fellow!\" --COOPER'S PILOT.\n\n\"The papers were brought in, and we saw in the Berlin Gazette that\nwhales had been introduced on the stage there.\" --ECKERMANN'S\nCONVERSATIONS WITH GOETHE.\n\n\"My God!  Mr. Chace, what is the matter?\"  I answered, \"we have been\nstove by a whale.\" --\"NARRATIVE OF THE SHIPWRECK OF THE WHALE SHIP\nESSEX OF NANTUCKET, WHICH WAS ATTACKED AND FINALLY DESTROYED BY A\nLARGE SPERM WHALE IN THE PACIFIC OCEAN.\"  BY OWEN CHACE OF NANTUCKET,\nFIRST MATE OF SAID VESSEL.  NEW YORK, 1821.\n\n\"A mariner sat in the shrouds one night,\nThe wind was piping free;\nNow bright, now dimmed, was the moonlight pale,\nAnd the phospher gleamed in the wake of the whale,\nAs it floundered in the sea.\" --ELIZABETH OAKES SMITH.\n\n\"The quantity of line withdrawn from the boats engaged in the capture\nof this one whale, amounted altogether to 10,440 yards or nearly six\nEnglish miles. ...\n\n\"Sometimes the whale shakes its tremendous tail in the air, which,\ncracking like a whip, resounds to the distance of three or four\nmiles.\" --SCORESBY.\n\n\"Mad with the agonies he endures from these fresh attacks, the\ninfuriated Sperm Whale rolls over and over; he rears his enormous\nhead, and with wide expanded jaws snaps at everything around him; he\nrushes at the boats with his head; they are propelled before him with\nvast swiftness, and sometimes utterly destroyed. ...  It is a matter\nof great astonishment that the consideration of the habits of so\ninteresting, and, in a commercial point of view, so important an\nanimal (as the Sperm Whale) should have been so entirely neglected,\nor should have excited so little curiosity among the numerous, and\nmany of them competent observers, that of late years, must have\npossessed the most abundant and the most convenient opportunities of\nwitnessing their habitudes.\" --THOMAS BEALE'S HISTORY OF THE SPERM\nWHALE, 1839.\n\n\"The Cachalot\" (Sperm Whale) \"is not only better armed than the True\nWhale\" (Greenland or Right Whale) \"in possessing a formidable weapon\nat either extremity of its body, but also more frequently displays a\ndisposition to employ these weapons offensively and in manner at once\nso artful, bold, and mischievous, as to lead to its being regarded as\nthe most dangerous to attack of all the known species of the whale\ntribe.\" --FREDERICK DEBELL BENNETT'S WHALING VOYAGE ROUND THE GLOBE,\n1840.\n\nOctober 13.  \"There she blows,\" was sung out from the mast-head.\n\"Where away?\" demanded the captain.\n\"Three points off the lee bow, sir.\"\n\"Raise up your wheel.  Steady!\"  \"Steady, sir.\"\n\"Mast-head ahoy!  Do you see that whale now?\"\n\"Ay ay, sir!  A shoal of Sperm Whales!  There she blows!  There she\nbreaches!\"\n\"Sing out! sing out every time!\"\n\"Ay Ay, sir!  There she blows! there--there--THAR she\nblows--bowes--bo-o-os!\"\n\"How far off?\"\n\"Two miles and a half.\"\n\"Thunder and lightning! so near!  Call all hands.\" --J. ROSS BROWNE'S\nETCHINGS OF A WHALING CRUIZE.  1846.\n\n\"The Whale-ship Globe, on board of which vessel occurred the horrid\ntransactions we are about to relate, belonged to the island of\nNantucket.\" --\"NARRATIVE OF THE GLOBE,\" BY LAY AND HUSSEY SURVIVORS.\nA.D. 1828.\n\nBeing once pursued by a whale which he had wounded, he parried the\nassault for some time with a lance; but the furious monster at length\nrushed on the boat; himself and comrades only being preserved by\nleaping into the water when they saw the onset was inevitable.\"\n--MISSIONARY JOURNAL OF TYERMAN AND BENNETT.\n\n\"Nantucket itself,\" said Mr. Webster, \"is a very striking and\npeculiar portion of the National interest.  There is a population of\neight or nine thousand persons living here in the sea, adding largely\nevery year to the National wealth by the boldest and most persevering\nindustry.\" --REPORT OF DANIEL WEBSTER'S SPEECH IN THE U.  S.  SENATE,\nON THE APPLICATION FOR THE ERECTION OF A BREAKWATER AT NANTUCKET.\n1828.\n\n\"The whale fell directly over him, and probably killed him in a\nmoment.\" --\"THE WHALE AND HIS CAPTORS, OR THE WHALEMAN'S ADVENTURES\nAND THE WHALE'S BIOGRAPHY, GATHERED ON THE HOMEWARD CRUISE OF THE\nCOMMODORE PREBLE.\"  BY REV. HENRY T. CHEEVER.\n\n\"If you make the least damn bit of noise,\" replied Samuel, \"I will\nsend you to hell.\" --LIFE OF SAMUEL COMSTOCK (THE MUTINEER), BY HIS\nBROTHER, WILLIAM COMSTOCK.  ANOTHER VERSION OF THE WHALE-SHIP GLOBE\nNARRATIVE.\n\n\"The voyages of the Dutch and English to the Northern Ocean, in\norder, if possible, to discover a passage through it to India, though\nthey failed of their main object, laid-open the haunts of the whale.\"\n--MCCULLOCH'S COMMERCIAL DICTIONARY.\n\n\"These things are reciprocal; the ball rebounds, only to bound\nforward again; for now in laying open the haunts of the whale, the\nwhalemen seem to have indirectly hit upon new clews to that same\nmystic North-West Passage.\" --FROM \"SOMETHING\" UNPUBLISHED.\n\n\"It is impossible to meet a whale-ship on the ocean without being\nstruck by her near appearance.  The vessel under short sail, with\nlook-outs at the mast-heads, eagerly scanning the wide expanse around\nthem, has a totally different air from those engaged in regular\nvoyage.\" --CURRENTS AND WHALING.  U.S. EX. EX.\n\n\"Pedestrians in the vicinity of London and elsewhere may recollect\nhaving seen large curved bones set upright in the earth, either to\nform arches over gateways, or entrances to alcoves, and they may\nperhaps have been told that these were the ribs of whales.\" --TALES\nOF A WHALE VOYAGER TO THE ARCTIC OCEAN.\n\n\"It was not till the boats returned from the pursuit of these whales,\nthat the whites saw their ship in bloody possession of the savages\nenrolled among the crew.\" --NEWSPAPER ACCOUNT OF THE TAKING AND\nRETAKING OF THE WHALE-SHIP HOBOMACK.\n\n\"It is generally well known that out of the crews of Whaling vessels\n(American) few ever return in the ships on board of which they\ndeparted.\" --CRUISE IN A WHALE BOAT.\n\n\"Suddenly a mighty mass emerged from the water, and shot up\nperpendicularly into the air.  It was the while.\" --MIRIAM COFFIN OR\nTHE WHALE FISHERMAN.\n\n\"The Whale is harpooned to be sure; but bethink you, how you would\nmanage a powerful unbroken colt, with the mere appliance of a rope\ntied to the root of his tail.\" --A CHAPTER ON WHALING IN RIBS AND\nTRUCKS.\n\n\"On one occasion I saw two of these monsters (whales) probably male\nand female, slowly swimming, one after the other, within less than a\nstone's throw of the shore\" (Terra Del Fuego), \"over which the beech\ntree extended its branches.\" --DARWIN'S VOYAGE OF A NATURALIST.\n\n\"'Stern all!' exclaimed the mate, as upon turning his head, he saw\nthe distended jaws of a large Sperm Whale close to the head of the\nboat, threatening it with instant destruction;--'Stern all, for your\nlives!'\" --WHARTON THE WHALE KILLER.\n\n\"So be cheery, my lads, let your hearts never fail,\nWhile the bold harpooneer is striking the whale!\" --NANTUCKET SONG.\n\n\"Oh, the rare old Whale, mid storm and gale\nIn his ocean home will be\nA giant in might, where might is right,\nAnd King of the boundless sea.\" --WHALE SONG.\n\n\n\nCHAPTER 1\n\nLoomings.\n\n\nCall me Ishmael.  Some years ago--never mind how long\nprecisely--having little or no money in my purse, and nothing\nparticular to interest me on shore, I thought I would sail about a\nlittle and see the watery part of the world.  It is a way I have of\ndriving off the spleen and regulating the circulation.  Whenever I\nfind myself growing grim about the mouth; whenever it is a damp,\ndrizzly November in my soul; whenever I find myself involuntarily\npausing before coffin warehouses, and bringing up the rear of every\nfuneral I meet; and especially whenever my hypos get such an upper\nhand of me, that it requires a strong moral principle to prevent me\nfrom deliberately stepping into the street, and methodically knocking\npeople's hats off--then, I account it high time to get to sea as soon\nas I can.  This is my substitute for pistol and ball.  With a\nphilosophical flourish Cato throws himself upon his sword; I quietly\ntake to the ship.  There is nothing surprising in this.  If they but\nknew it, almost all men in their degree, some time or other, cherish\nvery nearly the same feelings towards the ocean with me.\n\nThere now is your insular city of the Manhattoes, belted round by\nwharves as Indian isles by coral reefs--commerce surrounds it with\nher surf.  Right and left, the streets take you waterward.  Its\nextreme downtown is the battery, where that noble mole is washed by\nwaves, and cooled by breezes, which a few hours previous were out of\nsight of land.  Look at the crowds of water-gazers there.\n\nCircumambulate the city of a dreamy Sabbath afternoon.  Go from\nCorlears Hook to Coenties Slip, and from thence, by Whitehall,\nnorthward.  What do you see?--Posted like silent sentinels all around\nthe town, stand thousands upon thousands of mortal men fixed in ocean\nreveries.  Some leaning against the spiles; some seated upon the\npier-heads; some looking over the bulwarks of ships from China; some\nhigh aloft in the rigging, as if striving to get a still better\nseaward peep.  But these are all landsmen; of week days pent up in\nlath and plaster--tied to counters, nailed to benches, clinched to\ndesks.  How then is this?  Are the green fields gone?  What do they\nhere?\n\nBut look! here come more crowds, pacing straight for the water, and\nseemingly bound for a dive.  Strange!  Nothing will content them but\nthe extremest limit of the land; loitering under the shady lee of\nyonder warehouses will not suffice.  No.  They must get just as nigh\nthe water as they possibly can without falling in.  And there they\nstand--miles of them--leagues.  Inlanders all, they come from lanes\nand alleys, streets and avenues--north, east, south, and west.  Yet\nhere they all unite.  Tell me, does the magnetic virtue of the\nneedles of the compasses of all those ships attract them thither?\n\nOnce more.  Say you are in the country; in some high land of lakes.\nTake almost any path you please, and ten to one it carries you down\nin a dale, and leaves you there by a pool in the stream.  There is\nmagic in it.  Let the most absent-minded of men be plunged in his\ndeepest reveries--stand that man on his legs, set his feet a-going,\nand he will infallibly lead you to water, if water there be in all\nthat region.  Should you ever be athirst in the great American\ndesert, try this experiment, if your caravan happen to be supplied\nwith a metaphysical professor.  Yes, as every one knows, meditation\nand water are wedded for ever.\n\nBut here is an artist.  He desires to paint you the dreamiest,\nshadiest, quietest, most enchanting bit of romantic landscape in all\nthe valley of the Saco.  What is the chief element he employs?  There\nstand his trees, each with a hollow trunk, as if a hermit and a\ncrucifix were within; and here sleeps his meadow, and there sleep his\ncattle; and up from yonder cottage goes a sleepy smoke.  Deep into\ndistant woodlands winds a mazy way, reaching to overlapping spurs of\nmountains bathed in their hill-side blue.  But though the picture\nlies thus tranced, and though this pine-tree shakes down its sighs\nlike leaves upon this shepherd's head, yet all were vain, unless the\nshepherd's eye were fixed upon the magic stream before him.  Go visit\nthe Prairies in June, when for scores on scores of miles you wade\nknee-deep among Tiger-lilies--what is the one charm\nwanting?--Water--there is not a drop of water there!  Were Niagara\nbut a cataract of sand, would you travel your thousand miles to see\nit?  Why did the poor poet of Tennessee, upon suddenly receiving two\nhandfuls of silver, deliberate whether to buy him a coat, which he\nsadly needed, or invest his money in a pedestrian trip to Rockaway\nBeach?  Why is almost every robust healthy boy with a robust healthy\nsoul in him, at some time or other crazy to go to sea?  Why upon your\nfirst voyage as a passenger, did you yourself feel such a mystical\nvibration, when first told that you and your ship were now out of\nsight of land?  Why did the old Persians hold the sea holy?  Why did\nthe Greeks give it a separate deity, and own brother of Jove?  Surely\nall this is not without meaning.  And still deeper the meaning of\nthat story of Narcissus, who because he could not grasp the\ntormenting, mild image he saw in the fountain, plunged into it and\nwas drowned.  But that same image, we ourselves see in all rivers and\noceans.  It is the image of the ungraspable phantom of life; and this\nis the key to it all.\n\nNow, when I say that I am in the habit of going to sea whenever I\nbegin to grow hazy about the eyes, and begin to be over conscious of\nmy lungs, I do not mean to have it inferred that I ever go to sea as\na passenger.  For to go as a passenger you must needs have a purse,\nand a purse is but a rag unless you have something in it.  Besides,\npassengers get sea-sick--grow quarrelsome--don't sleep of nights--do\nnot enjoy themselves much, as a general thing;--no, I never go as a\npassenger; nor, though I am something of a salt, do I ever go to sea\nas a Commodore, or a Captain, or a Cook.  I abandon the glory and\ndistinction of such offices to those who like them.  For my part, I\nabominate all honourable respectable toils, trials, and tribulations\nof every kind whatsoever.  It is quite as much as I can do to take\ncare of myself, without taking care of ships, barques, brigs,\nschooners, and what not.  And as for going as cook,--though I confess\nthere is considerable glory in that, a cook being a sort of officer\non ship-board--yet, somehow, I never fancied broiling fowls;--though\nonce broiled, judiciously buttered, and judgmatically salted and\npeppered, there is no one who will speak more respectfully, not to\nsay reverentially, of a broiled fowl than I will.  It is out of the\nidolatrous dotings of the old Egyptians upon broiled ibis and roasted\nriver horse, that you see the mummies of those creatures in their\nhuge bake-houses the pyramids.\n\nNo, when I go to sea, I go as a simple sailor, right before the mast,\nplumb down into the forecastle, aloft there to the royal mast-head.\nTrue, they rather order me about some, and make me jump from spar to\nspar, like a grasshopper in a May meadow.  And at first, this sort of\nthing is unpleasant enough.  It touches one's sense of honour,\nparticularly if you come of an old established family in the land,\nthe Van Rensselaers, or Randolphs, or Hardicanutes.  And more than\nall, if just previous to putting your hand into the tar-pot, you have\nbeen lording it as a country schoolmaster, making the tallest boys\nstand in awe of you.  The transition is a keen one, I assure you,\nfrom a schoolmaster to a sailor, and requires a strong decoction of\nSeneca and the Stoics to enable you to grin and bear it.  But even\nthis wears off in time.\n\nWhat of it, if some old hunks of a sea-captain orders me to get a\nbroom and sweep down the decks?  What does that indignity amount to,\nweighed, I mean, in the scales of the New Testament?  Do you think\nthe archangel Gabriel thinks anything the less of me, because I\npromptly and respectfully obey that old hunks in that particular\ninstance?  Who ain't a slave?  Tell me that.  Well, then, however the\nold sea-captains may order me about--however they may thump and punch\nme about, I have the satisfaction of knowing that it is all right;\nthat everybody else is one way or other served in much the same\nway--either in a physical or metaphysical point of view, that is; and\nso the universal thump is passed round, and all hands should rub each\nother's shoulder-blades, and be content.\n\nAgain, I always go to sea as a sailor, because they make a point of\npaying me for my trouble, whereas they never pay passengers a single\npenny that I ever heard of.  On the contrary, passengers themselves\nmust pay.  And there is all the difference in the world between\npaying and being paid.  The act of paying is perhaps the most\nuncomfortable infliction that the two orchard thieves entailed upon\nus.  But BEING PAID,--what will compare with it?  The urbane activity\nwith which a man receives money is really marvellous, considering\nthat we so earnestly believe money to be the root of all earthly\nills, and that on no account can a monied man enter heaven.  Ah! how\ncheerfully we consign ourselves to perdition!\n\nFinally, I always go to sea as a sailor, because of the wholesome\nexercise and pure air of the fore-castle deck.  For as in this world,\nhead winds are far more prevalent than winds from astern (that is, if\nyou never violate the Pythagorean maxim), so for the most part the\nCommodore on the quarter-deck gets his atmosphere at second hand from\nthe sailors on the forecastle.  He thinks he breathes it first; but\nnot so.  In much the same way do the commonalty lead their leaders in\nmany other things, at the same time that the leaders little suspect\nit.  But wherefore it was that after having repeatedly smelt the sea\nas a merchant sailor, I should now take it into my head to go on a\nwhaling voyage; this the invisible police officer of the Fates, who\nhas the constant surveillance of me, and secretly dogs me, and\ninfluences me in some unaccountable way--he can better answer than\nany one else.  And, doubtless, my going on this whaling voyage,\nformed part of the grand programme of Providence that was drawn up a\nlong time ago.  It came in as a sort of brief interlude and solo\nbetween more extensive performances.  I take it that this part of the\nbill must have run something like this:\n\n\n\"GRAND CONTESTED ELECTION FOR THE PRESIDENCY OF THE UNITED STATES.\n\"WHALING VOYAGE BY ONE ISHMAEL.\n\"BLOODY BATTLE IN AFFGHANISTAN.\"\n\n\nThough I cannot tell why it was exactly that those stage managers,\nthe Fates, put me down for this shabby part of a whaling voyage, when\nothers were set down for magnificent parts in high tragedies, and\nshort and easy parts in genteel comedies, and jolly parts in\nfarces--though I cannot tell why this was exactly; yet, now that I\nrecall all the circumstances, I think I can see a little into the\nsprings and motives which being cunningly presented to me under\nvarious disguises, induced me to set about performing the part I did,\nbesides cajoling me into the delusion that it was a choice resulting\nfrom my own unbiased freewill and discriminating judgment.\n\nChief among these motives was the overwhelming idea of the great\nwhale himself.  Such a portentous and mysterious monster roused all\nmy curiosity.  Then the wild and distant seas where he rolled his\nisland bulk; the undeliverable, nameless perils of the whale; these,\nwith all the attending marvels of a thousand Patagonian sights and\nsounds, helped to sway me to my wish.  With other men, perhaps, such\nthings would not have been inducements; but as for me, I am tormented\nwith an everlasting itch for things remote.  I love to sail forbidden\nseas, and land on barbarous coasts.  Not ignoring what is good, I am\nquick to perceive a horror, and could still be social with it--would\nthey let me--since it is but well to be on friendly terms with all\nthe inmates of the place one lodges in.\n\nBy reason of these things, then, the whaling voyage was welcome; the\ngreat flood-gates of the wonder-world swung open, and in the wild\nconceits that swayed me to my purpose, two and two there floated into\nmy inmost soul, endless processions of the whale, and, mid most of\nthem all, one grand hooded phantom, like a snow hill in the air.\n\n\n\nCHAPTER 2\n\nThe Carpet-Bag.\n\n\nI stuffed a shirt or two into my old carpet-bag, tucked it under my\narm, and started for Cape Horn and the Pacific.  Quitting the good\ncity of old Manhatto, I duly arrived in New Bedford.  It was a\nSaturday night in December.  Much was I disappointed upon learning\nthat the little packet for Nantucket had already sailed, and that no\nway of reaching that place would offer, till the following Monday.\n\nAs most young candidates for the pains and penalties of whaling stop\nat this same New Bedford, thence to embark on their voyage, it may as\nwell be related that I, for one, had no idea of so doing.  For my\nmind was made up to sail in no other than a Nantucket craft, because\nthere was a fine, boisterous something about everything connected\nwith that famous old island, which amazingly pleased me.  Besides\nthough New Bedford has of late been gradually monopolising the\nbusiness of whaling, and though in this matter poor old Nantucket is\nnow much behind her, yet Nantucket was her great original--the Tyre\nof this Carthage;--the place where the first dead American whale was\nstranded.  Where else but from Nantucket did those aboriginal\nwhalemen, the Red-Men, first sally out in canoes to give chase to the\nLeviathan?  And where but from Nantucket, too, did that first\nadventurous little sloop put forth, partly laden with imported\ncobblestones--so goes the story--to throw at the whales, in order to\ndiscover when they were nigh enough to risk a harpoon from the\nbowsprit?\n\nNow having a night, a day, and still another night following before\nme in New Bedford, ere I could embark for my destined port, it\nbecame a matter of concernment where I was to eat and sleep\nmeanwhile.  It was a very dubious-looking, nay, a very dark and\ndismal night, bitingly cold and cheerless.  I knew no one in the\nplace.  With anxious grapnels I had sounded my pocket, and only\nbrought up a few pieces of silver,--So, wherever you go, Ishmael,\nsaid I to myself, as I stood in the middle of a dreary street\nshouldering my bag, and comparing the gloom towards the north with\nthe darkness towards the south--wherever in your wisdom you may\nconclude to lodge for the night, my dear Ishmael, be sure to inquire\nthe price, and don't be too particular.\n\nWith halting steps I paced the streets, and passed the sign of \"The\nCrossed Harpoons\"--but it looked too expensive and jolly there.\nFurther on, from the bright red windows of the \"Sword-Fish Inn,\"\nthere came such fervent rays, that it seemed to have melted the\npacked snow and ice from before the house, for everywhere else the\ncongealed frost lay ten inches thick in a hard, asphaltic\npavement,--rather weary for me, when I struck my foot against the\nflinty projections, because from hard, remorseless service the soles\nof my boots were in a most miserable plight.  Too expensive and\njolly, again thought I, pausing one moment to watch the broad glare\nin the street, and hear the sounds of the tinkling glasses within.\nBut go on, Ishmael, said I at last; don't you hear? get away from\nbefore the door; your patched boots are stopping the way.  So on I\nwent.  I now by instinct followed the streets that took me waterward,\nfor there, doubtless, were the cheapest, if not the cheeriest inns.\n\nSuch dreary streets! blocks of blackness, not houses, on either\nhand, and here and there a candle, like a candle moving about in a\ntomb.  At this hour of the night, of the last day of the week, that\nquarter of the town proved all but deserted.  But presently I came to\na smoky light proceeding from a low, wide building, the door of which\nstood invitingly open.  It had a careless look, as if it were meant\nfor the uses of the public; so, entering, the first thing I did was\nto stumble over an ash-box in the porch.  Ha! thought I, ha, as the\nflying particles almost choked me, are these ashes from that\ndestroyed city, Gomorrah?  But \"The Crossed Harpoons,\" and \"The\nSword-Fish?\"--this, then must needs be the sign of \"The Trap.\"\nHowever, I picked myself up and hearing a loud voice within, pushed\non and opened a second, interior door.\n\nIt seemed the great Black Parliament sitting in Tophet.  A hundred\nblack faces turned round in their rows to peer; and beyond, a black\nAngel of Doom was beating a book in a pulpit.  It was a negro church;\nand the preacher's text was about the blackness of darkness, and the\nweeping and wailing and teeth-gnashing there.  Ha, Ishmael, muttered\nI, backing out, Wretched entertainment at the sign of 'The Trap!'\n\nMoving on, I at last came to a dim sort of light not far from the\ndocks, and heard a forlorn creaking in the air; and looking up, saw a\nswinging sign over the door with a white painting upon it, faintly\nrepresenting a tall straight jet of misty spray, and these words\nunderneath--\"The Spouter Inn:--Peter Coffin.\"\n\nCoffin?--Spouter?--Rather ominous in that particular connexion,\nthought I.  But it is a common name in Nantucket, they say, and I\nsuppose this Peter here is an emigrant from there.  As the light\nlooked so dim, and the place, for the time, looked quiet enough, and\nthe dilapidated little wooden house itself looked as if it might have\nbeen carted here from the ruins of some burnt district, and as the\nswinging sign had a poverty-stricken sort of creak to it, I thought\nthat here was the very spot for cheap lodgings, and the best of pea\ncoffee.\n\nIt was a queer sort of place--a gable-ended old house, one side\npalsied as it were, and leaning over sadly.  It stood on a sharp\nbleak corner, where that tempestuous wind Euroclydon kept up a worse\nhowling than ever it did about poor Paul's tossed craft.  Euroclydon,\nnevertheless, is a mighty pleasant zephyr to any one in-doors, with\nhis feet on the hob quietly toasting for bed.  \"In judging of that\ntempestuous wind called Euroclydon,\" says an old writer--of whose\nworks I possess the only copy extant--\"it maketh a marvellous\ndifference, whether thou lookest out at it from a glass window where\nthe frost is all on the outside, or whether thou observest it from\nthat sashless window, where the frost is on both sides, and of which\nthe wight Death is the only glazier.\"  True enough, thought I, as\nthis passage occurred to my mind--old black-letter, thou reasonest\nwell.  Yes, these eyes are windows, and this body of mine is the\nhouse.  What a pity they didn't stop up the chinks and the crannies\nthough, and thrust in a little lint here and there.  But it's too\nlate to make any improvements now.  The universe is finished; the\ncopestone is on, and the chips were carted off a million years ago.\nPoor Lazarus there, chattering his teeth against the curbstone for\nhis pillow, and shaking off his tatters with his shiverings, he might\nplug up both ears with rags, and put a corn-cob into his mouth, and\nyet that would not keep out the tempestuous Euroclydon.  Euroclydon!\nsays old Dives, in his red silken wrapper--(he had a redder one\nafterwards) pooh, pooh!  What a fine frosty night; how Orion\nglitters; what northern lights!  Let them talk of their oriental\nsummer climes of everlasting conservatories; give me the privilege of\nmaking my own summer with my own coals.\n\nBut what thinks Lazarus?  Can he warm his blue hands by holding them\nup to the grand northern lights?  Would not Lazarus rather be in\nSumatra than here?  Would he not far rather lay him down lengthwise\nalong the line of the equator; yea, ye gods! go down to the fiery pit\nitself, in order to keep out this frost?\n\nNow, that Lazarus should lie stranded there on the curbstone before\nthe door of Dives, this is more wonderful than that an iceberg should\nbe moored to one of the Moluccas.  Yet Dives himself, he too lives\nlike a Czar in an ice palace made of frozen sighs, and being a\npresident of a temperance society, he only drinks the tepid tears of\norphans.\n\nBut no more of this blubbering now, we are going a-whaling, and there\nis plenty of that yet to come.  Let us scrape the ice from our\nfrosted feet, and see what sort of a place this \"Spouter\" may be.\n\n\n\nCHAPTER 3\n\nThe Spouter-Inn.\n\n\nEntering that gable-ended Spouter-Inn, you found yourself in a wide,\nlow, straggling entry with old-fashioned wainscots, reminding one of\nthe bulwarks of some condemned old craft.  On one side hung a very\nlarge oilpainting so thoroughly besmoked, and every way defaced,\nthat in the unequal crosslights by which you viewed it, it was only\nby diligent study and a series of systematic visits to it, and\ncareful inquiry of the neighbors, that you could any way arrive at an\nunderstanding of its purpose.  Such unaccountable masses of shades\nand shadows, that at first you almost thought some ambitious young\nartist, in the time of the New England hags, had endeavored to\ndelineate chaos bewitched.  But by dint of much and earnest\ncontemplation, and oft repeated ponderings, and especially by\nthrowing open the little window towards the back of the entry, you at\nlast come to the conclusion that such an idea, however wild, might\nnot be altogether unwarranted.\n\nBut what most puzzled and confounded you was a long, limber,\nportentous, black mass of something hovering in the centre of the\npicture over three blue, dim, perpendicular lines floating in a\nnameless yeast.  A boggy, soggy, squitchy picture truly, enough to\ndrive a nervous man distracted.  Yet was there a sort of indefinite,\nhalf-attained, unimaginable sublimity about it that fairly froze you\nto it, till you involuntarily took an oath with yourself to find out\nwhat that marvellous painting meant.  Ever and anon a bright, but,\nalas, deceptive idea would dart you through.--It's the Black Sea in a\nmidnight gale.--It's the unnatural combat of the four primal\nelements.--It's a blasted heath.--It's a Hyperborean winter\nscene.--It's the breaking-up of the icebound stream of Time.  But at\nlast all these fancies yielded to that one portentous something in\nthe picture's midst.  THAT once found out, and all the rest were\nplain.  But stop; does it not bear a faint resemblance to a gigantic\nfish? even the great leviathan himself?\n\nIn fact, the artist's design seemed this: a final theory of my own,\npartly based upon the aggregated opinions of many aged persons with\nwhom I conversed upon the subject.  The picture represents a\nCape-Horner in a great hurricane; the half-foundered ship weltering\nthere with its three dismantled masts alone visible; and an\nexasperated whale, purposing to spring clean over the craft, is in\nthe enormous act of impaling himself upon the three mast-heads.\n\nThe opposite wall of this entry was hung all over with a heathenish\narray of monstrous clubs and spears.  Some were thickly set with\nglittering teeth resembling ivory saws; others were tufted with knots\nof human hair; and one was sickle-shaped, with a vast handle sweeping\nround like the segment made in the new-mown grass by a long-armed\nmower.  You shuddered as you gazed, and wondered what monstrous\ncannibal and savage could ever have gone a death-harvesting with such\na hacking, horrifying implement.  Mixed with these were rusty old\nwhaling lances and harpoons all broken and deformed.  Some were\nstoried weapons.  With this once long lance, now wildly elbowed,\nfifty years ago did Nathan Swain kill fifteen whales between a\nsunrise and a sunset.  And that harpoon--so like a corkscrew now--was\nflung in Javan seas, and run away with by a whale, years afterwards\nslain off the Cape of Blanco.  The original iron entered nigh the\ntail, and, like a restless needle sojourning in the body of a man,\ntravelled full forty feet, and at last was found imbedded in the\nhump.\n\nCrossing this dusky entry, and on through yon low-arched way--cut\nthrough what in old times must have been a great central chimney with\nfireplaces all round--you enter the public room.  A still duskier\nplace is this, with such low ponderous beams above, and such old\nwrinkled planks beneath, that you would almost fancy you trod some\nold craft's cockpits, especially of such a howling night, when this\ncorner-anchored old ark rocked so furiously.  On one side stood a\nlong, low, shelf-like table covered with cracked glass cases, filled\nwith dusty rarities gathered from this wide world's remotest nooks.\nProjecting from the further angle of the room stands a dark-looking\nden--the bar--a rude attempt at a right whale's head.  Be that how it\nmay, there stands the vast arched bone of the whale's jaw, so wide, a\ncoach might almost drive beneath it.  Within are shabby shelves,\nranged round with old decanters, bottles, flasks; and in those jaws\nof swift destruction, like another cursed Jonah (by which name indeed\nthey called him), bustles a little withered old man, who, for their\nmoney, dearly sells the sailors deliriums and death.\n\nAbominable are the tumblers into which he pours his poison.  Though\ntrue cylinders without--within, the villanous green goggling glasses\ndeceitfully tapered downwards to a cheating bottom.  Parallel\nmeridians rudely pecked into the glass, surround these footpads'\ngoblets.  Fill to THIS mark, and your charge is but a penny; to THIS\na penny more; and so on to the full glass--the Cape Horn measure,\nwhich you may gulp down for a shilling.\n\nUpon entering the place I found a number of young seamen gathered\nabout a table, examining by a dim light divers specimens of\nSKRIMSHANDER.  I sought the landlord, and telling him I desired to be\naccommodated with a room, received for answer that his house was\nfull--not a bed unoccupied.  \"But avast,\" he added, tapping his\nforehead, \"you haint no objections to sharing a harpooneer's blanket,\nhave ye?  I s'pose you are goin' a-whalin', so you'd better get used\nto that sort of thing.\"\n\nI told him that I never liked to sleep two in a bed; that if I should\never do so, it would depend upon who the harpooneer might be, and\nthat if he (the landlord) really had no other place for me, and the\nharpooneer was not decidedly objectionable, why rather than wander\nfurther about a strange town on so bitter a night, I would put up\nwith the half of any decent man's blanket.\n\n\"I thought so.  All right; take a seat.  Supper?--you want supper?\nSupper'll be ready directly.\"\n\nI sat down on an old wooden settle, carved all over like a bench on\nthe Battery.  At one end a ruminating tar was still further adorning\nit with his jack-knife, stooping over and diligently working away at\nthe space between his legs.  He was trying his hand at a ship under\nfull sail, but he didn't make much headway, I thought.\n\nAt last some four or five of us were summoned to our meal in an\nadjoining room.  It was cold as Iceland--no fire at all--the landlord\nsaid he couldn't afford it.  Nothing but two dismal tallow candles,\neach in a winding sheet.  We were fain to button up our monkey\njackets, and hold to our lips cups of scalding tea with our half\nfrozen fingers.  But the fare was of the most substantial kind--not\nonly meat and potatoes, but dumplings; good heavens! dumplings for\nsupper!  One young fellow in a green box coat, addressed himself to\nthese dumplings in a most direful manner.\n\n\"My boy,\" said the landlord, \"you'll have the nightmare to a dead\nsartainty.\"\n\n\"Landlord,\" I whispered, \"that aint the harpooneer is it?\"\n\n\"Oh, no,\" said he, looking a sort of diabolically funny, \"the\nharpooneer is a dark complexioned chap.  He never eats dumplings, he\ndon't--he eats nothing but steaks, and he likes 'em rare.\"\n\n\"The devil he does,\" says I.  \"Where is that harpooneer?  Is he\nhere?\"\n\n\"He'll be here afore long,\" was the answer.\n\nI could not help it, but I began to feel suspicious of this \"dark\ncomplexioned\" harpooneer.  At any rate, I made up my mind that if it\nso turned out that we should sleep together, he must undress and get\ninto bed before I did.\n\nSupper over, the company went back to the bar-room, when, knowing not\nwhat else to do with myself, I resolved to spend the rest of the\nevening as a looker on.\n\nPresently a rioting noise was heard without.  Starting up, the\nlandlord cried, \"That's the Grampus's crew.  I seed her reported in\nthe offing this morning; a three years' voyage, and a full ship.\nHurrah, boys; now we'll have the latest news from the Feegees.\"\n\nA tramping of sea boots was heard in the entry; the door was flung\nopen, and in rolled a wild set of mariners enough.  Enveloped in\ntheir shaggy watch coats, and with their heads muffled in woollen\ncomforters, all bedarned and ragged, and their beards stiff with\nicicles, they seemed an eruption of bears from Labrador.  They had\njust landed from their boat, and this was the first house they\nentered.  No wonder, then, that they made a straight wake for the\nwhale's mouth--the bar--when the wrinkled little old Jonah, there\nofficiating, soon poured them out brimmers all round.  One complained\nof a bad cold in his head, upon which Jonah mixed him a pitch-like\npotion of gin and molasses, which he swore was a sovereign cure for\nall colds and catarrhs whatsoever, never mind of how long standing,\nor whether caught off the coast of Labrador, or on the weather side\nof an ice-island.\n\nThe liquor soon mounted into their heads, as it generally does even\nwith the arrantest topers newly landed from sea, and they began\ncapering about most obstreperously.\n\nI observed, however, that one of them held somewhat aloof, and though\nhe seemed desirous not to spoil the hilarity of his shipmates by his\nown sober face, yet upon the whole he refrained from making as much\nnoise as the rest.  This man interested me at once; and since the\nsea-gods had ordained that he should soon become my shipmate (though\nbut a sleeping-partner one, so far as this narrative is concerned),\nI will here venture upon a little description of him.  He stood full\nsix feet in height, with noble shoulders, and a chest like a\ncoffer-dam.  I have seldom seen such brawn in a man.  His face was\ndeeply brown and burnt, making his white teeth dazzling by the\ncontrast; while in the deep shadows of his eyes floated some\nreminiscences that did not seem to give him much joy.  His voice at\nonce announced that he was a Southerner, and from his fine stature, I\nthought he must be one of those tall mountaineers from the\nAlleghanian Ridge in Virginia.  When the revelry of his companions\nhad mounted to its height, this man slipped away unobserved, and I\nsaw no more of him till he became my comrade on the sea.  In a few\nminutes, however, he was missed by his shipmates, and being, it\nseems, for some reason a huge favourite with them, they raised a cry\nof \"Bulkington!  Bulkington! where's Bulkington?\" and darted out of\nthe house in pursuit of him.\n\nIt was now about nine o'clock, and the room seeming almost\nsupernaturally quiet after these orgies, I began to congratulate\nmyself upon a little plan that had occurred to me just previous to\nthe entrance of the seamen.\n\nNo man prefers to sleep two in a bed.  In fact, you would a good deal\nrather not sleep with your own brother.  I don't know how it is, but\npeople like to be private when they are sleeping.  And when it comes\nto sleeping with an unknown stranger, in a strange inn, in a strange\ntown, and that stranger a harpooneer, then your objections\nindefinitely multiply.  Nor was there any earthly reason why I as a\nsailor should sleep two in a bed, more than anybody else; for sailors\nno more sleep two in a bed at sea, than bachelor Kings do ashore.  To\nbe sure they all sleep together in one apartment, but you have your\nown hammock, and cover yourself with your own blanket, and sleep in\nyour own skin.\n\nThe more I pondered over this harpooneer, the more I abominated the\nthought of sleeping with him.  It was fair to presume that being a\nharpooneer, his linen or woollen, as the case might be, would not be\nof the tidiest, certainly none of the finest.  I began to twitch all\nover.  Besides, it was getting late, and my decent harpooneer ought\nto be home and going bedwards.  Suppose now, he should tumble in upon\nme at midnight--how could I tell from what vile hole he had been\ncoming?\n\n\"Landlord!  I've changed my mind about that harpooneer.--I shan't\nsleep with him.  I'll try the bench here.\"\n\n\"Just as you please; I'm sorry I cant spare ye a tablecloth for a\nmattress, and it's a plaguy rough board here\"--feeling of the knots\nand notches.  \"But wait a bit, Skrimshander; I've got a carpenter's\nplane there in the bar--wait, I say, and I'll make ye snug enough.\"\nSo saying he procured the plane; and with his old silk handkerchief\nfirst dusting the bench, vigorously set to planing away at my bed,\nthe while grinning like an ape.  The shavings flew right and left;\ntill at last the plane-iron came bump against an indestructible knot.\nThe landlord was near spraining his wrist, and I told him for\nheaven's sake to quit--the bed was soft enough to suit me, and I did\nnot know how all the planing in the world could make eider down of a\npine plank.  So gathering up the shavings with another grin, and\nthrowing them into the great stove in the middle of the room, he went\nabout his business, and left me in a brown study.\n\nI now took the measure of the bench, and found that it was a foot too\nshort; but that could be mended with a chair.  But it was a foot too\nnarrow, and the other bench in the room was about four inches higher\nthan the planed one--so there was no yoking them.  I then placed the\nfirst bench lengthwise along the only clear space against the wall,\nleaving a little interval between, for my back to settle down in.\nBut I soon found that there came such a draught of cold air over me\nfrom under the sill of the window, that this plan would never do at\nall, especially as another current from the rickety door met the one\nfrom the window, and both together formed a series of small\nwhirlwinds in the immediate vicinity of the spot where I had thought\nto spend the night.\n\nThe devil fetch that harpooneer, thought I, but stop, couldn't I\nsteal a march on him--bolt his door inside, and jump into his bed,\nnot to be wakened by the most violent knockings?  It seemed no bad\nidea; but upon second thoughts I dismissed it.  For who could tell\nbut what the next morning, so soon as I popped out of the room, the\nharpooneer might be standing in the entry, all ready to knock me\ndown!\n\nStill, looking round me again, and seeing no possible chance of\nspending a sufferable night unless in some other person's bed, I\nbegan to think that after all I might be cherishing unwarrantable\nprejudices against this unknown harpooneer.  Thinks I, I'll wait\nawhile; he must be dropping in before long.  I'll have a good look at\nhim then, and perhaps we may become jolly good bedfellows after\nall--there's no telling.\n\nBut though the other boarders kept coming in by ones, twos, and\nthrees, and going to bed, yet no sign of my harpooneer.\n\n\"Landlord! said I, \"what sort of a chap is he--does he always keep\nsuch late hours?\"  It was now hard upon twelve o'clock.\n\nThe landlord chuckled again with his lean chuckle, and seemed to be\nmightily tickled at something beyond my comprehension.  \"No,\" he\nanswered, \"generally he's an early bird--airley to bed and airley to\nrise--yes, he's the bird what catches the worm.  But to-night he\nwent out a peddling, you see, and I don't see what on airth keeps him\nso late, unless, may be, he can't sell his head.\"\n\n\"Can't sell his head?--What sort of a bamboozingly story is this you\nare telling me?\" getting into a towering rage.  \"Do you pretend to\nsay, landlord, that this harpooneer is actually engaged this blessed\nSaturday night, or rather Sunday morning, in peddling his head around\nthis town?\"\n\n\"That's precisely it,\" said the landlord, \"and I told him he couldn't\nsell it here, the market's overstocked.\"\n\n\"With what?\" shouted I.\n\n\"With heads to be sure; ain't there too many heads in the world?\"\n\n\"I tell you what it is, landlord,\" said I quite calmly, \"you'd better\nstop spinning that yarn to me--I'm not green.\"\n\n\"May be not,\" taking out a stick and whittling a toothpick, \"but I\nrayther guess you'll be done BROWN if that ere harpooneer hears you a\nslanderin' his head.\"\n\n\"I'll break it for him,\" said I, now flying into a passion again at\nthis unaccountable farrago of the landlord's.\n\n\"It's broke a'ready,\" said he.\n\n\"Broke,\" said I--\"BROKE, do you mean?\"\n\n\"Sartain, and that's the very reason he can't sell it, I guess.\"\n\n\"Landlord,\" said I, going up to him as cool as Mt. Hecla in a\nsnow-storm--\"landlord, stop whittling.  You and I must understand one\nanother, and that too without delay.  I come to your house and want a\nbed; you tell me you can only give me half a one; that the other half\nbelongs to a certain harpooneer.  And about this harpooneer, whom I\nhave not yet seen, you persist in telling me the most mystifying and\nexasperating stories tending to beget in me an uncomfortable feeling\ntowards the man whom you design for my bedfellow--a sort of\nconnexion, landlord, which is an intimate and confidential one in the\nhighest degree.  I now demand of you to speak out and tell me who and\nwhat this harpooneer is, and whether I shall be in all respects safe\nto spend the night with him.  And in the first place, you will be so\ngood as to unsay that story about selling his head, which if true I\ntake to be good evidence that this harpooneer is stark mad, and I've\nno idea of sleeping with a madman; and you, sir, YOU I mean,\nlandlord, YOU, sir, by trying to induce me to do so knowingly, would\nthereby render yourself liable to a criminal prosecution.\"\n\n\"Wall,\" said the landlord, fetching a long breath, \"that's a purty\nlong sarmon for a chap that rips a little now and then.  But be easy,\nbe easy, this here harpooneer I have been tellin' you of has just\narrived from the south seas, where he bought up a lot of 'balmed New\nZealand heads (great curios, you know), and he's sold all on 'em but\none, and that one he's trying to sell to-night, cause to-morrow's\nSunday, and it would not do to be sellin' human heads about the\nstreets when folks is goin' to churches.  He wanted to, last Sunday,\nbut I stopped him just as he was goin' out of the door with four\nheads strung on a string, for all the airth like a string of inions.\"\n\nThis account cleared up the otherwise unaccountable mystery, and\nshowed that the landlord, after all, had had no idea of fooling\nme--but at the same time what could I think of a harpooneer who\nstayed out of a Saturday night clean into the holy Sabbath, engaged\nin such a cannibal business as selling the heads of dead idolators?\n\n\"Depend upon it, landlord, that harpooneer is a dangerous man.\"\n\n\"He pays reg'lar,\" was the rejoinder.  \"But come, it's getting\ndreadful late, you had better be turning flukes--it's a nice bed;\nSal and me slept in that ere bed the night we were spliced.  There's\nplenty of room for two to kick about in that bed; it's an almighty\nbig bed that.  Why, afore we give it up, Sal used to put our Sam and\nlittle Johnny in the foot of it.  But I got a dreaming and sprawling\nabout one night, and somehow, Sam got pitched on the floor, and came\nnear breaking his arm.  Arter that, Sal said it wouldn't do.  Come\nalong here, I'll give ye a glim in a jiffy;\" and so saying he lighted\na candle and held it towards me, offering to lead the way.  But I\nstood irresolute; when looking at a clock in the corner, he exclaimed\n\"I vum it's Sunday--you won't see that harpooneer to-night; he's come\nto anchor somewhere--come along then; DO come; WON'T ye come?\"\n\nI considered the matter a moment, and then up stairs we went, and I\nwas ushered into a small room, cold as a clam, and furnished, sure\nenough, with a prodigious bed, almost big enough indeed for any four\nharpooneers to sleep abreast.\n\n\"There,\" said the landlord, placing the candle on a crazy old sea\nchest that did double duty as a wash-stand and centre table; \"there,\nmake yourself comfortable now, and good night to ye.\"  I turned\nround from eyeing the bed, but he had disappeared.\n\nFolding back the counterpane, I stooped over the bed.  Though none of\nthe most elegant, it yet stood the scrutiny tolerably well.  I then\nglanced round the room; and besides the bedstead and centre table,\ncould see no other furniture belonging to the place, but a rude\nshelf, the four walls, and a papered fireboard representing a man\nstriking a whale.  Of things not properly belonging to the room,\nthere was a hammock lashed up, and thrown upon the floor in one\ncorner; also a large seaman's bag, containing the harpooneer's\nwardrobe, no doubt in lieu of a land trunk.  Likewise, there was a\nparcel of outlandish bone fish hooks on the shelf over the\nfire-place, and a tall harpoon standing at the head of the bed.\n\nBut what is this on the chest?  I took it up, and held it close to\nthe light, and felt it, and smelt it, and tried every way possible to\narrive at some satisfactory conclusion concerning it.  I can compare\nit to nothing but a large door mat, ornamented at the edges with\nlittle tinkling tags something like the stained porcupine quills\nround an Indian moccasin.  There was a hole or slit in the middle of\nthis mat, as you see the same in South American ponchos.  But could\nit be possible that any sober harpooneer would get into a door mat,\nand parade the streets of any Christian town in that sort of guise?\nI put it on, to try it, and it weighed me down like a hamper, being\nuncommonly shaggy and thick, and I thought a little damp, as though\nthis mysterious harpooneer had been wearing it of a rainy day.  I\nwent up in it to a bit of glass stuck against the wall, and I never\nsaw such a sight in my life.  I tore myself out of it in such a hurry\nthat I gave myself a kink in the neck.\n\nI sat down on the side of the bed, and commenced thinking about this\nhead-peddling harpooneer, and his door mat.  After thinking some time\non the bed-side, I got up and took off my monkey jacket, and then\nstood in the middle of the room thinking.  I then took off my coat,\nand thought a little more in my shirt sleeves.  But beginning to feel\nvery cold now, half undressed as I was, and remembering what the\nlandlord said about the harpooneer's not coming home at all that\nnight, it being so very late, I made no more ado, but jumped out of\nmy pantaloons and boots, and then blowing out the light tumbled into\nbed, and commended myself to the care of heaven.\n\nWhether that mattress was stuffed with corn-cobs or broken crockery,\nthere is no telling, but I rolled about a good deal, and could not\nsleep for a long time.  At last I slid off into a light doze, and had\npretty nearly made a good offing towards the land of Nod, when I\nheard a heavy footfall in the passage, and saw a glimmer of light\ncome into the room from under the door.\n\nLord save me, thinks I, that must be the harpooneer, the infernal\nhead-peddler.  But I lay perfectly still, and resolved not to say a\nword till spoken to.  Holding a light in one hand, and that identical\nNew Zealand head in the other, the stranger entered the room, and\nwithout looking towards the bed, placed his candle a good way off\nfrom me on the floor in one corner, and then began working away at\nthe knotted cords of the large bag I before spoke of as being in the\nroom.  I was all eagerness to see his face, but he kept it averted\nfor some time while employed in unlacing the bag's mouth.  This\naccomplished, however, he turned round--when, good heavens! what a\nsight!  Such a face!  It was of a dark, purplish, yellow colour, here\nand there stuck over with large blackish looking squares.  Yes, it's\njust as I thought, he's a terrible bedfellow; he's been in a fight,\ngot dreadfully cut, and here he is, just from the surgeon.  But at\nthat moment he chanced to turn his face so towards the light, that I\nplainly saw they could not be sticking-plasters at all, those black\nsquares on his cheeks.  They were stains of some sort or other.  At\nfirst I knew not what to make of this; but soon an inkling of the\ntruth occurred to me.  I remembered a story of a white man--a\nwhaleman too--who, falling among the cannibals, had been tattooed by\nthem.  I concluded that this harpooneer, in the course of his distant\nvoyages, must have met with a similar adventure.  And what is it,\nthought I, after all!  It's only his outside; a man can be honest in\nany sort of skin.  But then, what to make of his unearthly\ncomplexion, that part of it, I mean, lying round about, and\ncompletely independent of the squares of tattooing.  To be sure, it\nmight be nothing but a good coat of tropical tanning; but I never\nheard of a hot sun's tanning a white man into a purplish yellow one.\nHowever, I had never been in the South Seas; and perhaps the sun\nthere produced these extraordinary effects upon the skin.  Now, while\nall these ideas were passing through me like lightning, this\nharpooneer never noticed me at all.  But, after some difficulty\nhaving opened his bag, he commenced fumbling in it, and presently\npulled out a sort of tomahawk, and a seal-skin wallet with the hair\non.  Placing these on the old chest in the middle of the room, he\nthen took the New Zealand head--a ghastly thing enough--and crammed\nit down into the bag.  He now took off his hat--a new beaver\nhat--when I came nigh singing out with fresh surprise.  There was no\nhair on his head--none to speak of at least--nothing but a small\nscalp-knot twisted up on his forehead.  His bald purplish head now\nlooked for all the world like a mildewed skull.  Had not the stranger\nstood between me and the door, I would have bolted out of it quicker\nthan ever I bolted a dinner.\n\nEven as it was, I thought something of slipping out of the window,\nbut it was the second floor back.  I am no coward, but what to make\nof this head-peddling purple rascal altogether passed my\ncomprehension.  Ignorance is the parent of fear, and being completely\nnonplussed and confounded about the stranger, I confess I was now as\nmuch afraid of him as if it was the devil himself who had thus broken\ninto my room at the dead of night.  In fact, I was so afraid of him\nthat I was not game enough just then to address him, and demand a\nsatisfactory answer concerning what seemed inexplicable in him.\n\nMeanwhile, he continued the business of undressing, and at last\nshowed his chest and arms.  As I live, these covered parts of him\nwere checkered with the same squares as his face; his back, too, was\nall over the same dark squares; he seemed to have been in a Thirty\nYears' War, and just escaped from it with a sticking-plaster shirt.\nStill more, his very legs were marked, as if a parcel of dark green\nfrogs were running up the trunks of young palms.  It was now quite\nplain that he must be some abominable savage or other shipped aboard\nof a whaleman in the South Seas, and so landed in this Christian\ncountry.  I quaked to think of it.  A peddler of heads too--perhaps\nthe heads of his own brothers.  He might take a fancy to\nmine--heavens! look at that tomahawk!\n\nBut there was no time for shuddering, for now the savage went about\nsomething that completely fascinated my attention, and convinced me\nthat he must indeed be a heathen.  Going to his heavy grego, or\nwrapall, or dreadnaught, which he had previously hung on a chair, he\nfumbled in the pockets, and produced at length a curious little\ndeformed image with a hunch on its back, and exactly the colour of a\nthree days' old Congo baby.  Remembering the embalmed head, at first\nI almost thought that this black manikin was a real baby preserved\nin some similar manner.  But seeing that it was not at all limber,\nand that it glistened a good deal like polished ebony, I concluded\nthat it must be nothing but a wooden idol, which indeed it proved to\nbe.  For now the savage goes up to the empty fire-place, and removing\nthe papered fire-board, sets up this little hunch-backed image, like\na tenpin, between the andirons.  The chimney jambs and all the bricks\ninside were very sooty, so that I thought this fire-place made a very\nappropriate little shrine or chapel for his Congo idol.\n\nI now screwed my eyes hard towards the half hidden image, feeling but\nill at ease meantime--to see what was next to follow.  First he takes\nabout a double handful of shavings out of his grego pocket, and\nplaces them carefully before the idol; then laying a bit of ship\nbiscuit on top and applying the flame from the lamp, he kindled the\nshavings into a sacrificial blaze.  Presently, after many hasty\nsnatches into the fire, and still hastier withdrawals of his fingers\n(whereby he seemed to be scorching them badly), he at last succeeded\nin drawing out the biscuit; then blowing off the heat and ashes a\nlittle, he made a polite offer of it to the little negro.  But the\nlittle devil did not seem to fancy such dry sort of fare at all; he\nnever moved his lips.  All these strange antics were accompanied by\nstill stranger guttural noises from the devotee, who seemed to be\npraying in a sing-song or else singing some pagan psalmody or other,\nduring which his face twitched about in the most unnatural manner.\nAt last extinguishing the fire, he took the idol up very\nunceremoniously, and bagged it again in his grego pocket as\ncarelessly as if he were a sportsman bagging a dead woodcock.\n\nAll these queer proceedings increased my uncomfortableness, and\nseeing him now exhibiting strong symptoms of concluding his business\noperations, and jumping into bed with me, I thought it was high time,\nnow or never, before the light was put out, to break the spell in\nwhich I had so long been bound.\n\nBut the interval I spent in deliberating what to say, was a fatal\none.  Taking up his tomahawk from the table, he examined the head of\nit for an instant, and then holding it to the light, with his mouth\nat the handle, he puffed out great clouds of tobacco smoke.  The next\nmoment the light was extinguished, and this wild cannibal, tomahawk\nbetween his teeth, sprang into bed with me.  I sang out, I could not\nhelp it now; and giving a sudden grunt of astonishment he began\nfeeling me.\n\nStammering out something, I knew not what, I rolled away from him\nagainst the wall, and then conjured him, whoever or whatever he might\nbe, to keep quiet, and let me get up and light the lamp again.  But\nhis guttural responses satisfied me at once that he but ill\ncomprehended my meaning.\n\n\"Who-e debel you?\"--he at last said--\"you no speak-e, dam-me, I\nkill-e.\"  And so saying the lighted tomahawk began flourishing about\nme in the dark.\n\n\"Landlord, for God's sake, Peter Coffin!\" shouted I.  \"Landlord!\nWatch!  Coffin!  Angels! save me!\"\n\n\"Speak-e! tell-ee me who-ee be, or dam-me, I kill-e!\" again growled\nthe cannibal, while his horrid flourishings of the tomahawk scattered\nthe hot tobacco ashes about me till I thought my linen would get on\nfire.  But thank heaven, at that moment the landlord came into the\nroom light in hand, and leaping from the bed I ran up to him.\n\n\"Don't be afraid now,\" said he, grinning again, \"Queequeg here\nwouldn't harm a hair of your head.\"\n\n\"Stop your grinning,\" shouted I, \"and why didn't you tell me that\nthat infernal harpooneer was a cannibal?\"\n\n\"I thought ye know'd it;--didn't I tell ye, he was a peddlin' heads\naround town?--but turn flukes again and go to sleep.  Queequeg, look\nhere--you sabbee me, I sabbee--you this man sleepe you--you sabbee?\"\n\n\"Me sabbee plenty\"--grunted Queequeg, puffing away at his pipe and\nsitting up in bed.\n\n\"You gettee in,\" he added, motioning to me with his tomahawk, and\nthrowing the clothes to one side.  He really did this in not only a\ncivil but a really kind and charitable way.  I stood looking at him a\nmoment.  For all his tattooings he was on the whole a clean, comely\nlooking cannibal.  What's all this fuss I have been making about,\nthought I to myself--the man's a human being just as I am: he has\njust as much reason to fear me, as I have to be afraid of him.\nBetter sleep with a sober cannibal than a drunken Christian.\n\n\"Landlord,\" said I, \"tell him to stash his tomahawk there, or pipe,\nor whatever you call it; tell him to stop smoking, in short, and I\nwill turn in with him.  But I don't fancy having a man smoking in bed\nwith me.  It's dangerous.  Besides, I ain't insured.\"\n\nThis being told to Queequeg, he at once complied, and again politely\nmotioned me to get into bed--rolling over to one side as much as to\nsay--I won't touch a leg of ye.\"\n\n\"Good night, landlord,\" said I, \"you may go.\"\n\nI turned in, and never slept better in my life.\n\n\n\nCHAPTER 4\n\nThe Counterpane.\n\n\nUpon waking next morning about daylight, I found Queequeg's arm\nthrown over me in the most loving and affectionate manner.  You had\nalmost thought I had been his wife.  The counterpane was of\npatchwork, full of odd little parti-coloured squares and triangles;\nand this arm of his tattooed all over with an interminable Cretan\nlabyrinth of a figure, no two parts of which were of one precise\nshade--owing I suppose to his keeping his arm at sea unmethodically\nin sun and shade, his shirt sleeves irregularly rolled up at various\ntimes--this same arm of his, I say, looked for all the world like a\nstrip of that same patchwork quilt.  Indeed, partly lying on it as\nthe arm did when I first awoke, I could hardly tell it from the\nquilt, they so blended their hues together; and it was only by the\nsense of weight and pressure that I could tell that Queequeg was\nhugging me.\n\nMy sensations were strange.  Let me try to explain them.  When I was\na child, I well remember a somewhat similar circumstance that befell\nme; whether it was a reality or a dream, I never could entirely\nsettle.  The circumstance was this.  I had been cutting up some caper\nor other--I think it was trying to crawl up the chimney, as I had\nseen a little sweep do a few days previous; and my stepmother who,\nsomehow or other, was all the time whipping me, or sending me to bed\nsupperless,--my mother dragged me by the legs out of the chimney and\npacked me off to bed, though it was only two o'clock in the afternoon\nof the 21st June, the longest day in the year in our hemisphere.  I\nfelt dreadfully.  But there was no help for it, so up stairs I went\nto my little room in the third floor, undressed myself as slowly as\npossible so as to kill time, and with a bitter sigh got between the\nsheets.\n\nI lay there dismally calculating that sixteen entire hours must\nelapse before I could hope for a resurrection.  Sixteen hours in bed!\nthe small of my back ached to think of it.  And it was so light too;\nthe sun shining in at the window, and a great rattling of coaches in\nthe streets, and the sound of gay voices all over the house.  I felt\nworse and worse--at last I got up, dressed, and softly going down in\nmy stockinged feet, sought out my stepmother, and suddenly threw\nmyself at her feet, beseeching her as a particular favour to give me a\ngood slippering for my misbehaviour; anything indeed but condemning\nme to lie abed such an unendurable length of time.  But she was the\nbest and most conscientious of stepmothers, and back I had to go to\nmy room.  For several hours I lay there broad awake, feeling a great\ndeal worse than I have ever done since, even from the greatest\nsubsequent misfortunes.  At last I must have fallen into a troubled\nnightmare of a doze; and slowly waking from it--half steeped in\ndreams--I opened my eyes, and the before sun-lit room was now wrapped\nin outer darkness.  Instantly I felt a shock running through all my\nframe; nothing was to be seen, and nothing was to be heard; but a\nsupernatural hand seemed placed in mine.  My arm hung over the\ncounterpane, and the nameless, unimaginable, silent form or phantom,\nto which the hand belonged, seemed closely seated by my bed-side.\nFor what seemed ages piled on ages, I lay there, frozen with the most\nawful fears, not daring to drag away my hand; yet ever thinking that\nif I could but stir it one single inch, the horrid spell would be\nbroken.  I knew not how this consciousness at last glided away from\nme; but waking in the morning, I shudderingly remembered it all, and\nfor days and weeks and months afterwards I lost myself in confounding\nattempts to explain the mystery.  Nay, to this very hour, I often\npuzzle myself with it.\n\nNow, take away the awful fear, and my sensations at feeling the\nsupernatural hand in mine were very similar, in their strangeness,\nto those which I experienced on waking up and seeing Queequeg's pagan\narm thrown round me.  But at length all the past night's events\nsoberly recurred, one by one, in fixed reality, and then I lay only\nalive to the comical predicament.  For though I tried to move his\narm--unlock his bridegroom clasp--yet, sleeping as he was, he still\nhugged me tightly, as though naught but death should part us twain.\nI now strove to rouse him--\"Queequeg!\"--but his only answer was a\nsnore.  I then rolled over, my neck feeling as if it were in a\nhorse-collar; and suddenly felt a slight scratch.  Throwing aside the\ncounterpane, there lay the tomahawk sleeping by the savage's side, as\nif it were a hatchet-faced baby.  A pretty pickle, truly, thought I;\nabed here in a strange house in the broad day, with a cannibal and a\ntomahawk!  \"Queequeg!--in the name of goodness, Queequeg, wake!\"  At\nlength, by dint of much wriggling, and loud and incessant\nexpostulations upon the unbecomingness of his hugging a fellow male\nin that matrimonial sort of style, I succeeded in extracting a grunt;\nand presently, he drew back his arm, shook himself all over like a\nNewfoundland dog just from the water, and sat up in bed, stiff as a\npike-staff, looking at me, and rubbing his eyes as if he did not\naltogether remember how I came to be there, though a dim\nconsciousness of knowing something about me seemed slowly dawning\nover him.  Meanwhile, I lay quietly eyeing him, having no serious\nmisgivings now, and bent upon narrowly observing so curious a\ncreature.  When, at last, his mind seemed made up touching the\ncharacter of his bedfellow, and he became, as it were, reconciled to\nthe fact; he jumped out upon the floor, and by certain signs and\nsounds gave me to understand that, if it pleased me, he would dress\nfirst and then leave me to dress afterwards, leaving the whole\napartment to myself.  Thinks I, Queequeg, under the circumstances,\nthis is a very civilized overture; but, the truth is, these savages\nhave an innate sense of delicacy, say what you will; it is marvellous\nhow essentially polite they are.  I pay this particular compliment to\nQueequeg, because he treated me with so much civility and\nconsideration, while I was guilty of great rudeness; staring at him\nfrom the bed, and watching all his toilette motions; for the time my\ncuriosity getting the better of my breeding.  Nevertheless, a man\nlike Queequeg you don't see every day, he and his ways were well\nworth unusual regarding.\n\nHe commenced dressing at top by donning his beaver hat, a very tall\none, by the by, and then--still minus his trowsers--he hunted up his\nboots.  What under the heavens he did it for, I cannot tell, but his\nnext movement was to crush himself--boots in hand, and hat on--under\nthe bed; when, from sundry violent gaspings and strainings, I\ninferred he was hard at work booting himself; though by no law of\npropriety that I ever heard of, is any man required to be private\nwhen putting on his boots.  But Queequeg, do you see, was a creature\nin the transition stage--neither caterpillar nor butterfly.  He was\njust enough civilized to show off his outlandishness in the strangest\npossible manners.  His education was not yet completed.  He was an\nundergraduate.  If he had not been a small degree civilized, he very\nprobably would not have troubled himself with boots at all; but then,\nif he had not been still a savage, he never would have dreamt of\ngetting under the bed to put them on.  At last, he emerged with his\nhat very much dented and crushed down over his eyes, and began\ncreaking and limping about the room, as if, not being much accustomed\nto boots, his pair of damp, wrinkled cowhide ones--probably not made\nto order either--rather pinched and tormented him at the first go off\nof a bitter cold morning.\n\nSeeing, now, that there were no curtains to the window, and that the\nstreet being very narrow, the house opposite commanded a plain view\ninto the room, and observing more and more the indecorous figure that\nQueequeg made, staving about with little else but his hat and boots\non; I begged him as well as I could, to accelerate his toilet\nsomewhat, and particularly to get into his pantaloons as soon as\npossible.  He complied, and then proceeded to wash himself.  At that\ntime in the morning any Christian would have washed his face; but\nQueequeg, to my amazement, contented himself with restricting his\nablutions to his chest, arms, and hands.  He then donned his\nwaistcoat, and taking up a piece of hard soap on the wash-stand\ncentre table, dipped it into water and commenced lathering his face.\nI was watching to see where he kept his razor, when lo and behold, he\ntakes the harpoon from the bed corner, slips out the long wooden\nstock, unsheathes the head, whets it a little on his boot, and\nstriding up to the bit of mirror against the wall, begins a vigorous\nscraping, or rather harpooning of his cheeks.  Thinks I, Queequeg,\nthis is using Rogers's best cutlery with a vengeance.  Afterwards I\nwondered the less at this operation when I came to know of what fine\nsteel the head of a harpoon is made, and how exceedingly sharp the\nlong straight edges are always kept.\n\nThe rest of his toilet was soon achieved, and he proudly marched out\nof the room, wrapped up in his great pilot monkey jacket, and\nsporting his harpoon like a marshal's baton.\n\n\n\nCHAPTER 5\n\nBreakfast.\n\n\nI quickly followed suit, and descending into the bar-room accosted\nthe grinning landlord very pleasantly.  I cherished no malice towards\nhim, though he had been skylarking with me not a little in the matter\nof my bedfellow.\n\nHowever, a good laugh is a mighty good thing, and rather too scarce a\ngood thing; the more's the pity.  So, if any one man, in his own\nproper person, afford stuff for a good joke to anybody, let him not\nbe backward, but let him cheerfully allow himself to spend and be\nspent in that way.  And the man that has anything bountifully\nlaughable about him, be sure there is more in that man than you\nperhaps think for.\n\nThe bar-room was now full of the boarders who had been dropping in\nthe night previous, and whom I had not as yet had a good look at.\nThey were nearly all whalemen; chief mates, and second mates, and\nthird mates, and sea carpenters, and sea coopers, and sea\nblacksmiths, and harpooneers, and ship keepers; a brown and brawny\ncompany, with bosky beards; an unshorn, shaggy set, all wearing\nmonkey jackets for morning gowns.\n\nYou could pretty plainly tell how long each one had been ashore.\nThis young fellow's healthy cheek is like a sun-toasted pear in hue,\nand would seem to smell almost as musky; he cannot have been three\ndays landed from his Indian voyage.  That man next him looks a few\nshades lighter; you might say a touch of satin wood is in him.  In\nthe complexion of a third still lingers a tropic tawn, but slightly\nbleached withal; HE doubtless has tarried whole weeks ashore.  But\nwho could show a cheek like Queequeg? which, barred with various\ntints, seemed like the Andes' western slope, to show forth in one\narray, contrasting climates, zone by zone.\n\n\"Grub, ho!\" now cried the landlord, flinging open a door, and in we\nwent to breakfast.\n\nThey say that men who have seen the world, thereby become quite at\nease in manner, quite self-possessed in company.  Not always, though:\nLedyard, the great New England traveller, and Mungo Park, the Scotch\none; of all men, they possessed the least assurance in the parlor.\nBut perhaps the mere crossing of Siberia in a sledge drawn by dogs as\nLedyard did, or the taking a long solitary walk on an empty stomach,\nin the negro heart of Africa, which was the sum of poor Mungo's\nperformances--this kind of travel, I say, may not be the very best\nmode of attaining a high social polish.  Still, for the most part,\nthat sort of thing is to be had anywhere.\n\nThese reflections just here are occasioned by the circumstance that\nafter we were all seated at the table, and I was preparing to hear\nsome good stories about whaling; to my no small surprise, nearly\nevery man maintained a profound silence.  And not only that, but they\nlooked embarrassed.  Yes, here were a set of sea-dogs, many of whom\nwithout the slightest bashfulness had boarded great whales on the\nhigh seas--entire strangers to them--and duelled them dead without\nwinking; and yet, here they sat at a social breakfast table--all of\nthe same calling, all of kindred tastes--looking round as sheepishly\nat each other as though they had never been out of sight of some\nsheepfold among the Green Mountains.  A curious sight; these bashful\nbears, these timid warrior whalemen!\n\nBut as for Queequeg--why, Queequeg sat there among them--at the head\nof the table, too, it so chanced; as cool as an icicle.  To be sure I\ncannot say much for his breeding.  His greatest admirer could not\nhave cordially justified his bringing his harpoon into breakfast with\nhim, and using it there without ceremony; reaching over the table\nwith it, to the imminent jeopardy of many heads, and grappling the\nbeefsteaks towards him.  But THAT was certainly very coolly done by\nhim, and every one knows that in most people's estimation, to do\nanything coolly is to do it genteelly.\n\nWe will not speak of all Queequeg's peculiarities here; how he\neschewed coffee and hot rolls, and applied his undivided attention to\nbeefsteaks, done rare.  Enough, that when breakfast was over he\nwithdrew like the rest into the public room, lighted his\ntomahawk-pipe, and was sitting there quietly digesting and smoking\nwith his inseparable hat on, when I sallied out for a stroll.\n\n\n\nCHAPTER 6\n\nThe Street.\n\n\nIf I had been astonished at first catching a glimpse of so outlandish\nan individual as Queequeg circulating among the polite society of a\ncivilized town, that astonishment soon departed upon taking my first\ndaylight stroll through the streets of New Bedford.\n\nIn thoroughfares nigh the docks, any considerable seaport will\nfrequently offer to view the queerest looking nondescripts from\nforeign parts.  Even in Broadway and Chestnut streets, Mediterranean\nmariners will sometimes jostle the affrighted ladies.  Regent Street\nis not unknown to Lascars and Malays; and at Bombay, in the Apollo\nGreen, live Yankees have often scared the natives.  But New Bedford\nbeats all Water Street and Wapping.  In these last-mentioned haunts\nyou see only sailors; but in New Bedford, actual cannibals stand\nchatting at street corners; savages outright; many of whom yet carry\non their bones unholy flesh.  It makes a stranger stare.\n\nBut, besides the Feegeeans, Tongatobooarrs, Erromanggoans,\nPannangians, and Brighggians, and, besides the wild specimens of the\nwhaling-craft which unheeded reel about the streets, you will see\nother sights still more curious, certainly more comical.  There\nweekly arrive in this town scores of green Vermonters and New\nHampshire men, all athirst for gain and glory in the fishery.  They\nare mostly young, of stalwart frames; fellows who have felled\nforests, and now seek to drop the axe and snatch the whale-lance.\nMany are as green as the Green Mountains whence they came.  In some\nthings you would think them but a few hours old.  Look there! that\nchap strutting round the corner.  He wears a beaver hat and\nswallow-tailed coat, girdled with a sailor-belt and sheath-knife.\nHere comes another with a sou'-wester and a bombazine cloak.\n\nNo town-bred dandy will compare with a country-bred one--I mean a\ndownright bumpkin dandy--a fellow that, in the dog-days, will mow his\ntwo acres in buckskin gloves for fear of tanning his hands.  Now when\na country dandy like this takes it into his head to make a\ndistinguished reputation, and joins the great whale-fishery, you\nshould see the comical things he does upon reaching the seaport.  In\nbespeaking his sea-outfit, he orders bell-buttons to his waistcoats;\nstraps to his canvas trowsers.  Ah, poor Hay-Seed! how bitterly will\nburst those straps in the first howling gale, when thou art driven,\nstraps, buttons, and all, down the throat of the tempest.\n\nBut think not that this famous town has only harpooneers, cannibals,\nand bumpkins to show her visitors.  Not at all.  Still New Bedford is\na queer place.  Had it not been for us whalemen, that tract of land\nwould this day perhaps have been in as howling condition as the coast\nof Labrador.  As it is, parts of her back country are enough to\nfrighten one, they look so bony.  The town itself is perhaps the\ndearest place to live in, in all New England.  It is a land of oil,\ntrue enough: but not like Canaan; a land, also, of corn and wine.\nThe streets do not run with milk; nor in the spring-time do they pave\nthem with fresh eggs.  Yet, in spite of this, nowhere in all America\nwill you find more patrician-like houses; parks and gardens more\nopulent, than in New Bedford.  Whence came they? how planted upon\nthis once scraggy scoria of a country?\n\nGo and gaze upon the iron emblematical harpoons round yonder lofty\nmansion, and your question will be answered.  Yes; all these brave\nhouses and flowery gardens came from the Atlantic, Pacific, and\nIndian oceans.  One and all, they were harpooned and dragged up\nhither from the bottom of the sea.  Can Herr Alexander perform a feat\nlike that?\n\nIn New Bedford, fathers, they say, give whales for dowers to their\ndaughters, and portion off their nieces with a few porpoises a-piece.\nYou must go to New Bedford to see a brilliant wedding; for, they\nsay, they have reservoirs of oil in every house, and every night\nrecklessly burn their lengths in spermaceti candles.\n\nIn summer time, the town is sweet to see; full of fine maples--long\navenues of green and gold.  And in August, high in air, the beautiful\nand bountiful horse-chestnuts, candelabra-wise, proffer the passer-by\ntheir tapering upright cones of congregated blossoms.  So omnipotent\nis art; which in many a district of New Bedford has superinduced\nbright terraces of flowers upon the barren refuse rocks thrown aside\nat creation's final day.\n\nAnd the women of New Bedford, they bloom like their own red roses.\nBut roses only bloom in summer; whereas the fine carnation of their\ncheeks is perennial as sunlight in the seventh heavens.  Elsewhere\nmatch that bloom of theirs, ye cannot, save in Salem, where they tell\nme the young girls breathe such musk, their sailor sweethearts smell\nthem miles off shore, as though they were drawing nigh the odorous\nMoluccas instead of the Puritanic sands.\n\n\n\nCHAPTER 7\n\nThe Chapel.\n\n\nIn this same New Bedford there stands a Whaleman's Chapel, and few\nare the moody fishermen, shortly bound for the Indian Ocean or\nPacific, who fail to make a Sunday visit to the spot.  I am sure that\nI did not.\n\nReturning from my first morning stroll, I again sallied out upon this\nspecial errand.  The sky had changed from clear, sunny cold, to\ndriving sleet and mist.  Wrapping myself in my shaggy jacket of the\ncloth called bearskin, I fought my way against the stubborn storm.\nEntering, I found a small scattered congregation of sailors, and\nsailors' wives and widows.  A muffled silence reigned, only broken at\ntimes by the shrieks of the storm.  Each silent worshipper seemed\npurposely sitting apart from the other, as if each silent grief were\ninsular and incommunicable.  The chaplain had not yet arrived; and\nthere these silent islands of men and women sat steadfastly eyeing\nseveral marble tablets, with black borders, masoned into the wall on\neither side the pulpit.  Three of them ran something like the\nfollowing, but I do not pretend to quote:--\n\nSACRED\nTO THE MEMORY\nOF\nJOHN TALBOT,\nWho, at the age of eighteen, was lost overboard,\nNear the Isle of Desolation, off Patagonia,\nNovember 1st, 1836.\nTHIS TABLET\nIs erected to his Memory\nBY HIS\nSISTER.\n_____________\n\nSACRED\nTO THE MEMORY\nOF\nROBERT LONG, WILLIS ELLERY,\nNATHAN COLEMAN, WALTER CANNY, SETH MACY,\nAND SAMUEL GLEIG,\nForming one of the boats' crews\nOF\nTHE SHIP ELIZA\nWho were towed out of sight by a Whale,\nOn the Off-shore Ground in the\nPACIFIC,\nDecember 31st, 1839.\nTHIS MARBLE\nIs here placed by their surviving\nSHIPMATES.\n_____________\n\nSACRED\nTO THE MEMORY\nOF\nThe late\nCAPTAIN EZEKIEL HARDY,\nWho in the bows of his boat was killed by a\nSperm Whale on the coast of Japan,\nAUGUST 3d, 1833.\nTHIS TABLET\nIs erected to his Memory\nBY\nHIS WIDOW.\n\nShaking off the sleet from my ice-glazed hat and jacket, I seated\nmyself near the door, and turning sideways was surprised to see\nQueequeg near me.  Affected by the solemnity of the scene, there was\na wondering gaze of incredulous curiosity in his countenance.  This\nsavage was the only person present who seemed to notice my entrance;\nbecause he was the only one who could not read, and, therefore, was\nnot reading those frigid inscriptions on the wall.  Whether any of\nthe relatives of the seamen whose names appeared there were now among\nthe congregation, I knew not; but so many are the unrecorded\naccidents in the fishery, and so plainly did several women present\nwear the countenance if not the trappings of some unceasing grief,\nthat I feel sure that here before me were assembled those, in whose\nunhealing hearts the sight of those bleak tablets sympathetically\ncaused the old wounds to bleed afresh.\n\nOh! ye whose dead lie buried beneath the green grass; who standing\namong flowers can say--here, HERE lies my beloved; ye know not the\ndesolation that broods in bosoms like these.  What bitter blanks in\nthose black-bordered marbles which cover no ashes!  What despair in\nthose immovable inscriptions!  What deadly voids and unbidden\ninfidelities in the lines that seem to gnaw upon all Faith, and\nrefuse resurrections to the beings who have placelessly perished\nwithout a grave.  As well might those tablets stand in the cave of\nElephanta as here.\n\nIn what census of living creatures, the dead of mankind are included;\nwhy it is that a universal proverb says of them, that they tell no\ntales, though containing more secrets than the Goodwin Sands; how it\nis that to his name who yesterday departed for the other world, we\nprefix so significant and infidel a word, and yet do not thus entitle\nhim, if he but embarks for the remotest Indies of this living earth;\nwhy the Life Insurance Companies pay death-forfeitures upon\nimmortals; in what eternal, unstirring paralysis, and deadly,\nhopeless trance, yet lies antique Adam who died sixty round centuries\nago; how it is that we still refuse to be comforted for those who we\nnevertheless maintain are dwelling in unspeakable bliss; why all the\nliving so strive to hush all the dead; wherefore but the rumor of a\nknocking in a tomb will terrify a whole city.  All these things are\nnot without their meanings.\n\nBut Faith, like a jackal, feeds among the tombs, and even from these\ndead doubts she gathers her most vital hope.\n\nIt needs scarcely to be told, with what feelings, on the eve of a\nNantucket voyage, I regarded those marble tablets, and by the murky\nlight of that darkened, doleful day read the fate of the whalemen who\nhad gone before me.  Yes, Ishmael, the same fate may be thine.  But\nsomehow I grew merry again.  Delightful inducements to embark, fine\nchance for promotion, it seems--aye, a stove boat will make me an\nimmortal by brevet.  Yes, there is death in this business of\nwhaling--a speechlessly quick chaotic bundling of a man into\nEternity.  But what then?  Methinks we have hugely mistaken this\nmatter of Life and Death.  Methinks that what they call my shadow\nhere on earth is my true substance.  Methinks that in looking at\nthings spiritual, we are too much like oysters observing the sun\nthrough the water, and thinking that thick water the thinnest of air.\nMethinks my body is but the lees of my better being.  In fact take\nmy body who will, take it I say, it is not me.  And therefore three\ncheers for Nantucket; and come a stove boat and stove body when they\nwill, for stave my soul, Jove himself cannot.\n\n\n\nCHAPTER 8\n\nThe Pulpit.\n\n\nI had not been seated very long ere a man of a certain venerable\nrobustness entered; immediately as the storm-pelted door flew back\nupon admitting him, a quick regardful eyeing of him by all the\ncongregation, sufficiently attested that this fine old man was the\nchaplain.  Yes, it was the famous Father Mapple, so called by the\nwhalemen, among whom he was a very great favourite.  He had been a\nsailor and a harpooneer in his youth, but for many years past had\ndedicated his life to the ministry.  At the time I now write of,\nFather Mapple was in the hardy winter of a healthy old age; that sort\nof old age which seems merging into a second flowering youth, for\namong all the fissures of his wrinkles, there shone certain mild\ngleams of a newly developing bloom--the spring verdure peeping forth\neven beneath February's snow.  No one having previously heard his\nhistory, could for the first time behold Father Mapple without the\nutmost interest, because there were certain engrafted clerical\npeculiarities about him, imputable to that adventurous maritime life\nhe had led.  When he entered I observed that he carried no umbrella,\nand certainly had not come in his carriage, for his tarpaulin hat ran\ndown with melting sleet, and his great pilot cloth jacket seemed\nalmost to drag him to the floor with the weight of the water it had\nabsorbed.  However, hat and coat and overshoes were one by one\nremoved, and hung up in a little space in an adjacent corner; when,\narrayed in a decent suit, he quietly approached the pulpit.\n\nLike most old fashioned pulpits, it was a very lofty one, and since a\nregular stairs to such a height would, by its long angle with the\nfloor, seriously contract the already small area of the chapel, the\narchitect, it seemed, had acted upon the hint of Father Mapple, and\nfinished the pulpit without a stairs, substituting a perpendicular\nside ladder, like those used in mounting a ship from a boat at sea.\nThe wife of a whaling captain had provided the chapel with a handsome\npair of red worsted man-ropes for this ladder, which, being itself\nnicely headed, and stained with a mahogany colour, the whole\ncontrivance, considering what manner of chapel it was, seemed by no\nmeans in bad taste.  Halting for an instant at the foot of the\nladder, and with both hands grasping the ornamental knobs of the\nman-ropes, Father Mapple cast a look upwards, and then with a truly\nsailor-like but still reverential dexterity, hand over hand, mounted\nthe steps as if ascending the main-top of his vessel.\n\nThe perpendicular parts of this side ladder, as is usually the case\nwith swinging ones, were of cloth-covered rope, only the rounds were\nof wood, so that at every step there was a joint.  At my first\nglimpse of the pulpit, it had not escaped me that however convenient\nfor a ship, these joints in the present instance seemed unnecessary.\nFor I was not prepared to see Father Mapple after gaining the height,\nslowly turn round, and stooping over the pulpit, deliberately drag up\nthe ladder step by step, till the whole was deposited within, leaving\nhim impregnable in his little Quebec.\n\nI pondered some time without fully comprehending the reason for this.\nFather Mapple enjoyed such a wide reputation for sincerity and\nsanctity, that I could not suspect him of courting notoriety by any\nmere tricks of the stage.  No, thought I, there must be some sober\nreason for this thing; furthermore, it must symbolize something\nunseen.  Can it be, then, that by that act of physical isolation, he\nsignifies his spiritual withdrawal for the time, from all outward\nworldly ties and connexions?  Yes, for replenished with the meat and\nwine of the word, to the faithful man of God, this pulpit, I see, is\na self-containing stronghold--a lofty Ehrenbreitstein, with a\nperennial well of water within the walls.\n\nBut the side ladder was not the only strange feature of the place,\nborrowed from the chaplain's former sea-farings.  Between the marble\ncenotaphs on either hand of the pulpit, the wall which formed its\nback was adorned with a large painting representing a gallant ship\nbeating against a terrible storm off a lee coast of black rocks and\nsnowy breakers.  But high above the flying scud and dark-rolling\nclouds, there floated a little isle of sunlight, from which beamed\nforth an angel's face; and this bright face shed a distinct spot of\nradiance upon the ship's tossed deck, something like that silver\nplate now inserted into the Victory's plank where Nelson fell.  \"Ah,\nnoble ship,\" the angel seemed to say, \"beat on, beat on, thou noble\nship, and bear a hardy helm; for lo! the sun is breaking through; the\nclouds are rolling off--serenest azure is at hand.\"\n\nNor was the pulpit itself without a trace of the same sea-taste that\nhad achieved the ladder and the picture.  Its panelled front was in\nthe likeness of a ship's bluff bows, and the Holy Bible rested on a\nprojecting piece of scroll work, fashioned after a ship's\nfiddle-headed beak.\n\nWhat could be more full of meaning?--for the pulpit is ever this\nearth's foremost part; all the rest comes in its rear; the pulpit\nleads the world.  From thence it is the storm of God's quick wrath is\nfirst descried, and the bow must bear the earliest brunt.  From\nthence it is the God of breezes fair or foul is first invoked for\nfavourable winds.  Yes, the world's a ship on its passage out, and not\na voyage complete; and the pulpit is its prow.\n\n\n\nCHAPTER 9\n\nThe Sermon.\n\n\nFather Mapple rose, and in a mild voice of unassuming authority\nordered the scattered people to condense.  \"Starboard gangway,\nthere! side away to larboard--larboard gangway to starboard!\nMidships! midships!\"\n\nThere was a low rumbling of heavy sea-boots among the benches, and a\nstill slighter shuffling of women's shoes, and all was quiet again,\nand every eye on the preacher.\n\nHe paused a little; then kneeling in the pulpit's bows, folded his\nlarge brown hands across his chest, uplifted his closed eyes, and\noffered a prayer so deeply devout that he seemed kneeling and praying\nat the bottom of the sea.\n\nThis ended, in prolonged solemn tones, like the continual tolling of\na bell in a ship that is foundering at sea in a fog--in such tones he\ncommenced reading the following hymn; but changing his manner towards\nthe concluding stanzas, burst forth with a pealing exultation and\njoy--\n\n\"The ribs and terrors in the whale,\nArched over me a dismal gloom,\nWhile all God's sun-lit waves rolled by,\nAnd lift me deepening down to doom.\n\n\"I saw the opening maw of hell,\nWith endless pains and sorrows there;\nWhich none but they that feel can tell--\nOh, I was plunging to despair.\n\n\"In black distress, I called my God,\nWhen I could scarce believe him mine,\nHe bowed his ear to my complaints--\nNo more the whale did me confine.\n\n\"With speed he flew to my relief,\nAs on a radiant dolphin borne;\nAwful, yet bright, as lightning shone\nThe face of my Deliverer God.\n\n\"My song for ever shall record\nThat terrible, that joyful hour;\nI give the glory to my God,\nHis all the mercy and the power.\n\n\nNearly all joined in singing this hymn, which swelled high above the\nhowling of the storm.  A brief pause ensued; the preacher slowly\nturned over the leaves of the Bible, and at last, folding his hand\ndown upon the proper page, said: \"Beloved shipmates, clinch the last\nverse of the first chapter of Jonah--'And God had prepared a great\nfish to swallow up Jonah.'\"\n\n\"Shipmates, this book, containing only four chapters--four yarns--is\none of the smallest strands in the mighty cable of the Scriptures.\nYet what depths of the soul does Jonah's deep sealine sound! what a\npregnant lesson to us is this prophet!  What a noble thing is that\ncanticle in the fish's belly!  How billow-like and boisterously\ngrand!  We feel the floods surging over us; we sound with him to the\nkelpy bottom of the waters; sea-weed and all the slime of the sea is\nabout us!  But WHAT is this lesson that the book of Jonah teaches?\nShipmates, it is a two-stranded lesson; a lesson to us all as sinful\nmen, and a lesson to me as a pilot of the living God.  As sinful men,\nit is a lesson to us all, because it is a story of the sin,\nhard-heartedness, suddenly awakened fears, the swift punishment,\nrepentance, prayers, and finally the deliverance and joy of Jonah.\nAs with all sinners among men, the sin of this son of Amittai was in\nhis wilful disobedience of the command of God--never mind now what\nthat command was, or how conveyed--which he found a hard command.\nBut all the things that God would have us do are hard for us to\ndo--remember that--and hence, he oftener commands us than endeavors\nto persuade.  And if we obey God, we must disobey ourselves; and it\nis in this disobeying ourselves, wherein the hardness of obeying God\nconsists.\n\n\"With this sin of disobedience in him, Jonah still further flouts at\nGod, by seeking to flee from Him.  He thinks that a ship made by men\nwill carry him into countries where God does not reign, but only the\nCaptains of this earth.  He skulks about the wharves of Joppa, and\nseeks a ship that's bound for Tarshish.  There lurks, perhaps, a\nhitherto unheeded meaning here.  By all accounts Tarshish could have\nbeen no other city than the modern Cadiz.  That's the opinion of\nlearned men.  And where is Cadiz, shipmates?  Cadiz is in Spain; as\nfar by water, from Joppa, as Jonah could possibly have sailed in\nthose ancient days, when the Atlantic was an almost unknown sea.\nBecause Joppa, the modern Jaffa, shipmates, is on the most easterly\ncoast of the Mediterranean, the Syrian; and Tarshish or Cadiz more\nthan two thousand miles to the westward from that, just outside the\nStraits of Gibraltar.  See ye not then, shipmates, that Jonah sought\nto flee world-wide from God?  Miserable man!  Oh! most contemptible\nand worthy of all scorn; with slouched hat and guilty eye, skulking\nfrom his God; prowling among the shipping like a vile burglar\nhastening to cross the seas.  So disordered, self-condemning is his\nlook, that had there been policemen in those days, Jonah, on the mere\nsuspicion of something wrong, had been arrested ere he touched a\ndeck.  How plainly he's a fugitive! no baggage, not a hat-box,\nvalise, or carpet-bag,--no friends accompany him to the wharf with\ntheir adieux.  At last, after much dodging search, he finds the\nTarshish ship receiving the last items of her cargo; and as he steps\non board to see its Captain in the cabin, all the sailors for the\nmoment desist from hoisting in the goods, to mark the stranger's evil\neye.  Jonah sees this; but in vain he tries to look all ease and\nconfidence; in vain essays his wretched smile.  Strong intuitions of\nthe man assure the mariners he can be no innocent.  In their gamesome\nbut still serious way, one whispers to the other--\"Jack, he's robbed\na widow;\" or, \"Joe, do you mark him; he's a bigamist;\" or, \"Harry\nlad, I guess he's the adulterer that broke jail in old Gomorrah, or\nbelike, one of the missing murderers from Sodom.\"  Another runs to\nread the bill that's stuck against the spile upon the wharf to which\nthe ship is moored, offering five hundred gold coins for the\napprehension of a parricide, and containing a description of his\nperson.  He reads, and looks from Jonah to the bill; while all his\nsympathetic shipmates now crowd round Jonah, prepared to lay their\nhands upon him.  Frighted Jonah trembles, and summoning all his\nboldness to his face, only looks so much the more a coward.  He will\nnot confess himself suspected; but that itself is strong suspicion.\nSo he makes the best of it; and when the sailors find him not to be\nthe man that is advertised, they let him pass, and he descends into\nthe cabin.\n\n\"'Who's there?' cries the Captain at his busy desk, hurriedly making\nout his papers for the Customs--'Who's there?'  Oh! how that harmless\nquestion mangles Jonah!  For the instant he almost turns to flee\nagain.  But he rallies.  'I seek a passage in this ship to Tarshish;\nhow soon sail ye, sir?'  Thus far the busy Captain had not looked up\nto Jonah, though the man now stands before him; but no sooner does he\nhear that hollow voice, than he darts a scrutinizing glance.  'We\nsail with the next coming tide,' at last he slowly answered, still\nintently eyeing him.  'No sooner, sir?'--'Soon enough for any honest\nman that goes a passenger.'  Ha!  Jonah, that's another stab.  But he\nswiftly calls away the Captain from that scent.  'I'll sail with\nye,'--he says,--'the passage money how much is that?--I'll pay now.'\nFor it is particularly written, shipmates, as if it were a thing not\nto be overlooked in this history, 'that he paid the fare thereof' ere\nthe craft did sail.  And taken with the context, this is full of\nmeaning.\n\n\"Now Jonah's Captain, shipmates, was one whose discernment detects\ncrime in any, but whose cupidity exposes it only in the penniless.\nIn this world, shipmates, sin that pays its way can travel freely,\nand without a passport; whereas Virtue, if a pauper, is stopped at\nall frontiers.  So Jonah's Captain prepares to test the length of\nJonah's purse, ere he judge him openly.  He charges him thrice the\nusual sum; and it's assented to.  Then the Captain knows that Jonah\nis a fugitive; but at the same time resolves to help a flight that\npaves its rear with gold.  Yet when Jonah fairly takes out his purse,\nprudent suspicions still molest the Captain.  He rings every coin to\nfind a counterfeit.  Not a forger, any way, he mutters; and Jonah is\nput down for his passage.  'Point out my state-room, Sir,' says Jonah\nnow, 'I'm travel-weary; I need sleep.'  'Thou lookest like it,' says\nthe Captain, 'there's thy room.'  Jonah enters, and would lock the\ndoor, but the lock contains no key.  Hearing him foolishly fumbling\nthere, the Captain laughs lowly to himself, and mutters something\nabout the doors of convicts' cells being never allowed to be locked\nwithin.  All dressed and dusty as he is, Jonah throws himself into\nhis berth, and finds the little state-room ceiling almost resting on\nhis forehead.  The air is close, and Jonah gasps.  Then, in that\ncontracted hole, sunk, too, beneath the ship's water-line, Jonah\nfeels the heralding presentiment of that stifling hour, when the\nwhale shall hold him in the smallest of his bowels' wards.\n\n\"Screwed at its axis against the side, a swinging lamp slightly\noscillates in Jonah's room; and the ship, heeling over towards the\nwharf with the weight of the last bales received, the lamp, flame and\nall, though in slight motion, still maintains a permanent obliquity\nwith reference to the room; though, in truth, infallibly straight\nitself, it but made obvious the false, lying levels among which it\nhung.  The lamp alarms and frightens Jonah; as lying in his berth his\ntormented eyes roll round the place, and this thus far successful\nfugitive finds no refuge for his restless glance.  But that\ncontradiction in the lamp more and more appals him.  The floor, the\nceiling, and the side, are all awry.  'Oh! so my conscience hangs in\nme!' he groans, 'straight upwards, so it burns; but the chambers of\nmy soul are all in crookedness!'\n\n\"Like one who after a night of drunken revelry hies to his bed, still\nreeling, but with conscience yet pricking him, as the plungings of\nthe Roman race-horse but so much the more strike his steel tags into\nhim; as one who in that miserable plight still turns and turns in\ngiddy anguish, praying God for annihilation until the fit be passed;\nand at last amid the whirl of woe he feels, a deep stupor steals over\nhim, as over the man who bleeds to death, for conscience is the\nwound, and there's naught to staunch it; so, after sore wrestlings in\nhis berth, Jonah's prodigy of ponderous misery drags him drowning\ndown to sleep.\n\n\"And now the time of tide has come; the ship casts off her cables;\nand from the deserted wharf the uncheered ship for Tarshish, all\ncareening, glides to sea.  That ship, my friends, was the first of\nrecorded smugglers! the contraband was Jonah.  But the sea rebels; he\nwill not bear the wicked burden.  A dreadful storm comes on, the\nship is like to break.  But now when the boatswain calls all hands to\nlighten her; when boxes, bales, and jars are clattering overboard;\nwhen the wind is shrieking, and the men are yelling, and every plank\nthunders with trampling feet right over Jonah's head; in all this\nraging tumult, Jonah sleeps his hideous sleep.  He sees no black sky\nand raging sea, feels not the reeling timbers, and little hears he or\nheeds he the far rush of the mighty whale, which even now with open\nmouth is cleaving the seas after him.  Aye, shipmates, Jonah was gone\ndown into the sides of the ship--a berth in the cabin as I have taken\nit, and was fast asleep.  But the frightened master comes to him, and\nshrieks in his dead ear, 'What meanest thou, O, sleeper! arise!'\nStartled from his lethargy by that direful cry, Jonah staggers to his\nfeet, and stumbling to the deck, grasps a shroud, to look out upon\nthe sea.  But at that moment he is sprung upon by a panther billow\nleaping over the bulwarks.  Wave after wave thus leaps into the ship,\nand finding no speedy vent runs roaring fore and aft, till the\nmariners come nigh to drowning while yet afloat.  And ever, as the\nwhite moon shows her affrighted face from the steep gullies in the\nblackness overhead, aghast Jonah sees the rearing bowsprit pointing\nhigh upward, but soon beat downward again towards the tormented deep.\n\n\"Terrors upon terrors run shouting through his soul.  In all his\ncringing attitudes, the God-fugitive is now too plainly known.  The\nsailors mark him; more and more certain grow their suspicions of him,\nand at last, fully to test the truth, by referring the whole matter\nto high Heaven, they fall to casting lots, to see for whose\ncause this great tempest was upon them.  The lot is Jonah's; that\ndiscovered, then how furiously they mob him with their questions.\n'What is thine occupation?  Whence comest thou?  Thy country?  What\npeople?  But mark now, my shipmates, the behavior of poor Jonah.  The\neager mariners but ask him who he is, and where from; whereas, they\nnot only receive an answer to those questions, but likewise another\nanswer to a question not put by them, but the unsolicited answer is\nforced from Jonah by the hard hand of God that is upon him.\n\n\"'I am a Hebrew,' he cries--and then--'I fear the Lord the God of\nHeaven who hath made the sea and the dry land!'  Fear him, O Jonah?\nAye, well mightest thou fear the Lord God THEN!  Straightway, he now\ngoes on to make a full confession; whereupon the mariners became more\nand more appalled, but still are pitiful.  For when Jonah, not yet\nsupplicating God for mercy, since he but too well knew the darkness\nof his deserts,--when wretched Jonah cries out to them to take him\nand cast him forth into the sea, for he knew that for HIS sake this\ngreat tempest was upon them; they mercifully turn from him, and seek\nby other means to save the ship.  But all in vain; the indignant gale\nhowls louder; then, with one hand raised invokingly to God, with the\nother they not unreluctantly lay hold of Jonah.\n\n\"And now behold Jonah taken up as an anchor and dropped into the sea;\nwhen instantly an oily calmness floats out from the east, and the sea\nis still, as Jonah carries down the gale with him, leaving smooth\nwater behind.  He goes down in the whirling heart of such a\nmasterless commotion that he scarce heeds the moment when he drops\nseething into the yawning jaws awaiting him; and the whale shoots-to\nall his ivory teeth, like so many white bolts, upon his prison.  Then\nJonah prayed unto the Lord out of the fish's belly.  But observe his\nprayer, and learn a weighty lesson.  For sinful as he is, Jonah does\nnot weep and wail for direct deliverance.  He feels that his dreadful\npunishment is just.  He leaves all his deliverance to God, contenting\nhimself with this, that spite of all his pains and pangs, he will\nstill look towards His holy temple.  And here, shipmates, is true and\nfaithful repentance; not clamorous for pardon, but grateful for\npunishment.  And how pleasing to God was this conduct in Jonah, is\nshown in the eventual deliverance of him from the sea and the whale.\nShipmates, I do not place Jonah before you to be copied for his sin\nbut I do place him before you as a model for repentance.  Sin not;\nbut if you do, take heed to repent of it like Jonah.\"\n\nWhile he was speaking these words, the howling of the shrieking,\nslanting storm without seemed to add new power to the preacher, who,\nwhen describing Jonah's sea-storm, seemed tossed by a storm himself.\nHis deep chest heaved as with a ground-swell; his tossed arms seemed\nthe warring elements at work; and the thunders that rolled away from\noff his swarthy brow, and the light leaping from his eye, made all\nhis simple hearers look on him with a quick fear that was strange to\nthem.\n\nThere now came a lull in his look, as he silently turned over the\nleaves of the Book once more; and, at last, standing motionless, with\nclosed eyes, for the moment, seemed communing with God and himself.\n\nBut again he leaned over towards the people, and bowing his head\nlowly, with an aspect of the deepest yet manliest humility, he spake\nthese words:\n\n\"Shipmates, God has laid but one hand upon you; both his hands press\nupon me.  I have read ye by what murky light may be mine the lesson\nthat Jonah teaches to all sinners; and therefore to ye, and still\nmore to me, for I am a greater sinner than ye.  And now how gladly\nwould I come down from this mast-head and sit on the hatches there\nwhere you sit, and listen as you listen, while some one of you reads\nME that other and more awful lesson which Jonah teaches to ME, as a\npilot of the living God.  How being an anointed pilot-prophet, or\nspeaker of true things, and bidden by the Lord to sound those\nunwelcome truths in the ears of a wicked Nineveh, Jonah, appalled at\nthe hostility he should raise, fled from his mission, and sought to\nescape his duty and his God by taking ship at Joppa.  But God is\neverywhere; Tarshish he never reached.  As we have seen, God came\nupon him in the whale, and swallowed him down to living gulfs of\ndoom, and with swift slantings tore him along 'into the midst of the\nseas,' where the eddying depths sucked him ten thousand fathoms down,\nand 'the weeds were wrapped about his head,' and all the watery world\nof woe bowled over him.  Yet even then beyond the reach of any\nplummet--'out of the belly of hell'--when the whale grounded upon the\nocean's utmost bones, even then, God heard the engulphed, repenting\nprophet when he cried.  Then God spake unto the fish; and from the\nshuddering cold and blackness of the sea, the whale came breeching up\ntowards the warm and pleasant sun, and all the delights of air and\nearth; and 'vomited out Jonah upon the dry land;' when the word of\nthe Lord came a second time; and Jonah, bruised and beaten--his ears,\nlike two sea-shells, still multitudinously murmuring of the\nocean--Jonah did the Almighty's bidding.  And what was that,\nshipmates?  To preach the Truth to the face of Falsehood!  That was\nit!\n\n\"This, shipmates, this is that other lesson; and woe to that pilot of\nthe living God who slights it.  Woe to him whom this world charms\nfrom Gospel duty!  Woe to him who seeks to pour oil upon the waters\nwhen God has brewed them into a gale!  Woe to him who seeks to please\nrather than to appal!  Woe to him whose good name is more to him than\ngoodness!  Woe to him who, in this world, courts not dishonour!  Woe\nto him who would not be true, even though to be false were salvation!\nYea, woe to him who, as the great Pilot Paul has it, while preaching\nto others is himself a castaway!\"\n\nHe dropped and fell away from himself for a moment; then lifting his\nface to them again, showed a deep joy in his eyes, as he cried out\nwith a heavenly enthusiasm,--\"But oh! shipmates! on the starboard\nhand of every woe, there is a sure delight; and higher the top of\nthat delight, than the bottom of the woe is deep.  Is not the\nmain-truck higher than the kelson is low?  Delight is to him--a far,\nfar upward, and inward delight--who against the proud gods and\ncommodores of this earth, ever stands forth his own inexorable self.\nDelight is to him whose strong arms yet support him, when the ship of\nthis base treacherous world has gone down beneath him.  Delight is to\nhim, who gives no quarter in the truth, and kills, burns, and\ndestroys all sin though he pluck it out from under the robes of\nSenators and Judges.  Delight,--top-gallant delight is to him, who\nacknowledges no law or lord, but the Lord his God, and is only a\npatriot to heaven.  Delight is to him, whom all the waves of the\nbillows of the seas of the boisterous mob can never shake from this\nsure Keel of the Ages.  And eternal delight and deliciousness will be\nhis, who coming to lay him down, can say with his final breath--O\nFather!--chiefly known to me by Thy rod--mortal or immortal, here I\ndie.  I have striven to be Thine, more than to be this world's, or\nmine own.  Yet this is nothing: I leave eternity to Thee; for what\nis man that he should live out the lifetime of his God?\"\n\nHe said no more, but slowly waving a benediction, covered his face\nwith his hands, and so remained kneeling, till all the people had\ndeparted, and he was left alone in the place.\n\n\n\nCHAPTER 10\n\nA Bosom Friend.\n\n\nReturning to the Spouter-Inn from the Chapel, I found Queequeg there\nquite alone; he having left the Chapel before the benediction some\ntime.  He was sitting on a bench before the fire, with his feet on\nthe stove hearth, and in one hand was holding close up to his face\nthat little negro idol of his; peering hard into its face, and with a\njack-knife gently whittling away at its nose, meanwhile humming to\nhimself in his heathenish way.\n\nBut being now interrupted, he put up the image; and pretty soon,\ngoing to the table, took up a large book there, and placing it on his\nlap began counting the pages with deliberate regularity; at every\nfiftieth page--as I fancied--stopping a moment, looking vacantly\naround him, and giving utterance to a long-drawn gurgling whistle of\nastonishment.  He would then begin again at the next fifty; seeming\nto commence at number one each time, as though he could not count\nmore than fifty, and it was only by such a large number of fifties\nbeing found together, that his astonishment at the multitude of pages\nwas excited.\n\nWith much interest I sat watching him.  Savage though he was, and\nhideously marred about the face--at least to my taste--his\ncountenance yet had a something in it which was by no means\ndisagreeable.  You cannot hide the soul.  Through all his unearthly\ntattooings, I thought I saw the traces of a simple honest heart; and\nin his large, deep eyes, fiery black and bold, there seemed tokens of\na spirit that would dare a thousand devils.  And besides all this,\nthere was a certain lofty bearing about the Pagan, which even his\nuncouthness could not altogether maim.  He looked like a man who had\nnever cringed and never had had a creditor.  Whether it was, too,\nthat his head being shaved, his forehead was drawn out in freer and\nbrighter relief, and looked more expansive than it otherwise would,\nthis I will not venture to decide; but certain it was his head was\nphrenologically an excellent one.  It may seem ridiculous, but it\nreminded me of General Washington's head, as seen in the popular\nbusts of him.  It had the same long regularly graded retreating slope\nfrom above the brows, which were likewise very projecting, like two\nlong promontories thickly wooded on top.  Queequeg was George\nWashington cannibalistically developed.\n\nWhilst I was thus closely scanning him, half-pretending meanwhile to\nbe looking out at the storm from the casement, he never heeded my\npresence, never troubled himself with so much as a single glance; but\nappeared wholly occupied with counting the pages of the marvellous\nbook.  Considering how sociably we had been sleeping together the\nnight previous, and especially considering the affectionate arm I had\nfound thrown over me upon waking in the morning, I thought this\nindifference of his very strange.  But savages are strange beings; at\ntimes you do not know exactly how to take them.  At first they are\noverawing; their calm self-collectedness of simplicity seems a\nSocratic wisdom.  I had noticed also that Queequeg never consorted at\nall, or but very little, with the other seamen in the inn.  He made\nno advances whatever; appeared to have no desire to enlarge the\ncircle of his acquaintances.  All this struck me as mighty singular;\nyet, upon second thoughts, there was something almost sublime in it.\nHere was a man some twenty thousand miles from home, by the way of\nCape Horn, that is--which was the only way he could get there--thrown\namong people as strange to him as though he were in the planet\nJupiter; and yet he seemed entirely at his ease; preserving the\nutmost serenity; content with his own companionship; always equal to\nhimself.  Surely this was a touch of fine philosophy; though no doubt\nhe had never heard there was such a thing as that.  But, perhaps, to\nbe true philosophers, we mortals should not be conscious of so living\nor so striving.  So soon as I hear that such or such a man gives\nhimself out for a philosopher, I conclude that, like the dyspeptic\nold woman, he must have \"broken his digester.\"\n\nAs I sat there in that now lonely room; the fire burning low, in that\nmild stage when, after its first intensity has warmed the air, it\nthen only glows to be looked at; the evening shades and phantoms\ngathering round the casements, and peering in upon us silent,\nsolitary twain; the storm booming without in solemn swells; I began\nto be sensible of strange feelings.  I felt a melting in me.  No more\nmy splintered heart and maddened hand were turned against the wolfish\nworld.  This soothing savage had redeemed it.  There he sat, his very\nindifference speaking a nature in which there lurked no civilized\nhypocrisies and bland deceits.  Wild he was; a very sight of sights\nto see; yet I began to feel myself mysteriously drawn towards him.\nAnd those same things that would have repelled most others, they were\nthe very magnets that thus drew me.  I'll try a pagan friend, thought\nI, since Christian kindness has proved but hollow courtesy.  I drew\nmy bench near him, and made some friendly signs and hints, doing my\nbest to talk with him meanwhile.  At first he little noticed these\nadvances; but presently, upon my referring to his last night's\nhospitalities, he made out to ask me whether we were again to be\nbedfellows.  I told him yes; whereat I thought he looked pleased,\nperhaps a little complimented.\n\nWe then turned over the book together, and I endeavored to explain to\nhim the purpose of the printing, and the meaning of the few pictures\nthat were in it.  Thus I soon engaged his interest; and from that we\nwent to jabbering the best we could about the various outer sights to\nbe seen in this famous town.  Soon I proposed a social smoke; and,\nproducing his pouch and tomahawk, he quietly offered me a puff.  And\nthen we sat exchanging puffs from that wild pipe of his, and keeping\nit regularly passing between us.\n\nIf there yet lurked any ice of indifference towards me in the Pagan's\nbreast, this pleasant, genial smoke we had, soon thawed it out, and\nleft us cronies.  He seemed to take to me quite as naturally and\nunbiddenly as I to him; and when our smoke was over, he pressed his\nforehead against mine, clasped me round the waist, and said that\nhenceforth we were married; meaning, in his country's phrase, that we\nwere bosom friends; he would gladly die for me, if need should be.\nIn a countryman, this sudden flame of friendship would have seemed\nfar too premature, a thing to be much distrusted; but in this simple\nsavage those old rules would not apply.\n\nAfter supper, and another social chat and smoke, we went to our room\ntogether.  He made me a present of his embalmed head; took out his\nenormous tobacco wallet, and groping under the tobacco, drew out some\nthirty dollars in silver; then spreading them on the table, and\nmechanically dividing them into two equal portions, pushed one of\nthem towards me, and said it was mine.  I was going to remonstrate;\nbut he silenced me by pouring them into my trowsers' pockets.  I let\nthem stay.  He then went about his evening prayers, took out his\nidol, and removed the paper fireboard.  By certain signs and\nsymptoms, I thought he seemed anxious for me to join him; but well\nknowing what was to follow, I deliberated a moment whether, in case\nhe invited me, I would comply or otherwise.\n\nI was a good Christian; born and bred in the bosom of the infallible\nPresbyterian Church.  How then could I unite with this wild idolator\nin worshipping his piece of wood?  But what is worship? thought I.\nDo you suppose now, Ishmael, that the magnanimous God of heaven and\nearth--pagans and all included--can possibly be jealous of an\ninsignificant bit of black wood?  Impossible!  But what is\nworship?--to do the will of God--THAT is worship.  And what is the\nwill of God?--to do to my fellow man what I would have my fellow man\nto do to me--THAT is the will of God.  Now, Queequeg is my fellow\nman.  And what do I wish that this Queequeg would do to me?  Why,\nunite with me in my particular Presbyterian form of worship.\nConsequently, I must then unite with him in his; ergo, I must turn\nidolator.  So I kindled the shavings; helped prop up the innocent\nlittle idol; offered him burnt biscuit with Queequeg; salamed before\nhim twice or thrice; kissed his nose; and that done, we undressed and\nwent to bed, at peace with our own consciences and all the world.\nBut we did not go to sleep without some little chat.\n\nHow it is I know not; but there is no place like a bed for\nconfidential disclosures between friends.  Man and wife, they say,\nthere open the very bottom of their souls to each other; and some old\ncouples often lie and chat over old times till nearly morning.  Thus,\nthen, in our hearts' honeymoon, lay I and Queequeg--a cosy, loving\npair.\n\n\n\nCHAPTER 11\n\nNightgown.\n\n\nWe had lain thus in bed, chatting and napping at short intervals, and\nQueequeg now and then affectionately throwing his brown tattooed legs\nover mine, and then drawing them back; so entirely sociable and free\nand easy were we; when, at last, by reason of our confabulations,\nwhat little nappishness remained in us altogether departed, and we\nfelt like getting up again, though day-break was yet some way down\nthe future.\n\nYes, we became very wakeful; so much so that our recumbent position\nbegan to grow wearisome, and by little and little we found ourselves\nsitting up; the clothes well tucked around us, leaning against the\nhead-board with our four knees drawn up close together, and our two\nnoses bending over them, as if our kneepans were warming-pans.  We\nfelt very nice and snug, the more so since it was so chilly out of\ndoors; indeed out of bed-clothes too, seeing that there was no fire\nin the room.  The more so, I say, because truly to enjoy bodily\nwarmth, some small part of you must be cold, for there is no quality\nin this world that is not what it is merely by contrast.  Nothing\nexists in itself.  If you flatter yourself that you are all over\ncomfortable, and have been so a long time, then you cannot be said to\nbe comfortable any more.  But if, like Queequeg and me in the bed,\nthe tip of your nose or the crown of your head be slightly chilled,\nwhy then, indeed, in the general consciousness you feel most\ndelightfully and unmistakably warm.  For this reason a sleeping\napartment should never be furnished with a fire, which is one of the\nluxurious discomforts of the rich.  For the height of this sort of\ndeliciousness is to have nothing but the blanket between you and\nyour snugness and the cold of the outer air.  Then there you lie like\nthe one warm spark in the heart of an arctic crystal.\n\nWe had been sitting in this crouching manner for some time, when all\nat once I thought I would open my eyes; for when between sheets,\nwhether by day or by night, and whether asleep or awake, I have a way\nof always keeping my eyes shut, in order the more to concentrate the\nsnugness of being in bed.  Because no man can ever feel his own\nidentity aright except his eyes be closed; as if darkness were\nindeed the proper element of our essences, though light be more\ncongenial to our clayey part.  Upon opening my eyes then, and coming\nout of my own pleasant and self-created darkness into the imposed and\ncoarse outer gloom of the unilluminated twelve-o'clock-at-night, I\nexperienced a disagreeable revulsion.  Nor did I at all object to the\nhint from Queequeg that perhaps it were best to strike a light,\nseeing that we were so wide awake; and besides he felt a strong\ndesire to have a few quiet puffs from his Tomahawk.  Be it said, that\nthough I had felt such a strong repugnance to his smoking in the bed\nthe night before, yet see how elastic our stiff prejudices grow when\nlove once comes to bend them.  For now I liked nothing better than\nto have Queequeg smoking by me, even in bed, because he seemed to be\nfull of such serene household joy then.  I no more felt unduly\nconcerned for the landlord's policy of insurance.  I was only alive\nto the condensed confidential comfortableness of sharing a pipe and a\nblanket with a real friend.  With our shaggy jackets drawn about our\nshoulders, we now passed the Tomahawk from one to the other, till\nslowly there grew over us a blue hanging tester of smoke, illuminated\nby the flame of the new-lit lamp.\n\nWhether it was that this undulating tester rolled the savage away to\nfar distant scenes, I know not, but he now spoke of his native\nisland; and, eager to hear his history, I begged him to go on and\ntell it.  He gladly complied.  Though at the time I but ill\ncomprehended not a few of his words, yet subsequent disclosures, when\nI had become more familiar with his broken phraseology, now enable me\nto present the whole story such as it may prove in the mere skeleton\nI give.\n\n\n\nCHAPTER 12\n\nBiographical.\n\n\nQueequeg was a native of Rokovoko, an island far away to the West\nand South.  It is not down in any map; true places never are.\n\nWhen a new-hatched savage running wild about his native woodlands in\na grass clout, followed by the nibbling goats, as if he were a green\nsapling; even then, in Queequeg's ambitious soul, lurked a strong\ndesire to see something more of Christendom than a specimen whaler or\ntwo.  His father was a High Chief, a King; his uncle a High Priest;\nand on the maternal side he boasted aunts who were the wives of\nunconquerable warriors.  There was excellent blood in his\nveins--royal stuff; though sadly vitiated, I fear, by the cannibal\npropensity he nourished in his untutored youth.\n\nA Sag Harbor ship visited his father's bay, and Queequeg sought a\npassage to Christian lands.  But the ship, having her full complement\nof seamen, spurned his suit; and not all the King his father's\ninfluence could prevail.  But Queequeg vowed a vow.  Alone in his\ncanoe, he paddled off to a distant strait, which he knew the ship\nmust pass through when she quitted the island.  On one side was a\ncoral reef; on the other a low tongue of land, covered with mangrove\nthickets that grew out into the water.  Hiding his canoe, still\nafloat, among these thickets, with its prow seaward, he sat down in\nthe stern, paddle low in hand; and when the ship was gliding by, like\na flash he darted out; gained her side; with one backward dash of his\nfoot capsized and sank his canoe; climbed up the chains; and throwing\nhimself at full length upon the deck, grappled a ring-bolt there, and\nswore not to let it go, though hacked in pieces.\n\nIn vain the captain threatened to throw him overboard; suspended a\ncutlass over his naked wrists; Queequeg was the son of a King, and\nQueequeg budged not.  Struck by his desperate dauntlessness, and his\nwild desire to visit Christendom, the captain at last relented, and\ntold him he might make himself at home.  But this fine young\nsavage--this sea Prince of Wales, never saw the Captain's cabin.\nThey put him down among the sailors, and made a whaleman of him.  But\nlike Czar Peter content to toil in the shipyards of foreign cities,\nQueequeg disdained no seeming ignominy, if thereby he might happily\ngain the power of enlightening his untutored countrymen.  For at\nbottom--so he told me--he was actuated by a profound desire to learn\namong the Christians, the arts whereby to make his people still\nhappier than they were; and more than that, still better than they\nwere.  But, alas! the practices of whalemen soon convinced him that\neven Christians could be both miserable and wicked; infinitely more\nso, than all his father's heathens.  Arrived at last in old Sag\nHarbor; and seeing what the sailors did there; and then going on to\nNantucket, and seeing how they spent their wages in that place also,\npoor Queequeg gave it up for lost.  Thought he, it's a wicked world\nin all meridians; I'll die a pagan.\n\nAnd thus an old idolator at heart, he yet lived among these\nChristians, wore their clothes, and tried to talk their gibberish.\nHence the queer ways about him, though now some time from home.\n\nBy hints, I asked him whether he did not propose going back, and\nhaving a coronation; since he might now consider his father dead and\ngone, he being very old and feeble at the last accounts.  He answered\nno, not yet; and added that he was fearful Christianity, or rather\nChristians, had unfitted him for ascending the pure and undefiled\nthrone of thirty pagan Kings before him.  But by and by, he said, he\nwould return,--as soon as he felt himself baptized again.  For the\nnonce, however, he proposed to sail about, and sow his wild oats in\nall four oceans.  They had made a harpooneer of him, and that barbed\niron was in lieu of a sceptre now.\n\nI asked him what might be his immediate purpose, touching his future\nmovements.  He answered, to go to sea again, in his old vocation.\nUpon this, I told him that whaling was my own design, and informed\nhim of my intention to sail out of Nantucket, as being the most\npromising port for an adventurous whaleman to embark from.  He at\nonce resolved to accompany me to that island, ship aboard the same\nvessel, get into the same watch, the same boat, the same mess with\nme, in short to share my every hap; with both my hands in his, boldly\ndip into the Potluck of both worlds.  To all this I joyously\nassented; for besides the affection I now felt for Queequeg, he was\nan experienced harpooneer, and as such, could not fail to be of great\nusefulness to one, who, like me, was wholly ignorant of the mysteries\nof whaling, though well acquainted with the sea, as known to merchant\nseamen.\n\nHis story being ended with his pipe's last dying puff, Queequeg\nembraced me, pressed his forehead against mine, and blowing out the\nlight, we rolled over from each other, this way and that, and very\nsoon were sleeping.\n\n\nCHAPTER 13\n\nWheelbarrow.\n\n\nNext morning, Monday, after disposing of the embalmed head to a\nbarber, for a block, I settled my own and comrade's bill; using,\nhowever, my comrade's money.  The grinning landlord, as well as the\nboarders, seemed amazingly tickled at the sudden friendship which had\nsprung up between me and Queequeg--especially as Peter Coffin's cock\nand bull stories about him had previously so much alarmed me\nconcerning the very person whom I now companied with.\n\nWe borrowed a wheelbarrow, and embarking our things, including my own\npoor carpet-bag, and Queequeg's canvas sack and hammock, away we went\ndown to \"the Moss,\" the little Nantucket packet schooner moored at\nthe wharf.  As we were going along the people stared; not at Queequeg\nso much--for they were used to seeing cannibals like him in their\nstreets,--but at seeing him and me upon such confidential terms.  But\nwe heeded them not, going along wheeling the barrow by turns, and\nQueequeg now and then stopping to adjust the sheath on his harpoon\nbarbs.  I asked him why he carried such a troublesome thing with him\nashore, and whether all whaling ships did not find their own\nharpoons.  To this, in substance, he replied, that though what I\nhinted was true enough, yet he had a particular affection for his own\nharpoon, because it was of assured stuff, well tried in many a mortal\ncombat, and deeply intimate with the hearts of whales.  In short,\nlike many inland reapers and mowers, who go into the farmers' meadows\narmed with their own scythes--though in no wise obliged to furnish\nthem--even so, Queequeg, for his own private reasons, preferred his\nown harpoon.\n\nShifting the barrow from my hand to his, he told me a funny story\nabout the first wheelbarrow he had ever seen.  It was in Sag Harbor.\nThe owners of his ship, it seems, had lent him one, in which to carry\nhis heavy chest to his boarding house.  Not to seem ignorant about\nthe thing--though in truth he was entirely so, concerning the precise\nway in which to manage the barrow--Queequeg puts his chest upon it;\nlashes it fast; and then shoulders the barrow and marches up the\nwharf.  \"Why,\" said I, \"Queequeg, you might have known better than\nthat, one would think.  Didn't the people laugh?\"\n\nUpon this, he told me another story.  The people of his island of\nRokovoko, it seems, at their wedding feasts express the fragrant\nwater of young cocoanuts into a large stained calabash like a\npunchbowl; and this punchbowl always forms the great central ornament\non the braided mat where the feast is held.  Now a certain grand\nmerchant ship once touched at Rokovoko, and its commander--from all\naccounts, a very stately punctilious gentleman, at least for a sea\ncaptain--this commander was invited to the wedding feast of\nQueequeg's sister, a pretty young princess just turned of ten.  Well;\nwhen all the wedding guests were assembled at the bride's bamboo\ncottage, this Captain marches in, and being assigned the post of\nhonour, placed himself over against the punchbowl, and between the\nHigh Priest and his majesty the King, Queequeg's father.  Grace being\nsaid,--for those people have their grace as well as we--though\nQueequeg told me that unlike us, who at such times look downwards to\nour platters, they, on the contrary, copying the ducks, glance\nupwards to the great Giver of all feasts--Grace, I say, being said,\nthe High Priest opens the banquet by the immemorial ceremony of the\nisland; that is, dipping his consecrated and consecrating fingers\ninto the bowl before the blessed beverage circulates.  Seeing himself\nplaced next the Priest, and noting the ceremony, and thinking\nhimself--being Captain of a ship--as having plain precedence over a\nmere island King, especially in the King's own house--the Captain\ncoolly proceeds to wash his hands in the punchbowl;--taking it I\nsuppose for a huge finger-glass.  \"Now,\" said Queequeg, \"what you\ntink now?--Didn't our people laugh?\"\n\nAt last, passage paid, and luggage safe, we stood on board the\nschooner.  Hoisting sail, it glided down the Acushnet river.  On one\nside, New Bedford rose in terraces of streets, their ice-covered\ntrees all glittering in the clear, cold air.  Huge hills and\nmountains of casks on casks were piled upon her wharves, and side by\nside the world-wandering whale ships lay silent and safely moored at\nlast; while from others came a sound of carpenters and coopers, with\nblended noises of fires and forges to melt the pitch, all betokening\nthat new cruises were on the start; that one most perilous and long\nvoyage ended, only begins a second; and a second ended, only begins a\nthird, and so on, for ever and for aye.  Such is the endlessness,\nyea, the intolerableness of all earthly effort.\n\nGaining the more open water, the bracing breeze waxed fresh; the\nlittle Moss tossed the quick foam from her bows, as a young colt his\nsnortings.  How I snuffed that Tartar air!--how I spurned that\nturnpike earth!--that common highway all over dented with the marks\nof slavish heels and hoofs; and turned me to admire the magnanimity\nof the sea which will permit no records.\n\nAt the same foam-fountain, Queequeg seemed to drink and reel with me.\nHis dusky nostrils swelled apart; he showed his filed and pointed\nteeth.  On, on we flew; and our offing gained, the Moss did homage to\nthe blast; ducked and dived her bows as a slave before the Sultan.\nSideways leaning, we sideways darted; every ropeyarn tingling like a\nwire; the two tall masts buckling like Indian canes in land\ntornadoes.  So full of this reeling scene were we, as we stood by the\nplunging bowsprit, that for some time we did not notice the jeering\nglances of the passengers, a lubber-like assembly, who marvelled that\ntwo fellow beings should be so companionable; as though a white man\nwere anything more dignified than a whitewashed negro.  But there\nwere some boobies and bumpkins there, who, by their intense\ngreenness, must have come from the heart and centre of all verdure.\nQueequeg caught one of these young saplings mimicking him behind his\nback.  I thought the bumpkin's hour of doom was come.  Dropping his\nharpoon, the brawny savage caught him in his arms, and by an almost\nmiraculous dexterity and strength, sent him high up bodily into the\nair; then slightly tapping his stern in mid-somerset, the fellow\nlanded with bursting lungs upon his feet, while Queequeg, turning his\nback upon him, lighted his tomahawk pipe and passed it to me for a\npuff.\n\n\"Capting!  Capting! yelled the bumpkin, running towards that officer;\n\"Capting, Capting, here's the devil.\"\n\n\"Hallo, YOU sir,\" cried the Captain, a gaunt rib of the sea, stalking\nup to Queequeg, \"what in thunder do you mean by that?  Don't you know\nyou might have killed that chap?\"\n\n\"What him say?\" said Queequeg, as he mildly turned to me.\n\n\"He say,\" said I, \"that you came near kill-e that man there,\"\npointing to the still shivering greenhorn.\n\n\"Kill-e,\" cried Queequeg, twisting his tattooed face into an\nunearthly expression of disdain, \"ah! him bevy small-e fish-e;\nQueequeg no kill-e so small-e fish-e; Queequeg kill-e big whale!\"\n\n\"Look you,\" roared the Captain, \"I'll kill-e YOU, you cannibal, if\nyou try any more of your tricks aboard here; so mind your eye.\"\n\nBut it so happened just then, that it was high time for the Captain\nto mind his own eye.  The prodigious strain upon the main-sail had\nparted the weather-sheet, and the tremendous boom was now flying from\nside to side, completely sweeping the entire after part of the deck.\nThe poor fellow whom Queequeg had handled so roughly, was swept\noverboard; all hands were in a panic; and to attempt snatching at the\nboom to stay it, seemed madness.  It flew from right to left, and\nback again, almost in one ticking of a watch, and every instant\nseemed on the point of snapping into splinters.  Nothing was done,\nand nothing seemed capable of being done; those on deck rushed\ntowards the bows, and stood eyeing the boom as if it were the lower\njaw of an exasperated whale.  In the midst of this consternation,\nQueequeg dropped deftly to his knees, and crawling under the path of\nthe boom, whipped hold of a rope, secured one end to the bulwarks,\nand then flinging the other like a lasso, caught it round the boom as\nit swept over his head, and at the next jerk, the spar was that way\ntrapped, and all was safe.  The schooner was run into the wind, and\nwhile the hands were clearing away the stern boat, Queequeg, stripped\nto the waist, darted from the side with a long living arc of a leap.\nFor three minutes or more he was seen swimming like a dog, throwing\nhis long arms straight out before him, and by turns revealing his\nbrawny shoulders through the freezing foam.  I looked at the grand\nand glorious fellow, but saw no one to be saved.  The greenhorn had\ngone down.  Shooting himself perpendicularly from the water,\nQueequeg, now took an instant's glance around him, and seeming to see\njust how matters were, dived down and disappeared.  A few minutes\nmore, and he rose again, one arm still striking out, and with the\nother dragging a lifeless form.  The boat soon picked them up.  The\npoor bumpkin was restored.  All hands voted Queequeg a noble trump;\nthe captain begged his pardon.  From that hour I clove to Queequeg\nlike a barnacle; yea, till poor Queequeg took his last long dive.\n\nWas there ever such unconsciousness?  He did not seem to think that\nhe at all deserved a medal from the Humane and Magnanimous Societies.\nHe only asked for water--fresh water--something to wipe the brine\noff; that done, he put on dry clothes, lighted his pipe, and leaning\nagainst the bulwarks, and mildly eyeing those around him, seemed to\nbe saying to himself--\"It's a mutual, joint-stock world, in all\nmeridians.  We cannibals must help these Christians.\"\n\n\n\nCHAPTER 14\n\nNantucket.\n\n\nNothing more happened on the passage worthy the mentioning; so, after\na fine run, we safely arrived in Nantucket.\n\nNantucket!  Take out your map and look at it.  See what a real corner\nof the world it occupies; how it stands there, away off shore, more\nlonely than the Eddystone lighthouse.  Look at it--a mere hillock,\nand elbow of sand; all beach, without a background.  There is more\nsand there than you would use in twenty years as a substitute for\nblotting paper.  Some gamesome wights will tell you that they have to\nplant weeds there, they don't grow naturally; that they import Canada\nthistles; that they have to send beyond seas for a spile to stop a\nleak in an oil cask; that pieces of wood in Nantucket are carried\nabout like bits of the true cross in Rome; that people there plant\ntoadstools before their houses, to get under the shade in summer\ntime; that one blade of grass makes an oasis, three blades in a day's\nwalk a prairie; that they wear quicksand shoes, something like\nLaplander snow-shoes; that they are so shut up, belted about, every\nway inclosed, surrounded, and made an utter island of by the ocean,\nthat to their very chairs and tables small clams will sometimes be\nfound adhering, as to the backs of sea turtles.  But these\nextravaganzas only show that Nantucket is no Illinois.\n\nLook now at the wondrous traditional story of how this island was\nsettled by the red-men.  Thus goes the legend.  In olden times an\neagle swooped down upon the New England coast, and carried off an\ninfant Indian in his talons.  With loud lament the parents saw their\nchild borne out of sight over the wide waters.  They resolved to\nfollow in the same direction.  Setting out in their canoes, after a\nperilous passage they discovered the island, and there they found an\nempty ivory casket,--the poor little Indian's skeleton.\n\nWhat wonder, then, that these Nantucketers, born on a beach, should\ntake to the sea for a livelihood!  They first caught crabs and\nquohogs in the sand; grown bolder, they waded out with nets for\nmackerel; more experienced, they pushed off in boats and captured\ncod; and at last, launching a navy of great ships on the sea,\nexplored this watery world; put an incessant belt of\ncircumnavigations round it; peeped in at Behring's Straits; and in\nall seasons and all oceans declared everlasting war with the\nmightiest animated mass that has survived the flood; most monstrous\nand most mountainous!  That Himmalehan, salt-sea Mastodon, clothed\nwith such portentousness of unconscious power, that his very panics\nare more to be dreaded than his most fearless and malicious assaults!\n\nAnd thus have these naked Nantucketers, these sea hermits, issuing\nfrom their ant-hill in the sea, overrun and conquered the watery\nworld like so many Alexanders; parcelling out among them the\nAtlantic, Pacific, and Indian oceans, as the three pirate powers did\nPoland.  Let America add Mexico to Texas, and pile Cuba upon Canada;\nlet the English overswarm all India, and hang out their blazing\nbanner from the sun; two thirds of this terraqueous globe are the\nNantucketer's.  For the sea is his; he owns it, as Emperors own\nempires; other seamen having but a right of way through it.  Merchant\nships are but extension bridges; armed ones but floating forts; even\npirates and privateers, though following the sea as highwaymen the\nroad, they but plunder other ships, other fragments of the land like\nthemselves, without seeking to draw their living from the bottomless\ndeep itself.  The Nantucketer, he alone resides and riots on the sea;\nhe alone, in Bible language, goes down to it in ships; to and fro\nploughing it as his own special plantation.  THERE is his home; THERE\nlies his business, which a Noah's flood would not interrupt, though\nit overwhelmed all the millions in China.  He lives on the sea, as\nprairie cocks in the prairie; he hides among the waves, he climbs\nthem as chamois hunters climb the Alps.  For years he knows not the\nland; so that when he comes to it at last, it smells like another\nworld, more strangely than the moon would to an Earthsman.  With the\nlandless gull, that at sunset folds her wings and is rocked to sleep\nbetween billows; so at nightfall, the Nantucketer, out of sight of\nland, furls his sails, and lays him to his rest, while under his very\npillow rush herds of walruses and whales.\n\n\n\nCHAPTER 15\n\nChowder.\n\n\nIt was quite late in the evening when the little Moss came snugly to\nanchor, and Queequeg and I went ashore; so we could attend to no\nbusiness that day, at least none but a supper and a bed.  The\nlandlord of the Spouter-Inn had recommended us to his cousin Hosea\nHussey of the Try Pots, whom he asserted to be the proprietor of one\nof the best kept hotels in all Nantucket, and moreover he had assured\nus that Cousin Hosea, as he called him, was famous for his chowders.\nIn short, he plainly hinted that we could not possibly do better than\ntry pot-luck at the Try Pots.  But the directions he had given us\nabout keeping a yellow warehouse on our starboard hand till we opened\na white church to the larboard, and then keeping that on the larboard\nhand till we made a corner three points to the starboard, and that\ndone, then ask the first man we met where the place was: these\ncrooked directions of his very much puzzled us at first, especially\nas, at the outset, Queequeg insisted that the yellow warehouse--our\nfirst point of departure--must be left on the larboard hand, whereas\nI had understood Peter Coffin to say it was on the starboard.\nHowever, by dint of beating about a little in the dark, and now and\nthen knocking up a peaceable inhabitant to inquire the way, we at\nlast came to something which there was no mistaking.\n\nTwo enormous wooden pots painted black, and suspended by asses' ears,\nswung from the cross-trees of an old top-mast, planted in front of an\nold doorway.  The horns of the cross-trees were sawed off on the\nother side, so that this old top-mast looked not a little like a\ngallows.  Perhaps I was over sensitive to such impressions at the\ntime, but I could not help staring at this gallows with a vague\nmisgiving.  A sort of crick was in my neck as I gazed up to the two\nremaining horns; yes, TWO of them, one for Queequeg, and one for me.\nIt's ominous, thinks I.  A Coffin my Innkeeper upon landing in my\nfirst whaling port; tombstones staring at me in the whalemen's\nchapel; and here a gallows! and a pair of prodigious black pots too!\nAre these last throwing out oblique hints touching Tophet?\n\nI was called from these reflections by the sight of a freckled woman\nwith yellow hair and a yellow gown, standing in the porch of the inn,\nunder a dull red lamp swinging there, that looked much like an\ninjured eye, and carrying on a brisk scolding with a man in a purple\nwoollen shirt.\n\n\"Get along with ye,\" said she to the man, \"or I'll be combing ye!\"\n\n\"Come on, Queequeg,\" said I, \"all right.  There's Mrs. Hussey.\"\n\nAnd so it turned out; Mr. Hosea Hussey being from home, but leaving\nMrs. Hussey entirely competent to attend to all his affairs.  Upon\nmaking known our desires for a supper and a bed, Mrs. Hussey,\npostponing further scolding for the present, ushered us into a little\nroom, and seating us at a table spread with the relics of a recently\nconcluded repast, turned round to us and said--\"Clam or Cod?\"\n\n\"What's that about Cods, ma'am?\" said I, with much politeness.\n\n\"Clam or Cod?\" she repeated.\n\n\"A clam for supper? a cold clam; is THAT what you mean, Mrs. Hussey?\"\nsays I, \"but that's a rather cold and clammy reception in the winter\ntime, ain't it, Mrs. Hussey?\"\n\nBut being in a great hurry to resume scolding the man in the purple\nShirt, who was waiting for it in the entry, and seeming to hear\nnothing but the word \"clam,\" Mrs. Hussey hurried towards an open door\nleading to the kitchen, and bawling out \"clam for two,\" disappeared.\n\n\"Queequeg,\" said I, \"do you think that we can make out a supper for\nus both on one clam?\"\n\nHowever, a warm savory steam from the kitchen served to belie the\napparently cheerless prospect before us.  But when that smoking\nchowder came in, the mystery was delightfully explained.  Oh, sweet\nfriends! hearken to me.  It was made of small juicy clams, scarcely\nbigger than hazel nuts, mixed with pounded ship biscuit, and salted\npork cut up into little flakes; the whole enriched with butter, and\nplentifully seasoned with pepper and salt.  Our appetites being\nsharpened by the frosty voyage, and in particular, Queequeg seeing\nhis favourite fishing food before him, and the chowder being\nsurpassingly excellent, we despatched it with great expedition: when\nleaning back a moment and bethinking me of Mrs. Hussey's clam and cod\nannouncement, I thought I would try a little experiment.  Stepping to\nthe kitchen door, I uttered the word \"cod\" with great emphasis, and\nresumed my seat.  In a few moments the savoury steam came forth\nagain, but with a different flavor, and in good time a fine\ncod-chowder was placed before us.\n\nWe resumed business; and while plying our spoons in the bowl, thinks\nI to myself, I wonder now if this here has any effect on the head?\nWhat's that stultifying saying about chowder-headed people?  \"But\nlook, Queequeg, ain't that a live eel in your bowl?  Where's your\nharpoon?\"\n\nFishiest of all fishy places was the Try Pots, which well deserved\nits name; for the pots there were always boiling chowders.  Chowder\nfor breakfast, and chowder for dinner, and chowder for supper, till\nyou began to look for fish-bones coming through your clothes.  The\narea before the house was paved with clam-shells.  Mrs. Hussey wore a\npolished necklace of codfish vertebra; and Hosea Hussey had his\naccount books bound in superior old shark-skin.  There was a fishy\nflavor to the milk, too, which I could not at all account for, till\none morning happening to take a stroll along the beach among some\nfishermen's boats, I saw Hosea's brindled cow feeding on fish\nremnants, and marching along the sand with each foot in a cod's\ndecapitated head, looking very slip-shod, I assure ye.\n\nSupper concluded, we received a lamp, and directions from Mrs. Hussey\nconcerning the nearest way to bed; but, as Queequeg was about to\nprecede me up the stairs, the lady reached forth her arm, and\ndemanded his harpoon; she allowed no harpoon in her chambers.  \"Why\nnot? said I; \"every true whaleman sleeps with his harpoon--but why\nnot?\"  \"Because it's dangerous,\" says she.  \"Ever since young Stiggs\ncoming from that unfort'nt v'y'ge of his, when he was gone four years\nand a half, with only three barrels of ILE, was found dead in my\nfirst floor back, with his harpoon in his side; ever since then I\nallow no boarders to take sich dangerous weepons in their rooms at\nnight.  So, Mr. Queequeg\" (for she had learned his name), \"I will\njust take this here iron, and keep it for you till morning.  But the\nchowder; clam or cod to-morrow for breakfast, men?\"\n\n\"Both,\" says I; \"and let's have a couple of smoked herring by way of\nvariety.\"\n\n\n\nCHAPTER 16\n\nThe Ship.\n\n\nIn bed we concocted our plans for the morrow.  But to my surprise and\nno small concern, Queequeg now gave me to understand, that he had\nbeen diligently consulting Yojo--the name of his black little\ngod--and Yojo had told him two or three times over, and strongly\ninsisted upon it everyway, that instead of our going together among\nthe whaling-fleet in harbor, and in concert selecting our craft;\ninstead of this, I say, Yojo earnestly enjoined that the selection of\nthe ship should rest wholly with me, inasmuch as Yojo purposed\nbefriending us; and, in order to do so, had already pitched upon a\nvessel, which, if left to myself, I, Ishmael, should infallibly light\nupon, for all the world as though it had turned out by chance; and in\nthat vessel I must immediately ship myself, for the present\nirrespective of Queequeg.\n\nI have forgotten to mention that, in many things, Queequeg placed\ngreat confidence in the excellence of Yojo's judgment and surprising\nforecast of things; and cherished Yojo with considerable esteem, as a\nrather good sort of god, who perhaps meant well enough upon the\nwhole, but in all cases did not succeed in his benevolent designs.\n\nNow, this plan of Queequeg's, or rather Yojo's, touching the\nselection of our craft; I did not like that plan at all.  I had not a\nlittle relied upon Queequeg's sagacity to point out the whaler best\nfitted to carry us and our fortunes securely.  But as all my\nremonstrances produced no effect upon Queequeg, I was obliged to\nacquiesce; and accordingly prepared to set about this business with a\ndetermined rushing sort of energy and vigor, that should quickly\nsettle that trifling little affair.  Next morning early, leaving\nQueequeg shut up with Yojo in our little bedroom--for it seemed that\nit was some sort of Lent or Ramadan, or day of fasting, humiliation,\nand prayer with Queequeg and Yojo that day; HOW it was I never could\nfind out, for, though I applied myself to it several times, I never\ncould master his liturgies and XXXIX Articles--leaving Queequeg,\nthen, fasting on his tomahawk pipe, and Yojo warming himself at his\nsacrificial fire of shavings, I sallied out among the shipping.\nAfter much prolonged sauntering and many random inquiries, I learnt\nthat there were three ships up for three-years' voyages--The\nDevil-dam, the Tit-bit, and the Pequod.  DEVIL-DAM, I do not know\nthe origin of; TIT-BIT is obvious; PEQUOD, you will no doubt\nremember, was the name of a celebrated tribe of Massachusetts\nIndians; now extinct as the ancient Medes.  I peered and pryed about\nthe Devil-dam; from her, hopped over to the Tit-bit; and finally,\ngoing on board the Pequod, looked around her for a moment, and then\ndecided that this was the very ship for us.\n\nYou may have seen many a quaint craft in your day, for aught I\nknow;--square-toed luggers; mountainous Japanese junks; butter-box\ngalliots, and what not; but take my word for it, you never saw such a\nrare old craft as this same rare old Pequod.  She was a ship of the\nold school, rather small if anything; with an old-fashioned\nclaw-footed look about her.  Long seasoned and weather-stained in the\ntyphoons and calms of all four oceans, her old hull's complexion was\ndarkened like a French grenadier's, who has alike fought in Egypt and\nSiberia.  Her venerable bows looked bearded.  Her masts--cut\nsomewhere on the coast of Japan, where her original ones were lost\noverboard in a gale--her masts stood stiffly up like the spines of\nthe three old kings of Cologne.  Her ancient decks were worn and\nwrinkled, like the pilgrim-worshipped flag-stone in Canterbury\nCathedral where Becket bled.  But to all these her old antiquities,\nwere added new and marvellous features, pertaining to the wild\nbusiness that for more than half a century she had followed.  Old\nCaptain Peleg, many years her chief-mate, before he commanded another\nvessel of his own, and now a retired seaman, and one of the principal\nowners of the Pequod,--this old Peleg, during the term of his\nchief-mateship, had built upon her original grotesqueness, and inlaid\nit, all over, with a quaintness both of material and device,\nunmatched by anything except it be Thorkill-Hake's carved buckler or\nbedstead.  She was apparelled like any barbaric Ethiopian emperor,\nhis neck heavy with pendants of polished ivory.  She was a thing of\ntrophies.  A cannibal of a craft, tricking herself forth in the\nchased bones of her enemies.  All round, her unpanelled, open\nbulwarks were garnished like one continuous jaw, with the long sharp\nteeth of the sperm whale, inserted there for pins, to fasten her old\nhempen thews and tendons to.  Those thews ran not through base blocks\nof land wood, but deftly travelled over sheaves of sea-ivory.\nScorning a turnstile wheel at her reverend helm, she sported there a\ntiller; and that tiller was in one mass, curiously carved from the\nlong narrow lower jaw of her hereditary foe.  The helmsman who\nsteered by that tiller in a tempest, felt like the Tartar, when he\nholds back his fiery steed by clutching its jaw.  A noble craft, but\nsomehow a most melancholy!  All noble things are touched with that.\n\nNow when I looked about the quarter-deck, for some one having\nauthority, in order to propose myself as a candidate for the voyage,\nat first I saw nobody; but I could not well overlook a strange sort\nof tent, or rather wigwam, pitched a little behind the main-mast.  It\nseemed only a temporary erection used in port.  It was of a conical\nshape, some ten feet high; consisting of the long, huge slabs of\nlimber black bone taken from the middle and highest part of the jaws\nof the right-whale.  Planted with their broad ends on the deck, a\ncircle of these slabs laced together, mutually sloped towards each\nother, and at the apex united in a tufted point, where the loose\nhairy fibres waved to and fro like the top-knot on some old\nPottowottamie Sachem's head.  A triangular opening faced towards the\nbows of the ship, so that the insider commanded a complete view\nforward.\n\nAnd half concealed in this queer tenement, I at length found one who\nby his aspect seemed to have authority; and who, it being noon, and\nthe ship's work suspended, was now enjoying respite from the burden\nof command.  He was seated on an old-fashioned oaken chair, wriggling\nall over with curious carving; and the bottom of which was formed of\na stout interlacing of the same elastic stuff of which the wigwam was\nconstructed.\n\nThere was nothing so very particular, perhaps, about the appearance\nof the elderly man I saw; he was brown and brawny, like most old\nseamen, and heavily rolled up in blue pilot-cloth, cut in the Quaker\nstyle; only there was a fine and almost microscopic net-work of the\nminutest wrinkles interlacing round his eyes, which must have arisen\nfrom his continual sailings in many hard gales, and always looking to\nwindward;--for this causes the muscles about the eyes to become\npursed together.  Such eye-wrinkles are very effectual in a scowl.\n\n\"Is this the Captain of the Pequod?\" said I, advancing to the door of\nthe tent.\n\n\"Supposing it be the captain of the Pequod, what dost thou want of\nhim?\" he demanded.\n\n\"I was thinking of shipping.\"\n\n\"Thou wast, wast thou?  I see thou art no Nantucketer--ever been in\na stove boat?\"\n\n\"No, Sir, I never have.\"\n\n\"Dost know nothing at all about whaling, I dare say--eh?\n\n\"Nothing, Sir; but I have no doubt I shall soon learn.  I've been\nseveral voyages in the merchant service, and I think that--\"\n\n\"Merchant service be damned.  Talk not that lingo to me.  Dost see\nthat leg?--I'll take that leg away from thy stern, if ever thou\ntalkest of the marchant service to me again.  Marchant service\nindeed!  I suppose now ye feel considerable proud of having served in\nthose marchant ships.  But flukes! man, what makes thee want to go a\nwhaling, eh?--it looks a little suspicious, don't it, eh?--Hast not\nbeen a pirate, hast thou?--Didst not rob thy last Captain, didst\nthou?--Dost not think of murdering the officers when thou gettest to\nsea?\"\n\nI protested my innocence of these things.  I saw that under the mask\nof these half humorous innuendoes, this old seaman, as an insulated\nQuakerish Nantucketer, was full of his insular prejudices, and rather\ndistrustful of all aliens, unless they hailed from Cape Cod or the\nVineyard.\n\n\"But what takes thee a-whaling?  I want to know that before I think\nof shipping ye.\"\n\n\"Well, sir, I want to see what whaling is.  I want to see the world.\"\n\n\"Want to see what whaling is, eh?  Have ye clapped eye on Captain\nAhab?\"\n\n\"Who is Captain Ahab, sir?\"\n\n\"Aye, aye, I thought so.  Captain Ahab is the Captain of this ship.\"\n\n\"I am mistaken then.  I thought I was speaking to the Captain\nhimself.\"\n\n\"Thou art speaking to Captain Peleg--that's who ye are speaking to,\nyoung man.  It belongs to me and Captain Bildad to see the Pequod\nfitted out for the voyage, and supplied with all her needs, including\ncrew.  We are part owners and agents.  But as I was going to say, if\nthou wantest to know what whaling is, as thou tellest ye do, I can\nput ye in a way of finding it out before ye bind yourself to it, past\nbacking out.  Clap eye on Captain Ahab, young man, and thou wilt find\nthat he has only one leg.\"\n\n\"What do you mean, sir?  Was the other one lost by a whale?\"\n\n\"Lost by a whale!  Young man, come nearer to me: it was devoured,\nchewed up, crunched by the monstrousest parmacetty that ever chipped\na boat!--ah, ah!\"\n\nI was a little alarmed by his energy, perhaps also a little touched\nat the hearty grief in his concluding exclamation, but said as calmly\nas I could, \"What you say is no doubt true enough, sir; but how could\nI know there was any peculiar ferocity in that particular whale,\nthough indeed I might have inferred as much from the simple fact of\nthe accident.\"\n\n\"Look ye now, young man, thy lungs are a sort of soft, d'ye see; thou\ndost not talk shark a bit.  SURE, ye've been to sea before now; sure\nof that?\"\n\n\"Sir,\" said I, \"I thought I told you that I had been four voyages in\nthe merchant--\"\n\n\"Hard down out of that!  Mind what I said about the marchant\nservice--don't aggravate me--I won't have it.  But let us understand\neach other.  I have given thee a hint about what whaling is; do ye\nyet feel inclined for it?\"\n\n\"I do, sir.\"\n\n\"Very good.  Now, art thou the man to pitch a harpoon down a live\nwhale's throat, and then jump after it?  Answer, quick!\"\n\n\"I am, sir, if it should be positively indispensable to do so; not to\nbe got rid of, that is; which I don't take to be the fact.\"\n\n\"Good again.  Now then, thou not only wantest to go a-whaling, to\nfind out by experience what whaling is, but ye also want to go in\norder to see the world?  Was not that what ye said?  I thought so.\nWell then, just step forward there, and take a peep over the\nweather-bow, and then back to me and tell me what ye see there.\"\n\nFor a moment I stood a little puzzled by this curious request, not\nknowing exactly how to take it, whether humorously or in earnest.\nBut concentrating all his crow's feet into one scowl, Captain Peleg\nstarted me on the errand.\n\nGoing forward and glancing over the weather bow, I perceived that the\nship swinging to her anchor with the flood-tide, was now obliquely\npointing towards the open ocean.  The prospect was unlimited, but\nexceedingly monotonous and forbidding; not the slightest variety that\nI could see.\n\n\"Well, what's the report?\" said Peleg when I came back; \"what did ye\nsee?\"\n\n\"Not much,\" I replied--\"nothing but water; considerable horizon\nthough, and there's a squall coming up, I think.\"\n\n\"Well, what does thou think then of seeing the world?  Do ye wish to\ngo round Cape Horn to see any more of it, eh?  Can't ye see the world\nwhere you stand?\"\n\nI was a little staggered, but go a-whaling I must, and I would; and\nthe Pequod was as good a ship as any--I thought the best--and all\nthis I now repeated to Peleg.  Seeing me so determined, he expressed\nhis willingness to ship me.\n\n\"And thou mayest as well sign the papers right off,\" he added--\"come\nalong with ye.\"  And so saying, he led the way below deck into the\ncabin.\n\nSeated on the transom was what seemed to me a most uncommon and\nsurprising figure.  It turned out to be Captain Bildad, who along\nwith Captain Peleg was one of the largest owners of the vessel; the\nother shares, as is sometimes the case in these ports, being held by\na crowd of old annuitants; widows, fatherless children, and chancery\nwards; each owning about the value of a timber head, or a foot of\nplank, or a nail or two in the ship.  People in Nantucket invest\ntheir money in whaling vessels, the same way that you do yours in\napproved state stocks bringing in good interest.\n\nNow, Bildad, like Peleg, and indeed many other Nantucketers, was a\nQuaker, the island having been originally settled by that sect; and\nto this day its inhabitants in general retain in an uncommon measure\nthe peculiarities of the Quaker, only variously and anomalously\nmodified by things altogether alien and heterogeneous.  For some of\nthese same Quakers are the most sanguinary of all sailors and\nwhale-hunters.  They are fighting Quakers; they are Quakers with a\nvengeance.\n\nSo that there are instances among them of men, who, named with\nScripture names--a singularly common fashion on the island--and in\nchildhood naturally imbibing the stately dramatic thee and thou of\nthe Quaker idiom; still, from the audacious, daring, and boundless\nadventure of their subsequent lives, strangely blend with these\nunoutgrown peculiarities, a thousand bold dashes of character, not\nunworthy a Scandinavian sea-king, or a poetical Pagan Roman.  And\nwhen these things unite in a man of greatly superior natural force,\nwith a globular brain and a ponderous heart; who has also by the\nstillness and seclusion of many long night-watches in the remotest\nwaters, and beneath constellations never seen here at the north, been\nled to think untraditionally and independently; receiving all\nnature's sweet or savage impressions fresh from her own virgin\nvoluntary and confiding breast, and thereby chiefly, but with some\nhelp from accidental advantages, to learn a bold and nervous lofty\nlanguage--that man makes one in a whole nation's census--a mighty\npageant creature, formed for noble tragedies.  Nor will it at all\ndetract from him, dramatically regarded, if either by birth or other\ncircumstances, he have what seems a half wilful overruling morbidness\nat the bottom of his nature.  For all men tragically great are made\nso through a certain morbidness.  Be sure of this, O young ambition,\nall mortal greatness is but disease.  But, as yet we have not to do\nwith such an one, but with quite another; and still a man, who, if\nindeed peculiar, it only results again from another phase of the\nQuaker, modified by individual circumstances.\n\nLike Captain Peleg, Captain Bildad was a well-to-do, retired\nwhaleman.  But unlike Captain Peleg--who cared not a rush for what\nare called serious things, and indeed deemed those self-same serious\nthings the veriest of all trifles--Captain Bildad had not only been\noriginally educated according to the strictest sect of Nantucket\nQuakerism, but all his subsequent ocean life, and the sight of many\nunclad, lovely island creatures, round the Horn--all that had not\nmoved this native born Quaker one single jot, had not so much as\naltered one angle of his vest.  Still, for all this immutableness,\nwas there some lack of common consistency about worthy Captain\nPeleg.  Though refusing, from conscientious scruples, to bear arms\nagainst land invaders, yet himself had illimitably invaded the\nAtlantic and Pacific; and though a sworn foe to human bloodshed, yet\nhad he in his straight-bodied coat, spilled tuns upon tuns of\nleviathan gore.  How now in the contemplative evening of his days,\nthe pious Bildad reconciled these things in the reminiscence, I do\nnot know; but it did not seem to concern him much, and very probably\nhe had long since come to the sage and sensible conclusion that a\nman's religion is one thing, and this practical world quite another.\nThis world pays dividends.  Rising from a little cabin-boy in short\nclothes of the drabbest drab, to a harpooneer in a broad shad-bellied\nwaistcoat; from that becoming boat-header, chief-mate, and captain,\nand finally a ship owner; Bildad, as I hinted before, had concluded\nhis adventurous career by wholly retiring from active life at the\ngoodly age of sixty, and dedicating his remaining days to the quiet\nreceiving of his well-earned income.\n\nNow, Bildad, I am sorry to say, had the reputation of being an\nincorrigible old hunks, and in his sea-going days, a bitter, hard\ntask-master.  They told me in Nantucket, though it certainly seems a\ncurious story, that when he sailed the old Categut whaleman, his\ncrew, upon arriving home, were mostly all carried ashore to the\nhospital, sore exhausted and worn out.  For a pious man, especially\nfor a Quaker, he was certainly rather hard-hearted, to say the\nleast.  He never used to swear, though, at his men, they said; but\nsomehow he got an inordinate quantity of cruel, unmitigated hard work\nout of them.  When Bildad was a chief-mate, to have his drab-coloured\neye intently looking at you, made you feel completely nervous, till\nyou could clutch something--a hammer or a marling-spike, and go to\nwork like mad, at something or other, never mind what.  Indolence and\nidleness perished before him.  His own person was the exact\nembodiment of his utilitarian character.  On his long, gaunt body, he\ncarried no spare flesh, no superfluous beard, his chin having a soft,\neconomical nap to it, like the worn nap of his broad-brimmed hat.\n\nSuch, then, was the person that I saw seated on the transom when I\nfollowed Captain Peleg down into the cabin.  The space between the\ndecks was small; and there, bolt-upright, sat old Bildad, who always\nsat so, and never leaned, and this to save his coat tails.  His\nbroad-brim was placed beside him; his legs were stiffly crossed; his\ndrab vesture was buttoned up to his chin; and spectacles on nose, he\nseemed absorbed in reading from a ponderous volume.\n\n\"Bildad,\" cried Captain Peleg, \"at it again, Bildad, eh?  Ye have\nbeen studying those Scriptures, now, for the last thirty years, to my\ncertain knowledge.  How far ye got, Bildad?\"\n\nAs if long habituated to such profane talk from his old shipmate,\nBildad, without noticing his present irreverence, quietly looked up,\nand seeing me, glanced again inquiringly towards Peleg.\n\n\"He says he's our man, Bildad,\" said Peleg, \"he wants to ship.\"\n\n\"Dost thee?\" said Bildad, in a hollow tone, and turning round to me.\n\n\"I dost,\" said I unconsciously, he was so intense a Quaker.\n\n\"What do ye think of him, Bildad?\" said Peleg.\n\n\"He'll do,\" said Bildad, eyeing me, and then went on spelling away at\nhis book in a mumbling tone quite audible.\n\nI thought him the queerest old Quaker I ever saw, especially as\nPeleg, his friend and old shipmate, seemed such a blusterer.  But I\nsaid nothing, only looking round me sharply.  Peleg now threw open a\nchest, and drawing forth the ship's articles, placed pen and ink\nbefore him, and seated himself at a little table.  I began to think\nit was high time to settle with myself at what terms I would be\nwilling to engage for the voyage.  I was already aware that in the\nwhaling business they paid no wages; but all hands, including the\ncaptain, received certain shares of the profits called lays, and that\nthese lays were proportioned to the degree of importance pertaining\nto the respective duties of the ship's company.  I was also aware\nthat being a green hand at whaling, my own lay would not be very\nlarge; but considering that I was used to the sea, could steer a\nship, splice a rope, and all that, I made no doubt that from all I\nhad heard I should be offered at least the 275th lay--that is, the\n275th part of the clear net proceeds of the voyage, whatever that\nmight eventually amount to.  And though the 275th lay was what they\ncall a rather LONG LAY, yet it was better than nothing; and if we had\na lucky voyage, might pretty nearly pay for the clothing I would wear\nout on it, not to speak of my three years' beef and board, for which\nI would not have to pay one stiver.\n\nIt might be thought that this was a poor way to accumulate a princely\nfortune--and so it was, a very poor way indeed.  But I am one of\nthose that never take on about princely fortunes, and am quite\ncontent if the world is ready to board and lodge me, while I am\nputting up at this grim sign of the Thunder Cloud.  Upon the whole, I\nthought that the 275th lay would be about the fair thing, but would not\nhave been surprised had I been offered the 200th, considering I was\nof a broad-shouldered make.\n\nBut one thing, nevertheless, that made me a little distrustful about\nreceiving a generous share of the profits was this: Ashore, I had\nheard something of both Captain Peleg and his unaccountable old crony\nBildad; how that they being the principal proprietors of the Pequod,\ntherefore the other and more inconsiderable and scattered owners,\nleft nearly the whole management of the ship's affairs to these two.\nAnd I did not know but what the stingy old Bildad might have a mighty\ndeal to say about shipping hands, especially as I now found him on\nboard the Pequod, quite at home there in the cabin, and reading his\nBible as if at his own fireside.  Now while Peleg was vainly trying\nto mend a pen with his jack-knife, old Bildad, to my no small\nsurprise, considering that he was such an interested party in these\nproceedings; Bildad never heeded us, but went on mumbling to himself\nout of his book, \"LAY not up for yourselves treasures upon earth,\nwhere moth--\"\n\n\"Well, Captain Bildad,\" interrupted Peleg, \"what d'ye say, what lay\nshall we give this young man?\"\n\n\"Thou knowest best,\" was the sepulchral reply, \"the seven hundred and\nseventy-seventh wouldn't be too much, would it?--'where moth and rust\ndo corrupt, but LAY--'\"\n\nLAY, indeed, thought I, and such a lay! the seven hundred and\nseventy-seventh!  Well, old Bildad, you are determined that I, for\none, shall not LAY up many LAYS here below, where moth and rust do\ncorrupt.  It was an exceedingly LONG LAY that, indeed; and though\nfrom the magnitude of the figure it might at first deceive a\nlandsman, yet the slightest consideration will show that though seven\nhundred and seventy-seven is a pretty large number, yet, when you\ncome to make a TEENTH of it, you will then see, I say, that the seven\nhundred and seventy-seventh part of a farthing is a good deal less\nthan seven hundred and seventy-seven gold doubloons; and so I thought\nat the time.\n\n\"Why, blast your eyes, Bildad,\" cried Peleg, \"thou dost not want to\nswindle this young man! he must have more than that.\"\n\n\"Seven hundred and seventy-seventh,\" again said Bildad, without\nlifting his eyes; and then went on mumbling--\"for where your treasure\nis, there will your heart be also.\"\n\n\"I am going to put him down for the three hundredth,\" said Peleg, \"do\nye hear that, Bildad!  The three hundredth lay, I say.\"\n\nBildad laid down his book, and turning solemnly towards him said,\n\"Captain Peleg, thou hast a generous heart; but thou must consider\nthe duty thou owest to the other owners of this ship--widows and\norphans, many of them--and that if we too abundantly reward the\nlabors of this young man, we may be taking the bread from those\nwidows and those orphans.  The seven hundred and seventy-seventh lay,\nCaptain Peleg.\"\n\n\"Thou Bildad!\" roared Peleg, starting up and clattering about the\ncabin.  \"Blast ye, Captain Bildad, if I had followed thy advice in\nthese matters, I would afore now had a conscience to lug about that\nwould be heavy enough to founder the largest ship that ever sailed\nround Cape Horn.\"\n\n\"Captain Peleg,\" said Bildad steadily, \"thy conscience may be drawing\nten inches of water, or ten fathoms, I can't tell; but as thou art\nstill an impenitent man, Captain Peleg, I greatly fear lest thy\nconscience be but a leaky one; and will in the end sink thee\nfoundering down to the fiery pit, Captain Peleg.\"\n\n\"Fiery pit! fiery pit! ye insult me, man; past all natural bearing,\nye insult me.  It's an all-fired outrage to tell any human creature\nthat he's bound to hell.  Flukes and flames!  Bildad, say that again\nto me, and start my soul-bolts, but I'll--I'll--yes, I'll swallow a\nlive goat with all his hair and horns on.  Out of the cabin, ye\ncanting, drab-coloured son of a wooden gun--a straight wake with ye!\"\n\nAs he thundered out this he made a rush at Bildad, but with a\nmarvellous oblique, sliding celerity, Bildad for that time eluded\nhim.\n\nAlarmed at this terrible outburst between the two principal and\nresponsible owners of the ship, and feeling half a mind to give up\nall idea of sailing in a vessel so questionably owned and temporarily\ncommanded, I stepped aside from the door to give egress to Bildad,\nwho, I made no doubt, was all eagerness to vanish from before the\nawakened wrath of Peleg.  But to my astonishment, he sat down again\non the transom very quietly, and seemed to have not the slightest\nintention of withdrawing.  He seemed quite used to impenitent Peleg\nand his ways.  As for Peleg, after letting off his rage as he had,\nthere seemed no more left in him, and he, too, sat down like a lamb,\nthough he twitched a little as if still nervously agitated.  \"Whew!\"\nhe whistled at last--\"the squall's gone off to leeward, I think.\nBildad, thou used to be good at sharpening a lance, mend that pen,\nwill ye.  My jack-knife here needs the grindstone.  That's he; thank\nye, Bildad.  Now then, my young man, Ishmael's thy name, didn't ye\nsay?  Well then, down ye go here, Ishmael, for the three hundredth\nlay.\"\n\n\"Captain Peleg,\" said I, \"I have a friend with me who wants to ship\ntoo--shall I bring him down to-morrow?\"\n\n\"To be sure,\" said Peleg.  \"Fetch him along, and we'll look at him.\"\n\n\"What lay does he want?\" groaned Bildad, glancing up from the book\nin which he had again been burying himself.\n\n\"Oh! never thee mind about that, Bildad,\" said Peleg.  \"Has he ever\nwhaled it any?\" turning to me.\n\n\"Killed more whales than I can count, Captain Peleg.\"\n\n\"Well, bring him along then.\"\n\nAnd, after signing the papers, off I went; nothing doubting but that\nI had done a good morning's work, and that the Pequod was the\nidentical ship that Yojo had provided to carry Queequeg and me round\nthe Cape.\n\nBut I had not proceeded far, when I began to bethink me that the\nCaptain with whom I was to sail yet remained unseen by me; though,\nindeed, in many cases, a whale-ship will be completely fitted out,\nand receive all her crew on board, ere the captain makes himself\nvisible by arriving to take command; for sometimes these voyages are\nso prolonged, and the shore intervals at home so exceedingly brief,\nthat if the captain have a family, or any absorbing concernment of\nthat sort, he does not trouble himself much about his ship in port,\nbut leaves her to the owners till all is ready for sea.  However, it\nis always as well to have a look at him before irrevocably committing\nyourself into his hands.  Turning back I accosted Captain Peleg,\ninquiring where Captain Ahab was to be found.\n\n\"And what dost thou want of Captain Ahab?  It's all right enough;\nthou art shipped.\"\n\n\"Yes, but I should like to see him.\"\n\n\"But I don't think thou wilt be able to at present.  I don't know\nexactly what's the matter with him; but he keeps close inside the\nhouse; a sort of sick, and yet he don't look so.  In fact, he ain't\nsick; but no, he isn't well either.  Any how, young man, he won't\nalways see me, so I don't suppose he will thee.  He's a queer man,\nCaptain Ahab--so some think--but a good one.  Oh, thou'lt like him\nwell enough; no fear, no fear.  He's a grand, ungodly, god-like man,\nCaptain Ahab; doesn't speak much; but, when he does speak, then you\nmay well listen.  Mark ye, be forewarned; Ahab's above the common;\nAhab's been in colleges, as well as 'mong the cannibals; been used to\ndeeper wonders than the waves; fixed his fiery lance in mightier,\nstranger foes than whales.  His lance! aye, the keenest and the surest\nthat out of all our isle!  Oh! he ain't Captain Bildad; no, and he\nain't Captain Peleg; HE'S AHAB, boy; and Ahab of old, thou knowest,\nwas a crowned king!\"\n\n\"And a very vile one.  When that wicked king was slain, the dogs, did\nthey not lick his blood?\"\n\n\"Come hither to me--hither, hither,\" said Peleg, with a significance\nin his eye that almost startled me.  \"Look ye, lad; never say that on\nboard the Pequod.  Never say it anywhere.  Captain Ahab did not name\nhimself.  'Twas a foolish, ignorant whim of his crazy, widowed\nmother, who died when he was only a twelvemonth old.  And yet the old\nsquaw Tistig, at Gayhead, said that the name would somehow prove\nprophetic.  And, perhaps, other fools like her may tell thee the\nsame.  I wish to warn thee.  It's a lie.  I know Captain Ahab well;\nI've sailed with him as mate years ago; I know what he is--a good\nman--not a pious, good man, like Bildad, but a swearing good\nman--something like me--only there's a good deal more of him.  Aye,\naye, I know that he was never very jolly; and I know that on the\npassage home, he was a little out of his mind for a spell; but it was\nthe sharp shooting pains in his bleeding stump that brought that\nabout, as any one might see.  I know, too, that ever since he lost\nhis leg last voyage by that accursed whale, he's been a kind of\nmoody--desperate moody, and savage sometimes; but that will all pass\noff.  And once for all, let me tell thee and assure thee, young man,\nit's better to sail with a moody good captain than a laughing bad\none.  So good-bye to thee--and wrong not Captain Ahab, because he\nhappens to have a wicked name.  Besides, my boy, he has a wife--not\nthree voyages wedded--a sweet, resigned girl.  Think of that; by that\nsweet girl that old man has a child: hold ye then there can be any\nutter, hopeless harm in Ahab?  No, no, my lad; stricken, blasted, if\nhe be, Ahab has his humanities!\"\n\nAs I walked away, I was full of thoughtfulness; what had been\nincidentally revealed to me of Captain Ahab, filled me with a certain\nwild vagueness of painfulness concerning him.  And somehow, at the\ntime, I felt a sympathy and a sorrow for him, but for I don't know\nwhat, unless it was the cruel loss of his leg.  And yet I also felt a\nstrange awe of him; but that sort of awe, which I cannot at all\ndescribe, was not exactly awe; I do not know what it was.  But I felt\nit; and it did not disincline me towards him; though I felt\nimpatience at what seemed like mystery in him, so imperfectly as he\nwas known to me then.  However, my thoughts were at length carried in\nother directions, so that for the present dark Ahab slipped my mind.\n\n\n\nCHAPTER 17\n\nThe Ramadan.\n\n\nAs Queequeg's Ramadan, or Fasting and Humiliation, was to continue\nall day, I did not choose to disturb him till towards night-fall; for\nI cherish the greatest respect towards everybody's religious\nobligations, never mind how comical, and could not find it in my\nheart to undervalue even a congregation of ants worshipping a\ntoad-stool; or those other creatures in certain parts of our earth,\nwho with a degree of footmanism quite unprecedented in other planets,\nbow down before the torso of a deceased landed proprietor merely on\naccount of the inordinate possessions yet owned and rented in his\nname.\n\nI say, we good Presbyterian Christians should be charitable in these\nthings, and not fancy ourselves so vastly superior to other mortals,\npagans and what not, because of their half-crazy conceits on these\nsubjects.  There was Queequeg, now, certainly entertaining the most\nabsurd notions about Yojo and his Ramadan;--but what of that?\nQueequeg thought he knew what he was about, I suppose; he seemed to\nbe content; and there let him rest.  All our arguing with him would\nnot avail; let him be, I say: and Heaven have mercy on us\nall--Presbyterians and Pagans alike--for we are all somehow\ndreadfully cracked about the head, and sadly need mending.\n\nTowards evening, when I felt assured that all his performances and\nrituals must be over, I went up to his room and knocked at the door;\nbut no answer.  I tried to open it, but it was fastened inside.\n\"Queequeg,\" said I softly through the key-hole:--all silent.  \"I say,\nQueequeg! why don't you speak?  It's I--Ishmael.\"  But all remained\nstill as before.  I began to grow alarmed.  I had allowed him such\nabundant time; I thought he might have had an apoplectic fit.  I\nlooked through the key-hole; but the door opening into an odd corner\nof the room, the key-hole prospect was but a crooked and sinister\none.  I could only see part of the foot-board of the bed and a line\nof the wall, but nothing more.  I was surprised to behold resting\nagainst the wall the wooden shaft of Queequeg's harpoon, which the\nlandlady the evening previous had taken from him, before our mounting\nto the chamber.  That's strange, thought I; but at any rate, since\nthe harpoon stands yonder, and he seldom or never goes abroad without\nit, therefore he must be inside here, and no possible mistake.\n\n\"Queequeg!--Queequeg!\"--all still.  Something must have happened.\nApoplexy!  I tried to burst open the door; but it stubbornly\nresisted.  Running down stairs, I quickly stated my suspicions to the\nfirst person I met--the chamber-maid.  \"La! la!\" she cried, \"I\nthought something must be the matter.  I went to make the bed after\nbreakfast, and the door was locked; and not a mouse to be heard; and\nit's been just so silent ever since.  But I thought, may be, you had\nboth gone off and locked your baggage in for safe keeping.  La! la,\nma'am!--Mistress! murder!  Mrs. Hussey! apoplexy!\"--and with these\ncries, she ran towards the kitchen, I following.\n\nMrs. Hussey soon appeared, with a mustard-pot in one hand and a\nvinegar-cruet in the other, having just broken away from the\noccupation of attending to the castors, and scolding her little black\nboy meantime.\n\n\"Wood-house!\" cried I, \"which way to it?  Run for God's sake, and\nfetch something to pry open the door--the axe!--the axe! he's had a\nstroke; depend upon it!\"--and so saying I was unmethodically rushing\nup stairs again empty-handed, when Mrs. Hussey interposed the\nmustard-pot and vinegar-cruet, and the entire castor of her\ncountenance.\n\n\"What's the matter with you, young man?\"\n\n\"Get the axe!  For God's sake, run for the doctor, some one, while I\npry it open!\"\n\n\"Look here,\" said the landlady, quickly putting down the\nvinegar-cruet, so as to have one hand free; \"look here; are you\ntalking about prying open any of my doors?\"--and with that she seized\nmy arm.  \"What's the matter with you?  What's the matter with you,\nshipmate?\"\n\nIn as calm, but rapid a manner as possible, I gave her to understand\nthe whole case.  Unconsciously clapping the vinegar-cruet to one side\nof her nose, she ruminated for an instant; then exclaimed--\"No!  I\nhaven't seen it since I put it there.\"  Running to a little closet\nunder the landing of the stairs, she glanced in, and returning, told\nme that Queequeg's harpoon was missing.  \"He's killed himself,\" she\ncried.  \"It's unfort'nate Stiggs done over again there goes another\ncounterpane--God pity his poor mother!--it will be the ruin of my\nhouse.  Has the poor lad a sister?  Where's that girl?--there, Betty,\ngo to Snarles the Painter, and tell him to paint me a sign, with--\"no\nsuicides permitted here, and no smoking in the parlor;\"--might as\nwell kill both birds at once.  Kill?  The Lord be merciful to his\nghost!  What's that noise there?  You, young man, avast there!\"\n\nAnd running up after me, she caught me as I was again trying to force\nopen the door.\n\n\"I don't allow it; I won't have my premises spoiled.  Go for the\nlocksmith, there's one about a mile from here.  But avast!\" putting\nher hand in her side-pocket, \"here's a key that'll fit, I guess;\nlet's see.\"  And with that, she turned it in the lock; but, alas!\nQueequeg's supplemental bolt remained unwithdrawn within.\n\n\"Have to burst it open,\" said I, and was running down the entry a\nlittle, for a good start, when the landlady caught at me, again\nvowing I should not break down her premises; but I tore from her, and\nwith a sudden bodily rush dashed myself full against the mark.\n\nWith a prodigious noise the door flew open, and the knob slamming\nagainst the wall, sent the plaster to the ceiling; and there, good\nheavens! there sat Queequeg, altogether cool and self-collected;\nright in the middle of the room; squatting on his hams, and holding\nYojo on top of his head.  He looked neither one way nor the other\nway, but sat like a carved image with scarce a sign of active life.\n\n\"Queequeg,\" said I, going up to him, \"Queequeg, what's the matter\nwith you?\"\n\n\"He hain't been a sittin' so all day, has he?\" said the landlady.\n\nBut all we said, not a word could we drag out of him; I almost felt\nlike pushing him over, so as to change his position, for it was\nalmost intolerable, it seemed so painfully and unnaturally\nconstrained; especially, as in all probability he had been sitting so\nfor upwards of eight or ten hours, going too without his regular\nmeals.\n\n\"Mrs. Hussey,\" said I, \"he's ALIVE at all events; so leave us, if you\nplease, and I will see to this strange affair myself.\"\n\nClosing the door upon the landlady, I endeavored to prevail upon\nQueequeg to take a chair; but in vain.  There he sat; and all he\ncould do--for all my polite arts and blandishments--he would not move\na peg, nor say a single word, nor even look at me, nor notice my\npresence in the slightest way.\n\nI wonder, thought I, if this can possibly be a part of his Ramadan;\ndo they fast on their hams that way in his native island.  It must be\nso; yes, it's part of his creed, I suppose; well, then, let him\nrest; he'll get up sooner or later, no doubt.  It can't last for\never, thank God, and his Ramadan only comes once a year; and I don't\nbelieve it's very punctual then.\n\nI went down to supper.  After sitting a long time listening to the\nlong stories of some sailors who had just come from a plum-pudding\nvoyage, as they called it (that is, a short whaling-voyage in a\nschooner or brig, confined to the north of the line, in the Atlantic\nOcean only); after listening to these plum-puddingers till nearly\neleven o'clock, I went up stairs to go to bed, feeling quite sure by\nthis time Queequeg must certainly have brought his Ramadan to a\ntermination.  But no; there he was just where I had left him; he had\nnot stirred an inch.  I began to grow vexed with him; it seemed so\ndownright senseless and insane to be sitting there all day and half\nthe night on his hams in a cold room, holding a piece of wood on his\nhead.\n\n\"For heaven's sake, Queequeg, get up and shake yourself; get up and\nhave some supper.  You'll starve; you'll kill yourself, Queequeg.\"\nBut not a word did he reply.\n\nDespairing of him, therefore, I determined to go to bed and to sleep;\nand no doubt, before a great while, he would follow me.  But previous\nto turning in, I took my heavy bearskin jacket, and threw it over\nhim, as it promised to be a very cold night; and he had nothing but\nhis ordinary round jacket on.  For some time, do all I would, I could\nnot get into the faintest doze.  I had blown out the candle; and the\nmere thought of Queequeg--not four feet off--sitting there in that\nuneasy position, stark alone in the cold and dark; this made me\nreally wretched.  Think of it; sleeping all night in the same room\nwith a wide awake pagan on his hams in this dreary, unaccountable\nRamadan!\n\nBut somehow I dropped off at last, and knew nothing more till break\nof day; when, looking over the bedside, there squatted Queequeg, as\nif he had been screwed down to the floor.  But as soon as the first\nglimpse of sun entered the window, up he got, with stiff and grating\njoints, but with a cheerful look; limped towards me where I lay;\npressed his forehead again against mine; and said his Ramadan was\nover.\n\nNow, as I before hinted, I have no objection to any person's\nreligion, be it what it may, so long as that person does not kill or\ninsult any other person, because that other person don't believe it\nalso.  But when a man's religion becomes really frantic; when it is a\npositive torment to him; and, in fine, makes this earth of ours an\nuncomfortable inn to lodge in; then I think it high time to take that\nindividual aside and argue the point with him.\n\nAnd just so I now did with Queequeg.  \"Queequeg,\" said I, \"get into\nbed now, and lie and listen to me.\"  I then went on, beginning with\nthe rise and progress of the primitive religions, and coming down to\nthe various religions of the present time, during which time I\nlabored to show Queequeg that all these Lents, Ramadans, and\nprolonged ham-squattings in cold, cheerless rooms were stark\nnonsense; bad for the health; useless for the soul; opposed, in\nshort, to the obvious laws of Hygiene and common sense.  I told him,\ntoo, that he being in other things such an extremely sensible and\nsagacious savage, it pained me, very badly pained me, to see him now\nso deplorably foolish about this ridiculous Ramadan of his.  Besides,\nargued I, fasting makes the body cave in; hence the spirit caves in;\nand all thoughts born of a fast must necessarily be half-starved.\nThis is the reason why most dyspeptic religionists cherish such\nmelancholy notions about their hereafters.  In one word, Queequeg,\nsaid I, rather digressively; hell is an idea first born on an\nundigested apple-dumpling; and since then perpetuated through the\nhereditary dyspepsias nurtured by Ramadans.\n\nI then asked Queequeg whether he himself was ever troubled with\ndyspepsia; expressing the idea very plainly, so that he could take it\nin.  He said no; only upon one memorable occasion.  It was after a\ngreat feast given by his father the king, on the gaining of a great\nbattle wherein fifty of the enemy had been killed by about two\no'clock in the afternoon, and all cooked and eaten that very evening.\n\n\"No more, Queequeg,\" said I, shuddering; \"that will do;\" for I knew\nthe inferences without his further hinting them.  I had seen a sailor\nwho had visited that very island, and he told me that it was the\ncustom, when a great battle had been gained there, to barbecue all\nthe slain in the yard or garden of the victor; and then, one by one,\nthey were placed in great wooden trenchers, and garnished round like\na pilau, with breadfruit and cocoanuts; and with some parsley in\ntheir mouths, were sent round with the victor's compliments to all\nhis friends, just as though these presents were so many Christmas\nturkeys.\n\nAfter all, I do not think that my remarks about religion made much\nimpression upon Queequeg.  Because, in the first place, he somehow\nseemed dull of hearing on that important subject, unless considered\nfrom his own point of view; and, in the second place, he did not more\nthan one third understand me, couch my ideas simply as I would; and,\nfinally, he no doubt thought he knew a good deal more about the true\nreligion than I did.  He looked at me with a sort of condescending\nconcern and compassion, as though he thought it a great pity that\nsuch a sensible young man should be so hopelessly lost to evangelical\npagan piety.\n\nAt last we rose and dressed; and Queequeg, taking a prodigiously\nhearty breakfast of chowders of all sorts, so that the landlady\nshould not make much profit by reason of his Ramadan, we sallied out\nto board the Pequod, sauntering along, and picking our teeth with\nhalibut bones.\n\n\n\nCHAPTER 18\n\nHis Mark.\n\n\nAs we were walking down the end of the wharf towards the ship,\nQueequeg carrying his harpoon, Captain Peleg in his gruff voice\nloudly hailed us from his wigwam, saying he had not suspected my\nfriend was a cannibal, and furthermore announcing that he let no\ncannibals on board that craft, unless they previously produced their\npapers.\n\n\"What do you mean by that, Captain Peleg?\" said I, now jumping on the\nbulwarks, and leaving my comrade standing on the wharf.\n\n\"I mean,\" he replied, \"he must show his papers.\"\n\n\"Yes,\" said Captain Bildad in his hollow voice, sticking his head\nfrom behind Peleg's, out of the wigwam.  \"He must show that he's\nconverted.  Son of darkness,\" he added, turning to Queequeg, \"art\nthou at present in communion with any Christian church?\"\n\n\"Why,\" said I, \"he's a member of the first Congregational Church.\"\nHere be it said, that many tattooed savages sailing in Nantucket\nships at last come to be converted into the churches.\n\n\"First Congregational Church,\" cried Bildad, \"what! that worships in\nDeacon Deuteronomy Coleman's meeting-house?\" and so saying, taking\nout his spectacles, he rubbed them with his great yellow bandana\nhandkerchief, and putting them on very carefully, came out of the\nwigwam, and leaning stiffly over the bulwarks, took a good long look\nat Queequeg.\n\n\"How long hath he been a member?\" he then said, turning to me; \"not\nvery long, I rather guess, young man.\"\n\n\"No,\" said Peleg, \"and he hasn't been baptized right either, or it\nwould have washed some of that devil's blue off his face.\"\n\n\"Do tell, now,\" cried Bildad, \"is this Philistine a regular member of\nDeacon Deuteronomy's meeting?  I never saw him going there, and I\npass it every Lord's day.\"\n\n\"I don't know anything about Deacon Deuteronomy or his meeting,\" said\nI; \"all I know is, that Queequeg here is a born member of the First\nCongregational Church.  He is a deacon himself, Queequeg is.\"\n\n\"Young man,\" said Bildad sternly, \"thou art skylarking with\nme--explain thyself, thou young Hittite.  What church dost thee mean?\nanswer me.\"\n\nFinding myself thus hard pushed, I replied.  \"I mean, sir, the same\nancient Catholic Church to which you and I, and Captain Peleg there,\nand Queequeg here, and all of us, and every mother's son and soul of\nus belong; the great and everlasting First Congregation of this whole\nworshipping world; we all belong to that; only some of us cherish\nsome queer crotchets no ways touching the grand belief; in THAT we\nall join hands.\"\n\n\"Splice, thou mean'st SPLICE hands,\" cried Peleg, drawing nearer.\n\"Young man, you'd better ship for a missionary, instead of a\nfore-mast hand; I never heard a better sermon.  Deacon\nDeuteronomy--why Father Mapple himself couldn't beat it, and he's\nreckoned something.  Come aboard, come aboard; never mind about the\npapers.  I say, tell Quohog there--what's that you call him? tell\nQuohog to step along.  By the great anchor, what a harpoon he's got\nthere! looks like good stuff that; and he handles it about right.  I\nsay, Quohog, or whatever your name is, did you ever stand in the head\nof a whale-boat? did you ever strike a fish?\"\n\nWithout saying a word, Queequeg, in his wild sort of way, jumped upon\nthe bulwarks, from thence into the bows of one of the whale-boats\nhanging to the side; and then bracing his left knee, and poising his\nharpoon, cried out in some such way as this:--\n\n\"Cap'ain, you see him small drop tar on water dere?  You see him?\nwell, spose him one whale eye, well, den!\" and taking sharp aim at\nit, he darted the iron right over old Bildad's broad brim, clean\nacross the ship's decks, and struck the glistening tar spot out of\nsight.\n\n\"Now,\" said Queequeg, quietly hauling in the line, \"spos-ee him\nwhale-e eye; why, dad whale dead.\"\n\n\"Quick, Bildad,\" said Peleg, his partner, who, aghast at the close\nvicinity of the flying harpoon, had retreated towards the cabin\ngangway.  \"Quick, I say, you Bildad, and get the ship's papers.  We\nmust have Hedgehog there, I mean Quohog, in one of our boats.  Look\nye, Quohog, we'll give ye the ninetieth lay, and that's more than\never was given a harpooneer yet out of Nantucket.\"\n\nSo down we went into the cabin, and to my great joy Queequeg was soon\nenrolled among the same ship's company to which I myself belonged.\n\nWhen all preliminaries were over and Peleg had got everything ready\nfor signing, he turned to me and said, \"I guess, Quohog there don't\nknow how to write, does he?  I say, Quohog, blast ye! dost thou sign\nthy name or make thy mark?\n\nBut at this question, Queequeg, who had twice or thrice before taken\npart in similar ceremonies, looked no ways abashed; but taking the\noffered pen, copied upon the paper, in the proper place, an exact\ncounterpart of a queer round figure which was tattooed upon his arm;\nso that through Captain Peleg's obstinate mistake touching his\nappellative, it stood something like this:--\n\nQuohog.\nhis X mark.\n\nMeanwhile Captain Bildad sat earnestly and steadfastly eyeing\nQueequeg, and at last rising solemnly and fumbling in the huge\npockets of his broad-skirted drab coat, took out a bundle of tracts,\nand selecting one entitled \"The Latter Day Coming; or No Time to\nLose,\" placed it in Queequeg's hands, and then grasping them and the\nbook with both his, looked earnestly into his eyes, and said, \"Son of\ndarkness, I must do my duty by thee; I am part owner of this ship,\nand feel concerned for the souls of all its crew; if thou still\nclingest to thy Pagan ways, which I sadly fear, I beseech thee,\nremain not for aye a Belial bondsman.  Spurn the idol Bell, and the\nhideous dragon; turn from the wrath to come; mind thine eye, I say;\noh! goodness gracious! steer clear of the fiery pit!\"\n\nSomething of the salt sea yet lingered in old Bildad's language,\nheterogeneously mixed with Scriptural and domestic phrases.\n\n\"Avast there, avast there, Bildad, avast now spoiling our\nharpooneer,\" Peleg.  \"Pious harpooneers never make good voyagers--it\ntakes the shark out of 'em; no harpooneer is worth a straw who aint\npretty sharkish.  There was young Nat Swaine, once the bravest\nboat-header out of all Nantucket and the Vineyard; he joined the\nmeeting, and never came to good.  He got so frightened about his\nplaguy soul, that he shrinked and sheered away from whales, for fear\nof after-claps, in case he got stove and went to Davy Jones.\"\n\n\"Peleg!  Peleg!\" said Bildad, lifting his eyes and hands, \"thou\nthyself, as I myself, hast seen many a perilous time; thou knowest,\nPeleg, what it is to have the fear of death; how, then, can'st thou\nprate in this ungodly guise.  Thou beliest thine own heart, Peleg.\nTell me, when this same Pequod here had her three masts overboard in\nthat typhoon on Japan, that same voyage when thou went mate with\nCaptain Ahab, did'st thou not think of Death and the Judgment then?\"\n\n\"Hear him, hear him now,\" cried Peleg, marching across the cabin, and\nthrusting his hands far down into his pockets,--\"hear him, all of ye.\nThink of that!  When every moment we thought the ship would sink!\nDeath and the Judgment then?  What?  With all three masts making such\nan everlasting thundering against the side; and every sea breaking\nover us, fore and aft.  Think of Death and the Judgment then?  No!\nno time to think about Death then.  Life was what Captain Ahab and I\nwas thinking of; and how to save all hands--how to rig\njury-masts--how to get into the nearest port; that was what I was\nthinking of.\"\n\nBildad said no more, but buttoning up his coat, stalked on deck,\nwhere we followed him.  There he stood, very quietly overlooking some\nsailmakers who were mending a top-sail in the waist.  Now and then he\nstooped to pick up a patch, or save an end of tarred twine, which\notherwise might have been wasted.\n\n\n\nCHAPTER 19\n\nThe Prophet.\n\n\n\"Shipmates, have ye shipped in that ship?\"\n\nQueequeg and I had just left the Pequod, and were sauntering away from\nthe water, for the moment each occupied with his own thoughts, when\nthe above words were put to us by a stranger, who, pausing before us,\nlevelled his massive forefinger at the vessel in question.  He was\nbut shabbily apparelled in faded jacket and patched trowsers; a rag\nof a black handkerchief investing his neck.  A confluent small-pox\nhad in all directions flowed over his face, and left it like the\ncomplicated ribbed bed of a torrent, when the rushing waters have\nbeen dried up.\n\n\"Have ye shipped in her?\" he repeated.\n\n\"You mean the ship Pequod, I suppose,\" said I, trying to gain a\nlittle more time for an uninterrupted look at him.\n\n\"Aye, the Pequod--that ship there,\" he said, drawing back his whole\narm, and then rapidly shoving it straight out from him, with the\nfixed bayonet of his pointed finger darted full at the object.\n\n\"Yes,\" said I, \"we have just signed the articles.\"\n\n\"Anything down there about your souls?\"\n\n\"About what?\"\n\n\"Oh, perhaps you hav'n't got any,\" he said quickly.  \"No matter\nthough, I know many chaps that hav'n't got any,--good luck to 'em;\nand they are all the better off for it.  A soul's a sort of a fifth\nwheel to a wagon.\"\n\n\"What are you jabbering about, shipmate?\" said I.\n\n\"HE'S got enough, though, to make up for all deficiencies of that\nsort in other chaps,\" abruptly said the stranger, placing a nervous\nemphasis upon the word HE.\n\n\"Queequeg,\" said I, \"let's go; this fellow has broken loose from\nsomewhere; he's talking about something and somebody we don't know.\"\n\n\"Stop!\" cried the stranger.  \"Ye said true--ye hav'n't seen Old\nThunder yet, have ye?\"\n\n\"Who's Old Thunder?\" said I, again riveted with the insane\nearnestness of his manner.\n\n\"Captain Ahab.\"\n\n\"What! the captain of our ship, the Pequod?\"\n\n\"Aye, among some of us old sailor chaps, he goes by that name.  Ye\nhav'n't seen him yet, have ye?\"\n\n\"No, we hav'n't.  He's sick they say, but is getting better, and will\nbe all right again before long.\"\n\n\"All right again before long!\" laughed the stranger, with a solemnly\nderisive sort of laugh.  \"Look ye; when Captain Ahab is all right,\nthen this left arm of mine will be all right; not before.\"\n\n\"What do you know about him?\"\n\n\"What did they TELL you about him?  Say that!\"\n\n\"They didn't tell much of anything about him; only I've heard that\nhe's a good whale-hunter, and a good captain to his crew.\"\n\n\"That's true, that's true--yes, both true enough.  But you must jump\nwhen he gives an order.  Step and growl; growl and go--that's the\nword with Captain Ahab.  But nothing about that thing that happened\nto him off Cape Horn, long ago, when he lay like dead for three days\nand nights; nothing about that deadly skrimmage with the Spaniard\nafore the altar in Santa?--heard nothing about that, eh?  Nothing\nabout the silver calabash he spat into?  And nothing about his losing\nhis leg last voyage, according to the prophecy.  Didn't ye hear a\nword about them matters and something more, eh?  No, I don't think ye\ndid; how could ye?  Who knows it?  Not all Nantucket, I guess.  But\nhows'ever, mayhap, ye've heard tell about the leg, and how he lost\nit; aye, ye have heard of that, I dare say.  Oh yes, THAT every one\nknows a'most--I mean they know he's only one leg; and that a\nparmacetti took the other off.\"\n\n\"My friend,\" said I, \"what all this gibberish of yours is about, I\ndon't know, and I don't much care; for it seems to me that you must\nbe a little damaged in the head.  But if you are speaking of Captain\nAhab, of that ship there, the Pequod, then let me tell you, that I\nknow all about the loss of his leg.\"\n\n\"ALL about it, eh--sure you do?--all?\"\n\n\"Pretty sure.\"\n\nWith finger pointed and eye levelled at the Pequod, the beggar-like\nstranger stood a moment, as if in a troubled reverie; then starting a\nlittle, turned and said:--\"Ye've shipped, have ye?  Names down on the\npapers?  Well, well, what's signed, is signed; and what's to be, will\nbe; and then again, perhaps it won't be, after all.  Anyhow, it's\nall fixed and arranged a'ready; and some sailors or other must go\nwith him, I suppose; as well these as any other men, God pity 'em!\nMorning to ye, shipmates, morning; the ineffable heavens bless ye;\nI'm sorry I stopped ye.\"\n\n\"Look here, friend,\" said I, \"if you have anything important to tell\nus, out with it; but if you are only trying to bamboozle us, you are\nmistaken in your game; that's all I have to say.\"\n\n\"And it's said very well, and I like to hear a chap talk up that way;\nyou are just the man for him--the likes of ye.  Morning to ye,\nshipmates, morning!  Oh! when ye get there, tell 'em I've concluded\nnot to make one of 'em.\"\n\n\"Ah, my dear fellow, you can't fool us that way--you can't fool us.\nIt is the easiest thing in the world for a man to look as if he had a\ngreat secret in him.\"\n\n\"Morning to ye, shipmates, morning.\"\n\n\"Morning it is,\" said I.  \"Come along, Queequeg, let's leave this\ncrazy man.  But stop, tell me your name, will you?\"\n\n\"Elijah.\"\n\nElijah! thought I, and we walked away, both commenting, after each\nother's fashion, upon this ragged old sailor; and agreed that he was\nnothing but a humbug, trying to be a bugbear.  But we had not gone\nperhaps above a hundred yards, when chancing to turn a corner, and\nlooking back as I did so, who should be seen but Elijah following us,\nthough at a distance.  Somehow, the sight of him struck me so, that I\nsaid nothing to Queequeg of his being behind, but passed on with my\ncomrade, anxious to see whether the stranger would turn the same\ncorner that we did.  He did; and then it seemed to me that he was\ndogging us, but with what intent I could not for the life of me\nimagine.  This circumstance, coupled with his ambiguous,\nhalf-hinting, half-revealing, shrouded sort of talk, now begat in me\nall kinds of vague wonderments and half-apprehensions, and all\nconnected with the Pequod; and Captain Ahab; and the leg he had lost;\nand the Cape Horn fit; and the silver calabash; and what Captain\nPeleg had said of him, when I left the ship the day previous; and the\nprediction of the squaw Tistig; and the voyage we had bound ourselves\nto sail; and a hundred other shadowy things.\n\nI was resolved to satisfy myself whether this ragged Elijah was\nreally dogging us or not, and with that intent crossed the way with\nQueequeg, and on that side of it retraced our steps.  But Elijah\npassed on, without seeming to notice us.  This relieved me; and once\nmore, and finally as it seemed to me, I pronounced him in my heart, a\nhumbug.\n\n\n\nCHAPTER 20\n\nAll Astir.\n\n\nA day or two passed, and there was great activity aboard the Pequod.\nNot only were the old sails being mended, but new sails were coming\non board, and bolts of canvas, and coils of rigging; in short,\neverything betokened that the ship's preparations were hurrying to a\nclose.  Captain Peleg seldom or never went ashore, but sat in his\nwigwam keeping a sharp look-out upon the hands: Bildad did all the\npurchasing and providing at the stores; and the men employed in the\nhold and on the rigging were working till long after night-fall.\n\nOn the day following Queequeg's signing the articles, word was given\nat all the inns where the ship's company were stopping, that their\nchests must be on board before night, for there was no telling how\nsoon the vessel might be sailing.  So Queequeg and I got down our\ntraps, resolving, however, to sleep ashore till the last.  But it\nseems they always give very long notice in these cases, and the ship\ndid not sail for several days.  But no wonder; there was a good deal\nto be done, and there is no telling how many things to be thought of,\nbefore the Pequod was fully equipped.\n\nEvery one knows what a multitude of things--beds, sauce-pans, knives\nand forks, shovels and tongs, napkins, nut-crackers, and what not,\nare indispensable to the business of housekeeping.  Just so with\nwhaling, which necessitates a three-years' housekeeping upon the wide\nocean, far from all grocers, costermongers, doctors, bakers, and\nbankers.  And though this also holds true of merchant vessels, yet\nnot by any means to the same extent as with whalemen.  For besides\nthe great length of the whaling voyage, the numerous articles\npeculiar to the prosecution of the fishery, and the impossibility of\nreplacing them at the remote harbors usually frequented, it must be\nremembered, that of all ships, whaling vessels are the most exposed\nto accidents of all kinds, and especially to the destruction and loss\nof the very things upon which the success of the voyage most depends.\nHence, the spare boats, spare spars, and spare lines and harpoons,\nand spare everythings, almost, but a spare Captain and duplicate\nship.\n\nAt the period of our arrival at the Island, the heaviest storage of\nthe Pequod had been almost completed; comprising her beef, bread,\nwater, fuel, and iron hoops and staves.  But, as before hinted, for\nsome time there was a continual fetching and carrying on board of\ndivers odds and ends of things, both large and small.\n\nChief among those who did this fetching and carrying was Captain\nBildad's sister, a lean old lady of a most determined and\nindefatigable spirit, but withal very kindhearted, who seemed\nresolved that, if SHE could help it, nothing should be found wanting\nin the Pequod, after once fairly getting to sea.  At one time she\nwould come on board with a jar of pickles for the steward's pantry;\nanother time with a bunch of quills for the chief mate's desk, where\nhe kept his log; a third time with a roll of flannel for the small of\nsome one's rheumatic back.  Never did any woman better deserve her\nname, which was Charity--Aunt Charity, as everybody called her.  And\nlike a sister of charity did this charitable Aunt Charity bustle\nabout hither and thither, ready to turn her hand and heart to\nanything that promised to yield safety, comfort, and consolation to\nall on board a ship in which her beloved brother Bildad was\nconcerned, and in which she herself owned a score or two of\nwell-saved dollars.\n\nBut it was startling to see this excellent hearted Quakeress coming\non board, as she did the last day, with a long oil-ladle in one hand,\nand a still longer whaling lance in the other.  Nor was Bildad himself\nnor Captain Peleg at all backward.  As for Bildad, he carried about\nwith him a long list of the articles needed, and at every fresh\narrival, down went his mark opposite that article upon the paper.\nEvery once in a while Peleg came hobbling out of his whalebone den,\nroaring at the men down the hatchways, roaring up to the riggers at\nthe mast-head, and then concluded by roaring back into his wigwam.\n\nDuring these days of preparation, Queequeg and I often visited the\ncraft, and as often I asked about Captain Ahab, and how he was, and\nwhen he was going to come on board his ship.  To these questions they\nwould answer, that he was getting better and better, and was expected\naboard every day; meantime, the two captains, Peleg and Bildad, could\nattend to everything necessary to fit the vessel for the voyage.  If\nI had been downright honest with myself, I would have seen very\nplainly in my heart that I did but half fancy being committed this\nway to so long a voyage, without once laying my eyes on the man who\nwas to be the absolute dictator of it, so soon as the ship sailed out\nupon the open sea.  But when a man suspects any wrong, it sometimes\nhappens that if he be already involved in the matter, he insensibly\nstrives to cover up his suspicions even from himself.  And much this\nway it was with me.  I said nothing, and tried to think nothing.\n\nAt last it was given out that some time next day the ship would\ncertainly sail.  So next morning, Queequeg and I took a very early\nstart.\n\n\n\nCHAPTER 21\n\nGoing Aboard.\n\n\nIt was nearly six o'clock, but only grey imperfect misty dawn, when\nwe drew nigh the wharf.\n\n\"There are some sailors running ahead there, if I see right,\" said I\nto Queequeg, \"it can't be shadows; she's off by sunrise, I guess;\ncome on!\"\n\n\"Avast!\" cried a voice, whose owner at the same time coming close\nbehind us, laid a hand upon both our shoulders, and then insinuating\nhimself between us, stood stooping forward a little, in the uncertain\ntwilight, strangely peering from Queequeg to me.  It was Elijah.\n\n\"Going aboard?\"\n\n\"Hands off, will you,\" said I.\n\n\"Lookee here,\" said Queequeg, shaking himself, \"go 'way!\"\n\n\"Ain't going aboard, then?\"\n\n\"Yes, we are,\" said I, \"but what business is that of yours?  Do you\nknow, Mr. Elijah, that I consider you a little impertinent?\"\n\n\"No, no, no; I wasn't aware of that,\" said Elijah, slowly and\nwonderingly looking from me to Queequeg, with the most unaccountable\nglances.\n\n\"Elijah,\" said I, \"you will oblige my friend and me by withdrawing.\nWe are going to the Indian and Pacific Oceans, and would prefer not\nto be detained.\"\n\n\"Ye be, be ye?  Coming back afore breakfast?\"\n\n\"He's cracked, Queequeg,\" said I, \"come on.\"\n\n\"Holloa!\" cried stationary Elijah, hailing us when we had removed a\nfew paces.\n\n\"Never mind him,\" said I, \"Queequeg, come on.\"\n\nBut he stole up to us again, and suddenly clapping his hand on my\nshoulder, said--\"Did ye see anything looking like men going towards\nthat ship a while ago?\"\n\nStruck by this plain matter-of-fact question, I answered, saying,\n\"Yes, I thought I did see four or five men; but it was too dim to be\nsure.\"\n\n\"Very dim, very dim,\" said Elijah.  \"Morning to ye.\"\n\nOnce more we quitted him; but once more he came softly after us; and\ntouching my shoulder again, said, \"See if you can find 'em now, will\nye?\n\n\"Find who?\"\n\n\"Morning to ye! morning to ye!\" he rejoined, again moving off.  \"Oh!\nI was going to warn ye against--but never mind, never mind--it's all\none, all in the family too;--sharp frost this morning, ain't it?\nGood-bye to ye.  Shan't see ye again very soon, I guess; unless it's\nbefore the Grand Jury.\"  And with these cracked words he finally\ndeparted, leaving me, for the moment, in no small wonderment at his\nfrantic impudence.\n\nAt last, stepping on board the Pequod, we found everything in\nprofound quiet, not a soul moving.  The cabin entrance was locked\nwithin; the hatches were all on, and lumbered with coils of rigging.\nGoing forward to the forecastle, we found the slide of the scuttle\nopen.  Seeing a light, we went down, and found only an old rigger\nthere, wrapped in a tattered pea-jacket.  He was thrown at whole\nlength upon two chests, his face downwards and inclosed in his folded\narms.  The profoundest slumber slept upon him.\n\n\"Those sailors we saw, Queequeg, where can they have gone to?\" said\nI, looking dubiously at the sleeper.  But it seemed that, when on the\nwharf, Queequeg had not at all noticed what I now alluded to; hence I\nwould have thought myself to have been optically deceived in that\nmatter, were it not for Elijah's otherwise inexplicable question.\nBut I beat the thing down; and again marking the sleeper, jocularly\nhinted to Queequeg that perhaps we had best sit up with the body;\ntelling him to establish himself accordingly.  He put his hand upon\nthe sleeper's rear, as though feeling if it was soft enough; and\nthen, without more ado, sat quietly down there.\n\n\"Gracious!  Queequeg, don't sit there,\" said I.\n\n\"Oh! perry dood seat,\" said Queequeg, \"my country way; won't hurt\nhim face.\"\n\n\"Face!\" said I, \"call that his face? very benevolent countenance\nthen; but how hard he breathes, he's heaving himself; get off,\nQueequeg, you are heavy, it's grinding the face of the poor.  Get\noff, Queequeg!  Look, he'll twitch you off soon.  I wonder he don't\nwake.\"\n\nQueequeg removed himself to just beyond the head of the sleeper, and\nlighted his tomahawk pipe.  I sat at the feet.  We kept the pipe\npassing over the sleeper, from one to the other.  Meanwhile, upon\nquestioning him in his broken fashion, Queequeg gave me to understand\nthat, in his land, owing to the absence of settees and sofas of all\nsorts, the king, chiefs, and great people generally, were in the\ncustom of fattening some of the lower orders for ottomans; and to\nfurnish a house comfortably in that respect, you had only to buy up\neight or ten lazy fellows, and lay them round in the piers and\nalcoves.  Besides, it was very convenient on an excursion; much\nbetter than those garden-chairs which are convertible into\nwalking-sticks; upon occasion, a chief calling his attendant, and\ndesiring him to make a settee of himself under a spreading tree,\nperhaps in some damp marshy place.\n\nWhile narrating these things, every time Queequeg received the\ntomahawk from me, he flourished the hatchet-side of it over the\nsleeper's head.\n\n\"What's that for, Queequeg?\"\n\n\"Perry easy, kill-e; oh! perry easy!\n\nHe was going on with some wild reminiscences about his tomahawk-pipe,\nwhich, it seemed, had in its two uses both brained his foes and\nsoothed his soul, when we were directly attracted to the sleeping\nrigger.  The strong vapour now completely filling the contracted hole,\nit began to tell upon him.  He breathed with a sort of muffledness;\nthen seemed troubled in the nose; then revolved over once or twice;\nthen sat up and rubbed his eyes.\n\n\"Holloa!\" he breathed at last, \"who be ye smokers?\"\n\n\"Shipped men,\" answered I, \"when does she sail?\"\n\n\"Aye, aye, ye are going in her, be ye?  She sails to-day.  The\nCaptain came aboard last night.\"\n\n\"What Captain?--Ahab?\"\n\n\"Who but him indeed?\"\n\nI was going to ask him some further questions concerning Ahab, when\nwe heard a noise on deck.\n\n\"Holloa!  Starbuck's astir,\" said the rigger.  \"He's a lively chief\nmate, that; good man, and a pious; but all alive now, I must turn\nto.\"  And so saying he went on deck, and we followed.\n\nIt was now clear sunrise.  Soon the crew came on board in twos and\nthrees; the riggers bestirred themselves; the mates were actively\nengaged; and several of the shore people were busy in bringing\nvarious last things on board.  Meanwhile Captain Ahab remained\ninvisibly enshrined within his cabin.\n\n\n\nCHAPTER 22\n\nMerry Christmas.\n\n\nAt length, towards noon, upon the final dismissal of the ship's\nriggers, and after the Pequod had been hauled out from the wharf, and\nafter the ever-thoughtful Charity had come off in a whale-boat, with\nher last gift--a night-cap for Stubb, the second mate, her\nbrother-in-law, and a spare Bible for the steward--after all this,\nthe two Captains, Peleg and Bildad, issued from the cabin, and\nturning to the chief mate, Peleg said:\n\n\"Now, Mr. Starbuck, are you sure everything is right?  Captain Ahab\nis all ready--just spoke to him--nothing more to be got from shore,\neh?  Well, call all hands, then.  Muster 'em aft here--blast 'em!\"\n\n\"No need of profane words, however great the hurry, Peleg,\" said\nBildad, \"but away with thee, friend Starbuck, and do our bidding.\"\n\nHow now!  Here upon the very point of starting for the voyage,\nCaptain Peleg and Captain Bildad were going it with a high hand on\nthe quarter-deck, just as if they were to be joint-commanders at sea,\nas well as to all appearances in port.  And, as for Captain Ahab, no\nsign of him was yet to be seen; only, they said he was in the cabin.\nBut then, the idea was, that his presence was by no means necessary\nin getting the ship under weigh, and steering her well out to sea.\nIndeed, as that was not at all his proper business, but the pilot's;\nand as he was not yet completely recovered--so they said--therefore,\nCaptain Ahab stayed below.  And all this seemed natural enough;\nespecially as in the merchant service many captains never show\nthemselves on deck for a considerable time after heaving up the\nanchor, but remain over the cabin table, having a farewell\nmerry-making with their shore friends, before they quit the ship for\ngood with the pilot.\n\nBut there was not much chance to think over the matter, for Captain\nPeleg was now all alive.  He seemed to do most of the talking and\ncommanding, and not Bildad.\n\n\"Aft here, ye sons of bachelors,\" he cried, as the sailors lingered\nat the main-mast.  \"Mr. Starbuck, drive'em aft.\"\n\n\"Strike the tent there!\"--was the next order.  As I hinted before,\nthis whalebone marquee was never pitched except in port; and on board\nthe Pequod, for thirty years, the order to strike the tent was well\nknown to be the next thing to heaving up the anchor.\n\n\"Man the capstan!  Blood and thunder!--jump!\"--was the next command,\nand the crew sprang for the handspikes.\n\nNow in getting under weigh, the station generally occupied by the\npilot is the forward part of the ship.  And here Bildad, who, with\nPeleg, be it known, in addition to his other officers, was one of the\nlicensed pilots of the port--he being suspected to have got himself\nmade a pilot in order to save the Nantucket pilot-fee to all the\nships he was concerned in, for he never piloted any other\ncraft--Bildad, I say, might now be seen actively engaged in looking\nover the bows for the approaching anchor, and at intervals singing\nwhat seemed a dismal stave of psalmody, to cheer the hands at the\nwindlass, who roared forth some sort of a chorus about the girls in\nBooble Alley, with hearty good will.  Nevertheless, not three days\nprevious, Bildad had told them that no profane songs would be allowed\non board the Pequod, particularly in getting under weigh; and\nCharity, his sister, had placed a small choice copy of Watts in each\nseaman's berth.\n\nMeantime, overseeing the other part of the ship, Captain Peleg ripped\nand swore astern in the most frightful manner.  I almost thought he\nwould sink the ship before the anchor could be got up; involuntarily\nI paused on my handspike, and told Queequeg to do the same, thinking\nof the perils we both ran, in starting on the voyage with such a\ndevil for a pilot.  I was comforting myself, however, with the\nthought that in pious Bildad might be found some salvation, spite of\nhis seven hundred and seventy-seventh lay; when I felt a sudden sharp\npoke in my rear, and turning round, was horrified at the apparition\nof Captain Peleg in the act of withdrawing his leg from my immediate\nvicinity.  That was my first kick.\n\n\"Is that the way they heave in the marchant service?\" he roared.\n\"Spring, thou sheep-head; spring, and break thy backbone!  Why don't\nye spring, I say, all of ye--spring!  Quohog! spring, thou chap with\nthe red whiskers; spring there, Scotch-cap; spring, thou green\npants.  Spring, I say, all of ye, and spring your eyes out!\"  And so\nsaying, he moved along the windlass, here and there using his leg\nvery freely, while imperturbable Bildad kept leading off with his\npsalmody.  Thinks I, Captain Peleg must have been drinking something\nto-day.\n\nAt last the anchor was up, the sails were set, and off we glided.  It\nwas a short, cold Christmas; and as the short northern day merged\ninto night, we found ourselves almost broad upon the wintry ocean,\nwhose freezing spray cased us in ice, as in polished armor.  The long\nrows of teeth on the bulwarks glistened in the moonlight; and like\nthe white ivory tusks of some huge elephant, vast curving icicles\ndepended from the bows.\n\nLank Bildad, as pilot, headed the first watch, and ever and anon, as\nthe old craft deep dived into the green seas, and sent the shivering\nfrost all over her, and the winds howled, and the cordage rang, his\nsteady notes were heard,--\n\n\"Sweet fields beyond the swelling flood,\nStand dressed in living green.\nSo to the Jews old Canaan stood,\nWhile Jordan rolled between.\"\n\n\nNever did those sweet words sound more sweetly to me than then.  They\nwere full of hope and fruition.  Spite of this frigid winter night in\nthe boisterous Atlantic, spite of my wet feet and wetter jacket,\nthere was yet, it then seemed to me, many a pleasant haven in store;\nand meads and glades so eternally vernal, that the grass shot up by\nthe spring, untrodden, unwilted, remains at midsummer.\n\nAt last we gained such an offing, that the two pilots were needed no\nlonger.  The stout sail-boat that had accompanied us began ranging\nalongside.\n\nIt was curious and not unpleasing, how Peleg and Bildad were affected\nat this juncture, especially Captain Bildad.  For loath to depart,\nyet; very loath to leave, for good, a ship bound on so long and\nperilous a voyage--beyond both stormy Capes; a ship in which some\nthousands of his hard earned dollars were invested; a ship, in which\nan old shipmate sailed as captain; a man almost as old as he, once\nmore starting to encounter all the terrors of the pitiless jaw; loath\nto say good-bye to a thing so every way brimful of every interest to\nhim,--poor old Bildad lingered long; paced the deck with anxious\nstrides; ran down into the cabin to speak another farewell word\nthere; again came on deck, and looked to windward; looked towards the\nwide and endless waters, only bounded by the far-off unseen Eastern\nContinents; looked towards the land; looked aloft; looked right and\nleft; looked everywhere and nowhere; and at last, mechanically\ncoiling a rope upon its pin, convulsively grasped stout Peleg by the\nhand, and holding up a lantern, for a moment stood gazing heroically\nin his face, as much as to say, \"Nevertheless, friend Peleg, I can\nstand it; yes, I can.\"\n\nAs for Peleg himself, he took it more like a philosopher; but for all\nhis philosophy, there was a tear twinkling in his eye, when the\nlantern came too near.  And he, too, did not a little run from cabin\nto deck--now a word below, and now a word with Starbuck, the chief\nmate.\n\nBut, at last, he turned to his comrade, with a final sort of look\nabout him,--\"Captain Bildad--come, old shipmate, we must go.  Back\nthe main-yard there!  Boat ahoy!  Stand by to come close alongside,\nnow!  Careful, careful!--come, Bildad, boy--say your last.  Luck to\nye, Starbuck--luck to ye, Mr. Stubb--luck to ye, Mr. Flask--good-bye\nand good luck to ye all--and this day three years I'll have a hot\nsupper smoking for ye in old Nantucket.  Hurrah and away!\"\n\n\"God bless ye, and have ye in His holy keeping, men,\" murmured old\nBildad, almost incoherently.  \"I hope ye'll have fine weather now, so\nthat Captain Ahab may soon be moving among ye--a pleasant sun is all\nhe needs, and ye'll have plenty of them in the tropic voyage ye go.\nBe careful in the hunt, ye mates.  Don't stave the boats needlessly,\nye harpooneers; good white cedar plank is raised full three per cent.\nwithin the year.  Don't forget your prayers, either.  Mr. Starbuck,\nmind that cooper don't waste the spare staves.  Oh! the sail-needles\nare in the green locker!  Don't whale it too much a' Lord's days,\nmen; but don't miss a fair chance either, that's rejecting Heaven's\ngood gifts.  Have an eye to the molasses tierce, Mr. Stubb; it was a\nlittle leaky, I thought.  If ye touch at the islands, Mr. Flask,\nbeware of fornication.  Good-bye, good-bye!  Don't keep that cheese\ntoo long down in the hold, Mr. Starbuck; it'll spoil.  Be careful\nwith the butter--twenty cents the pound it was, and mind ye, if--\"\n\n\"Come, come, Captain Bildad; stop palavering,--away!\" and with that,\nPeleg hurried him over the side, and both dropt into the boat.\n\nShip and boat diverged; the cold, damp night breeze blew between; a\nscreaming gull flew overhead; the two hulls wildly rolled; we gave\nthree heavy-hearted cheers, and blindly plunged like fate into the\nlone Atlantic.\n\n\n\nCHAPTER 23\n\nThe Lee Shore.\n\n\nSome chapters back, one Bulkington was spoken of, a tall, newlanded\nmariner, encountered in New Bedford at the inn.\n\nWhen on that shivering winter's night, the Pequod thrust her\nvindictive bows into the cold malicious waves, who should I see\nstanding at her helm but Bulkington!  I looked with sympathetic awe\nand fearfulness upon the man, who in mid-winter just landed from a\nfour years' dangerous voyage, could so unrestingly push off again for\nstill another tempestuous term.  The land seemed scorching to his\nfeet.  Wonderfullest things are ever the unmentionable; deep memories\nyield no epitaphs; this six-inch chapter is the stoneless grave of\nBulkington.  Let me only say that it fared with him as with the\nstorm-tossed ship, that miserably drives along the leeward land.  The\nport would fain give succor; the port is pitiful; in the port is\nsafety, comfort, hearthstone, supper, warm blankets, friends, all\nthat's kind to our mortalities.  But in that gale, the port, the\nland, is that ship's direst jeopardy; she must fly all hospitality;\none touch of land, though it but graze the keel, would make her\nshudder through and through.  With all her might she crowds all sail\noff shore; in so doing, fights 'gainst the very winds that fain would\nblow her homeward; seeks all the lashed sea's landlessness again; for\nrefuge's sake forlornly rushing into peril; her only friend her\nbitterest foe!\n\nKnow ye now, Bulkington?  Glimpses do ye seem to see of that mortally\nintolerable truth; that all deep, earnest thinking is but the\nintrepid effort of the soul to keep the open independence of her sea;\nwhile the wildest winds of heaven and earth conspire to cast her on\nthe treacherous, slavish shore?\n\nBut as in landlessness alone resides highest truth, shoreless,\nindefinite as God--so, better is it to perish in that howling\ninfinite, than be ingloriously dashed upon the lee, even if that were\nsafety!  For worm-like, then, oh! who would craven crawl to land!\nTerrors of the terrible! is all this agony so vain?  Take heart, take\nheart, O Bulkington!  Bear thee grimly, demigod!  Up from the spray\nof thy ocean-perishing--straight up, leaps thy apotheosis!\n\n\n\nCHAPTER 24\n\nThe Advocate.\n\n\nAs Queequeg and I are now fairly embarked in this business of\nwhaling; and as this business of whaling has somehow come to be\nregarded among landsmen as a rather unpoetical and disreputable\npursuit; therefore, I am all anxiety to convince ye, ye landsmen, of\nthe injustice hereby done to us hunters of whales.\n\nIn the first place, it may be deemed almost superfluous to establish\nthe fact, that among people at large, the business of whaling is not\naccounted on a level with what are called the liberal professions.\nIf a stranger were introduced into any miscellaneous metropolitan\nsociety, it would but slightly advance the general opinion of his\nmerits, were he presented to the company as a harpooneer, say; and if\nin emulation of the naval officers he should append the initials\nS.W.F. (Sperm Whale Fishery) to his visiting card, such a procedure\nwould be deemed pre-eminently presuming and ridiculous.\n\nDoubtless one leading reason why the world declines honouring us\nwhalemen, is this: they think that, at best, our vocation amounts to\na butchering sort of business; and that when actively engaged\ntherein, we are surrounded by all manner of defilements.  Butchers we\nare, that is true.  But butchers, also, and butchers of the bloodiest\nbadge have been all Martial Commanders whom the world invariably\ndelights to honour.  And as for the matter of the alleged\nuncleanliness of our business, ye shall soon be initiated into\ncertain facts hitherto pretty generally unknown, and which, upon the\nwhole, will triumphantly plant the sperm whale-ship at least among\nthe cleanliest things of this tidy earth.  But even granting the\ncharge in question to be true; what disordered slippery decks of a\nwhale-ship are comparable to the unspeakable carrion of those\nbattle-fields from which so many soldiers return to drink in all\nladies' plaudits?  And if the idea of peril so much enhances the\npopular conceit of the soldier's profession; let me assure ye that\nmany a veteran who has freely marched up to a battery, would quickly\nrecoil at the apparition of the sperm whale's vast tail, fanning into\neddies the air over his head.  For what are the comprehensible\nterrors of man compared with the interlinked terrors and wonders of\nGod!\n\nBut, though the world scouts at us whale hunters, yet does it\nunwittingly pay us the profoundest homage; yea, an all-abounding\nadoration! for almost all the tapers, lamps, and candles that burn\nround the globe, burn, as before so many shrines, to our glory!\n\nBut look at this matter in other lights; weigh it in all sorts of\nscales; see what we whalemen are, and have been.\n\nWhy did the Dutch in De Witt's time have admirals of their whaling\nfleets?  Why did Louis XVI. of France, at his own personal expense,\nfit out whaling ships from Dunkirk, and politely invite to that town\nsome score or two of families from our own island of Nantucket?  Why\ndid Britain between the years 1750 and 1788 pay to her whalemen in\nbounties upwards of L1,000,000?  And lastly, how comes it that we\nwhalemen of America now outnumber all the rest of the banded whalemen\nin the world; sail a navy of upwards of seven hundred vessels; manned\nby eighteen thousand men; yearly consuming 4,000,000 of dollars; the\nships worth, at the time of sailing, $20,000,000! and every year\nimporting into our harbors a well reaped harvest of $7,000,000.  How\ncomes all this, if there be not something puissant in whaling?\n\nBut this is not the half; look again.\n\nI freely assert, that the cosmopolite philosopher cannot, for his\nlife, point out one single peaceful influence, which within the last\nsixty years has operated more potentially upon the whole broad world,\ntaken in one aggregate, than the high and mighty business of whaling.\nOne way and another, it has begotten events so remarkable in\nthemselves, and so continuously momentous in their sequential issues,\nthat whaling may well be regarded as that Egyptian mother, who bore\noffspring themselves pregnant from her womb.  It would be a hopeless,\nendless task to catalogue all these things.  Let a handful suffice.\nFor many years past the whale-ship has been the pioneer in ferreting\nout the remotest and least known parts of the earth.  She has\nexplored seas and archipelagoes which had no chart, where no Cook or\nVancouver had ever sailed.  If American and European men-of-war\nnow peacefully ride in once savage harbors, let them fire salutes to\nthe honour and glory of the whale-ship, which originally showed them\nthe way, and first interpreted between them and the savages.  They\nmay celebrate as they will the heroes of Exploring Expeditions, your\nCooks, your Krusensterns; but I say that scores of anonymous\nCaptains have sailed out of Nantucket, that were as great, and\ngreater than your Cook and your Krusenstern.  For in their\nsuccourless empty-handedness, they, in the heathenish sharked waters,\nand by the beaches of unrecorded, javelin islands, battled with\nvirgin wonders and terrors that Cook with all his marines and\nmuskets would not willingly have dared.  All that is made such a\nflourish of in the old South Sea Voyages, those things were but the\nlife-time commonplaces of our heroic Nantucketers.  Often,\nadventures which Vancouver dedicates three chapters to, these men\naccounted unworthy of being set down in the ship's common log.  Ah,\nthe world!  Oh, the world!\n\nUntil the whale fishery rounded Cape Horn, no commerce but colonial,\nscarcely any intercourse but colonial, was carried on between Europe\nand the long line of the opulent Spanish provinces on the Pacific\ncoast.  It was the whaleman who first broke through the jealous\npolicy of the Spanish crown, touching those colonies; and, if space\npermitted, it might be distinctly shown how from those whalemen at\nlast eventuated the liberation of Peru, Chili, and Bolivia from the\nyoke of Old Spain, and the establishment of the eternal democracy in\nthose parts.\n\nThat great America on the other side of the sphere, Australia, was\ngiven to the enlightened world by the whaleman.  After its first\nblunder-born discovery by a Dutchman, all other ships long shunned\nthose shores as pestiferously barbarous; but the whale-ship touched\nthere.  The whale-ship is the true mother of that now mighty colony.\nMoreover, in the infancy of the first Australian settlement, the\nemigrants were several times saved from starvation by the benevolent\nbiscuit of the whale-ship luckily dropping an anchor in their waters.\nThe uncounted isles of all Polynesia confess the same truth, and do\ncommercial homage to the whale-ship, that cleared the way for the\nmissionary and the merchant, and in many cases carried the primitive\nmissionaries to their first destinations.  If that double-bolted\nland, Japan, is ever to become hospitable, it is the whale-ship alone\nto whom the credit will be due; for already she is on the threshold.\n\nBut if, in the face of all this, you still declare that whaling has\nno aesthetically noble associations connected with it, then am I\nready to shiver fifty lances with you there, and unhorse you with a\nsplit helmet every time.\n\nThe whale has no famous author, and whaling no famous chronicler, you\nwill say.\n\nTHE WHALE NO FAMOUS AUTHOR, AND WHALING NO FAMOUS CHRONICLER?  Who\nwrote the first account of our Leviathan?  Who but mighty Job!  And\nwho composed the first narrative of a whaling-voyage?  Who, but no\nless a prince than Alfred the Great, who, with his own royal pen,\ntook down the words from Other, the Norwegian whale-hunter of those\ntimes!  And who pronounced our glowing eulogy in Parliament?  Who,\nbut Edmund Burke!\n\nTrue enough, but then whalemen themselves are poor devils; they have\nno good blood in their veins.\n\nNO GOOD BLOOD IN THEIR VEINS?  They have something better than royal\nblood there.  The grandmother of Benjamin Franklin was Mary Morrel;\nafterwards, by marriage, Mary Folger, one of the old settlers of\nNantucket, and the ancestress to a long line of Folgers and\nharpooneers--all kith and kin to noble Benjamin--this day darting the\nbarbed iron from one side of the world to the other.\n\nGood again; but then all confess that somehow whaling is not\nrespectable.\n\nWHALING NOT RESPECTABLE?  Whaling is imperial!  By old English\nstatutory law, the whale is declared \"a royal fish.\"*\n\nOh, that's only nominal!  The whale himself has never figured in any\ngrand imposing way.\n\nTHE WHALE NEVER FIGURED IN ANY GRAND IMPOSING WAY?  In one of the\nmighty triumphs given to a Roman general upon his entering the\nworld's capital, the bones of a whale, brought all the way from the\nSyrian coast, were the most conspicuous object in the cymballed\nprocession.*\n\n\n*See subsequent chapters for something more on this head.\n\n\nGrant it, since you cite it; but, say what you will, there is no real\ndignity in whaling.\n\nNO DIGNITY IN WHALING?  The dignity of our calling the very heavens\nattest.  Cetus is a constellation in the South!  No more!  Drive\ndown your hat in presence of the Czar, and take it off to Queequeg!\nNo more!  I know a man that, in his lifetime, has taken three hundred\nand fifty whales.  I account that man more honourable than that great\ncaptain of antiquity who boasted of taking as many walled towns.\n\nAnd, as for me, if, by any possibility, there be any as yet\nundiscovered prime thing in me; if I shall ever deserve any real\nrepute in that small but high hushed world which I might not be\nunreasonably ambitious of; if hereafter I shall do anything that, upon\nthe whole, a man might rather have done than to have left undone; if,\nat my death, my executors, or more properly my creditors, find any\nprecious MSS. in my desk, then here I prospectively ascribe all the\nhonour and the glory to whaling; for a whale-ship was my Yale College\nand my Harvard.\n\n\n\nCHAPTER 25\n\nPostscript.\n\n\nIn behalf of the dignity of whaling, I would fain advance naught but\nsubstantiated facts.  But after embattling his facts, an advocate who\nshould wholly suppress a not unreasonable surmise, which might tell\neloquently upon his cause--such an advocate, would he not be\nblameworthy?\n\nIt is well known that at the coronation of kings and queens, even\nmodern ones, a certain curious process of seasoning them for their\nfunctions is gone through.  There is a saltcellar of state, so\ncalled, and there may be a castor of state.  How they use the salt,\nprecisely--who knows?  Certain I am, however, that a king's head is\nsolemnly oiled at his coronation, even as a head of salad.  Can it\nbe, though, that they anoint it with a view of making its interior\nrun well, as they anoint machinery?  Much might be ruminated here,\nconcerning the essential dignity of this regal process, because in\ncommon life we esteem but meanly and contemptibly a fellow who\nanoints his hair, and palpably smells of that anointing.  In truth, a\nmature man who uses hair-oil, unless medicinally, that man has\nprobably got a quoggy spot in him somewhere.  As a general rule, he\ncan't amount to much in his totality.\n\nBut the only thing to be considered here, is this--what kind of oil\nis used at coronations?  Certainly it cannot be olive oil, nor\nmacassar oil, nor castor oil, nor bear's oil, nor train oil, nor\ncod-liver oil.  What then can it possibly be, but sperm oil in\nits unmanufactured, unpolluted state, the sweetest of all oils?\n\nThink of that, ye loyal Britons! we whalemen supply your kings and\nqueens with coronation stuff!\n\n\n\nCHAPTER 26\n\nKnights and Squires.\n\n\nThe chief mate of the Pequod was Starbuck, a native of Nantucket, and\na Quaker by descent.  He was a long, earnest man, and though born on\nan icy coast, seemed well adapted to endure hot latitudes, his flesh\nbeing hard as twice-baked biscuit.  Transported to the Indies, his\nlive blood would not spoil like bottled ale.  He must have been born\nin some time of general drought and famine, or upon one of those fast\ndays for which his state is famous.  Only some thirty arid summers\nhad he seen; those summers had dried up all his physical\nsuperfluousness.  But this, his thinness, so to speak, seemed no more\nthe token of wasting anxieties and cares, than it seemed the\nindication of any bodily blight.  It was merely the condensation of\nthe man.  He was by no means ill-looking; quite the contrary.  His\npure tight skin was an excellent fit; and closely wrapped up in it,\nand embalmed with inner health and strength, like a revivified\nEgyptian, this Starbuck seemed prepared to endure for long ages to\ncome, and to endure always, as now; for be it Polar snow or torrid\nsun, like a patent chronometer, his interior vitality was warranted\nto do well in all climates.  Looking into his eyes, you seemed to\nsee there the yet lingering images of those thousand-fold perils he\nhad calmly confronted through life.  A staid, steadfast man, whose\nlife for the most part was a telling pantomime of action, and not a\ntame chapter of sounds.  Yet, for all his hardy sobriety and\nfortitude, there were certain qualities in him which at times\naffected, and in some cases seemed well nigh to overbalance all the\nrest.  Uncommonly conscientious for a seaman, and endued with a deep\nnatural reverence, the wild watery loneliness of his life did\ntherefore strongly incline him to superstition; but to that sort of\nsuperstition, which in some organizations seems rather to spring,\nsomehow, from intelligence than from ignorance.  Outward portents and\ninward presentiments were his.  And if at times these things bent the\nwelded iron of his soul, much more did his far-away domestic memories\nof his young Cape wife and child, tend to bend him still more from\nthe original ruggedness of his nature, and open him still further to\nthose latent influences which, in some honest-hearted men, restrain\nthe gush of dare-devil daring, so often evinced by others in the more\nperilous vicissitudes of the fishery.  \"I will have no man in my\nboat,\" said Starbuck, \"who is not afraid of a whale.\"  By this, he\nseemed to mean, not only that the most reliable and useful courage\nwas that which arises from the fair estimation of the encountered\nperil, but that an utterly fearless man is a far more dangerous\ncomrade than a coward.\n\n\"Aye, aye,\" said Stubb, the second mate, \"Starbuck, there, is as\ncareful a man as you'll find anywhere in this fishery.\"  But we shall\nere long see what that word \"careful\" precisely means when used by a\nman like Stubb, or almost any other whale hunter.\n\nStarbuck was no crusader after perils; in him courage was not a\nsentiment; but a thing simply useful to him, and always at hand upon\nall mortally practical occasions.  Besides, he thought, perhaps, that\nin this business of whaling, courage was one of the great staple\noutfits of the ship, like her beef and her bread, and not to be\nfoolishly wasted.  Wherefore he had no fancy for lowering for whales\nafter sun-down; nor for persisting in fighting a fish that too much\npersisted in fighting him.  For, thought Starbuck, I am here in this\ncritical ocean to kill whales for my living, and not to be killed by\nthem for theirs; and that hundreds of men had been so killed Starbuck\nwell knew.  What doom was his own father's?  Where, in the bottomless\ndeeps, could he find the torn limbs of his brother?\n\nWith memories like these in him, and, moreover, given to a certain\nsuperstitiousness, as has been said; the courage of this Starbuck\nwhich could, nevertheless, still flourish, must indeed have been\nextreme.  But it was not in reasonable nature that a man so\norganized, and with such terrible experiences and remembrances as he\nhad; it was not in nature that these things should fail in latently\nengendering an element in him, which, under suitable circumstances,\nwould break out from its confinement, and burn all his courage up.\nAnd brave as he might be, it was that sort of bravery chiefly,\nvisible in some intrepid men, which, while generally abiding firm in\nthe conflict with seas, or winds, or whales, or any of the ordinary\nirrational horrors of the world, yet cannot withstand those more\nterrific, because more spiritual terrors, which sometimes menace you\nfrom the concentrating brow of an enraged and mighty man.\n\nBut were the coming narrative to reveal in any instance, the complete\nabasement of poor Starbuck's fortitude, scarce might I have the heart\nto write it; for it is a thing most sorrowful, nay shocking, to\nexpose the fall of valour in the soul.  Men may seem detestable as\njoint stock-companies and nations; knaves, fools, and murderers there\nmay be; men may have mean and meagre faces; but man, in the ideal,\nis so noble and so sparkling, such a grand and glowing creature, that\nover any ignominious blemish in him all his fellows should run to\nthrow their costliest robes.  That immaculate manliness we feel\nwithin ourselves, so far within us, that it remains intact though all\nthe outer character seem gone; bleeds with keenest anguish at the\nundraped spectacle of a valor-ruined man.  Nor can piety itself, at\nsuch a shameful sight, completely stifle her upbraidings against the\npermitting stars.  But this august dignity I treat of, is not the\ndignity of kings and robes, but that abounding dignity which has no\nrobed investiture.  Thou shalt see it shining in the arm that wields\na pick or drives a spike; that democratic dignity which, on all\nhands, radiates without end from God; Himself!  The great God\nabsolute!  The centre and circumference of all democracy!  His\nomnipresence, our divine equality!\n\nIf, then, to meanest mariners, and renegades and castaways, I shall\nhereafter ascribe high qualities, though dark; weave round them\ntragic graces; if even the most mournful, perchance the most abased,\namong them all, shall at times lift himself to the exalted mounts; if\nI shall touch that workman's arm with some ethereal light; if I shall\nspread a rainbow over his disastrous set of sun; then against all\nmortal critics bear me out in it, thou Just Spirit of Equality,\nwhich hast spread one royal mantle of humanity over all my kind!\nBear me out in it, thou great democratic God! who didst not refuse to\nthe swart convict, Bunyan, the pale, poetic pearl; Thou who didst\nclothe with doubly hammered leaves of finest gold, the stumped and\npaupered arm of old Cervantes; Thou who didst pick up Andrew Jackson\nfrom the pebbles; who didst hurl him upon a war-horse; who didst\nthunder him higher than a throne!  Thou who, in all Thy mighty,\nearthly marchings, ever cullest Thy selectest champions from the\nkingly commons; bear me out in it, O God!\n\n\n\nCHAPTER 27\n\nKnights and Squires.\n\n\nStubb was the second mate.  He was a native of Cape Cod; and hence,\naccording to local usage, was called a Cape-Cod-man.  A\nhappy-go-lucky; neither craven nor valiant; taking perils as they\ncame with an indifferent air; and while engaged in the most imminent\ncrisis of the chase, toiling away, calm and collected as a journeyman\njoiner engaged for the year.  Good-humored, easy, and careless, he\npresided over his whale-boat as if the most deadly encounter were but\na dinner, and his crew all invited guests.  He was as particular\nabout the comfortable arrangement of his part of the boat, as an\nold stage-driver is about the snugness of his box.  When close to the\nwhale, in the very death-lock of the fight, he handled his unpitying\nlance coolly and off-handedly, as a whistling tinker his hammer.  He\nwould hum over his old rigadig tunes while flank and flank with the\nmost exasperated monster.  Long usage had, for this Stubb, converted\nthe jaws of death into an easy chair.  What he thought of death\nitself, there is no telling.  Whether he ever thought of it at all,\nmight be a question; but, if he ever did chance to cast his mind that\nway after a comfortable dinner, no doubt, like a good sailor, he took\nit to be a sort of call of the watch to tumble aloft, and bestir\nthemselves there, about something which he would find out when he\nobeyed the order, and not sooner.\n\nWhat, perhaps, with other things, made Stubb such an easy-going,\nunfearing man, so cheerily trudging off with the burden of life in a\nworld full of grave pedlars, all bowed to the ground with their\npacks; what helped to bring about that almost impious good-humor of\nhis; that thing must have been his pipe.  For, like his nose, his\nshort, black little pipe was one of the regular features of his face.\nYou would almost as soon have expected him to turn out of his bunk\nwithout his nose as without his pipe.  He kept a whole row of pipes\nthere ready loaded, stuck in a rack, within easy reach of his hand;\nand, whenever he turned in, he smoked them all out in succession,\nlighting one from the other to the end of the chapter; then loading\nthem again to be in readiness anew.  For, when Stubb dressed, instead\nof first putting his legs into his trowsers, he put his pipe into his\nmouth.\n\nI say this continual smoking must have been one cause, at least, of\nhis peculiar disposition; for every one knows that this earthly air,\nwhether ashore or afloat, is terribly infected with the nameless\nmiseries of the numberless mortals who have died exhaling it; and as\nin time of the cholera, some people go about with a camphorated\nhandkerchief to their mouths; so, likewise, against all mortal\ntribulations, Stubb's tobacco smoke might have operated as a sort of\ndisinfecting agent.\n\nThe third mate was Flask, a native of Tisbury, in Martha's Vineyard.\nA short, stout, ruddy young fellow, very pugnacious concerning\nwhales, who somehow seemed to think that the great leviathans had\npersonally and hereditarily affronted him; and therefore it was a\nsort of point of honour with him, to destroy them whenever\nencountered.  So utterly lost was he to all sense of reverence for\nthe many marvels of their majestic bulk and mystic ways; and so dead\nto anything like an apprehension of any possible danger from\nencountering them; that in his poor opinion, the wondrous whale was\nbut a species of magnified mouse, or at least water-rat, requiring\nonly a little circumvention and some small application of time and\ntrouble in order to kill and boil.  This ignorant, unconscious\nfearlessness of his made him a little waggish in the matter of\nwhales; he followed these fish for the fun of it; and a three years'\nvoyage round Cape Horn was only a jolly joke that lasted that length\nof time.  As a carpenter's nails are divided into wrought nails and\ncut nails; so mankind may be similarly divided.  Little Flask was one\nof the wrought ones; made to clinch tight and last long.  They called\nhim King-Post on board of the Pequod; because, in form, he could be\nwell likened to the short, square timber known by that name in Arctic\nwhalers; and which by the means of many radiating side timbers\ninserted into it, serves to brace the ship against the icy\nconcussions of those battering seas.\n\nNow these three mates--Starbuck, Stubb, and Flask, were momentous\nmen.  They it was who by universal prescription commanded three of the\nPequod's boats as headsmen.  In that grand order of battle in which\nCaptain Ahab would probably marshal his forces to descend on the\nwhales, these three headsmen were as captains of companies.  Or,\nbeing armed with their long keen whaling spears, they were as a\npicked trio of lancers; even as the harpooneers were flingers of\njavelins.\n\nAnd since in this famous fishery, each mate or headsman, like a\nGothic Knight of old, is always accompanied by his boat-steerer or\nharpooneer, who in certain conjunctures provides him with a fresh\nlance, when the former one has been badly twisted, or elbowed in the\nassault; and moreover, as there generally subsists between the two, a\nclose intimacy and friendliness; it is therefore but meet, that in\nthis place we set down who the Pequod's harpooneers were, and to what\nheadsman each of them belonged.\n\nFirst of all was Queequeg, whom Starbuck, the chief mate, had\nselected for his squire.  But Queequeg is already known.\n\nNext was Tashtego, an unmixed Indian from Gay Head, the most westerly\npromontory of Martha's Vineyard, where there still exists the last\nremnant of a village of red men, which has long supplied the\nneighboring island of Nantucket with many of her most daring\nharpooneers.  In the fishery, they usually go by the generic name of\nGay-Headers.  Tashtego's long, lean, sable hair, his high cheek\nbones, and black rounding eyes--for an Indian, Oriental in their\nlargeness, but Antarctic in their glittering expression--all this\nsufficiently proclaimed him an inheritor of the unvitiated blood of\nthose proud warrior hunters, who, in quest of the great New England\nmoose, had scoured, bow in hand, the aboriginal forests of the main.\nBut no longer snuffing in the trail of the wild beasts of the\nwoodland, Tashtego now hunted in the wake of the great whales of the\nsea; the unerring harpoon of the son fitly replacing the infallible\narrow of the sires.  To look at the tawny brawn of his lithe snaky\nlimbs, you would almost have credited the superstitions of some of\nthe earlier Puritans, and half-believed this wild Indian to be a son\nof the Prince of the Powers of the Air.  Tashtego was Stubb the\nsecond mate's squire.\n\nThird among the harpooneers was Daggoo, a gigantic, coal-black\nnegro-savage, with a lion-like tread--an Ahasuerus to behold.\nSuspended from his ears were two golden hoops, so large that the\nsailors called them ring-bolts, and would talk of securing the\ntop-sail halyards to them.  In his youth Daggoo had voluntarily\nshipped on board of a whaler, lying in a lonely bay on his native\ncoast.  And never having been anywhere in the world but in Africa,\nNantucket, and the pagan harbors most frequented by whalemen; and\nhaving now led for many years the bold life of the fishery in the\nships of owners uncommonly heedful of what manner of men they\nshipped; Daggoo retained all his barbaric virtues, and erect as a\ngiraffe, moved about the decks in all the pomp of six feet five in\nhis socks.  There was a corporeal humility in looking up at him; and\na white man standing before him seemed a white flag come to beg truce\nof a fortress.  Curious to tell, this imperial negro, Ahasuerus\nDaggoo, was the Squire of little Flask, who looked like a chess-man\nbeside him.  As for the residue of the Pequod's company, be it said,\nthat at the present day not one in two of the many thousand men\nbefore the mast employed in the American whale fishery, are Americans\nborn, though pretty nearly all the officers are.  Herein it is the\nsame with the American whale fishery as with the American army and\nmilitary and merchant navies, and the engineering forces employed in\nthe construction of the American Canals and Railroads.  The same, I\nsay, because in all these cases the native American liberally\nprovides the brains, the rest of the world as generously supplying\nthe muscles.  No small number of these whaling seamen belong to the\nAzores, where the outward bound Nantucket whalers frequently touch to\naugment their crews from the hardy peasants of those rocky shores.\nIn like manner, the Greenland whalers sailing out of Hull or London,\nput in at the Shetland Islands, to receive the full complement of\ntheir crew.  Upon the passage homewards, they drop them there again.\nHow it is, there is no telling, but Islanders seem to make the best\nwhalemen.  They were nearly all Islanders in the Pequod, ISOLATOES\ntoo, I call such, not acknowledging the common continent of men, but\neach ISOLATO living on a separate continent of his own.  Yet now,\nfederated along one keel, what a set these Isolatoes were!  An\nAnacharsis Clootz deputation from all the isles of the sea, and all\nthe ends of the earth, accompanying Old Ahab in the Pequod to lay the\nworld's grievances before that bar from which not very many of them\never come back.  Black Little Pip--he never did--oh, no! he went\nbefore.  Poor Alabama boy!  On the grim Pequod's forecastle, ye shall\nere long see him, beating his tambourine; prelusive of the eternal\ntime, when sent for, to the great quarter-deck on high, he was bid\nstrike in with angels, and beat his tambourine in glory; called a\ncoward here, hailed a hero there!\n\n\n\nCHAPTER 28\n\nAhab.\n\n\nFor several days after leaving Nantucket, nothing above hatches was\nseen of Captain Ahab.  The mates regularly relieved each other at the\nwatches, and for aught that could be seen to the contrary, they\nseemed to be the only commanders of the ship; only they sometimes\nissued from the cabin with orders so sudden and peremptory, that\nafter all it was plain they but commanded vicariously.  Yes, their\nsupreme lord and dictator was there, though hitherto unseen by any\neyes not permitted to penetrate into the now sacred retreat of the\ncabin.\n\nEvery time I ascended to the deck from my watches below, I instantly\ngazed aft to mark if any strange face were visible; for my first\nvague disquietude touching the unknown captain, now in the seclusion\nof the sea, became almost a perturbation.  This was strangely\nheightened at times by the ragged Elijah's diabolical incoherences\nuninvitedly recurring to me, with a subtle energy I could not have\nbefore conceived of.  But poorly could I withstand them, much as in\nother moods I was almost ready to smile at the solemn whimsicalities\nof that outlandish prophet of the wharves.  But whatever it was of\napprehensiveness or uneasiness--to call it so--which I felt, yet\nwhenever I came to look about me in the ship, it seemed against all\nwarrantry to cherish such emotions.  For though the harpooneers, with\nthe great body of the crew, were a far more barbaric, heathenish, and\nmotley set than any of the tame merchant-ship companies which my\nprevious experiences had made me acquainted with, still I ascribed\nthis--and rightly ascribed it--to the fierce uniqueness of the very\nnature of that wild Scandinavian vocation in which I had so\nabandonedly embarked.  But it was especially the aspect of the three\nchief officers of the ship, the mates, which was most forcibly\ncalculated to allay these colourless misgivings, and induce confidence\nand cheerfulness in every presentment of the voyage.  Three better,\nmore likely sea-officers and men, each in his own different way,\ncould not readily be found, and they were every one of them\nAmericans; a Nantucketer, a Vineyarder, a Cape man.  Now, it being\nChristmas when the ship shot from out her harbor, for a space we had\nbiting Polar weather, though all the time running away from it to the\nsouthward; and by every degree and minute of latitude which we\nsailed, gradually leaving that merciless winter, and all its\nintolerable weather behind us.  It was one of those less lowering,\nbut still grey and gloomy enough mornings of the transition, when\nwith a fair wind the ship was rushing through the water with a\nvindictive sort of leaping and melancholy rapidity, that as I mounted\nto the deck at the call of the forenoon watch, so soon as I levelled\nmy glance towards the taffrail, foreboding shivers ran over me.\nReality outran apprehension; Captain Ahab stood upon his\nquarter-deck.\n\nThere seemed no sign of common bodily illness about him, nor of the\nrecovery from any.  He looked like a man cut away from the stake,\nwhen the fire has overrunningly wasted all the limbs without\nconsuming them, or taking away one particle from their compacted aged\nrobustness.  His whole high, broad form, seemed made of solid bronze,\nand shaped in an unalterable mould, like Cellini's cast Perseus.\nThreading its way out from among his grey hairs, and continuing right\ndown one side of his tawny scorched face and neck, till it\ndisappeared in his clothing, you saw a slender rod-like mark, lividly\nwhitish.  It resembled that perpendicular seam sometimes made in the\nstraight, lofty trunk of a great tree, when the upper lightning\ntearingly darts down it, and without wrenching a single twig, peels\nand grooves out the bark from top to bottom, ere running off into the\nsoil, leaving the tree still greenly alive, but branded.  Whether\nthat mark was born with him, or whether it was the scar left by some\ndesperate wound, no one could certainly say.  By some tacit consent,\nthroughout the voyage little or no allusion was made to it,\nespecially by the mates.  But once Tashtego's senior, an old Gay-Head\nIndian among the crew, superstitiously asserted that not till he was\nfull forty years old did Ahab become that way branded, and then it\ncame upon him, not in the fury of any mortal fray, but in an\nelemental strife at sea.  Yet, this wild hint seemed inferentially\nnegatived, by what a grey Manxman insinuated, an old sepulchral man,\nwho, having never before sailed out of Nantucket, had never ere this\nlaid eye upon wild Ahab.  Nevertheless, the old sea-traditions, the\nimmemorial credulities, popularly invested this old Manxman with\npreternatural powers of discernment.  So that no white sailor\nseriously contradicted him when he said that if ever Captain Ahab\nshould be tranquilly laid out--which might hardly come to pass, so he\nmuttered--then, whoever should do that last office for the dead,\nwould find a birth-mark on him from crown to sole.\n\nSo powerfully did the whole grim aspect of Ahab affect me, and the\nlivid brand which streaked it, that for the first few moments I\nhardly noted that not a little of this overbearing grimness was owing\nto the barbaric white leg upon which he partly stood.  It had\npreviously come to me that this ivory leg had at sea been fashioned\nfrom the polished bone of the sperm whale's jaw.  \"Aye, he was\ndismasted off Japan,\" said the old Gay-Head Indian once; \"but like\nhis dismasted craft, he shipped another mast without coming home for\nit.  He has a quiver of 'em.\"\n\nI was struck with the singular posture he maintained.  Upon each side\nof the Pequod's quarter deck, and pretty close to the mizzen shrouds,\nthere was an auger hole, bored about half an inch or so, into the\nplank.  His bone leg steadied in that hole; one arm elevated, and\nholding by a shroud; Captain Ahab stood erect, looking straight out\nbeyond the ship's ever-pitching prow.  There was an infinity of\nfirmest fortitude, a determinate, unsurrenderable wilfulness, in the\nfixed and fearless, forward dedication of that glance.  Not a word he\nspoke; nor did his officers say aught to him; though by all their\nminutest gestures and expressions, they plainly showed the uneasy, if\nnot painful, consciousness of being under a troubled master-eye.  And\nnot only that, but moody stricken Ahab stood before them with a\ncrucifixion in his face; in all the nameless regal overbearing\ndignity of some mighty woe.\n\nEre long, from his first visit in the air, he withdrew into his\ncabin.  But after that morning, he was every day visible to the crew;\neither standing in his pivot-hole, or seated upon an ivory stool he\nhad; or heavily walking the deck.  As the sky grew less gloomy;\nindeed, began to grow a little genial, he became still less and less\na recluse; as if, when the ship had sailed from home, nothing but the\ndead wintry bleakness of the sea had then kept him so secluded.  And,\nby and by, it came to pass, that he was almost continually in the\nair; but, as yet, for all that he said, or perceptibly did, on the at\nlast sunny deck, he seemed as unnecessary there as another mast.  But\nthe Pequod was only making a passage now; not regularly cruising;\nnearly all whaling preparatives needing supervision the mates were\nfully competent to, so that there was little or nothing, out of\nhimself, to employ or excite Ahab, now; and thus chase away, for that\none interval, the clouds that layer upon layer were piled upon his\nbrow, as ever all clouds choose the loftiest peaks to pile themselves\nupon.\n\nNevertheless, ere long, the warm, warbling persuasiveness of the\npleasant, holiday weather we came to, seemed gradually to charm him\nfrom his mood.  For, as when the red-cheeked, dancing girls, April\nand May, trip home to the wintry, misanthropic woods; even the\nbarest, ruggedest, most thunder-cloven old oak will at least send\nforth some few green sprouts, to welcome such glad-hearted visitants;\nso Ahab did, in the end, a little respond to the playful allurings of\nthat girlish air.  More than once did he put forth the faint blossom\nof a look, which, in any other man, would have soon flowered out in a\nsmile.\n\n\n\nCHAPTER 29\n\nEnter Ahab; to Him, Stubb.\n\n\nSome days elapsed, and ice and icebergs all astern, the Pequod now\nwent rolling through the bright Quito spring, which, at sea, almost\nperpetually reigns on the threshold of the eternal August of the\nTropic.  The warmly cool, clear, ringing, perfumed, overflowing,\nredundant days, were as crystal goblets of Persian sherbet, heaped\nup--flaked up, with rose-water snow.  The starred and stately nights\nseemed haughty dames in jewelled velvets, nursing at home in lonely\npride, the memory of their absent conquering Earls, the golden\nhelmeted suns!  For sleeping man, 'twas hard to choose between such\nwinsome days and such seducing nights.  But all the witcheries of\nthat unwaning weather did not merely lend new spells and potencies to\nthe outward world.  Inward they turned upon the soul, especially when\nthe still mild hours of eve came on; then, memory shot her crystals\nas the clear ice most forms of noiseless twilights.  And all these\nsubtle agencies, more and more they wrought on Ahab's texture.\n\nOld age is always wakeful; as if, the longer linked with life, the\nless man has to do with aught that looks like death.  Among\nsea-commanders, the old greybeards will oftenest leave their berths\nto visit the night-cloaked deck.  It was so with Ahab; only that now,\nof late, he seemed so much to live in the open air, that truly\nspeaking, his visits were more to the cabin, than from the cabin to\nthe planks.  \"It feels like going down into one's tomb,\"--he would\nmutter to himself--\"for an old captain like me to be descending this\nnarrow scuttle, to go to my grave-dug berth.\"\n\nSo, almost every twenty-four hours, when the watches of the night\nwere set, and the band on deck sentinelled the slumbers of the band\nbelow; and when if a rope was to be hauled upon the forecastle, the\nsailors flung it not rudely down, as by day, but with some\ncautiousness dropt it to its place for fear of disturbing their\nslumbering shipmates; when this sort of steady quietude would begin\nto prevail, habitually, the silent steersman would watch the\ncabin-scuttle; and ere long the old man would emerge, gripping at the\niron banister, to help his crippled way.  Some considering touch of\nhumanity was in him; for at times like these, he usually abstained\nfrom patrolling the quarter-deck; because to his wearied mates,\nseeking repose within six inches of his ivory heel, such would have\nbeen the reverberating crack and din of that bony step, that their\ndreams would have been on the crunching teeth of sharks.  But once,\nthe mood was on him too deep for common regardings; and as with\nheavy, lumber-like pace he was measuring the ship from taffrail to\nmainmast, Stubb, the old second mate, came up from below, with a\ncertain unassured, deprecating humorousness, hinted that if Captain\nAhab was pleased to walk the planks, then, no one could say nay; but\nthere might be some way of muffling the noise; hinting something\nindistinctly and hesitatingly about a globe of tow, and the insertion\ninto it, of the ivory heel.  Ah!  Stubb, thou didst not know Ahab\nthen.\n\n\"Am I a cannon-ball, Stubb,\" said Ahab, \"that thou wouldst wad me\nthat fashion?  But go thy ways; I had forgot.  Below to thy nightly\ngrave; where such as ye sleep between shrouds, to use ye to the\nfilling one at last.--Down, dog, and kennel!\"\n\nStarting at the unforseen concluding exclamation of the so suddenly\nscornful old man, Stubb was speechless a moment; then said excitedly,\n\"I am not used to be spoken to that way, sir; I do but less than half\nlike it, sir.\"\n\n\"Avast! gritted Ahab between his set teeth, and violently moving\naway, as if to avoid some passionate temptation.\n\n\"No, sir; not yet,\" said Stubb, emboldened, \"I will not tamely be\ncalled a dog, sir.\"\n\n\"Then be called ten times a donkey, and a mule, and an ass, and\nbegone, or I'll clear the world of thee!\"\n\nAs he said this, Ahab advanced upon him with such overbearing terrors\nin his aspect, that Stubb involuntarily retreated.\n\n\"I was never served so before without giving a hard blow for it,\"\nmuttered Stubb, as he found himself descending the cabin-scuttle.\n\"It's very queer.  Stop, Stubb; somehow, now, I don't well know\nwhether to go back and strike him, or--what's that?--down here on my\nknees and pray for him?  Yes, that was the thought coming up in me;\nbut it would be the first time I ever DID pray.  It's queer; very\nqueer; and he's queer too; aye, take him fore and aft, he's about the\nqueerest old man Stubb ever sailed with.  How he flashed at me!--his\neyes like powder-pans! is he mad?  Anyway there's something on his\nmind, as sure as there must be something on a deck when it cracks.\nHe aint in his bed now, either, more than three hours out of the\ntwenty-four; and he don't sleep then.  Didn't that Dough-Boy, the\nsteward, tell me that of a morning he always finds the old man's\nhammock clothes all rumpled and tumbled, and the sheets down at the\nfoot, and the coverlid almost tied into knots, and the pillow a sort\nof frightful hot, as though a baked brick had been on it?  A hot old\nman!  I guess he's got what some folks ashore call a conscience; it's\na kind of Tic-Dolly-row they say--worse nor a toothache.  Well, well;\nI don't know what it is, but the Lord keep me from catching it.  He's\nfull of riddles; I wonder what he goes into the after hold for, every\nnight, as Dough-Boy tells me he suspects; what's that for, I should\nlike to know?  Who's made appointments with him in the hold?  Ain't\nthat queer, now?  But there's no telling, it's the old game--Here\ngoes for a snooze.  Damn me, it's worth a fellow's while to be born\ninto the world, if only to fall right asleep.  And now that I think\nof it, that's about the first thing babies do, and that's a sort of\nqueer, too.  Damn me, but all things are queer, come to think of 'em.\nBut that's against my principles.  Think not, is my eleventh\ncommandment; and sleep when you can, is my twelfth--So here goes\nagain.  But how's that? didn't he call me a dog? blazes! he called me\nten times a donkey, and piled a lot of jackasses on top of THAT!  He\nmight as well have kicked me, and done with it.  Maybe he DID kick\nme, and I didn't observe it, I was so taken all aback with his brow,\nsomehow.  It flashed like a bleached bone.  What the devil's the\nmatter with me?  I don't stand right on my legs.  Coming afoul of\nthat old man has a sort of turned me wrong side out.  By the Lord, I\nmust have been dreaming, though--How? how? how?--but the only way's\nto stash it; so here goes to hammock again; and in the morning, I'll\nsee how this plaguey juggling thinks over by daylight.\"\n\n\n\nCHAPTER 30\n\nThe Pipe.\n\n\nWhen Stubb had departed, Ahab stood for a while leaning over the\nbulwarks; and then, as had been usual with him of late, calling a\nsailor of the watch, he sent him below for his ivory stool, and also\nhis pipe.  Lighting the pipe at the binnacle lamp and planting the\nstool on the weather side of the deck, he sat and smoked.\n\nIn old Norse times, the thrones of the sea-loving Danish kings were\nfabricated, saith tradition, of the tusks of the narwhale.  How could\none look at Ahab then, seated on that tripod of bones, without\nbethinking him of the royalty it symbolized?  For a Khan of the\nplank, and a king of the sea, and a great lord of Leviathans was\nAhab.\n\nSome moments passed, during which the thick vapour came from his mouth\nin quick and constant puffs, which blew back again into his face.\n\"How now,\" he soliloquized at last, withdrawing the tube, \"this\nsmoking no longer soothes.  Oh, my pipe! hard must it go with me if\nthy charm be gone!  Here have I been unconsciously toiling, not\npleasuring--aye, and ignorantly smoking to windward all the while; to\nwindward, and with such nervous whiffs, as if, like the dying whale,\nmy final jets were the strongest and fullest of trouble.  What\nbusiness have I with this pipe?  This thing that is meant for\nsereneness, to send up mild white vapours among mild white hairs, not\namong torn iron-grey locks like mine.  I'll smoke no more--\"\n\nHe tossed the still lighted pipe into the sea.  The fire hissed in\nthe waves; the same instant the ship shot by the bubble the sinking\npipe made.  With slouched hat, Ahab lurchingly paced the planks.\n\n\n\nCHAPTER 31\n\nQueen Mab.\n\n\nNext morning Stubb accosted Flask.\n\n\"Such a queer dream, King-Post, I never had.  You know the old man's\nivory leg, well I dreamed he kicked me with it; and when I tried to\nkick back, upon my soul, my little man, I kicked my leg right off!\nAnd then, presto!  Ahab seemed a pyramid, and I, like a blazing fool,\nkept kicking at it.  But what was still more curious, Flask--you know\nhow curious all dreams are--through all this rage that I was in, I\nsomehow seemed to be thinking to myself, that after all, it was not\nmuch of an insult, that kick from Ahab.  'Why,' thinks I, 'what's the\nrow?  It's not a real leg, only a false leg.'  And there's a mighty\ndifference between a living thump and a dead thump.  That's what\nmakes a blow from the hand, Flask, fifty times more savage to bear\nthan a blow from a cane.  The living member--that makes the living\ninsult, my little man.  And thinks I to myself all the while, mind,\nwhile I was stubbing my silly toes against that cursed pyramid--so\nconfoundedly contradictory was it all, all the while, I say, I was\nthinking to myself, 'what's his leg now, but a cane--a whalebone\ncane.  Yes,' thinks I, 'it was only a playful cudgelling--in fact,\nonly a whaleboning that he gave me--not a base kick.  Besides,'\nthinks I, 'look at it once; why, the end of it--the foot part--what a\nsmall sort of end it is; whereas, if a broad footed farmer kicked me,\nTHERE'S a devilish broad insult.  But this insult is whittled down to\na point only.'  But now comes the greatest joke of the dream, Flask.\nWhile I was battering away at the pyramid, a sort of badger-haired\nold merman, with a hump on his back, takes me by the shoulders, and\nslews me round.  'What are you 'bout?' says he.  Slid! man, but I was\nfrightened.  Such a phiz!  But, somehow, next moment I was over the\nfright.  'What am I about?' says I at last.  'And what business is\nthat of yours, I should like to know, Mr. Humpback?  Do YOU want a\nkick?'  By the lord, Flask, I had no sooner said that, than he turned\nround his stern to me, bent over, and dragging up a lot of seaweed he\nhad for a clout--what do you think, I saw?--why thunder alive, man,\nhis stern was stuck full of marlinspikes, with the points out.  Says\nI, on second thoughts, 'I guess I won't kick you, old fellow.'  'Wise\nStubb,' said he, 'wise Stubb;' and kept muttering it all the time, a\nsort of eating of his own gums like a chimney hag.  Seeing he wasn't\ngoing to stop saying over his 'wise Stubb, wise Stubb,' I thought I\nmight as well fall to kicking the pyramid again.  But I had only just\nlifted my foot for it, when he roared out, 'Stop that kicking!'\n'Halloa,' says I, 'what's the matter now, old fellow?'  'Look ye\nhere,' says he; 'let's argue the insult.  Captain Ahab kicked ye,\ndidn't he?'  'Yes, he did,' says I--'right HERE it was.'  'Very\ngood,' says he--'he used his ivory leg, didn't he?'  'Yes, he did,'\nsays I.  'Well then,' says he, 'wise Stubb, what have you to complain\nof?  Didn't he kick with right good will? it wasn't a common pitch\npine leg he kicked with, was it?  No, you were kicked by a great man,\nand with a beautiful ivory leg, Stubb.  It's an honour; I consider it\nan honour.  Listen, wise Stubb.  In old England the greatest lords\nthink it great glory to be slapped by a queen, and made\ngarter-knights of; but, be YOUR boast, Stubb, that ye were kicked by\nold Ahab, and made a wise man of.  Remember what I say; BE kicked by\nhim; account his kicks honours; and on no account kick back; for you\ncan't help yourself, wise Stubb.  Don't you see that pyramid?'  With\nthat, he all of a sudden seemed somehow, in some queer fashion, to\nswim off into the air.  I snored; rolled over; and there I was in my\nhammock!  Now, what do you think of that dream, Flask?\"\n\n\"I don't know; it seems a sort of foolish to me, tho.'\"\n\n\"May be; may be.  But it's made a wise man of me, Flask.  D'ye see\nAhab standing there, sideways looking over the stern?  Well, the best\nthing you can do, Flask, is to let the old man alone; never speak to\nhim, whatever he says.  Halloa!  What's that he shouts?  Hark!\"\n\n\"Mast-head, there!  Look sharp, all of ye!  There are whales\nhereabouts!\n\nIf ye see a white one, split your lungs for him!\n\n\"What do you think of that now, Flask? ain't there a small drop of\nsomething queer about that, eh?  A white whale--did ye mark that,\nman?  Look ye--there's something special in the wind.  Stand by for\nit, Flask.  Ahab has that that's bloody on his mind.  But, mum; he\ncomes this way.\"\n\n\n\nCHAPTER 32\n\nCetology.\n\n\nAlready we are boldly launched upon the deep; but soon we shall be\nlost in its unshored, harbourless immensities.  Ere that come to pass;\nere the Pequod's weedy hull rolls side by side with the barnacled\nhulls of the leviathan; at the outset it is but well to attend to a\nmatter almost indispensable to a thorough appreciative understanding\nof the more special leviathanic revelations and allusions of all\nsorts which are to follow.\n\nIt is some systematized exhibition of the whale in his broad genera,\nthat I would now fain put before you.  Yet is it no easy task.  The\nclassification of the constituents of a chaos, nothing less is here\nessayed.  Listen to what the best and latest authorities have laid\ndown.\n\n\"No branch of Zoology is so much involved as that which is entitled\nCetology,\" says Captain Scoresby, A.D. 1820.\n\n\"It is not my intention, were it in my power, to enter into the\ninquiry as to the true method of dividing the cetacea into groups and\nfamilies....  Utter confusion exists among the historians of this\nanimal\" (sperm whale), says Surgeon Beale, A.D. 1839.\n\n\"Unfitness to pursue our research in the unfathomable waters.\"\n\"Impenetrable veil covering our knowledge of the cetacea.\"  \"A field\nstrewn with thorns.\"  \"All these incomplete indications but serve to\ntorture us naturalists.\"\n\nThus speak of the whale, the great Cuvier, and John Hunter, and\nLesson, those lights of zoology and anatomy.  Nevertheless, though of\nreal knowledge there be little, yet of books there are a plenty; and\nso in some small degree, with cetology, or the science of whales.\nMany are the men, small and great, old and new, landsmen and seamen,\nwho have at large or in little, written of the whale.  Run over a\nfew:--The Authors of the Bible; Aristotle; Pliny; Aldrovandi; Sir\nThomas Browne; Gesner; Ray; Linnaeus; Rondeletius; Willoughby; Green;\nArtedi; Sibbald; Brisson; Marten; Lacepede; Bonneterre; Desmarest;\nBaron Cuvier; Frederick Cuvier; John Hunter; Owen; Scoresby; Beale;\nBennett; J.  Ross Browne; the Author of Miriam Coffin; Olmstead; and\nthe Rev.  T.  Cheever.  But to what ultimate generalizing purpose all\nthese have written, the above cited extracts will show.\n\nOf the names in this list of whale authors, only those following Owen\never saw living whales; and but one of them was a real professional\nharpooneer and whaleman.  I mean Captain Scoresby.  On the separate\nsubject of the Greenland or right-whale, he is the best existing\nauthority.  But Scoresby knew nothing and says nothing of the great\nsperm whale, compared with which the Greenland whale is almost\nunworthy mentioning.  And here be it said, that the Greenland whale\nis an usurper upon the throne of the seas.  He is not even by any\nmeans the largest of the whales.  Yet, owing to the long priority of\nhis claims, and the profound ignorance which, till some seventy years\nback, invested the then fabulous or utterly unknown sperm-whale, and\nwhich ignorance to this present day still reigns in all but some few\nscientific retreats and whale-ports; this usurpation has been every\nway complete.  Reference to nearly all the leviathanic allusions in\nthe great poets of past days, will satisfy you that the Greenland\nwhale, without one rival, was to them the monarch of the seas.  But\nthe time has at last come for a new proclamation.  This is Charing\nCross; hear ye! good people all,--the Greenland whale is\ndeposed,--the great sperm whale now reigneth!\n\nThere are only two books in being which at all pretend to put the\nliving sperm whale before you, and at the same time, in the remotest\ndegree succeed in the attempt.  Those books are Beale's and\nBennett's; both in their time surgeons to English South-Sea\nwhale-ships, and both exact and reliable men.  The original matter\ntouching the sperm whale to be found in their volumes is necessarily\nsmall; but so far as it goes, it is of excellent quality, though\nmostly confined to scientific description.  As yet, however, the\nsperm whale, scientific or poetic, lives not complete in any\nliterature.  Far above all other hunted whales, his is an unwritten\nlife.\n\nNow the various species of whales need some sort of popular\ncomprehensive classification, if only an easy outline one for the\npresent, hereafter to be filled in all its departments by subsequent\nlaborers.  As no better man advances to take this matter in hand, I\nhereupon offer my own poor endeavors.  I promise nothing complete;\nbecause any human thing supposed to be complete, must for that very\nreason infallibly be faulty.  I shall not pretend to a minute\nanatomical description of the various species, or--in this place at\nleast--to much of any description.  My object here is simply to\nproject the draught of a systematization of cetology.  I am the\narchitect, not the builder.\n\nBut it is a ponderous task; no ordinary letter-sorter in the\nPost-Office is equal to it.  To grope down into the bottom of the sea\nafter them; to have one's hands among the unspeakable foundations,\nribs, and very pelvis of the world; this is a fearful thing.  What am\nI that I should essay to hook the nose of this leviathan!  The awful\ntauntings in Job might well appal me.  \"Will he the (leviathan) make\na covenant with thee?  Behold the hope of him is vain!  But I have\nswam through libraries and sailed through oceans; I have had to do\nwith whales with these visible hands; I am in earnest; and I will\ntry.  There are some preliminaries to settle.\n\nFirst: The uncertain, unsettled condition of this science of Cetology\nis in the very vestibule attested by the fact, that in some quarters\nit still remains a moot point whether a whale be a fish.  In his\nSystem of Nature, A.D. 1776, Linnaeus declares, \"I hereby separate\nthe whales from the fish.\"  But of my own knowledge, I know that down\nto the year 1850, sharks and shad, alewives and herring, against\nLinnaeus's express edict, were still found dividing the possession of\nthe same seas with the Leviathan.\n\nThe grounds upon which Linnaeus would fain have banished the whales\nfrom the waters, he states as follows: \"On account of their warm\nbilocular heart, their lungs, their movable eyelids, their hollow\nears, penem intrantem feminam mammis lactantem,\" and finally, \"ex\nlege naturae jure meritoque.\"  I submitted all this to my friends\nSimeon Macey and Charley Coffin, of Nantucket, both messmates of mine\nin a certain voyage, and they united in the opinion that the reasons\nset forth were altogether insufficient.  Charley profanely hinted\nthey were humbug.\n\nBe it known that, waiving all argument, I take the good old fashioned\nground that the whale is a fish, and call upon holy Jonah to back me.\nThis fundamental thing settled, the next point is, in what internal\nrespect does the whale differ from other fish.  Above, Linnaeus has\ngiven you those items.  But in brief, they are these: lungs and warm\nblood; whereas, all other fish are lungless and cold blooded.\n\nNext: how shall we define the whale, by his obvious externals, so as\nconspicuously to label him for all time to come?  To be short, then,\na whale is A SPOUTING FISH WITH A HORIZONTAL TAIL.  There you have\nhim.  However contracted, that definition is the result of expanded\nmeditation.  A walrus spouts much like a whale, but the walrus is not\na fish, because he is amphibious.  But the last term of the\ndefinition is still more cogent, as coupled with the first.  Almost\nany one must have noticed that all the fish familiar to landsmen have\nnot a flat, but a vertical, or up-and-down tail.  Whereas, among\nspouting fish the tail, though it may be similarly shaped, invariably\nassumes a horizontal position.\n\nBy the above definition of what a whale is, I do by no means exclude\nfrom the leviathanic brotherhood any sea creature hitherto identified\nwith the whale by the best informed Nantucketers; nor, on the other\nhand, link with it any fish hitherto authoritatively regarded as\nalien.*  Hence, all the smaller, spouting, and horizontal tailed fish\nmust be included in this ground-plan of Cetology.  Now, then, come\nthe grand divisions of the entire whale host.\n\n\n*I am aware that down to the present time, the fish styled Lamatins\nand Dugongs (Pig-fish and Sow-fish of the Coffins of Nantucket) are\nincluded by many naturalists among the whales.  But as these pig-fish\nare a noisy, contemptible set, mostly lurking in the mouths of\nrivers, and feeding on wet hay, and especially as they do not spout,\nI deny their credentials as whales; and have presented them with\ntheir passports to quit the Kingdom of Cetology.\n\n\nFirst: According to magnitude I divide the whales into three primary\nBOOKS (subdivisible into CHAPTERS), and these shall comprehend them\nall, both small and large.\n\nI. THE FOLIO WHALE; II. the OCTAVO WHALE; III. the DUODECIMO WHALE.\n\nAs the type of the FOLIO I present the SPERM WHALE; of the OCTAVO,\nthe GRAMPUS; of the DUODECIMO, the PORPOISE.\n\nFOLIOS.  Among these I here include the following chapters:--I. The\nSPERM WHALE; II. the RIGHT WHALE; III. the FIN-BACK WHALE; IV. the\nHUMP-BACKED WHALE; V. the RAZOR-BACK WHALE; VI. the SULPHUR-BOTTOM\nWHALE.\n\nBOOK I. (FOLIO), CHAPTER I. (SPERM WHALE).--This whale, among the\nEnglish of old vaguely known as the Trumpa whale, and the Physeter\nwhale, and the Anvil Headed whale, is the present Cachalot of the\nFrench, and the Pottsfich of the Germans, and the Macrocephalus of\nthe Long Words.  He is, without doubt, the largest inhabitant of the\nglobe; the most formidable of all whales to encounter; the most\nmajestic in aspect; and lastly, by far the most valuable in commerce;\nhe being the only creature from which that valuable substance,\nspermaceti, is obtained.  All his peculiarities will, in many other\nplaces, be enlarged upon.  It is chiefly with his name that I now\nhave to do.  Philologically considered, it is absurd.  Some centuries\nago, when the Sperm whale was almost wholly unknown in his own\nproper individuality, and when his oil was only accidentally obtained\nfrom the stranded fish; in those days spermaceti, it would seem, was\npopularly supposed to be derived from a creature identical with the\none then known in England as the Greenland or Right Whale.  It was\nthe idea also, that this same spermaceti was that quickening humor of\nthe Greenland Whale which the first syllable of the word literally\nexpresses.  In those times, also, spermaceti was exceedingly scarce,\nnot being used for light, but only as an ointment and medicament.  It\nwas only to be had from the druggists as you nowadays buy an ounce of\nrhubarb.  When, as I opine, in the course of time, the true nature of\nspermaceti became known, its original name was still retained by the\ndealers; no doubt to enhance its value by a notion so strangely\nsignificant of its scarcity.  And so the appellation must at last\nhave come to be bestowed upon the whale from which this spermaceti\nwas really derived.\n\nBOOK I. (FOLIO), CHAPTER II. (RIGHT WHALE).--In one respect this is\nthe most venerable of the leviathans, being the one first regularly\nhunted by man.  It yields the article commonly known as whalebone or\nbaleen; and the oil specially known as \"whale oil,\" an inferior\narticle in commerce.  Among the fishermen, he is indiscriminately\ndesignated by all the following titles: The Whale; the Greenland\nWhale; the Black Whale; the Great Whale; the True Whale; the Right\nWhale.  There is a deal of obscurity concerning the identity of the\nspecies thus multitudinously baptised.  What then is the whale, which\nI include in the second species of my Folios?  It is the Great\nMysticetus of the English naturalists; the Greenland Whale of the\nEnglish whalemen; the Baliene Ordinaire of the French whalemen; the\nGrowlands Walfish of the Swedes.  It is the whale which for more than\ntwo centuries past has been hunted by the Dutch and English in the\nArctic seas; it is the whale which the American fishermen have long\npursued in the Indian ocean, on the Brazil Banks, on the Nor' West\nCoast, and various other parts of the world, designated by them Right\nWhale Cruising Grounds.\n\nSome pretend to see a difference between the Greenland whale of the\nEnglish and the right whale of the Americans.  But they precisely\nagree in all their grand features; nor has there yet been presented a\nsingle determinate fact upon which to ground a radical distinction.\nIt is by endless subdivisions based upon the most inconclusive\ndifferences, that some departments of natural history become so\nrepellingly intricate.  The right whale will be elsewhere treated of\nat some length, with reference to elucidating the sperm whale.\n\nBOOK I. (FOLIO), CHAPTER III. (FIN-BACK).--Under this head I reckon a\nmonster which, by the various names of Fin-Back, Tall-Spout, and\nLong-John, has been seen almost in every sea and is commonly the\nwhale whose distant jet is so often descried by passengers crossing\nthe Atlantic, in the New York packet-tracks.  In the length he\nattains, and in his baleen, the Fin-back resembles the right whale,\nbut is of a less portly girth, and a lighter colour, approaching to\nolive.  His great lips present a cable-like aspect, formed by the\nintertwisting, slanting folds of large wrinkles.  His grand\ndistinguishing feature, the fin, from which he derives his name, is\noften a conspicuous object.  This fin is some three or four feet\nlong, growing vertically from the hinder part of the back, of an\nangular shape, and with a very sharp pointed end.  Even if not the\nslightest other part of the creature be visible, this isolated fin\nwill, at times, be seen plainly projecting from the surface.  When\nthe sea is moderately calm, and slightly marked with spherical\nripples, and this gnomon-like fin stands up and casts shadows upon\nthe wrinkled surface, it may well be supposed that the watery circle\nsurrounding it somewhat resembles a dial, with its style and wavy\nhour-lines graved on it.  On that Ahaz-dial the shadow often goes\nback.  The Fin-Back is not gregarious.  He seems a whale-hater, as\nsome men are man-haters.  Very shy; always going solitary;\nunexpectedly rising to the surface in the remotest and most sullen\nwaters; his straight and single lofty jet rising like a tall\nmisanthropic spear upon a barren plain; gifted with such wondrous\npower and velocity in swimming, as to defy all present pursuit from\nman; this leviathan seems the banished and unconquerable Cain of his\nrace, bearing for his mark that style upon his back.  From having the\nbaleen in his mouth, the Fin-Back is sometimes included with the\nright whale, among a theoretic species denominated WHALEBONE WHALES,\nthat is, whales with baleen.  Of these so called Whalebone whales,\nthere would seem to be several varieties, most of which, however, are\nlittle known.  Broad-nosed whales and beaked whales; pike-headed\nwhales; bunched whales; under-jawed whales and rostrated whales, are\nthe fishermen's names for a few sorts.\n\nIn connection with this appellative of \"Whalebone whales,\" it is of\ngreat importance to mention, that however such a nomenclature may be\nconvenient in facilitating allusions to some kind of whales, yet it\nis in vain to attempt a clear classification of the Leviathan,\nfounded upon either his baleen, or hump, or fin, or teeth;\nnotwithstanding that those marked parts or features very obviously\nseem better adapted to afford the basis for a regular system of\nCetology than any other detached bodily distinctions, which the\nwhale, in his kinds, presents.  How then?  The baleen, hump,\nback-fin, and teeth; these are things whose peculiarities are\nindiscriminately dispersed among all sorts of whales, without any\nregard to what may be the nature of their structure in other and\nmore essential particulars.  Thus, the sperm whale and the humpbacked\nwhale, each has a hump; but there the similitude ceases.  Then, this\nsame humpbacked whale and the Greenland whale, each of these has\nbaleen; but there again the similitude ceases.  And it is just the\nsame with the other parts above mentioned.  In various sorts of\nwhales, they form such irregular combinations; or, in the case of any\none of them detached, such an irregular isolation; as utterly to defy\nall general methodization formed upon such a basis.  On this rock\nevery one of the whale-naturalists has split.\n\nBut it may possibly be conceived that, in the internal parts of the\nwhale, in his anatomy--there, at least, we shall be able to hit the\nright classification.  Nay; what thing, for example, is there in the\nGreenland whale's anatomy more striking than his baleen?  Yet we have\nseen that by his baleen it is impossible correctly to classify the\nGreenland whale.  And if you descend into the bowels of the various\nleviathans, why there you will not find distinctions a fiftieth part\nas available to the systematizer as those external ones already\nenumerated.  What then remains? nothing but to take hold of the\nwhales bodily, in their entire liberal volume, and boldly sort them\nthat way.  And this is the Bibliographical system here adopted; and\nit is the only one that can possibly succeed, for it alone is\npracticable.  To proceed.\n\nBOOK I. (FOLIO) CHAPTER IV. (HUMP-BACK).--This whale is often seen on\nthe northern American coast.  He has been frequently captured there,\nand towed into harbor.  He has a great pack on him like a peddler; or\nyou might call him the Elephant and Castle whale.  At any rate, the\npopular name for him does not sufficiently distinguish him, since the\nsperm whale also has a hump though a smaller one.  His oil is not\nvery valuable.  He has baleen.  He is the most gamesome and\nlight-hearted of all the whales, making more gay foam and white water\ngenerally than any other of them.\n\nBOOK I. (FOLIO), CHAPTER V. (RAZOR-BACK).--Of this whale little is\nknown but his name.  I have seen him at a distance off Cape Horn.  Of\na retiring nature, he eludes both hunters and philosophers.  Though\nno coward, he has never yet shown any part of him but his back, which\nrises in a long sharp ridge.  Let him go.  I know little more of him,\nnor does anybody else.\n\nBOOK I. (FOLIO), CHAPTER VI. (SULPHUR-BOTTOM).--Another retiring\ngentleman, with a brimstone belly, doubtless got by scraping along\nthe Tartarian tiles in some of his profounder divings.  He is seldom\nseen; at least I have never seen him except in the remoter southern\nseas, and then always at too great a distance to study his\ncountenance.  He is never chased; he would run away with rope-walks\nof line.  Prodigies are told of him.  Adieu, Sulphur Bottom!  I can\nsay nothing more that is true of ye, nor can the oldest Nantucketer.\n\nThus ends BOOK I. (FOLIO), and now begins BOOK II. (OCTAVO).\n\nOCTAVOES.*--These embrace the whales of middling magnitude, among\nwhich present may be numbered:--I., the GRAMPUS; II., the BLACK FISH;\nIII., the NARWHALE; IV., the THRASHER; V., the KILLER.\n\n\n*Why this book of whales is not denominated the Quarto is very plain.\nBecause, while the whales of this order, though smaller than those\nof the former order, nevertheless retain a proportionate likeness to\nthem in figure, yet the bookbinder's Quarto volume in its dimensioned\nform does not preserve the shape of the Folio volume, but the Octavo\nvolume does.\n\n\nBOOK II. (OCTAVO), CHAPTER I. (GRAMPUS).--Though this fish, whose\nloud sonorous breathing, or rather blowing, has furnished a proverb\nto landsmen, is so well known a denizen of the deep, yet is he not\npopularly classed among whales.  But possessing all the grand\ndistinctive features of the leviathan, most naturalists have\nrecognised him for one.  He is of moderate octavo size, varying from\nfifteen to twenty-five feet in length, and of corresponding\ndimensions round the waist.  He swims in herds; he is never regularly\nhunted, though his oil is considerable in quantity, and pretty good\nfor light.  By some fishermen his approach is regarded as premonitory\nof the advance of the great sperm whale.\n\nBOOK II. (OCTAVO), CHAPTER II. (BLACK FISH).--I give the popular\nfishermen's names for all these fish, for generally they are the\nbest.  Where any name happens to be vague or inexpressive, I shall\nsay so, and suggest another.  I do so now, touching the Black Fish,\nso-called, because blackness is the rule among almost all whales.\nSo, call him the Hyena Whale, if you please.  His voracity is well\nknown, and from the circumstance that the inner angles of his lips\nare curved upwards, he carries an everlasting Mephistophelean grin on\nhis face.  This whale averages some sixteen or eighteen feet in\nlength.  He is found in almost all latitudes.  He has a peculiar way\nof showing his dorsal hooked fin in swimming, which looks something\nlike a Roman nose.  When not more profitably employed, the sperm\nwhale hunters sometimes capture the Hyena whale, to keep up the\nsupply of cheap oil for domestic employment--as some frugal\nhousekeepers, in the absence of company, and quite alone by\nthemselves, burn unsavory tallow instead of odorous wax.  Though\ntheir blubber is very thin, some of these whales will yield you\nupwards of thirty gallons of oil.\n\nBOOK II. (OCTAVO), CHAPTER III. (NARWHALE), that is, NOSTRIL\nWHALE.--Another instance of a curiously named whale, so named I\nsuppose from his peculiar horn being originally mistaken for a peaked\nnose.  The creature is some sixteen feet in length, while its horn\naverages five feet, though some exceed ten, and even attain to\nfifteen feet.  Strictly speaking, this horn is but a lengthened tusk,\ngrowing out from the jaw in a line a little depressed from the\nhorizontal.  But it is only found on the sinister side, which has an\nill effect, giving its owner something analogous to the aspect of a\nclumsy left-handed man.  What precise purpose this ivory horn or\nlance answers, it would be hard to say.  It does not seem to be used\nlike the blade of the sword-fish and bill-fish; though some sailors\ntell me that the Narwhale employs it for a rake in turning over the\nbottom of the sea for food.  Charley Coffin said it was used for an\nice-piercer; for the Narwhale, rising to the surface of the Polar\nSea, and finding it sheeted with ice, thrusts his horn up, and so\nbreaks through.  But you cannot prove either of these surmises to be\ncorrect.  My own opinion is, that however this one-sided horn may\nreally be used by the Narwhale--however that may be--it would\ncertainly be very convenient to him for a folder in reading\npamphlets.  The Narwhale I have heard called the Tusked whale, the\nHorned whale, and the Unicorn whale.  He is certainly a curious\nexample of the Unicornism to be found in almost every kingdom of\nanimated nature.  From certain cloistered old authors I have gathered\nthat this same sea-unicorn's horn was in ancient days regarded as the\ngreat antidote against poison, and as such, preparations of it\nbrought immense prices.  It was also distilled to a volatile salts\nfor fainting ladies, the same way that the horns of the male deer are\nmanufactured into hartshorn.  Originally it was in itself accounted\nan object of great curiosity.  Black Letter tells me that Sir Martin\nFrobisher on his return from that voyage, when Queen Bess did\ngallantly wave her jewelled hand to him from a window of Greenwich\nPalace, as his bold ship sailed down the Thames; \"when Sir Martin\nreturned from that voyage,\" saith Black Letter, \"on bended knees he\npresented to her highness a prodigious long horn of the Narwhale,\nwhich for a long period after hung in the castle at Windsor.\"  An\nIrish author avers that the Earl of Leicester, on bended knees, did\nlikewise present to her highness another horn, pertaining to a land\nbeast of the unicorn nature.\n\nThe Narwhale has a very picturesque, leopard-like look, being of a\nmilk-white ground colour, dotted with round and oblong spots of black.\nHis oil is very superior, clear and fine; but there is little of it,\nand he is seldom hunted.  He is mostly found in the circumpolar seas.\n\nBOOK II. (OCTAVO), CHAPTER IV. (KILLER).--Of this whale little is\nprecisely known to the Nantucketer, and nothing at all to the\nprofessed naturalist.  From what I have seen of him at a distance,\nI should say that he was about the bigness of a grampus.  He is very\nsavage--a sort of Feegee fish.  He sometimes takes the great Folio\nwhales by the lip, and hangs there like a leech, till the mighty\nbrute is worried to death.  The Killer is never hunted.  I never\nheard what sort of oil he has.  Exception might be taken to the name\nbestowed upon this whale, on the ground of its indistinctness.  For\nwe are all killers, on land and on sea; Bonapartes and Sharks\nincluded.\n\nBOOK II. (OCTAVO), CHAPTER V. (THRASHER).--This gentleman is famous\nfor his tail, which he uses for a ferule in thrashing his foes.  He\nmounts the Folio whale's back, and as he swims, he works his passage\nby flogging him; as some schoolmasters get along in the world by a\nsimilar process.  Still less is known of the Thrasher than of the\nKiller.  Both are outlaws, even in the lawless seas.\n\nThus ends BOOK II. (OCTAVO), and begins BOOK III. (DUODECIMO).\n\nDUODECIMOES.--These include the smaller whales.  I. The Huzza\nPorpoise.  II. The Algerine Porpoise.  III. The Mealy-mouthed\nPorpoise.\n\nTo those who have not chanced specially to study the subject, it may\npossibly seem strange, that fishes not commonly exceeding four or\nfive feet should be marshalled among WHALES--a word, which, in the\npopular sense, always conveys an idea of hugeness.  But the creatures\nset down above as Duodecimoes are infallibly whales, by the terms of\nmy definition of what a whale is--i.e. a spouting fish, with a\nhorizontal tail.\n\nBOOK III. (DUODECIMO), CHAPTER 1. (HUZZA PORPOISE).--This is the\ncommon porpoise found almost all over the globe.  The name is of my\nown bestowal; for there are more than one sort of porpoises, and\nsomething must be done to distinguish them.  I call him thus, because\nhe always swims in hilarious shoals, which upon the broad sea keep\ntossing themselves to heaven like caps in a Fourth-of-July crowd.\nTheir appearance is generally hailed with delight by the mariner.\nFull of fine spirits, they invariably come from the breezy billows to\nwindward.  They are the lads that always live before the wind.  They\nare accounted a lucky omen.  If you yourself can withstand three\ncheers at beholding these vivacious fish, then heaven help ye; the\nspirit of godly gamesomeness is not in ye.  A well-fed, plump Huzza\nPorpoise will yield you one good gallon of good oil.  But the fine\nand delicate fluid extracted from his jaws is exceedingly valuable.\nIt is in request among jewellers and watchmakers.  Sailors put it on\ntheir hones.  Porpoise meat is good eating, you know.  It may never\nhave occurred to you that a porpoise spouts.  Indeed, his spout is so\nsmall that it is not very readily discernible.  But the next time you\nhave a chance, watch him; and you will then see the great Sperm whale\nhimself in miniature.\n\nBOOK III. (DUODECIMO), CHAPTER II. (ALGERINE PORPOISE).--A pirate.\nVery savage.  He is only found, I think, in the Pacific.  He is\nsomewhat larger than the Huzza Porpoise, but much of the same general\nmake.  Provoke him, and he will buckle to a shark.  I have lowered\nfor him many times, but never yet saw him captured.\n\nBOOK III. (DUODECIMO), CHAPTER III. (MEALY-MOUTHED PORPOISE).--The\nlargest kind of Porpoise; and only found in the Pacific, so far as it\nis known.  The only English name, by which he has hitherto been\ndesignated, is that of the fishers--Right-Whale Porpoise, from the\ncircumstance that he is chiefly found in the vicinity of that Folio.\nIn shape, he differs in some degree from the Huzza Porpoise, being of\na less rotund and jolly girth; indeed, he is of quite a neat and\ngentleman-like figure.  He has no fins on his back (most other\nporpoises have), he has a lovely tail, and sentimental Indian eyes of\na hazel hue.  But his mealy-mouth spoils all.  Though his entire\nback down to his side fins is of a deep sable, yet a boundary line,\ndistinct as the mark in a ship's hull, called the \"bright waist,\"\nthat line streaks him from stem to stern, with two separate colours,\nblack above and white below.  The white comprises part of his head,\nand the whole of his mouth, which makes him look as if he had just\nescaped from a felonious visit to a meal-bag.  A most mean and mealy\naspect!  His oil is much like that of the common porpoise.\n\n\nBeyond the DUODECIMO, this system does not proceed, inasmuch as the\nPorpoise is the smallest of the whales.  Above, you have all the\nLeviathans of note.  But there are a rabble of uncertain, fugitive,\nhalf-fabulous whales, which, as an American whaleman, I know by\nreputation, but not personally.  I shall enumerate them by their\nfore-castle appellations; for possibly such a list may be valuable to\nfuture investigators, who may complete what I have here but begun.\nIf any of the following whales, shall hereafter be caught and marked,\nthen he can readily be incorporated into this System, according to\nhis Folio, Octavo, or Duodecimo magnitude:--The Bottle-Nose Whale;\nthe Junk Whale; the Pudding-Headed Whale; the Cape Whale; the Leading\nWhale; the Cannon Whale; the Scragg Whale; the Coppered Whale; the\nElephant Whale; the Iceberg Whale; the Quog Whale; the Blue Whale; etc.\nFrom Icelandic, Dutch, and old English authorities, there might\nbe quoted other lists of uncertain whales, blessed with all manner of\nuncouth names.  But I omit them as altogether obsolete; and can\nhardly help suspecting them for mere sounds, full of Leviathanism,\nbut signifying nothing.\n\nFinally: It was stated at the outset, that this system would not be\nhere, and at once, perfected.  You cannot but plainly see that I have\nkept my word.  But I now leave my cetological System standing thus\nunfinished, even as the great Cathedral of Cologne was left, with the\ncrane still standing upon the top of the uncompleted tower.  For\nsmall erections may be finished by their first architects; grand\nones, true ones, ever leave the copestone to posterity.  God keep me\nfrom ever completing anything.  This whole book is but a\ndraught--nay, but the draught of a draught.  Oh, Time, Strength,\nCash, and Patience!\n\n\n\nCHAPTER 33\n\nThe Specksynder.\n\n\nConcerning the officers of the whale-craft, this seems as good a\nplace as any to set down a little domestic peculiarity on ship-board,\narising from the existence of the harpooneer class of officers, a\nclass unknown of course in any other marine than the whale-fleet.\n\nThe large importance attached to the harpooneer's vocation is evinced\nby the fact, that originally in the old Dutch Fishery, two centuries\nand more ago, the command of a whale ship was not wholly lodged in\nthe person now called the captain, but was divided between him and an\nofficer called the Specksynder.  Literally this word means\nFat-Cutter; usage, however, in time made it equivalent to Chief\nHarpooneer.  In those days, the captain's authority was restricted to\nthe navigation and general management of the vessel; while over the\nwhale-hunting department and all its concerns, the Specksynder or\nChief Harpooneer reigned supreme.  In the British Greenland Fishery,\nunder the corrupted title of Specksioneer, this old Dutch official is\nstill retained, but his former dignity is sadly abridged.  At present\nhe ranks simply as senior Harpooneer; and as such, is but one of the\ncaptain's more inferior subalterns.  Nevertheless, as upon the good\nconduct of the harpooneers the success of a whaling voyage largely\ndepends, and since in the American Fishery he is not only an\nimportant officer in the boat, but under certain circumstances (night\nwatches on a whaling ground) the command of the ship's deck is also\nhis; therefore the grand political maxim of the sea demands, that he\nshould nominally live apart from the men before the mast, and be in\nsome way distinguished as their professional superior; though always,\nby them, familiarly regarded as their social equal.\n\nNow, the grand distinction drawn between officer and man at sea, is\nthis--the first lives aft, the last forward.  Hence, in whale-ships\nand merchantmen alike, the mates have their quarters with the\ncaptain; and so, too, in most of the American whalers the harpooneers\nare lodged in the after part of the ship.  That is to say, they take\ntheir meals in the captain's cabin, and sleep in a place indirectly\ncommunicating with it.\n\nThough the long period of a Southern whaling voyage (by far the\nlongest of all voyages now or ever made by man), the peculiar perils\nof it, and the community of interest prevailing among a company, all\nof whom, high or low, depend for their profits, not upon fixed wages,\nbut upon their common luck, together with their common vigilance,\nintrepidity, and hard work; though all these things do in some cases\ntend to beget a less rigorous discipline than in merchantmen\ngenerally; yet, never mind how much like an old Mesopotamian family\nthese whalemen may, in some primitive instances, live together; for\nall that, the punctilious externals, at least, of the quarter-deck\nare seldom materially relaxed, and in no instance done away.  Indeed,\nmany are the Nantucket ships in which you will see the skipper\nparading his quarter-deck with an elated grandeur not surpassed in\nany military navy; nay, extorting almost as much outward homage as if\nhe wore the imperial purple, and not the shabbiest of pilot-cloth.\n\nAnd though of all men the moody captain of the Pequod was the least\ngiven to that sort of shallowest assumption; and though the only\nhomage he ever exacted, was implicit, instantaneous obedience; though\nhe required no man to remove the shoes from his feet ere stepping\nupon the quarter-deck; and though there were times when, owing to\npeculiar circumstances connected with events hereafter to be\ndetailed, he addressed them in unusual terms, whether of\ncondescension or IN TERROREM, or otherwise; yet even Captain Ahab was\nby no means unobservant of the paramount forms and usages of the sea.\n\nNor, perhaps, will it fail to be eventually perceived, that behind\nthose forms and usages, as it were, he sometimes masked himself;\nincidentally making use of them for other and more private ends than\nthey were legitimately intended to subserve.  That certain sultanism\nof his brain, which had otherwise in a good degree remained\nunmanifested; through those forms that same sultanism became\nincarnate in an irresistible dictatorship.  For be a man's\nintellectual superiority what it will, it can never assume the\npractical, available supremacy over other men, without the aid of\nsome sort of external arts and entrenchments, always, in themselves,\nmore or less paltry and base.  This it is, that for ever keeps God's\ntrue princes of the Empire from the world's hustings; and leaves the\nhighest honours that this air can give, to those men who become famous\nmore through their infinite inferiority to the choice hidden handful\nof the Divine Inert, than through their undoubted superiority over\nthe dead level of the mass.  Such large virtue lurks in these small\nthings when extreme political superstitions invest them, that in some\nroyal instances even to idiot imbecility they have imparted potency.\nBut when, as in the case of Nicholas the Czar, the ringed crown of\ngeographical empire encircles an imperial brain; then, the plebeian\nherds crouch abased before the tremendous centralization.  Nor, will\nthe tragic dramatist who would depict mortal indomitableness in its\nfullest sweep and direct swing, ever forget a hint, incidentally so\nimportant in his art, as the one now alluded to.\n\nBut Ahab, my Captain, still moves before me in all his Nantucket\ngrimness and shagginess; and in this episode touching Emperors and\nKings, I must not conceal that I have only to do with a poor old\nwhale-hunter like him; and, therefore, all outward majestical\ntrappings and housings are denied me.  Oh, Ahab! what shall be grand\nin thee, it must needs be plucked at from the skies, and dived for in\nthe deep, and featured in the unbodied air!\n\n\n\nCHAPTER 34\n\nThe Cabin-Table.\n\n\nIt is noon; and Dough-Boy, the steward, thrusting his pale\nloaf-of-bread face from the cabin-scuttle, announces dinner to his\nlord and master; who, sitting in the lee quarter-boat, has just been\ntaking an observation of the sun; and is now mutely reckoning the\nlatitude on the smooth, medallion-shaped tablet, reserved for that\ndaily purpose on the upper part of his ivory leg.  From his complete\ninattention to the tidings, you would think that moody Ahab had not\nheard his menial.  But presently, catching hold of the mizen shrouds,\nhe swings himself to the deck, and in an even, unexhilarated voice,\nsaying, \"Dinner, Mr. Starbuck,\" disappears into the cabin.\n\nWhen the last echo of his sultan's step has died away, and Starbuck,\nthe first Emir, has every reason to suppose that he is seated, then\nStarbuck rouses from his quietude, takes a few turns along the\nplanks, and, after a grave peep into the binnacle, says, with some\ntouch of pleasantness, \"Dinner, Mr. Stubb,\" and descends the scuttle.\nThe second Emir lounges about the rigging awhile, and then slightly\nshaking the main brace, to see whether it will be all right with\nthat important rope, he likewise takes up the old burden, and with a\nrapid \"Dinner, Mr. Flask,\" follows after his predecessors.\n\nBut the third Emir, now seeing himself all alone on the quarter-deck,\nseems to feel relieved from some curious restraint; for, tipping all\nsorts of knowing winks in all sorts of directions, and kicking off\nhis shoes, he strikes into a sharp but noiseless squall of a hornpipe\nright over the Grand Turk's head; and then, by a dexterous sleight,\npitching his cap up into the mizentop for a shelf, he goes down\nrollicking so far at least as he remains visible from the deck,\nreversing all other processions, by bringing up the rear with music.\nBut ere stepping into the cabin doorway below, he pauses, ships a new\nface altogether, and, then, independent, hilarious little Flask\nenters King Ahab's presence, in the character of Abjectus, or the\nSlave.\n\nIt is not the least among the strange things bred by the intense\nartificialness of sea-usages, that while in the open air of the deck\nsome officers will, upon provocation, bear themselves boldly and\ndefyingly enough towards their commander; yet, ten to one, let those\nvery officers the next moment go down to their customary dinner in\nthat same commander's cabin, and straightway their inoffensive, not\nto say deprecatory and humble air towards him, as he sits at the head\nof the table; this is marvellous, sometimes most comical.  Wherefore\nthis difference?  A problem?  Perhaps not.  To have been Belshazzar,\nKing of Babylon; and to have been Belshazzar, not haughtily but\ncourteously, therein certainly must have been some touch of mundane\ngrandeur.  But he who in the rightly regal and intelligent spirit\npresides over his own private dinner-table of invited guests, that\nman's unchallenged power and dominion of individual influence for the\ntime; that man's royalty of state transcends Belshazzar's, for\nBelshazzar was not the greatest.  Who has but once dined his friends,\nhas tasted what it is to be Caesar.  It is a witchery of social\nczarship which there is no withstanding.  Now, if to this\nconsideration you superadd the official supremacy of a ship-master,\nthen, by inference, you will derive the cause of that peculiarity of\nsea-life just mentioned.\n\nOver his ivory-inlaid table, Ahab presided like a mute, maned\nsea-lion on the white coral beach, surrounded by his warlike but\nstill deferential cubs.  In his own proper turn, each officer waited\nto be served.  They were as little children before Ahab; and yet, in\nAhab, there seemed not to lurk the smallest social arrogance.  With\none mind, their intent eyes all fastened upon the old man's knife, as\nhe carved the chief dish before him.  I do not suppose that for the\nworld they would have profaned that moment with the slightest\nobservation, even upon so neutral a topic as the weather.  No!  And\nwhen reaching out his knife and fork, between which the slice of beef\nwas locked, Ahab thereby motioned Starbuck's plate towards him, the\nmate received his meat as though receiving alms; and cut it tenderly;\nand a little started if, perchance, the knife grazed against the\nplate; and chewed it noiselessly; and swallowed it, not without\ncircumspection.  For, like the Coronation banquet at Frankfort, where\nthe German Emperor profoundly dines with the seven Imperial\nElectors, so these cabin meals were somehow solemn meals, eaten in\nawful silence; and yet at table old Ahab forbade not conversation;\nonly he himself was dumb.  What a relief it was to choking Stubb,\nwhen a rat made a sudden racket in the hold below.  And poor little\nFlask, he was the youngest son, and little boy of this weary family\nparty.  His were the shinbones of the saline beef; his would have\nbeen the drumsticks.  For Flask to have presumed to help himself,\nthis must have seemed to him tantamount to larceny in the first\ndegree.  Had he helped himself at that table, doubtless, never more\nwould he have been able to hold his head up in this honest world;\nnevertheless, strange to say, Ahab never forbade him.  And had Flask\nhelped himself, the chances were Ahab had never so much as noticed\nit.  Least of all, did Flask presume to help himself to butter.\nWhether he thought the owners of the ship denied it to him, on\naccount of its clotting his clear, sunny complexion; or whether he\ndeemed that, on so long a voyage in such marketless waters, butter\nwas at a premium, and therefore was not for him, a subaltern; however\nit was, Flask, alas! was a butterless man!\n\nAnother thing.  Flask was the last person down at the dinner, and\nFlask is the first man up.  Consider!  For hereby Flask's dinner was\nbadly jammed in point of time.  Starbuck and Stubb both had the start\nof him; and yet they also have the privilege of lounging in the rear.\nIf Stubb even, who is but a peg higher than Flask, happens to have\nbut a small appetite, and soon shows symptoms of concluding his\nrepast, then Flask must bestir himself, he will not get more than\nthree mouthfuls that day; for it is against holy usage for Stubb to\nprecede Flask to the deck.  Therefore it was that Flask once admitted\nin private, that ever since he had arisen to the dignity of an\nofficer, from that moment he had never known what it was to be\notherwise than hungry, more or less.  For what he ate did not so much\nrelieve his hunger, as keep it immortal in him.  Peace and\nsatisfaction, thought Flask, have for ever departed from my stomach.\nI am an officer; but, how I wish I could fish a bit of old-fashioned\nbeef in the forecastle, as I used to when I was before the mast.\nThere's the fruits of promotion now; there's the vanity of glory:\nthere's the insanity of life!  Besides, if it were so that any mere\nsailor of the Pequod had a grudge against Flask in Flask's official\ncapacity, all that sailor had to do, in order to obtain ample\nvengeance, was to go aft at dinner-time, and get a peep at Flask\nthrough the cabin sky-light, sitting silly and dumfoundered before\nawful Ahab.\n\nNow, Ahab and his three mates formed what may be called the first\ntable in the Pequod's cabin.  After their departure, taking place in\ninverted order to their arrival, the canvas cloth was cleared, or\nrather was restored to some hurried order by the pallid steward.  And\nthen the three harpooneers were bidden to the feast, they being its\nresiduary legatees.  They made a sort of temporary servants' hall of\nthe high and mighty cabin.\n\nIn strange contrast to the hardly tolerable constraint and nameless\ninvisible domineerings of the captain's table, was the entire\ncare-free license and ease, the almost frantic democracy of those\ninferior fellows the harpooneers.  While their masters, the mates,\nseemed afraid of the sound of the hinges of their own jaws, the\nharpooneers chewed their food with such a relish that there was a\nreport to it.  They dined like lords; they filled their bellies like\nIndian ships all day loading with spices.  Such portentous appetites\nhad Queequeg and Tashtego, that to fill out the vacancies made by the\nprevious repast, often the pale Dough-Boy was fain to bring on a\ngreat baron of salt-junk, seemingly quarried out of the solid ox.\nAnd if he were not lively about it, if he did not go with a nimble\nhop-skip-and-jump, then Tashtego had an ungentlemanly way of\naccelerating him by darting a fork at his back, harpoon-wise.  And\nonce Daggoo, seized with a sudden humor, assisted Dough-Boy's memory\nby snatching him up bodily, and thrusting his head into a great empty\nwooden trencher, while Tashtego, knife in hand, began laying out the\ncircle preliminary to scalping him.  He was naturally a very nervous,\nshuddering sort of little fellow, this bread-faced steward; the\nprogeny of a bankrupt baker and a hospital nurse.  And what with the\nstanding spectacle of the black terrific Ahab, and the periodical\ntumultuous visitations of these three savages, Dough-Boy's whole life\nwas one continual lip-quiver.  Commonly, after seeing the harpooneers\nfurnished with all things they demanded, he would escape from their\nclutches into his little pantry adjoining, and fearfully peep out at\nthem through the blinds of its door, till all was over.\n\nIt was a sight to see Queequeg seated over against Tashtego, opposing\nhis filed teeth to the Indian's: crosswise to them, Daggoo seated on\nthe floor, for a bench would have brought his hearse-plumed head to\nthe low carlines; at every motion of his colossal limbs, making the\nlow cabin framework to shake, as when an African elephant goes\npassenger in a ship.  But for all this, the great negro was\nwonderfully abstemious, not to say dainty.  It seemed hardly possible\nthat by such comparatively small mouthfuls he could keep up the\nvitality diffused through so broad, baronial, and superb a person.\nBut, doubtless, this noble savage fed strong and drank deep of the\nabounding element of air; and through his dilated nostrils snuffed in\nthe sublime life of the worlds.  Not by beef or by bread, are giants\nmade or nourished.  But Queequeg, he had a mortal, barbaric smack of\nthe lip in eating--an ugly sound enough--so much so, that the\ntrembling Dough-Boy almost looked to see whether any marks of teeth\nlurked in his own lean arms.  And when he would hear Tashtego singing\nout for him to produce himself, that his bones might be picked, the\nsimple-witted steward all but shattered the crockery hanging round\nhim in the pantry, by his sudden fits of the palsy.  Nor did the\nwhetstone which the harpooneers carried in their pockets, for their\nlances and other weapons; and with which whetstones, at dinner, they\nwould ostentatiously sharpen their knives; that grating sound did not\nat all tend to tranquillize poor Dough-Boy.  How could he forget that\nin his Island days, Queequeg, for one, must certainly have been\nguilty of some murderous, convivial indiscretions.  Alas!  Dough-Boy!\nhard fares the white waiter who waits upon cannibals.  Not a napkin\nshould he carry on his arm, but a buckler.  In good time, though, to\nhis great delight, the three salt-sea warriors would rise and depart;\nto his credulous, fable-mongering ears, all their martial bones\njingling in them at every step, like Moorish scimetars in scabbards.\n\nBut, though these barbarians dined in the cabin, and nominally lived\nthere; still, being anything but sedentary in their habits, they were\nscarcely ever in it except at mealtimes, and just before\nsleeping-time, when they passed through it to their own peculiar\nquarters.\n\nIn this one matter, Ahab seemed no exception to most American whale\ncaptains, who, as a set, rather incline to the opinion that by rights\nthe ship's cabin belongs to them; and that it is by courtesy alone\nthat anybody else is, at any time, permitted there.  So that, in real\ntruth, the mates and harpooneers of the Pequod might more properly be\nsaid to have lived out of the cabin than in it.  For when they did\nenter it, it was something as a street-door enters a house; turning\ninwards for a moment, only to be turned out the next; and, as a\npermanent thing, residing in the open air.  Nor did they lose much\nhereby; in the cabin was no companionship; socially, Ahab was\ninaccessible.  Though nominally included in the census of\nChristendom, he was still an alien to it.  He lived in the world, as\nthe last of the Grisly Bears lived in settled Missouri.  And as when\nSpring and Summer had departed, that wild Logan of the woods, burying\nhimself in the hollow of a tree, lived out the winter there, sucking\nhis own paws; so, in his inclement, howling old age, Ahab's soul,\nshut up in the caved trunk of his body, there fed upon the sullen\npaws of its gloom!\n\n\n\nCHAPTER 35\n\nThe Mast-Head.\n\n\nIt was during the more pleasant weather, that in due rotation with\nthe other seamen my first mast-head came round.\n\nIn most American whalemen the mast-heads are manned almost\nsimultaneously with the vessel's leaving her port; even though she\nmay have fifteen thousand miles, and more, to sail ere reaching her\nproper cruising ground.  And if, after a three, four, or five years'\nvoyage she is drawing nigh home with anything empty in her--say, an\nempty vial even--then, her mast-heads are kept manned to the last;\nand not till her skysail-poles sail in among the spires of the port,\ndoes she altogether relinquish the hope of capturing one whale more.\n\nNow, as the business of standing mast-heads, ashore or afloat, is a\nvery ancient and interesting one, let us in some measure expatiate\nhere.  I take it, that the earliest standers of mast-heads were the\nold Egyptians; because, in all my researches, I find none prior to\nthem.  For though their progenitors, the builders of Babel, must\ndoubtless, by their tower, have intended to rear the loftiest\nmast-head in all Asia, or Africa either; yet (ere the final truck was\nput to it) as that great stone mast of theirs may be said to have\ngone by the board, in the dread gale of God's wrath; therefore, we\ncannot give these Babel builders priority over the Egyptians.  And\nthat the Egyptians were a nation of mast-head standers, is an\nassertion based upon the general belief among archaeologists, that\nthe first pyramids were founded for astronomical purposes: a theory\nsingularly supported by the peculiar stair-like formation of all four\nsides of those edifices; whereby, with prodigious long upliftings of\ntheir legs, those old astronomers were wont to mount to the apex, and\nsing out for new stars; even as the look-outs of a modern ship sing\nout for a sail, or a whale just bearing in sight.  In Saint Stylites,\nthe famous Christian hermit of old times, who built him a lofty stone\npillar in the desert and spent the whole latter portion of his life\non its summit, hoisting his food from the ground with a tackle; in\nhim we have a remarkable instance of a dauntless\nstander-of-mast-heads; who was not to be driven from his place by\nfogs or frosts, rain, hail, or sleet; but valiantly facing everything\nout to the last, literally died at his post.  Of modern\nstanders-of-mast-heads we have but a lifeless set; mere stone, iron,\nand bronze men; who, though well capable of facing out a stiff gale,\nare still entirely incompetent to the business of singing out upon\ndiscovering any strange sight.  There is Napoleon; who, upon the top\nof the column of Vendome, stands with arms folded, some one hundred\nand fifty feet in the air; careless, now, who rules the decks below;\nwhether Louis Philippe, Louis Blanc, or Louis the Devil.  Great\nWashington, too, stands high aloft on his towering main-mast in\nBaltimore, and like one of Hercules' pillars, his column marks that\npoint of human grandeur beyond which few mortals will go.  Admiral\nNelson, also, on a capstan of gun-metal, stands his mast-head in\nTrafalgar Square; and ever when most obscured by that London smoke,\ntoken is yet given that a hidden hero is there; for where there is\nsmoke, must be fire.  But neither great Washington, nor Napoleon, nor\nNelson, will answer a single hail from below, however madly invoked\nto befriend by their counsels the distracted decks upon which they\ngaze; however it may be surmised, that their spirits penetrate\nthrough the thick haze of the future, and descry what shoals and what\nrocks must be shunned.\n\nIt may seem unwarrantable to couple in any respect the mast-head\nstanders of the land with those of the sea; but that in truth it is\nnot so, is plainly evinced by an item for which Obed Macy, the sole\nhistorian of Nantucket, stands accountable.  The worthy Obed tells\nus, that in the early times of the whale fishery, ere ships were\nregularly launched in pursuit of the game, the people of that island\nerected lofty spars along the sea-coast, to which the look-outs\nascended by means of nailed cleats, something as fowls go upstairs in\na hen-house.  A few years ago this same plan was adopted by the Bay\nwhalemen of New Zealand, who, upon descrying the game, gave notice to\nthe ready-manned boats nigh the beach.  But this custom has now\nbecome obsolete; turn we then to the one proper mast-head, that of a\nwhale-ship at sea.  The three mast-heads are kept manned from\nsun-rise to sun-set; the seamen taking their regular turns (as at the\nhelm), and relieving each other every two hours.  In the serene\nweather of the tropics it is exceedingly pleasant the mast-head; nay,\nto a dreamy meditative man it is delightful.  There you stand, a\nhundred feet above the silent decks, striding along the deep, as if\nthe masts were gigantic stilts, while beneath you and between your\nlegs, as it were, swim the hugest monsters of the sea, even as ships\nonce sailed between the boots of the famous Colossus at old Rhodes.\nThere you stand, lost in the infinite series of the sea, with nothing\nruffled but the waves.  The tranced ship indolently rolls; the drowsy\ntrade winds blow; everything resolves you into languor.  For the most\npart, in this tropic whaling life, a sublime uneventfulness invests\nyou; you hear no news; read no gazettes; extras with startling\naccounts of commonplaces never delude you into unnecessary\nexcitements; you hear of no domestic afflictions; bankrupt\nsecurities; fall of stocks; are never troubled with the thought of\nwhat you shall have for dinner--for all your meals for three years\nand more are snugly stowed in casks, and your bill of fare is\nimmutable.\n\nIn one of those southern whalesmen, on a long three or four years'\nvoyage, as often happens, the sum of the various hours you spend at\nthe mast-head would amount to several entire months.  And it is much\nto be deplored that the place to which you devote so considerable a\nportion of the whole term of your natural life, should be so sadly\ndestitute of anything approaching to a cosy inhabitiveness, or\nadapted to breed a comfortable localness of feeling, such as pertains\nto a bed, a hammock, a hearse, a sentry box, a pulpit, a coach, or\nany other of those small and snug contrivances in which men\ntemporarily isolate themselves.  Your most usual point of perch is\nthe head of the t' gallant-mast, where you stand upon two thin\nparallel sticks (almost peculiar to whalemen) called the t' gallant\ncross-trees.  Here, tossed about by the sea, the beginner feels about\nas cosy as he would standing on a bull's horns.  To be sure, in cold\nweather you may carry your house aloft with you, in the shape of a\nwatch-coat; but properly speaking the thickest watch-coat is no more\nof a house than the unclad body; for as the soul is glued inside of\nits fleshy tabernacle, and cannot freely move about in it, nor even\nmove out of it, without running great risk of perishing (like an\nignorant pilgrim crossing the snowy Alps in winter); so a watch-coat\nis not so much of a house as it is a mere envelope, or additional\nskin encasing you.  You cannot put a shelf or chest of drawers in\nyour body, and no more can you make a convenient closet of your\nwatch-coat.\n\nConcerning all this, it is much to be deplored that the mast-heads of\na southern whale ship are unprovided with those enviable little tents\nor pulpits, called CROW'S-NESTS, in which the look-outs of a\nGreenland whaler are protected from the inclement weather of the\nfrozen seas.  In the fireside narrative of Captain Sleet, entitled\n\"A Voyage among the Icebergs, in quest of the Greenland Whale, and\nincidentally for the re-discovery of the Lost Icelandic Colonies of\nOld Greenland;\" in this admirable volume, all standers of mast-heads\nare furnished with a charmingly circumstantial account of the then\nrecently invented CROW'S-NEST of the Glacier, which was the name of\nCaptain Sleet's good craft.  He called it the SLEET'S CROW'S-NEST, in\nhonour of himself; he being the original inventor and patentee, and\nfree from all ridiculous false delicacy, and holding that if we call\nour own children after our own names (we fathers being the original\ninventors and patentees), so likewise should we denominate after\nourselves any other apparatus we may beget.  In shape, the Sleet's\ncrow's-nest is something like a large tierce or pipe; it is open\nabove, however, where it is furnished with a movable side-screen to\nkeep to windward of your head in a hard gale.  Being fixed on the\nsummit of the mast, you ascend into it through a little trap-hatch in\nthe bottom.  On the after side, or side next the stern of the ship,\nis a comfortable seat, with a locker underneath for umbrellas,\ncomforters, and coats.  In front is a leather rack, in which to keep\nyour speaking trumpet, pipe, telescope, and other nautical\nconveniences.  When Captain Sleet in person stood his mast-head in\nthis crow's-nest of his, he tells us that he always had a rifle with\nhim (also fixed in the rack), together with a powder flask and shot,\nfor the purpose of popping off the stray narwhales, or vagrant sea\nunicorns infesting those waters; for you cannot successfully shoot at\nthem from the deck owing to the resistance of the water, but to shoot\ndown upon them is a very different thing.  Now, it was plainly a\nlabor of love for Captain Sleet to describe, as he does, all the\nlittle detailed conveniences of his crow's-nest; but though he so\nenlarges upon many of these, and though he treats us to a very\nscientific account of his experiments in this crow's-nest, with a\nsmall compass he kept there for the purpose of counteracting the\nerrors resulting from what is called the \"local attraction\" of all\nbinnacle magnets; an error ascribable to the horizontal vicinity of\nthe iron in the ship's planks, and in the Glacier's case, perhaps, to\nthere having been so many broken-down blacksmiths among her crew; I\nsay, that though the Captain is very discreet and scientific here,\nyet, for all his learned \"binnacle deviations,\" \"azimuth compass\nobservations,\" and \"approximate errors,\" he knows very well, Captain\nSleet, that he was not so much immersed in those profound magnetic\nmeditations, as to fail being attracted occasionally towards that\nwell replenished little case-bottle, so nicely tucked in on one side\nof his crow's nest, within easy reach of his hand.  Though, upon the\nwhole, I greatly admire and even love the brave, the honest, and\nlearned Captain; yet I take it very ill of him that he should so\nutterly ignore that case-bottle, seeing what a faithful friend and\ncomforter it must have been, while with mittened fingers and hooded\nhead he was studying the mathematics aloft there in that bird's nest\nwithin three or four perches of the pole.\n\nBut if we Southern whale-fishers are not so snugly housed aloft as\nCaptain Sleet and his Greenlandmen were; yet that disadvantage is\ngreatly counter-balanced by the widely contrasting serenity of those\nseductive seas in which we South fishers mostly float.  For one, I\nused to lounge up the rigging very leisurely, resting in the top to\nhave a chat with Queequeg, or any one else off duty whom I might find\nthere; then ascending a little way further, and throwing a lazy leg\nover the top-sail yard, take a preliminary view of the watery\npastures, and so at last mount to my ultimate destination.\n\nLet me make a clean breast of it here, and frankly admit that I kept\nbut sorry guard.  With the problem of the universe revolving in me,\nhow could I--being left completely to myself at such a\nthought-engendering altitude--how could I but lightly hold my\nobligations to observe all whale-ships' standing orders, \"Keep your\nweather eye open, and sing out every time.\"\n\nAnd let me in this place movingly admonish you, ye ship-owners of\nNantucket!  Beware of enlisting in your vigilant fisheries any lad\nwith lean brow and hollow eye; given to unseasonable meditativeness;\nand who offers to ship with the Phaedon instead of Bowditch in his\nhead.  Beware of such an one, I say; your whales must be seen before\nthey can be killed; and this sunken-eyed young Platonist will tow you\nten wakes round the world, and never make you one pint of sperm the\nricher.  Nor are these monitions at all unneeded.  For nowadays, the\nwhale-fishery furnishes an asylum for many romantic, melancholy, and\nabsent-minded young men, disgusted with the carking cares of earth,\nand seeking sentiment in tar and blubber.  Childe Harold not\nunfrequently perches himself upon the mast-head of some luckless\ndisappointed whale-ship, and in moody phrase ejaculates:--\n\n\"Roll on, thou deep and dark blue ocean, roll!  Ten thousand\nblubber-hunters sweep over thee in vain.\"\n\nVery often do the captains of such ships take those absent-minded\nyoung philosophers to task, upbraiding them with not feeling\nsufficient \"interest\" in the voyage; half-hinting that they are so\nhopelessly lost to all honourable ambition, as that in their secret\nsouls they would rather not see whales than otherwise.  But all in\nvain; those young Platonists have a notion that their vision is\nimperfect; they are short-sighted; what use, then, to strain the\nvisual nerve?  They have left their opera-glasses at home.\n\n\"Why, thou monkey,\" said a harpooneer to one of these lads, \"we've\nbeen cruising now hard upon three years, and thou hast not raised a\nwhale yet.  Whales are scarce as hen's teeth whenever thou art up\nhere.\"  Perhaps they were; or perhaps there might have been shoals of\nthem in the far horizon; but lulled into such an opium-like\nlistlessness of vacant, unconscious reverie is this absent-minded\nyouth by the blending cadence of waves with thoughts, that at last he\nloses his identity; takes the mystic ocean at his feet for the\nvisible image of that deep, blue, bottomless soul, pervading mankind\nand nature; and every strange, half-seen, gliding, beautiful thing\nthat eludes him; every dimly-discovered, uprising fin of some\nundiscernible form, seems to him the embodiment of those elusive\nthoughts that only people the soul by continually flitting through\nit.  In this enchanted mood, thy spirit ebbs away to whence it came;\nbecomes diffused through time and space; like Crammer's sprinkled\nPantheistic ashes, forming at last a part of every shore the round\nglobe over.\n\nThere is no life in thee, now, except that rocking life imparted by a\ngently rolling ship; by her, borrowed from the sea; by the sea, from\nthe inscrutable tides of God.  But while this sleep, this dream is on\nye, move your foot or hand an inch; slip your hold at all; and your\nidentity comes back in horror.  Over Descartian vortices you hover.\nAnd perhaps, at mid-day, in the fairest weather, with one\nhalf-throttled shriek you drop through that transparent air into the\nsummer sea, no more to rise for ever.  Heed it well, ye Pantheists!\n\n\n\nCHAPTER 36\n\nThe Quarter-Deck.\n\n\n(ENTER AHAB: THEN, ALL)\n\n\nIt was not a great while after the affair of the pipe, that one\nmorning shortly after breakfast, Ahab, as was his wont, ascended the\ncabin-gangway to the deck.  There most sea-captains usually walk at\nthat hour, as country gentlemen, after the same meal, take a few\nturns in the garden.\n\nSoon his steady, ivory stride was heard, as to and fro he paced his\nold rounds, upon planks so familiar to his tread, that they were all\nover dented, like geological stones, with the peculiar mark of his\nwalk.  Did you fixedly gaze, too, upon that ribbed and dented brow;\nthere also, you would see still stranger foot-prints--the foot-prints\nof his one unsleeping, ever-pacing thought.\n\nBut on the occasion in question, those dents looked deeper, even as\nhis nervous step that morning left a deeper mark.  And, so full of\nhis thought was Ahab, that at every uniform turn that he made, now at\nthe main-mast and now at the binnacle, you could almost see that\nthought turn in him as he turned, and pace in him as he paced; so\ncompletely possessing him, indeed, that it all but seemed the inward\nmould of every outer movement.\n\n\"D'ye mark him, Flask?\" whispered Stubb; \"the chick that's in him\npecks the shell.  'Twill soon be out.\"\n\nThe hours wore on;--Ahab now shut up within his cabin; anon, pacing\nthe deck, with the same intense bigotry of purpose in his aspect.\n\nIt drew near the close of day.  Suddenly he came to a halt by the\nbulwarks, and inserting his bone leg into the auger-hole there, and\nwith one hand grasping a shroud, he ordered Starbuck to send\neverybody aft.\n\n\"Sir!\" said the mate, astonished at an order seldom or never given on\nship-board except in some extraordinary case.\n\n\"Send everybody aft,\" repeated Ahab.  \"Mast-heads, there! come down!\"\n\nWhen the entire ship's company were assembled, and with curious and\nnot wholly unapprehensive faces, were eyeing him, for he looked not\nunlike the weather horizon when a storm is coming up, Ahab, after\nrapidly glancing over the bulwarks, and then darting his eyes among\nthe crew, started from his standpoint; and as though not a soul were\nnigh him resumed his heavy turns upon the deck.  With bent head and\nhalf-slouched hat he continued to pace, unmindful of the wondering\nwhispering among the men; till Stubb cautiously whispered to Flask,\nthat Ahab must have summoned them there for the purpose of witnessing\na pedestrian feat.  But this did not last long.  Vehemently pausing,\nhe cried:--\n\n\"What do ye do when ye see a whale, men?\"\n\n\"Sing out for him!\" was the impulsive rejoinder from a score of\nclubbed voices.\n\n\"Good!\" cried Ahab, with a wild approval in his tones; observing the\nhearty animation into which his unexpected question had so\nmagnetically thrown them.\n\n\"And what do ye next, men?\"\n\n\"Lower away, and after him!\"\n\n\"And what tune is it ye pull to, men?\"\n\n\"A dead whale or a stove boat!\"\n\nMore and more strangely and fiercely glad and approving, grew the\ncountenance of the old man at every shout; while the mariners began\nto gaze curiously at each other, as if marvelling how it was that\nthey themselves became so excited at such seemingly purposeless\nquestions.\n\nBut, they were all eagerness again, as Ahab, now half-revolving in\nhis pivot-hole, with one hand reaching high up a shroud, and tightly,\nalmost convulsively grasping it, addressed them thus:--\n\n\"All ye mast-headers have before now heard me give orders about a\nwhite whale.  Look ye! d'ye see this Spanish ounce of gold?\"--holding\nup a broad bright coin to the sun--\"it is a sixteen dollar piece,\nmen.  D'ye see it?  Mr. Starbuck, hand me yon top-maul.\"\n\nWhile the mate was getting the hammer, Ahab, without speaking, was\nslowly rubbing the gold piece against the skirts of his jacket, as if\nto heighten its lustre, and without using any words was meanwhile\nlowly humming to himself, producing a sound so strangely muffled and\ninarticulate that it seemed the mechanical humming of the wheels of\nhis vitality in him.\n\nReceiving the top-maul from Starbuck, he advanced towards the\nmain-mast with the hammer uplifted in one hand, exhibiting the gold\nwith the other, and with a high raised voice exclaiming: \"Whosoever\nof ye raises me a white-headed whale with a wrinkled brow and a\ncrooked jaw; whosoever of ye raises me that white-headed whale, with\nthree holes punctured in his starboard fluke--look ye, whosoever of\nye raises me that same white whale, he shall have this gold ounce, my\nboys!\"\n\n\"Huzza! huzza!\" cried the seamen, as with swinging tarpaulins they\nhailed the act of nailing the gold to the mast.\n\n\"It's a white whale, I say,\" resumed Ahab, as he threw down the\ntopmaul: \"a white whale.  Skin your eyes for him, men; look sharp for\nwhite water; if ye see but a bubble, sing out.\"\n\nAll this while Tashtego, Daggoo, and Queequeg had looked on with even\nmore intense interest and surprise than the rest, and at the mention\nof the wrinkled brow and crooked jaw they had started as if each was\nseparately touched by some specific recollection.\n\n\"Captain Ahab,\" said Tashtego, \"that white whale must be the same\nthat some call Moby Dick.\"\n\n\"Moby Dick?\" shouted Ahab.  \"Do ye know the white whale then, Tash?\"\n\n\"Does he fan-tail a little curious, sir, before he goes down?\" said\nthe Gay-Header deliberately.\n\n\"And has he a curious spout, too,\" said Daggoo, \"very bushy, even for\na parmacetty, and mighty quick, Captain Ahab?\"\n\n\"And he have one, two, three--oh! good many iron in him hide, too,\nCaptain,\" cried Queequeg disjointedly, \"all twiske-tee be-twisk, like\nhim--him--\" faltering hard for a word, and screwing his hand round\nand round as though uncorking a bottle--\"like him--him--\"\n\n\"Corkscrew!\" cried Ahab, \"aye, Queequeg, the harpoons lie all twisted\nand wrenched in him; aye, Daggoo, his spout is a big one, like a\nwhole shock of wheat, and white as a pile of our Nantucket wool after\nthe great annual sheep-shearing; aye, Tashtego, and he fan-tails like\na split jib in a squall.  Death and devils! men, it is Moby Dick ye\nhave seen--Moby Dick--Moby Dick!\"\n\n\"Captain Ahab,\" said Starbuck, who, with Stubb and Flask, had thus\nfar been eyeing his superior with increasing surprise, but at last\nseemed struck with a thought which somewhat explained all the wonder.\n\"Captain Ahab, I have heard of Moby Dick--but it was not Moby Dick\nthat took off thy leg?\"\n\n\"Who told thee that?\" cried Ahab; then pausing, \"Aye, Starbuck; aye,\nmy hearties all round; it was Moby Dick that dismasted me; Moby Dick\nthat brought me to this dead stump I stand on now.  Aye, aye,\" he\nshouted with a terrific, loud, animal sob, like that of a\nheart-stricken moose; \"Aye, aye! it was that accursed white whale\nthat razeed me; made a poor pegging lubber of me for ever and a day!\"\nThen tossing both arms, with measureless imprecations he shouted\nout: \"Aye, aye! and I'll chase him round Good Hope, and round the\nHorn, and round the Norway Maelstrom, and round perdition's flames\nbefore I give him up.  And this is what ye have shipped for, men! to\nchase that white whale on both sides of land, and over all sides of\nearth, till he spouts black blood and rolls fin out.  What say ye,\nmen, will ye splice hands on it, now?  I think ye do look brave.\"\n\n\"Aye, aye!\" shouted the harpooneers and seamen, running closer to the\nexcited old man: \"A sharp eye for the white whale; a sharp lance for\nMoby Dick!\"\n\n\"God bless ye,\" he seemed to half sob and half shout.  \"God bless ye,\nmen.  Steward! go draw the great measure of grog.  But what's this\nlong face about, Mr. Starbuck; wilt thou not chase the white whale?\nart not game for Moby Dick?\"\n\n\"I am game for his crooked jaw, and for the jaws of Death too,\nCaptain Ahab, if it fairly comes in the way of the business we\nfollow; but I came here to hunt whales, not my commander's vengeance.\nHow many barrels will thy vengeance yield thee even if thou gettest\nit, Captain Ahab? it will not fetch thee much in our Nantucket\nmarket.\"\n\n\"Nantucket market!  Hoot!  But come closer, Starbuck; thou requirest\na little lower layer.  If money's to be the measurer, man, and the\naccountants have computed their great counting-house the globe, by\ngirdling it with guineas, one to every three parts of an inch; then,\nlet me tell thee, that my vengeance will fetch a great premium HERE!\"\n\n\"He smites his chest,\" whispered Stubb, \"what's that for? methinks it\nrings most vast, but hollow.\"\n\n\"Vengeance on a dumb brute!\" cried Starbuck, \"that simply smote thee\nfrom blindest instinct!  Madness!  To be enraged with a dumb thing,\nCaptain Ahab, seems blasphemous.\"\n\n\"Hark ye yet again--the little lower layer.  All visible objects,\nman, are but as pasteboard masks.  But in each event--in the living\nact, the undoubted deed--there, some unknown but still reasoning\nthing puts forth the mouldings of its features from behind the\nunreasoning mask.  If man will strike, strike through the mask!  How\ncan the prisoner reach outside except by thrusting through the wall?\nTo me, the white whale is that wall, shoved near to me.  Sometimes I\nthink there's naught beyond.  But 'tis enough.  He tasks me; he heaps\nme; I see in him outrageous strength, with an inscrutable malice\nsinewing it.  That inscrutable thing is chiefly what I hate; and be\nthe white whale agent, or be the white whale principal, I will wreak\nthat hate upon him.  Talk not to me of blasphemy, man; I'd strike the\nsun if it insulted me.  For could the sun do that, then could I do\nthe other; since there is ever a sort of fair play herein, jealousy\npresiding over all creations.  But not my master, man, is even that\nfair play.  Who's over me?  Truth hath no confines.  Take off thine\neye! more intolerable than fiends' glarings is a doltish stare!  So,\nso; thou reddenest and palest; my heat has melted thee to anger-glow.\nBut look ye, Starbuck, what is said in heat, that thing unsays\nitself.  There are men from whom warm words are small indignity.  I\nmeant not to incense thee.  Let it go.  Look! see yonder Turkish\ncheeks of spotted tawn--living, breathing pictures painted by the\nsun.  The Pagan leopards--the unrecking and unworshipping things,\nthat live; and seek, and give no reasons for the torrid life they\nfeel!  The crew, man, the crew!  Are they not one and all with Ahab,\nin this matter of the whale?  See Stubb! he laughs!  See yonder\nChilian! he snorts to think of it.  Stand up amid the general\nhurricane, thy one tost sapling cannot, Starbuck!  And what is it?\nReckon it.  'Tis but to help strike a fin; no wondrous feat for\nStarbuck.  What is it more?  From this one poor hunt, then, the best\nlance out of all Nantucket, surely he will not hang back, when every\nforemast-hand has clutched a whetstone?  Ah! constrainings seize\nthee; I see! the billow lifts thee!  Speak, but speak!--Aye, aye! thy\nsilence, then, THAT voices thee.  (ASIDE) Something shot from my\ndilated nostrils, he has inhaled it in his lungs.  Starbuck now is\nmine; cannot oppose me now, without rebellion.\"\n\n\"God keep me!--keep us all!\" murmured Starbuck, lowly.\n\nBut in his joy at the enchanted, tacit acquiescence of the mate, Ahab\ndid not hear his foreboding invocation; nor yet the low laugh from\nthe hold; nor yet the presaging vibrations of the winds in the\ncordage; nor yet the hollow flap of the sails against the masts, as\nfor a moment their hearts sank in.  For again Starbuck's downcast\neyes lighted up with the stubbornness of life; the subterranean laugh\ndied away; the winds blew on; the sails filled out; the ship heaved\nand rolled as before.  Ah, ye admonitions and warnings! why stay ye\nnot when ye come?  But rather are ye predictions than warnings, ye\nshadows!  Yet not so much predictions from without, as verifications\nof the foregoing things within.  For with little external to\nconstrain us, the innermost necessities in our being, these still\ndrive us on.\n\n\"The measure! the measure!\" cried Ahab.\n\nReceiving the brimming pewter, and turning to the harpooneers, he\nordered them to produce their weapons.  Then ranging them before him\nnear the capstan, with their harpoons in their hands, while his three\nmates stood at his side with their lances, and the rest of the ship's\ncompany formed a circle round the group; he stood for an instant\nsearchingly eyeing every man of his crew.  But those wild eyes met\nhis, as the bloodshot eyes of the prairie wolves meet the eye of\ntheir leader, ere he rushes on at their head in the trail of the\nbison; but, alas! only to fall into the hidden snare of the Indian.\n\n\"Drink and pass!\" he cried, handing the heavy charged flagon to the\nnearest seaman.  \"The crew alone now drink.  Round with it, round!\nShort draughts--long swallows, men; 'tis hot as Satan's hoof.  So,\nso; it goes round excellently.  It spiralizes in ye; forks out at the\nserpent-snapping eye.  Well done; almost drained.  That way it went,\nthis way it comes.  Hand it me--here's a hollow!  Men, ye seem the\nyears; so brimming life is gulped and gone.  Steward, refill!\n\n\"Attend now, my braves.  I have mustered ye all round this capstan;\nand ye mates, flank me with your lances; and ye harpooneers, stand\nthere with your irons; and ye, stout mariners, ring me in, that I may\nin some sort revive a noble custom of my fisherman fathers before\nme.  O men, you will yet see that--Ha! boy, come back? bad pennies\ncome not sooner.  Hand it me.  Why, now, this pewter had run brimming\nagain, were't not thou St. Vitus' imp--away, thou ague!\n\n\"Advance, ye mates!  Cross your lances full before me.  Well done!\nLet me touch the axis.\"  So saying, with extended arm, he grasped the\nthree level, radiating lances at their crossed centre; while so\ndoing, suddenly and nervously twitched them; meanwhile, glancing\nintently from Starbuck to Stubb; from Stubb to Flask.  It seemed as\nthough, by some nameless, interior volition, he would fain have\nshocked into them the same fiery emotion accumulated within the\nLeyden jar of his own magnetic life.  The three mates quailed before\nhis strong, sustained, and mystic aspect.  Stubb and Flask looked\nsideways from him; the honest eye of Starbuck fell downright.\n\n\"In vain!\" cried Ahab; \"but, maybe, 'tis well.  For did ye three but\nonce take the full-forced shock, then mine own electric thing, THAT\nhad perhaps expired from out me.  Perchance, too, it would have\ndropped ye dead.  Perchance ye need it not.  Down lances!  And now,\nye mates, I do appoint ye three cupbearers to my three pagan kinsmen\nthere--yon three most honourable gentlemen and noblemen, my valiant\nharpooneers.  Disdain the task?  What, when the great Pope washes the\nfeet of beggars, using his tiara for ewer?  Oh, my sweet cardinals!\nyour own condescension, THAT shall bend ye to it.  I do not order ye;\nye will it.  Cut your seizings and draw the poles, ye harpooneers!\"\n\nSilently obeying the order, the three harpooneers now stood with the\ndetached iron part of their harpoons, some three feet long, held,\nbarbs up, before him.\n\n\"Stab me not with that keen steel!  Cant them; cant them over! know\nye not the goblet end?  Turn up the socket!  So, so; now, ye\ncup-bearers, advance.  The irons! take them; hold them while I fill!\"\nForthwith, slowly going from one officer to the other, he brimmed\nthe harpoon sockets with the fiery waters from the pewter.\n\n\"Now, three to three, ye stand.  Commend the murderous chalices!\nBestow them, ye who are now made parties to this indissoluble league.\nHa!  Starbuck! but the deed is done!  Yon ratifying sun now waits to\nsit upon it.  Drink, ye harpooneers! drink and swear, ye men that man\nthe deathful whaleboat's bow--Death to Moby Dick!  God hunt us all,\nif we do not hunt Moby Dick to his death!\"  The long, barbed steel\ngoblets were lifted; and to cries and maledictions against the white\nwhale, the spirits were simultaneously quaffed down with a hiss.\nStarbuck paled, and turned, and shivered.  Once more, and finally,\nthe replenished pewter went the rounds among the frantic crew; when,\nwaving his free hand to them, they all dispersed; and Ahab retired\nwithin his cabin.\n\n\n\nCHAPTER 37\n\nSunset.\n\n\nTHE CABIN; BY THE STERN WINDOWS; AHAB SITTING ALONE, AND GAZING OUT.\n\n\nI leave a white and turbid wake; pale waters, paler cheeks, where'er\nI sail.  The envious billows sidelong swell to whelm my track; let\nthem; but first I pass.\n\nYonder, by ever-brimming goblet's rim, the warm waves blush like\nwine.  The gold brow plumbs the blue.  The diver sun--slow dived from\nnoon--goes down; my soul mounts up! she wearies with her endless\nhill.  Is, then, the crown too heavy that I wear? this Iron Crown of\nLombardy.  Yet is it bright with many a gem; I the wearer, see not\nits far flashings; but darkly feel that I wear that, that dazzlingly\nconfounds.  'Tis iron--that I know--not gold.  'Tis split, too--that\nI feel; the jagged edge galls me so, my brain seems to beat against\nthe solid metal; aye, steel skull, mine; the sort that needs no\nhelmet in the most brain-battering fight!\n\nDry heat upon my brow?  Oh! time was, when as the sunrise nobly\nspurred me, so the sunset soothed.  No more.  This lovely light, it\nlights not me; all loveliness is anguish to me, since I can ne'er\nenjoy.  Gifted with the high perception, I lack the low, enjoying\npower; damned, most subtly and most malignantly! damned in the midst\nof Paradise!  Good night--good night! (WAVING HIS HAND, HE MOVES FROM\nTHE WINDOW.)\n\n'Twas not so hard a task.  I thought to find one stubborn, at the\nleast; but my one cogged circle fits into all their various wheels,\nand they revolve.  Or, if you will, like so many ant-hills of powder,\nthey all stand before me; and I their match.  Oh, hard! that to fire\nothers, the match itself must needs be wasting!  What I've dared,\nI've willed; and what I've willed, I'll do!  They think me\nmad--Starbuck does; but I'm demoniac, I am madness maddened!  That\nwild madness that's only calm to comprehend itself!  The prophecy was\nthat I should be dismembered; and--Aye!  I lost this leg.  I now\nprophesy that I will dismember my dismemberer.  Now, then, be the\nprophet and the fulfiller one.  That's more than ye, ye great gods,\never were.  I laugh and hoot at ye, ye cricket-players, ye pugilists,\nye deaf Burkes and blinded Bendigoes!  I will not say as schoolboys\ndo to bullies--Take some one of your own size; don't pommel ME!  No,\nye've knocked me down, and I am up again; but YE have run and hidden.\nCome forth from behind your cotton bags!  I have no long gun to\nreach ye.  Come, Ahab's compliments to ye; come and see if ye can\nswerve me.  Swerve me? ye cannot swerve me, else ye swerve\nyourselves! man has ye there.  Swerve me?  The path to my fixed\npurpose is laid with iron rails, whereon my soul is grooved to run.\nOver unsounded gorges, through the rifled hearts of mountains, under\ntorrents' beds, unerringly I rush!  Naught's an obstacle, naught's an\nangle to the iron way!\n\n\n\nCHAPTER 38\n\nDusk.\n\n\nBY THE MAINMAST; STARBUCK LEANING AGAINST IT.\n\n\nMy soul is more than matched; she's overmanned; and by a madman!\nInsufferable sting, that sanity should ground arms on such a field!\nBut he drilled deep down, and blasted all my reason out of me!  I\nthink I see his impious end; but feel that I must help him to it.\nWill I, nill I, the ineffable thing has tied me to him; tows me with\na cable I have no knife to cut.  Horrible old man!  Who's over him,\nhe cries;--aye, he would be a democrat to all above; look, how he\nlords it over all below!  Oh!  I plainly see my miserable office,--to\nobey, rebelling; and worse yet, to hate with touch of pity!  For in\nhis eyes I read some lurid woe would shrivel me up, had I it.  Yet is\nthere hope.  Time and tide flow wide.  The hated whale has the round\nwatery world to swim in, as the small gold-fish has its glassy globe.\nHis heaven-insulting purpose, God may wedge aside.  I would up\nheart, were it not like lead.  But my whole clock's run down; my\nheart the all-controlling weight, I have no key to lift again.\n\n\n[A BURST OF REVELRY FROM THE FORECASTLE.]\n\n\nOh, God! to sail with such a heathen crew that have small touch of\nhuman mothers in them!  Whelped somewhere by the sharkish sea.  The\nwhite whale is their demigorgon.  Hark! the infernal orgies! that\nrevelry is forward! mark the unfaltering silence aft!  Methinks it\npictures life.  Foremost through the sparkling sea shoots on the gay,\nembattled, bantering bow, but only to drag dark Ahab after it, where\nhe broods within his sternward cabin, builded over the dead water of\nthe wake, and further on, hunted by its wolfish gurglings.  The long\nhowl thrills me through!  Peace! ye revellers, and set the watch!\nOh, life!  'tis in an hour like this, with soul beat down and held to\nknowledge,--as wild, untutored things are forced to feed--Oh, life!\n'tis now that I do feel the latent horror in thee! but 'tis not me!\nthat horror's out of me! and with the soft feeling of the human in\nme, yet will I try to fight ye, ye grim, phantom futures!  Stand by\nme, hold me, bind me, O ye blessed influences!\n\n\n\nCHAPTER 39\n\nFirst Night Watch.\n\nFore-Top.\n\n(STUBB SOLUS, AND MENDING A BRACE.)\n\n\nHa! ha! ha! ha! hem! clear my throat!--I've been thinking over it\never since, and that ha, ha's the final consequence.  Why so?\nBecause a laugh's the wisest, easiest answer to all that's queer; and\ncome what will, one comfort's always left--that unfailing comfort is,\nit's all predestinated.  I heard not all his talk with Starbuck; but\nto my poor eye Starbuck then looked something as I the other evening\nfelt.  Be sure the old Mogul has fixed him, too.  I twigged it, knew\nit; had had the gift, might readily have prophesied it--for when I\nclapped my eye upon his skull I saw it.  Well, Stubb, WISE\nStubb--that's my title--well, Stubb, what of it, Stubb?  Here's a\ncarcase.  I know not all that may be coming, but be it what it will,\nI'll go to it laughing.  Such a waggish leering as lurks in all your\nhorribles!  I feel funny.  Fa, la! lirra, skirra!  What's my juicy\nlittle pear at home doing now?  Crying its eyes out?--Giving a party\nto the last arrived harpooneers, I dare say, gay as a frigate's\npennant, and so am I--fa, la! lirra, skirra!  Oh--\n\nWe'll drink to-night with hearts as light,\nTo love, as gay and fleeting\nAs bubbles that swim, on the beaker's brim,\nAnd break on the lips while meeting.\n\n\nA brave stave that--who calls?  Mr. Starbuck?  Aye, aye, sir--(ASIDE)\nhe's my superior, he has his too, if I'm not mistaken.--Aye, aye,\nsir, just through with this job--coming.\n\n\n\nCHAPTER 40\n\nMidnight, Forecastle.\n\nHARPOONEERS AND SAILORS.\n\n(FORESAIL RISES AND DISCOVERS THE WATCH STANDING, LOUNGING, LEANING,\nAND LYING IN VARIOUS ATTITUDES, ALL SINGING IN CHORUS.)\n\nFarewell and adieu to you, Spanish ladies!\nFarewell and adieu to you, ladies of Spain!\nOur captain's commanded.--\n\n1ST NANTUCKET SAILOR.\nOh, boys, don't be sentimental; it's bad for the digestion!  Take a\ntonic, follow me!\n(SINGS, AND ALL FOLLOW)\n\nOur captain stood upon the deck,\nA spy-glass in his hand,\nA viewing of those gallant whales\nThat blew at every strand.\nOh, your tubs in your boats, my boys,\nAnd by your braces stand,\nAnd we'll have one of those fine whales,\nHand, boys, over hand!\nSo, be cheery, my lads! may your hearts never fail!\nWhile the bold harpooner is striking the whale!\n\nMATE'S VOICE FROM THE QUARTER-DECK.\nEight bells there, forward!\n\n2ND NANTUCKET SAILOR.\nAvast the chorus!  Eight bells there! d'ye hear, bell-boy?  Strike\nthe bell eight, thou Pip! thou blackling! and let me call the watch.\nI've the sort of mouth for that--the hogshead mouth.  So, so,\n(THRUSTS HIS HEAD DOWN THE SCUTTLE,) Star-bo-l-e-e-n-s, a-h-o-y!\nEight bells there below!  Tumble up!\n\nDUTCH SAILOR.\nGrand snoozing to-night, maty; fat night for that.  I mark this in\nour old Mogul's wine; it's quite as deadening to some as filliping to\nothers.  We sing; they sleep--aye, lie down there, like ground-tier\nbutts.  At 'em again!  There, take this copper-pump, and hail 'em\nthrough it.  Tell 'em to avast dreaming of their lasses.  Tell 'em\nit's the resurrection; they must kiss their last, and come to\njudgment.  That's the way--THAT'S it; thy throat ain't spoiled with\neating Amsterdam butter.\n\nFRENCH SAILOR.\nHist, boys! let's have a jig or two before we ride to anchor in\nBlanket Bay.  What say ye?  There comes the other watch.  Stand by\nall legs!  Pip! little Pip! hurrah with your tambourine!\n\nPIP.\n(SULKY AND SLEEPY)\nDon't know where it is.\n\nFRENCH SAILOR.\nBeat thy belly, then, and wag thy ears.  Jig it, men, I say; merry's\nthe word; hurrah!  Damn me, won't you dance?  Form, now, Indian-file,\nand gallop into the double-shuffle?  Throw yourselves!  Legs! legs!\n\nICELAND SAILOR.\nI don't like your floor, maty; it's too springy to my taste.  I'm\nused to ice-floors.  I'm sorry to throw cold water on the subject;\nbut excuse me.\n\nMALTESE SAILOR.\nMe too; where's your girls?  Who but a fool would take his left hand\nby his right, and say to himself, how d'ye do?  Partners!  I must\nhave partners!\n\nSICILIAN SAILOR.\nAye; girls and a green!--then I'll hop with ye; yea, turn\ngrasshopper!\n\nLONG-ISLAND SAILOR.\nWell, well, ye sulkies, there's plenty more of us.  Hoe corn when you\nmay, say I.  All legs go to harvest soon.  Ah! here comes the music;\nnow for it!\n\nAZORE SAILOR.\n(ASCENDING, AND PITCHING THE TAMBOURINE UP THE SCUTTLE.)\nHere you are, Pip; and there's the windlass-bitts; up you mount!\nNow, boys!\n(THE HALF OF THEM DANCE TO THE TAMBOURINE; SOME GO BELOW; SOME SLEEP\nOR LIE AMONG THE COILS OF RIGGING.  OATHS A-PLENTY.)\n\nAZORE SAILOR.\n(DANCING)\nGo it, Pip!  Bang it, bell-boy!  Rig it, dig it, stig it, quig it,\nbell-boy!  Make fire-flies; break the jinglers!\n\nPIP.\nJinglers, you say?--there goes another, dropped off; I pound it so.\n\nCHINA SAILOR.\nRattle thy teeth, then, and pound away; make a pagoda of thyself.\n\n\nFRENCH SAILOR.\nMerry-mad!  Hold up thy hoop, Pip, till I jump through it!  Split\njibs! tear yourselves!\n\nTASHTEGO.\n(QUIETLY SMOKING)\nThat's a white man; he calls that fun: humph!  I save my sweat.\n\nOLD MANX SAILOR.\nI wonder whether those jolly lads bethink them of what they are\ndancing over.  I'll dance over your grave, I will--that's the\nbitterest threat of your night-women, that beat head-winds round\ncorners.  O Christ! to think of the green navies and the\ngreen-skulled crews!  Well, well; belike the whole world's a ball, as\nyou scholars have it; and so 'tis right to make one ballroom of it.\nDance on, lads, you're young; I was once.\n\n3D NANTUCKET SAILOR.\nSpell oh!--whew! this is worse than pulling after whales in a\ncalm--give us a whiff, Tash.\n\n(THEY CEASE DANCING, AND GATHER IN CLUSTERS.  MEANTIME THE SKY\nDARKENS--THE WIND RISES.)\n\nLASCAR SAILOR.\nBy Brahma! boys, it'll be douse sail soon.  The sky-born, high-tide\nGanges turned to wind!  Thou showest thy black brow, Seeva!\n\nMALTESE SAILOR.\n(RECLINING AND SHAKING HIS CAP.)\nIt's the waves--the snow's caps turn to jig it now.  They'll shake\ntheir tassels soon.  Now would all the waves were women, then I'd go\ndrown, and chassee with them evermore!  There's naught so sweet on\nearth--heaven may not match it!--as those swift glances of warm, wild\nbosoms in the dance, when the over-arboring arms hide such ripe,\nbursting grapes.\n\nSICILIAN SAILOR.\n(RECLINING.)\nTell me not of it!  Hark ye, lad--fleet interlacings of the\nlimbs--lithe swayings--coyings--flutterings! lip! heart! hip! all\ngraze: unceasing touch and go! not taste, observe ye, else come\nsatiety.  Eh, Pagan? (NUDGING.)\n\nTAHITAN SAILOR.\n(RECLINING ON A MAT.)\nHail, holy nakedness of our dancing girls!--the Heeva-Heeva!  Ah! low\nveiled, high palmed Tahiti!  I still rest me on thy mat, but the soft\nsoil has slid!  I saw thee woven in the wood, my mat! green the first\nday I brought ye thence; now worn and wilted quite.  Ah me!--not thou\nnor I can bear the change!  How then, if so be transplanted to yon\nsky?  Hear I the roaring streams from Pirohitee's peak of spears,\nwhen they leap down the crags and drown the villages?--The blast! the\nblast!  Up, spine, and meet it! (LEAPS TO HIS FEET.)\n\nPORTUGUESE SAILOR.\nHow the sea rolls swashing 'gainst the side!  Stand by for reefing,\nhearties! the winds are just crossing swords, pell-mell they'll go\nlunging presently.\n\nDANISH SAILOR.\nCrack, crack, old ship! so long as thou crackest, thou holdest!  Well\ndone!  The mate there holds ye to it stiffly.  He's no more afraid\nthan the isle fort at Cattegat, put there to fight the Baltic with\nstorm-lashed guns, on which the sea-salt cakes!\n\n4TH NANTUCKET SAILOR.\nHe has his orders, mind ye that.  I heard old Ahab tell him he must\nalways kill a squall, something as they burst a waterspout with a\npistol--fire your ship right into it!\n\nENGLISH SAILOR.\nBlood! but that old man's a grand old cove!  We are the lads to hunt\nhim up his whale!\n\nALL.\nAye! aye!\n\nOLD MANX SAILOR.\nHow the three pines shake!  Pines are the hardest sort of tree to\nlive when shifted to any other soil, and here there's none but the\ncrew's cursed clay.  Steady, helmsman! steady.  This is the sort of\nweather when brave hearts snap ashore, and keeled hulls split at sea.\nOur captain has his birthmark; look yonder, boys, there's another in\nthe sky--lurid-like, ye see, all else pitch black.\n\nDAGGOO.\nWhat of that?  Who's afraid of black's afraid of me!  I'm quarried\nout of it!\n\nSPANISH SAILOR.\n(ASIDE.) He wants to bully, ah!--the old grudge makes me touchy\n(ADVANCING.) Aye, harpooneer, thy race is the undeniable dark side of\nmankind--devilish dark at that.  No offence.\n\nDAGGOO (GRIMLY).\nNone.\n\nST. JAGO'S SAILOR.\nThat Spaniard's mad or drunk.  But that can't be, or else in his one\ncase our old Mogul's fire-waters are somewhat long in working.\n\n5TH NANTUCKET SAILOR.\nWhat's that I saw--lightning?  Yes.\n\nSPANISH SAILOR.\nNo; Daggoo showing his teeth.\n\nDAGGOO (SPRINGING).\nSwallow thine, mannikin!  White skin, white liver!\n\nSPANISH SAILOR (MEETING HIM).\nKnife thee heartily! big frame, small spirit!\n\nALL.\nA row! a row! a row!\n\nTASHTEGO (WITH A WHIFF).\nA row a'low, and a row aloft--Gods and men--both brawlers!  Humph!\n\nBELFAST SAILOR.\nA row! arrah a row!  The Virgin be blessed, a row!  Plunge in with\nye!\n\nENGLISH SAILOR.\nFair play!  Snatch the Spaniard's knife!  A ring, a ring!\n\nOLD MANX SAILOR.\nReady formed.  There! the ringed horizon.  In that ring Cain struck\nAbel.  Sweet work, right work!  No?  Why then, God, mad'st thou the\nring?\n\nMATE'S VOICE FROM THE QUARTER-DECK.\nHands by the halyards! in top-gallant sails!  Stand by to reef\ntopsails!\n\nALL.\nThe squall! the squall! jump, my jollies! (THEY SCATTER.)\n\n\nPIP (SHRINKING UNDER THE WINDLASS).\nJollies?  Lord help such jollies!  Crish, crash! there goes the\njib-stay!  Blang-whang!  God!  Duck lower, Pip, here comes the royal\nyard!  It's worse than being in the whirled woods, the last day of\nthe year!  Who'd go climbing after chestnuts now?  But there they\ngo, all cursing, and here I don't.  Fine prospects to 'em; they're on\nthe road to heaven.  Hold on hard!  Jimmini, what a squall!  But\nthose chaps there are worse yet--they are your white squalls, they.\nWhite squalls? white whale, shirr! shirr!  Here have I heard all\ntheir chat just now, and the white whale--shirr! shirr!--but spoken\nof once! and only this evening--it makes me jingle all over like my\ntambourine--that anaconda of an old man swore 'em in to hunt him!\nOh, thou big white God aloft there somewhere in yon darkness, have\nmercy on this small black boy down here; preserve him from all men\nthat have no bowels to feel fear!\n\n\n\nCHAPTER 41\n\nMoby Dick.\n\n\nI, Ishmael, was one of that crew; my shouts had gone up with the\nrest; my oath had been welded with theirs; and stronger I shouted,\nand more did I hammer and clinch my oath, because of the dread in my\nsoul.  A wild, mystical, sympathetical feeling was in me; Ahab's\nquenchless feud seemed mine.  With greedy ears I learned the history\nof that murderous monster against whom I and all the others had taken\nour oaths of violence and revenge.\n\nFor some time past, though at intervals only, the unaccompanied,\nsecluded White Whale had haunted those uncivilized seas mostly\nfrequented by the Sperm Whale fishermen.  But not all of them knew of\nhis existence; only a few of them, comparatively, had knowingly seen\nhim; while the number who as yet had actually and knowingly given\nbattle to him, was small indeed.  For, owing to the large number of\nwhale-cruisers; the disorderly way they were sprinkled over the\nentire watery circumference, many of them adventurously pushing their\nquest along solitary latitudes, so as seldom or never for a whole\ntwelvemonth or more on a stretch, to encounter a single news-telling\nsail of any sort; the inordinate length of each separate voyage; the\nirregularity of the times of sailing from home; all these, with other\ncircumstances, direct and indirect, long obstructed the spread\nthrough the whole world-wide whaling-fleet of the special\nindividualizing tidings concerning Moby Dick.  It was hardly to be\ndoubted, that several vessels reported to have encountered, at such\nor such a time, or on such or such a meridian, a Sperm Whale of\nuncommon magnitude and malignity, which whale, after doing great\nmischief to his assailants, had completely escaped them; to some\nminds it was not an unfair presumption, I say, that the whale in\nquestion must have been no other than Moby Dick.  Yet as of late the\nSperm Whale fishery had been marked by various and not unfrequent\ninstances of great ferocity, cunning, and malice in the monster\nattacked; therefore it was, that those who by accident ignorantly\ngave battle to Moby Dick; such hunters, perhaps, for the most part,\nwere content to ascribe the peculiar terror he bred, more, as it\nwere, to the perils of the Sperm Whale fishery at large, than to the\nindividual cause.  In that way, mostly, the disastrous encounter\nbetween Ahab and the whale had hitherto been popularly regarded.\n\nAnd as for those who, previously hearing of the White Whale, by\nchance caught sight of him; in the beginning of the thing they had\nevery one of them, almost, as boldly and fearlessly lowered for him,\nas for any other whale of that species.  But at length, such\ncalamities did ensue in these assaults--not restricted to sprained\nwrists and ankles, broken limbs, or devouring amputations--but fatal\nto the last degree of fatality; those repeated disastrous repulses,\nall accumulating and piling their terrors upon Moby Dick; those\nthings had gone far to shake the fortitude of many brave hunters, to\nwhom the story of the White Whale had eventually come.\n\nNor did wild rumors of all sorts fail to exaggerate, and still the\nmore horrify the true histories of these deadly encounters.  For not\nonly do fabulous rumors naturally grow out of the very body of all\nsurprising terrible events,--as the smitten tree gives birth to its\nfungi; but, in maritime life, far more than in that of terra firma,\nwild rumors abound, wherever there is any adequate reality for them\nto cling to.  And as the sea surpasses the land in this matter, so\nthe whale fishery surpasses every other sort of maritime life, in the\nwonderfulness and fearfulness of the rumors which sometimes circulate\nthere.  For not only are whalemen as a body unexempt from that\nignorance and superstitiousness hereditary to all sailors; but of all\nsailors, they are by all odds the most directly brought into contact\nwith whatever is appallingly astonishing in the sea; face to face\nthey not only eye its greatest marvels, but, hand to jaw, give battle\nto them.  Alone, in such remotest waters, that though you sailed a\nthousand miles, and passed a thousand shores, you would not come to\nany chiseled hearth-stone, or aught hospitable beneath that part of\nthe sun; in such latitudes and longitudes, pursuing too such a\ncalling as he does, the whaleman is wrapped by influences all tending\nto make his fancy pregnant with many a mighty birth.\n\nNo wonder, then, that ever gathering volume from the mere transit\nover the widest watery spaces, the outblown rumors of the White Whale\ndid in the end incorporate with themselves all manner of morbid\nhints, and half-formed foetal suggestions of supernatural agencies,\nwhich eventually invested Moby Dick with new terrors unborrowed from\nanything that visibly appears.  So that in many cases such a panic\ndid he finally strike, that few who by those rumors, at least, had\nheard of the White Whale, few of those hunters were willing to\nencounter the perils of his jaw.\n\nBut there were still other and more vital practical influences at\nwork.  Not even at the present day has the original prestige of the\nSperm Whale, as fearfully distinguished from all other species of the\nleviathan, died out of the minds of the whalemen as a body.  There\nare those this day among them, who, though intelligent and courageous\nenough in offering battle to the Greenland or Right whale, would\nperhaps--either from professional inexperience, or incompetency, or\ntimidity, decline a contest with the Sperm Whale; at any rate, there\nare plenty of whalemen, especially among those whaling nations not\nsailing under the American flag, who have never hostilely encountered\nthe Sperm Whale, but whose sole knowledge of the leviathan is\nrestricted to the ignoble monster primitively pursued in the North;\nseated on their hatches, these men will hearken with a childish\nfireside interest and awe, to the wild, strange tales of Southern\nwhaling.  Nor is the pre-eminent tremendousness of the great Sperm\nWhale anywhere more feelingly comprehended, than on board of those\nprows which stem him.\n\nAnd as if the now tested reality of his might had in former legendary\ntimes thrown its shadow before it; we find some book\nnaturalists--Olassen and Povelson--declaring the Sperm Whale not only\nto be a consternation to every other creature in the sea, but also to\nbe so incredibly ferocious as continually to be athirst for human\nblood.  Nor even down to so late a time as Cuvier's, were these or\nalmost similar impressions effaced.  For in his Natural History, the\nBaron himself affirms that at sight of the Sperm Whale, all fish\n(sharks included) are \"struck with the most lively terrors,\" and\n\"often in the precipitancy of their flight dash themselves against\nthe rocks with such violence as to cause instantaneous death.\"  And\nhowever the general experiences in the fishery may amend such reports\nas these; yet in their full terribleness, even to the bloodthirsty\nitem of Povelson, the superstitious belief in them is, in some\nvicissitudes of their vocation, revived in the minds of the hunters.\n\nSo that overawed by the rumors and portents concerning him, not a few\nof the fishermen recalled, in reference to Moby Dick, the earlier\ndays of the Sperm Whale fishery, when it was oftentimes hard to\ninduce long practised Right whalemen to embark in the perils of this\nnew and daring warfare; such men protesting that although other\nleviathans might be hopefully pursued, yet to chase and point lance\nat such an apparition as the Sperm Whale was not for mortal man.\nThat to attempt it, would be inevitably to be torn into a quick\neternity.  On this head, there are some remarkable documents that may\nbe consulted.\n\nNevertheless, some there were, who even in the face of these things\nwere ready to give chase to Moby Dick; and a still greater number\nwho, chancing only to hear of him distantly and vaguely, without the\nspecific details of any certain calamity, and without superstitious\naccompaniments, were sufficiently hardy not to flee from the battle\nif offered.\n\nOne of the wild suggestions referred to, as at last coming to be\nlinked with the White Whale in the minds of the superstitiously\ninclined, was the unearthly conceit that Moby Dick was ubiquitous;\nthat he had actually been encountered in opposite latitudes at one\nand the same instant of time.\n\nNor, credulous as such minds must have been, was this conceit\naltogether without some faint show of superstitious probability.  For\nas the secrets of the currents in the seas have never yet been\ndivulged, even to the most erudite research; so the hidden ways of\nthe Sperm Whale when beneath the surface remain, in great part,\nunaccountable to his pursuers; and from time to time have originated\nthe most curious and contradictory speculations regarding them,\nespecially concerning the mystic modes whereby, after sounding to a\ngreat depth, he transports himself with such vast swiftness to the\nmost widely distant points.\n\nIt is a thing well known to both American and English whale-ships,\nand as well a thing placed upon authoritative record years ago by\nScoresby, that some whales have been captured far north in the\nPacific, in whose bodies have been found the barbs of harpoons darted\nin the Greenland seas.  Nor is it to be gainsaid, that in some of\nthese instances it has been declared that the interval of time\nbetween the two assaults could not have exceeded very many days.\nHence, by inference, it has been believed by some whalemen, that the\nNor' West Passage, so long a problem to man, was never a problem to\nthe whale.  So that here, in the real living experience of living\nmen, the prodigies related in old times of the inland Strello\nmountain in Portugal (near whose top there was said to be a lake in\nwhich the wrecks of ships floated up to the surface); and that still\nmore wonderful story of the Arethusa fountain near Syracuse (whose\nwaters were believed to have come from the Holy Land by an\nunderground passage); these fabulous narrations are almost fully\nequalled by the realities of the whalemen.\n\nForced into familiarity, then, with such prodigies as these; and\nknowing that after repeated, intrepid assaults, the White Whale had\nescaped alive; it cannot be much matter of surprise that some\nwhalemen should go still further in their superstitions; declaring\nMoby Dick not only ubiquitous, but immortal (for immortality is but\nubiquity in time); that though groves of spears should be planted in\nhis flanks, he would still swim away unharmed; or if indeed he should\never be made to spout thick blood, such a sight would be but a\nghastly deception; for again in unensanguined billows hundreds of\nleagues away, his unsullied jet would once more be seen.\n\nBut even stripped of these supernatural surmisings, there was enough\nin the earthly make and incontestable character of the monster to\nstrike the imagination with unwonted power.  For, it was not so much\nhis uncommon bulk that so much distinguished him from other sperm\nwhales, but, as was elsewhere thrown out--a peculiar snow-white\nwrinkled forehead, and a high, pyramidical white hump.  These were\nhis prominent features; the tokens whereby, even in the limitless,\nuncharted seas, he revealed his identity, at a long distance, to\nthose who knew him.\n\nThe rest of his body was so streaked, and spotted, and marbled with\nthe same shrouded hue, that, in the end, he had gained his\ndistinctive appellation of the White Whale; a name, indeed, literally\njustified by his vivid aspect, when seen gliding at high noon through\na dark blue sea, leaving a milky-way wake of creamy foam, all\nspangled with golden gleamings.\n\nNor was it his unwonted magnitude, nor his remarkable hue, nor yet\nhis deformed lower jaw, that so much invested the whale with natural\nterror, as that unexampled, intelligent malignity which, according to\nspecific accounts, he had over and over again evinced in his\nassaults.  More than all, his treacherous retreats struck more of\ndismay than perhaps aught else.  For, when swimming before his\nexulting pursuers, with every apparent symptom of alarm, he had\nseveral times been known to turn round suddenly, and, bearing down\nupon them, either stave their boats to splinters, or drive them back\nin consternation to their ship.\n\nAlready several fatalities had attended his chase.  But though\nsimilar disasters, however little bruited ashore, were by no means\nunusual in the fishery; yet, in most instances, such seemed the White\nWhale's infernal aforethought of ferocity, that every dismembering or\ndeath that he caused, was not wholly regarded as having been\ninflicted by an unintelligent agent.\n\nJudge, then, to what pitches of inflamed, distracted fury the minds\nof his more desperate hunters were impelled, when amid the chips of\nchewed boats, and the sinking limbs of torn comrades, they swam out\nof the white curds of the whale's direful wrath into the serene,\nexasperating sunlight, that smiled on, as if at a birth or a bridal.\n\nHis three boats stove around him, and oars and men both whirling in\nthe eddies; one captain, seizing the line-knife from his broken prow,\nhad dashed at the whale, as an Arkansas duellist at his foe, blindly\nseeking with a six inch blade to reach the fathom-deep life of the\nwhale.  That captain was Ahab.  And then it was, that suddenly\nsweeping his sickle-shaped lower jaw beneath him, Moby Dick had\nreaped away Ahab's leg, as a mower a blade of grass in the field.  No\nturbaned Turk, no hired Venetian or Malay, could have smote him with\nmore seeming malice.  Small reason was there to doubt, then, that\never since that almost fatal encounter, Ahab had cherished a wild\nvindictiveness against the whale, all the more fell for that in his\nfrantic morbidness he at last came to identify with him, not only all\nhis bodily woes, but all his intellectual and spiritual\nexasperations.  The White Whale swam before him as the monomaniac\nincarnation of all those malicious agencies which some deep men feel\neating in them, till they are left living on with half a heart and\nhalf a lung.  That intangible malignity which has been from the\nbeginning; to whose dominion even the modern Christians ascribe\none-half of the worlds; which the ancient Ophites of the east\nreverenced in their statue devil;--Ahab did not fall down and worship\nit like them; but deliriously transferring its idea to the abhorred\nwhite whale, he pitted himself, all mutilated, against it.  All that\nmost maddens and torments; all that stirs up the lees of things; all\ntruth with malice in it; all that cracks the sinews and cakes the\nbrain; all the subtle demonisms of life and thought; all evil, to\ncrazy Ahab, were visibly personified, and made practically assailable\nin Moby Dick.  He piled upon the whale's white hump the sum of all\nthe general rage and hate felt by his whole race from Adam down; and\nthen, as if his chest had been a mortar, he burst his hot heart's\nshell upon it.\n\nIt is not probable that this monomania in him took its instant rise\nat the precise time of his bodily dismemberment.  Then, in darting at\nthe monster, knife in hand, he had but given loose to a sudden,\npassionate, corporal animosity; and when he received the stroke that\ntore him, he probably but felt the agonizing bodily laceration, but\nnothing more.  Yet, when by this collision forced to turn towards\nhome, and for long months of days and weeks, Ahab and anguish lay\nstretched together in one hammock, rounding in mid winter that\ndreary, howling Patagonian Cape; then it was, that his torn body and\ngashed soul bled into one another; and so interfusing, made him mad.\nThat it was only then, on the homeward voyage, after the encounter,\nthat the final monomania seized him, seems all but certain from the\nfact that, at intervals during the passage, he was a raving lunatic;\nand, though unlimbed of a leg, yet such vital strength yet lurked in\nhis Egyptian chest, and was moreover intensified by his delirium,\nthat his mates were forced to lace him fast, even there, as he\nsailed, raving in his hammock.  In a strait-jacket, he swung to the\nmad rockings of the gales.  And, when running into more sufferable\nlatitudes, the ship, with mild stun'sails spread, floated across the\ntranquil tropics, and, to all appearances, the old man's delirium\nseemed left behind him with the Cape Horn swells, and he came forth\nfrom his dark den into the blessed light and air; even then, when he\nbore that firm, collected front, however pale, and issued his calm\norders once again; and his mates thanked God the direful madness was\nnow gone; even then, Ahab, in his hidden self, raved on.  Human\nmadness is oftentimes a cunning and most feline thing.  When you\nthink it fled, it may have but become transfigured into some still\nsubtler form.  Ahab's full lunacy subsided not, but deepeningly\ncontracted; like the unabated Hudson, when that noble Northman flows\nnarrowly, but unfathomably through the Highland gorge.  But, as in\nhis narrow-flowing monomania, not one jot of Ahab's broad madness had\nbeen left behind; so in that broad madness, not one jot of his great\nnatural intellect had perished.  That before living agent, now became\nthe living instrument.  If such a furious trope may stand, his\nspecial lunacy stormed his general sanity, and carried it, and turned\nall its concentred cannon upon its own mad mark; so that far from\nhaving lost his strength, Ahab, to that one end, did now possess a\nthousand fold more potency than ever he had sanely brought to bear\nupon any one reasonable object.\n\nThis is much; yet Ahab's larger, darker, deeper part remains\nunhinted.  But vain to popularize profundities, and all truth is\nprofound.  Winding far down from within the very heart of this spiked\nHotel de Cluny where we here stand--however grand and wonderful, now\nquit it;--and take your way, ye nobler, sadder souls, to those vast\nRoman halls of Thermes; where far beneath the fantastic towers of\nman's upper earth, his root of grandeur, his whole awful essence sits\nin bearded state; an antique buried beneath antiquities, and throned\non torsoes!  So with a broken throne, the great gods mock that\ncaptive king; so like a Caryatid, he patient sits, upholding on his\nfrozen brow the piled entablatures of ages.  Wind ye down there, ye\nprouder, sadder souls! question that proud, sad king!  A family\nlikeness! aye, he did beget ye, ye young exiled royalties; and from\nyour grim sire only will the old State-secret come.\n\nNow, in his heart, Ahab had some glimpse of this, namely: all my\nmeans are sane, my motive and my object mad.  Yet without power to\nkill, or change, or shun the fact; he likewise knew that to mankind\nhe did long dissemble; in some sort, did still.  But that thing of\nhis dissembling was only subject to his perceptibility, not to his\nwill determinate.  Nevertheless, so well did he succeed in that\ndissembling, that when with ivory leg he stepped ashore at last, no\nNantucketer thought him otherwise than but naturally grieved, and\nthat to the quick, with the terrible casualty which had overtaken\nhim.\n\nThe report of his undeniable delirium at sea was likewise popularly\nascribed to a kindred cause.  And so too, all the added moodiness\nwhich always afterwards, to the very day of sailing in the Pequod on\nthe present voyage, sat brooding on his brow.  Nor is it so very\nunlikely, that far from distrusting his fitness for another whaling\nvoyage, on account of such dark symptoms, the calculating people of\nthat prudent isle were inclined to harbor the conceit, that for those\nvery reasons he was all the better qualified and set on edge, for a\npursuit so full of rage and wildness as the bloody hunt of whales.\nGnawed within and scorched without, with the infixed, unrelenting\nfangs of some incurable idea; such an one, could he be found, would\nseem the very man to dart his iron and lift his lance against the\nmost appalling of all brutes.  Or, if for any reason thought to be\ncorporeally incapacitated for that, yet such an one would seem\nsuperlatively competent to cheer and howl on his underlings to the\nattack.  But be all this as it may, certain it is, that with the mad\nsecret of his unabated rage bolted up and keyed in him, Ahab had\npurposely sailed upon the present voyage with the one only and\nall-engrossing object of hunting the White Whale.  Had any one of his\nold acquaintances on shore but half dreamed of what was lurking in\nhim then, how soon would their aghast and righteous souls have\nwrenched the ship from such a fiendish man!  They were bent on\nprofitable cruises, the profit to be counted down in dollars from the\nmint.  He was intent on an audacious, immitigable, and supernatural\nrevenge.\n\nHere, then, was this grey-headed, ungodly old man, chasing with\ncurses a Job's whale round the world, at the head of a crew, too,\nchiefly made up of mongrel renegades, and castaways, and\ncannibals--morally enfeebled also, by the incompetence of mere\nunaided virtue or right-mindedness in Starbuck, the invunerable\njollity of indifference and recklessness in Stubb, and the pervading\nmediocrity in Flask.  Such a crew, so officered, seemed specially\npicked and packed by some infernal fatality to help him to his\nmonomaniac revenge.  How it was that they so aboundingly responded to\nthe old man's ire--by what evil magic their souls were possessed,\nthat at times his hate seemed almost theirs; the White Whale as much\ntheir insufferable foe as his; how all this came to be--what the\nWhite Whale was to them, or how to their unconscious understandings,\nalso, in some dim, unsuspected way, he might have seemed the gliding\ngreat demon of the seas of life,--all this to explain, would be to\ndive deeper than Ishmael can go.  The subterranean miner that works\nin us all, how can one tell whither leads his shaft by the ever\nshifting, muffled sound of his pick?  Who does not feel the\nirresistible arm drag?  What skiff in tow of a seventy-four can stand\nstill?  For one, I gave myself up to the abandonment of the time and\nthe place; but while yet all a-rush to encounter the whale, could see\nnaught in that brute but the deadliest ill.\n\n\n\nCHAPTER 42\n\nThe Whiteness of The Whale.\n\n\nWhat the white whale was to Ahab, has been hinted; what, at times, he\nwas to me, as yet remains unsaid.\n\nAside from those more obvious considerations touching Moby Dick,\nwhich could not but occasionally awaken in any man's soul some alarm,\nthere was another thought, or rather vague, nameless horror\nconcerning him, which at times by its intensity completely\noverpowered all the rest; and yet so mystical and well nigh ineffable\nwas it, that I almost despair of putting it in a comprehensible form.\nIt was the whiteness of the whale that above all things appalled me.\nBut how can I hope to explain myself here; and yet, in some dim,\nrandom way, explain myself I must, else all these chapters might be\nnaught.\n\nThough in many natural objects, whiteness refiningly enhances beauty,\nas if imparting some special virtue of its own, as in marbles,\njaponicas, and pearls; and though various nations have in some way\nrecognised a certain royal preeminence in this hue; even the\nbarbaric, grand old kings of Pegu placing the title \"Lord of the\nWhite Elephants\" above all their other magniloquent ascriptions of\ndominion; and the modern kings of Siam unfurling the same snow-white\nquadruped in the royal standard; and the Hanoverian flag bearing the\none figure of a snow-white charger; and the great Austrian Empire,\nCaesarian, heir to overlording Rome, having for the imperial colour\nthe same imperial hue; and though this pre-eminence in it applies to\nthe human race itself, giving the white man ideal mastership over\nevery dusky tribe; and though, besides, all this, whiteness has been\neven made significant of gladness, for among the Romans a white stone\nmarked a joyful day; and though in other mortal sympathies and\nsymbolizings, this same hue is made the emblem of many touching,\nnoble things--the innocence of brides, the benignity of age; though\namong the Red Men of America the giving of the white belt of wampum\nwas the deepest pledge of honour; though in many climes, whiteness\ntypifies the majesty of Justice in the ermine of the Judge, and\ncontributes to the daily state of kings and queens drawn by\nmilk-white steeds; though even in the higher mysteries of the most\naugust religions it has been made the symbol of the divine\nspotlessness and power; by the Persian fire worshippers, the white\nforked flame being held the holiest on the altar; and in the Greek\nmythologies, Great Jove himself being made incarnate in a snow-white\nbull; and though to the noble Iroquois, the midwinter sacrifice of\nthe sacred White Dog was by far the holiest festival of their\ntheology, that spotless, faithful creature being held the purest\nenvoy they could send to the Great Spirit with the annual tidings of\ntheir own fidelity; and though directly from the Latin word for\nwhite, all Christian priests derive the name of one part of their\nsacred vesture, the alb or tunic, worn beneath the cassock; and\nthough among the holy pomps of the Romish faith, white is specially\nemployed in the celebration of the Passion of our Lord; though in the\nVision of St. John, white robes are given to the redeemed, and the\nfour-and-twenty elders stand clothed in white before the great-white\nthrone, and the Holy One that sitteth there white like wool; yet for\nall these accumulated associations, with whatever is sweet, and\nhonourable, and sublime, there yet lurks an elusive something in the\ninnermost idea of this hue, which strikes more of panic to the soul\nthan that redness which affrights in blood.\n\nThis elusive quality it is, which causes the thought of whiteness,\nwhen divorced from more kindly associations, and coupled with any\nobject terrible in itself, to heighten that terror to the furthest\nbounds.  Witness the white bear of the poles, and the white shark of\nthe tropics; what but their smooth, flaky whiteness makes them the\ntranscendent horrors they are?  That ghastly whiteness it is which\nimparts such an abhorrent mildness, even more loathsome than\nterrific, to the dumb gloating of their aspect.  So that not the\nfierce-fanged tiger in his heraldic coat can so stagger courage as\nthe white-shrouded bear or shark.*\n\n\n*With reference to the Polar bear, it may possibly be urged by him\nwho would fain go still deeper into this matter, that it is not the\nwhiteness, separately regarded, which heightens the intolerable\nhideousness of that brute; for, analysed, that heightened\nhideousness, it might be said, only rises from the circumstance, that\nthe irresponsible ferociousness of the creature stands invested in\nthe fleece of celestial innocence and love; and hence, by bringing\ntogether two such opposite emotions in our minds, the Polar bear\nfrightens us with so unnatural a contrast.  But even assuming all\nthis to be true; yet, were it not for the whiteness, you would not\nhave that intensified terror.\n\nAs for the white shark, the white gliding ghostliness of repose in\nthat creature, when beheld in his ordinary moods, strangely tallies\nwith the same quality in the Polar quadruped.  This peculiarity is\nmost vividly hit by the French in the name they bestow upon that\nfish.  The Romish mass for the dead begins with \"Requiem eternam\"\n(eternal rest), whence REQUIEM denominating the mass itself, and any\nother funeral music.  Now, in allusion to the white, silent stillness\nof death in this shark, and the mild deadliness of his habits, the\nFrench call him REQUIN.\n\n\nBethink thee of the albatross, whence come those clouds of spiritual\nwonderment and pale dread, in which that white phantom sails in all\nimaginations?  Not Coleridge first threw that spell; but God's great,\nunflattering laureate, Nature.*\n\n\n*I remember the first albatross I ever saw.  It was during a\nprolonged gale, in waters hard upon the Antarctic seas.  From my\nforenoon watch below, I ascended to the overclouded deck; and there,\ndashed upon the main hatches, I saw a regal, feathery thing of\nunspotted whiteness, and with a hooked, Roman bill sublime.  At\nintervals, it arched forth its vast archangel wings, as if to embrace\nsome holy ark.  Wondrous flutterings and throbbings shook it.  Though\nbodily unharmed, it uttered cries, as some king's ghost in\nsupernatural distress.  Through its inexpressible, strange eyes,\nmethought I peeped to secrets which took hold of God.  As Abraham\nbefore the angels, I bowed myself; the white thing was so white, its\nwings so wide, and in those for ever exiled waters, I had lost the\nmiserable warping memories of traditions and of towns.  Long I gazed\nat that prodigy of plumage.  I cannot tell, can only hint, the things\nthat darted through me then.  But at last I awoke; and turning, asked\na sailor what bird was this.  A goney, he replied.  Goney! never had\nheard that name before; is it conceivable that this glorious thing is\nutterly unknown to men ashore! never!  But some time after, I learned\nthat goney was some seaman's name for albatross.  So that by no\npossibility could Coleridge's wild Rhyme have had aught to do with\nthose mystical impressions which were mine, when I saw that bird upon\nour deck.  For neither had I then read the Rhyme, nor knew the bird\nto be an albatross.  Yet, in saying this, I do but indirectly burnish\na little brighter the noble merit of the poem and the poet.\n\nI assert, then, that in the wondrous bodily whiteness of the bird\nchiefly lurks the secret of the spell; a truth the more evinced in\nthis, that by a solecism of terms there are birds called grey\nalbatrosses; and these I have frequently seen, but never with such\nemotions as when I beheld the Antarctic fowl.\n\nBut how had the mystic thing been caught?  Whisper it not, and I will\ntell; with a treacherous hook and line, as the fowl floated on the\nsea.  At last the Captain made a postman of it; tying a lettered,\nleathern tally round its neck, with the ship's time and place; and\nthen letting it escape.  But I doubt not, that leathern tally, meant\nfor man, was taken off in Heaven, when the white fowl flew to join\nthe wing-folding, the invoking, and adoring cherubim!\n\n\nMost famous in our Western annals and Indian traditions is that of\nthe White Steed of the Prairies; a magnificent milk-white charger,\nlarge-eyed, small-headed, bluff-chested, and with the dignity of a\nthousand monarchs in his lofty, overscorning carriage.  He was the\nelected Xerxes of vast herds of wild horses, whose pastures in those\ndays were only fenced by the Rocky Mountains and the Alleghanies.  At\ntheir flaming head he westward trooped it like that chosen star which\nevery evening leads on the hosts of light.  The flashing cascade of\nhis mane, the curving comet of his tail, invested him with housings\nmore resplendent than gold and silver-beaters could have furnished\nhim.  A most imperial and archangelical apparition of that unfallen,\nwestern world, which to the eyes of the old trappers and hunters\nrevived the glories of those primeval times when Adam walked majestic\nas a god, bluff-browed and fearless as this mighty steed.  Whether\nmarching amid his aides and marshals in the van of countless cohorts\nthat endlessly streamed it over the plains, like an Ohio; or whether\nwith his circumambient subjects browsing all around at the horizon,\nthe White Steed gallopingly reviewed them with warm nostrils\nreddening through his cool milkiness; in whatever aspect he presented\nhimself, always to the bravest Indians he was the object of trembling\nreverence and awe.  Nor can it be questioned from what stands on\nlegendary record of this noble horse, that it was his spiritual\nwhiteness chiefly, which so clothed him with divineness; and that\nthis divineness had that in it which, though commanding worship, at\nthe same time enforced a certain nameless terror.\n\nBut there are other instances where this whiteness loses all that\naccessory and strange glory which invests it in the White Steed and\nAlbatross.\n\nWhat is it that in the Albino man so peculiarly repels and often\nshocks the eye, as that sometimes he is loathed by his own kith and\nkin!  It is that whiteness which invests him, a thing expressed by\nthe name he bears.  The Albino is as well made as other men--has no\nsubstantive deformity--and yet this mere aspect of all-pervading\nwhiteness makes him more strangely hideous than the ugliest abortion.\nWhy should this be so?\n\nNor, in quite other aspects, does Nature in her least palpable but\nnot the less malicious agencies, fail to enlist among her forces this\ncrowning attribute of the terrible.  From its snowy aspect, the\ngauntleted ghost of the Southern Seas has been denominated the White\nSquall.  Nor, in some historic instances, has the art of human malice\nomitted so potent an auxiliary.  How wildly it heightens the effect\nof that passage in Froissart, when, masked in the snowy symbol of\ntheir faction, the desperate White Hoods of Ghent murder their\nbailiff in the market-place!\n\nNor, in some things, does the common, hereditary experience of all\nmankind fail to bear witness to the supernaturalism of this hue.  It\ncannot well be doubted, that the one visible quality in the aspect of\nthe dead which most appals the gazer, is the marble pallor lingering\nthere; as if indeed that pallor were as much like the badge of\nconsternation in the other world, as of mortal trepidation here.  And\nfrom that pallor of the dead, we borrow the expressive hue of the\nshroud in which we wrap them.  Nor even in our superstitions do we\nfail to throw the same snowy mantle round our phantoms; all ghosts\nrising in a milk-white fog--Yea, while these terrors seize us, let us\nadd, that even the king of terrors, when personified by the\nevangelist, rides on his pallid horse.\n\nTherefore, in his other moods, symbolize whatever grand or gracious\nthing he will by whiteness, no man can deny that in its profoundest\nidealized significance it calls up a peculiar apparition to the soul.\n\nBut though without dissent this point be fixed, how is mortal man to\naccount for it?  To analyse it, would seem impossible.  Can we,\nthen, by the citation of some of those instances wherein this thing\nof whiteness--though for the time either wholly or in great part\nstripped of all direct associations calculated to impart to it aught\nfearful, but nevertheless, is found to exert over us the same\nsorcery, however modified;--can we thus hope to light upon some\nchance clue to conduct us to the hidden cause we seek?\n\nLet us try.  But in a matter like this, subtlety appeals to subtlety,\nand without imagination no man can follow another into these halls.\nAnd though, doubtless, some at least of the imaginative impressions\nabout to be presented may have been shared by most men, yet few\nperhaps were entirely conscious of them at the time, and therefore\nmay not be able to recall them now.\n\nWhy to the man of untutored ideality, who happens to be but loosely\nacquainted with the peculiar character of the day, does the bare\nmention of Whitsuntide marshal in the fancy such long, dreary,\nspeechless processions of slow-pacing pilgrims, down-cast and hooded\nwith new-fallen snow?  Or, to the unread, unsophisticated Protestant\nof the Middle American States, why does the passing mention of a\nWhite Friar or a White Nun, evoke such an eyeless statue in the soul?\n\nOr what is there apart from the traditions of dungeoned warriors and\nkings (which will not wholly account for it) that makes the White\nTower of London tell so much more strongly on the imagination of an\nuntravelled American, than those other storied structures, its\nneighbors--the Byward Tower, or even the Bloody?  And those sublimer\ntowers, the White Mountains of New Hampshire, whence, in peculiar\nmoods, comes that gigantic ghostliness over the soul at the bare\nmention of that name, while the thought of Virginia's Blue Ridge is\nfull of a soft, dewy, distant dreaminess?  Or why, irrespective of\nall latitudes and longitudes, does the name of the White Sea exert\nsuch a spectralness over the fancy, while that of the Yellow Sea\nlulls us with mortal thoughts of long lacquered mild afternoons on\nthe waves, followed by the gaudiest and yet sleepiest of sunsets?\nOr, to choose a wholly unsubstantial instance, purely addressed to\nthe fancy, why, in reading the old fairy tales of Central Europe,\ndoes \"the tall pale man\" of the Hartz forests, whose changeless\npallor unrustlingly glides through the green of the groves--why is\nthis phantom more terrible than all the whooping imps of the\nBlocksburg?\n\nNor is it, altogether, the remembrance of her cathedral-toppling\nearthquakes; nor the stampedoes of her frantic seas; nor the\ntearlessness of arid skies that never rain; nor the sight of her\nwide field of leaning spires, wrenched cope-stones, and crosses all\nadroop (like canted yards of anchored fleets); and her suburban\navenues of house-walls lying over upon each other, as a tossed pack\nof cards;--it is not these things alone which make tearless Lima, the\nstrangest, saddest city thou can'st see.  For Lima has taken the\nwhite veil; and there is a higher horror in this whiteness of her\nwoe.  Old as Pizarro, this whiteness keeps her ruins for ever new;\nadmits not the cheerful greenness of complete decay; spreads over her\nbroken ramparts the rigid pallor of an apoplexy that fixes its own\ndistortions.\n\nI know that, to the common apprehension, this phenomenon of whiteness\nis not confessed to be the prime agent in exaggerating the terror of\nobjects otherwise terrible; nor to the unimaginative mind is there\naught of terror in those appearances whose awfulness to another mind\nalmost solely consists in this one phenomenon, especially when\nexhibited under any form at all approaching to muteness or\nuniversality.  What I mean by these two statements may perhaps be\nrespectively elucidated by the following examples.\n\nFirst: The mariner, when drawing nigh the coasts of foreign lands, if\nby night he hear the roar of breakers, starts to vigilance, and feels\njust enough of trepidation to sharpen all his faculties; but under\nprecisely similar circumstances, let him be called from his hammock\nto view his ship sailing through a midnight sea of milky\nwhiteness--as if from encircling headlands shoals of combed white\nbears were swimming round him, then he feels a silent, superstitious\ndread; the shrouded phantom of the whitened waters is horrible to him\nas a real ghost; in vain the lead assures him he is still off\nsoundings; heart and helm they both go down; he never rests till blue\nwater is under him again.  Yet where is the mariner who will tell\nthee, \"Sir, it was not so much the fear of striking hidden rocks, as\nthe fear of that hideous whiteness that so stirred me?\"\n\nSecond: To the native Indian of Peru, the continual sight of the\nsnowhowdahed Andes conveys naught of dread, except, perhaps, in the\nmere fancying of the eternal frosted desolateness reigning at such\nvast altitudes, and the natural conceit of what a fearfulness it\nwould be to lose oneself in such inhuman solitudes.  Much the same is\nit with the backwoodsman of the West, who with comparative\nindifference views an unbounded prairie sheeted with driven snow, no\nshadow of tree or twig to break the fixed trance of whiteness.  Not\nso the sailor, beholding the scenery of the Antarctic seas; where at\ntimes, by some infernal trick of legerdemain in the powers of frost\nand air, he, shivering and half shipwrecked, instead of rainbows\nspeaking hope and solace to his misery, views what seems a boundless\nchurchyard grinning upon him with its lean ice monuments and\nsplintered crosses.\n\nBut thou sayest, methinks that white-lead chapter about whiteness is\nbut a white flag hung out from a craven soul; thou surrenderest to a\nhypo, Ishmael.\n\nTell me, why this strong young colt, foaled in some peaceful valley\nof Vermont, far removed from all beasts of prey--why is it that upon\nthe sunniest day, if you but shake a fresh buffalo robe behind him,\nso that he cannot even see it, but only smells its wild animal\nmuskiness--why will he start, snort, and with bursting eyes paw the\nground in phrensies of affright?  There is no remembrance in him of\nany gorings of wild creatures in his green northern home, so that the\nstrange muskiness he smells cannot recall to him anything associated\nwith the experience of former perils; for what knows he, this New\nEngland colt, of the black bisons of distant Oregon?\n\nNo; but here thou beholdest even in a dumb brute, the instinct of the\nknowledge of the demonism in the world.  Though thousands of miles\nfrom Oregon, still when he smells that savage musk, the rending,\ngoring bison herds are as present as to the deserted wild foal of the\nprairies, which this instant they may be trampling into dust.\n\nThus, then, the muffled rollings of a milky sea; the bleak rustlings\nof the festooned frosts of mountains; the desolate shiftings of the\nwindrowed snows of prairies; all these, to Ishmael, are as the\nshaking of that buffalo robe to the frightened colt!\n\nThough neither knows where lie the nameless things of which the\nmystic sign gives forth such hints; yet with me, as with the colt,\nsomewhere those things must exist.  Though in many of its aspects\nthis visible world seems formed in love, the invisible spheres were\nformed in fright.\n\nBut not yet have we solved the incantation of this whiteness, and\nlearned why it appeals with such power to the soul; and more strange\nand far more portentous--why, as we have seen, it is at once the most\nmeaning symbol of spiritual things, nay, the very veil of the\nChristian's Deity; and yet should be as it is, the intensifying agent\nin things the most appalling to mankind.\n\nIs it that by its indefiniteness it shadows forth the heartless voids\nand immensities of the universe, and thus stabs us from behind with\nthe thought of annihilation, when beholding the white depths of the\nmilky way?  Or is it, that as in essence whiteness is not so much a\ncolour as the visible absence of colour; and at the same time the\nconcrete of all colours; is it for these reasons that there is such a\ndumb blankness, full of meaning, in a wide landscape of snows--a\ncolourless, all-colour of atheism from which we shrink?  And when we\nconsider that other theory of the natural philosophers, that all\nother earthly hues--every stately or lovely emblazoning--the sweet\ntinges of sunset skies and woods; yea, and the gilded velvets of\nbutterflies, and the butterfly cheeks of young girls; all these are\nbut subtile deceits, not actually inherent in substances, but only\nlaid on from without; so that all deified Nature absolutely paints\nlike the harlot, whose allurements cover nothing but the\ncharnel-house within; and when we proceed further, and consider that\nthe mystical cosmetic which produces every one of her hues, the great\nprinciple of light, for ever remains white or colourless in itself,\nand if operating without medium upon matter, would touch all objects,\neven tulips and roses, with its own blank tinge--pondering all this,\nthe palsied universe lies before us a leper; and like wilful\ntravellers in Lapland, who refuse to wear coloured and colouring\nglasses upon their eyes, so the wretched infidel gazes himself blind\nat the monumental white shroud that wraps all the prospect around\nhim.  And of all these things the Albino whale was the symbol.\nWonder ye then at the fiery hunt?\n\n\n\nCHAPTER 43\n\nHark!\n\n\n\"HIST!  Did you hear that noise, Cabaco?\n\nIt was the middle-watch; a fair moonlight; the seamen were standing\nin a cordon, extending from one of the fresh-water butts in the\nwaist, to the scuttle-butt near the taffrail.  In this manner, they\npassed the buckets to fill the scuttle-butt.  Standing, for the most\npart, on the hallowed precincts of the quarter-deck, they were\ncareful not to speak or rustle their feet.  From hand to hand, the\nbuckets went in the deepest silence, only broken by the occasional\nflap of a sail, and the steady hum of the unceasingly advancing keel.\n\nIt was in the midst of this repose, that Archy, one of the cordon,\nwhose post was near the after-hatches, whispered to his neighbor, a\nCholo, the words above.\n\n\"Hist! did you hear that noise, Cabaco?\"\n\n\"Take the bucket, will ye, Archy? what noise d'ye mean?\"\n\n\"There it is again--under the hatches--don't you hear it--a cough--it\nsounded like a cough.\"\n\n\"Cough be damned!  Pass along that return bucket.\"\n\n\"There again--there it is!--it sounds like two or three sleepers\nturning over, now!\"\n\n\"Caramba! have done, shipmate, will ye?  It's the three soaked\nbiscuits ye eat for supper turning over inside of ye--nothing else.\nLook to the bucket!\"\n\n\"Say what ye will, shipmate; I've sharp ears.\"\n\n\"Aye, you are the chap, ain't ye, that heard the hum of the old\nQuakeress's knitting-needles fifty miles at sea from Nantucket;\nyou're the chap.\"\n\n\"Grin away; we'll see what turns up.  Hark ye, Cabaco, there is\nsomebody down in the after-hold that has not yet been seen on deck;\nand I suspect our old Mogul knows something of it too.  I heard Stubb\ntell Flask, one morning watch, that there was something of that sort\nin the wind.\"\n\n\"Tish! the bucket!\"\n\n\n\nCHAPTER 44\n\nThe Chart.\n\n\nHad you followed Captain Ahab down into his cabin after the squall\nthat took place on the night succeeding that wild ratification of his\npurpose with his crew, you would have seen him go to a locker in the\ntransom, and bringing out a large wrinkled roll of yellowish sea\ncharts, spread them before him on his screwed-down table.  Then\nseating himself before it, you would have seen him intently study the\nvarious lines and shadings which there met his eye; and with slow but\nsteady pencil trace additional courses over spaces that before were\nblank.  At intervals, he would refer to piles of old log-books beside\nhim, wherein were set down the seasons and places in which, on\nvarious former voyages of various ships, sperm whales had been\ncaptured or seen.\n\nWhile thus employed, the heavy pewter lamp suspended in chains over\nhis head, continually rocked with the motion of the ship, and for\never threw shifting gleams and shadows of lines upon his wrinkled\nbrow, till it almost seemed that while he himself was marking out\nlines and courses on the wrinkled charts, some invisible pencil was\nalso tracing lines and courses upon the deeply marked chart of his\nforehead.\n\nBut it was not this night in particular that, in the solitude of his\ncabin, Ahab thus pondered over his charts.  Almost every night they\nwere brought out; almost every night some pencil marks were effaced,\nand others were substituted.  For with the charts of all four oceans\nbefore him, Ahab was threading a maze of currents and eddies, with a\nview to the more certain accomplishment of that monomaniac thought of\nhis soul.\n\nNow, to any one not fully acquainted with the ways of the leviathans,\nit might seem an absurdly hopeless task thus to seek out one solitary\ncreature in the unhooped oceans of this planet.  But not so did it\nseem to Ahab, who knew the sets of all tides and currents; and\nthereby calculating the driftings of the sperm whale's food; and,\nalso, calling to mind the regular, ascertained seasons for hunting\nhim in particular latitudes; could arrive at reasonable surmises,\nalmost approaching to certainties, concerning the timeliest day to be\nupon this or that ground in search of his prey.\n\nSo assured, indeed, is the fact concerning the periodicalness of the\nsperm whale's resorting to given waters, that many hunters believe\nthat, could he be closely observed and studied throughout the world;\nwere the logs for one voyage of the entire whale fleet carefully\ncollated, then the migrations of the sperm whale would be found to\ncorrespond in invariability to those of the herring-shoals or the\nflights of swallows.  On this hint, attempts have been made to\nconstruct elaborate migratory charts of the sperm whale.*\n\n\n*Since the above was written, the statement is happily borne out by\nan official circular, issued by Lieutenant Maury, of the National\nObservatory, Washington, April 16th, 1851.  By that circular, it\nappears that precisely such a chart is in course of completion; and\nportions of it are presented in the circular.  \"This chart divides\nthe ocean into districts of five degrees of latitude by five degrees\nof longitude; perpendicularly through each of which districts are\ntwelve columns for the twelve months; and horizontally through each\nof which districts are three lines; one to show the number of days\nthat have been spent in each month in every district, and the two\nothers to show the number of days in which whales, sperm or right,\nhave been seen.\"\n\n\nBesides, when making a passage from one feeding-ground to another,\nthe sperm whales, guided by some infallible instinct--say, rather,\nsecret intelligence from the Deity--mostly swim in VEINS, as they are\ncalled; continuing their way along a given ocean-line with such\nundeviating exactitude, that no ship ever sailed her course, by any\nchart, with one tithe of such marvellous precision.  Though, in these\ncases, the direction taken by any one whale be straight as a\nsurveyor's parallel, and though the line of advance be strictly\nconfined to its own unavoidable, straight wake, yet the arbitrary\nVEIN in which at these times he is said to swim, generally embraces\nsome few miles in width (more or less, as the vein is presumed to\nexpand or contract); but never exceeds the visual sweep from the\nwhale-ship's mast-heads, when circumspectly gliding along this magic\nzone.  The sum is, that at particular seasons within that breadth and\nalong that path, migrating whales may with great confidence be looked\nfor.\n\nAnd hence not only at substantiated times, upon well known separate\nfeeding-grounds, could Ahab hope to encounter his prey; but in\ncrossing the widest expanses of water between those grounds he could,\nby his art, so place and time himself on his way, as even then not to\nbe wholly without prospect of a meeting.\n\nThere was a circumstance which at first sight seemed to entangle his\ndelirious but still methodical scheme.  But not so in the reality,\nperhaps.  Though the gregarious sperm whales have their regular\nseasons for particular grounds, yet in general you cannot conclude\nthat the herds which haunted such and such a latitude or longitude\nthis year, say, will turn out to be identically the same with those\nthat were found there the preceding season; though there are peculiar\nand unquestionable instances where the contrary of this has proved\ntrue.  In general, the same remark, only within a less wide limit,\napplies to the solitaries and hermits among the matured, aged sperm\nwhales.  So that though Moby Dick had in a former year been seen, for\nexample, on what is called the Seychelle ground in the Indian ocean,\nor Volcano Bay on the Japanese Coast; yet it did not follow, that\nwere the Pequod to visit either of those spots at any subsequent\ncorresponding season, she would infallibly encounter him there.  So,\ntoo, with some other feeding grounds, where he had at times revealed\nhimself.  But all these seemed only his casual stopping-places and\nocean-inns, so to speak, not his places of prolonged abode.  And\nwhere Ahab's chances of accomplishing his object have hitherto been\nspoken of, allusion has only been made to whatever way-side,\nantecedent, extra prospects were his, ere a particular set time or\nplace were attained, when all possibilities would become\nprobabilities, and, as Ahab fondly thought, every possibility the\nnext thing to a certainty.  That particular set time and place were\nconjoined in the one technical phrase--the Season-on-the-Line.  For\nthere and then, for several consecutive years, Moby Dick had been\nperiodically descried, lingering in those waters for awhile, as the\nsun, in its annual round, loiters for a predicted interval in any one\nsign of the Zodiac.  There it was, too, that most of the deadly\nencounters with the white whale had taken place; there the waves were\nstoried with his deeds; there also was that tragic spot where the\nmonomaniac old man had found the awful motive to his vengeance.  But\nin the cautious comprehensiveness and unloitering vigilance with\nwhich Ahab threw his brooding soul into this unfaltering hunt, he\nwould not permit himself to rest all his hopes upon the one crowning\nfact above mentioned, however flattering it might be to those hopes;\nnor in the sleeplessness of his vow could he so tranquillize his\nunquiet heart as to postpone all intervening quest.\n\nNow, the Pequod had sailed from Nantucket at the very beginning of\nthe Season-on-the-Line.  No possible endeavor then could enable her\ncommander to make the great passage southwards, double Cape Horn, and\nthen running down sixty degrees of latitude arrive in the equatorial\nPacific in time to cruise there.  Therefore, he must wait for the\nnext ensuing season.  Yet the premature hour of the Pequod's sailing\nhad, perhaps, been correctly selected by Ahab, with a view to this\nvery complexion of things.  Because, an interval of three hundred and\nsixty-five days and nights was before him; an interval which, instead\nof impatiently enduring ashore, he would spend in a miscellaneous\nhunt; if by chance the White Whale, spending his vacation in seas far\nremote from his periodical feeding-grounds, should turn up his\nwrinkled brow off the Persian Gulf, or in the Bengal Bay, or China\nSeas, or in any other waters haunted by his race.  So that Monsoons,\nPampas, Nor'-Westers, Harmattans, Trades; any wind but the Levanter\nand Simoon, might blow Moby Dick into the devious zig-zag\nworld-circle of the Pequod's circumnavigating wake.\n\nBut granting all this; yet, regarded discreetly and coolly, seems it\nnot but a mad idea, this; that in the broad boundless ocean, one\nsolitary whale, even if encountered, should be thought capable of\nindividual recognition from his hunter, even as a white-bearded Mufti\nin the thronged thoroughfares of Constantinople?  Yes.  For the\npeculiar snow-white brow of Moby Dick, and his snow-white hump, could\nnot but be unmistakable.  And have I not tallied the whale, Ahab\nwould mutter to himself, as after poring over his charts till long\nafter midnight he would throw himself back in reveries--tallied him,\nand shall he escape?  His broad fins are bored, and scalloped out\nlike a lost sheep's ear!  And here, his mad mind would run on in a\nbreathless race; till a weariness and faintness of pondering came\nover him; and in the open air of the deck he would seek to recover\nhis strength.  Ah, God! what trances of torments does that man endure\nwho is consumed with one unachieved revengeful desire.  He sleeps\nwith clenched hands; and wakes with his own bloody nails in his\npalms.\n\nOften, when forced from his hammock by exhausting and intolerably\nvivid dreams of the night, which, resuming his own intense thoughts\nthrough the day, carried them on amid a clashing of phrensies, and\nwhirled them round and round and round in his blazing brain, till\nthe very throbbing of his life-spot became insufferable anguish; and\nwhen, as was sometimes the case, these spiritual throes in him heaved\nhis being up from its base, and a chasm seemed opening in him, from\nwhich forked flames and lightnings shot up, and accursed fiends\nbeckoned him to leap down among them; when this hell in himself\nyawned beneath him, a wild cry would be heard through the ship; and\nwith glaring eyes Ahab would burst from his state room, as though\nescaping from a bed that was on fire.  Yet these, perhaps, instead of\nbeing the unsuppressable symptoms of some latent weakness, or fright\nat his own resolve, were but the plainest tokens of its intensity.\nFor, at such times, crazy Ahab, the scheming, unappeasedly steadfast\nhunter of the white whale; this Ahab that had gone to his hammock,\nwas not the agent that so caused him to burst from it in horror\nagain.  The latter was the eternal, living principle or soul in him;\nand in sleep, being for the time dissociated from the characterizing\nmind, which at other times employed it for its outer vehicle or\nagent, it spontaneously sought escape from the scorching contiguity\nof the frantic thing, of which, for the time, it was no longer an\nintegral.  But as the mind does not exist unless leagued with the\nsoul, therefore it must have been that, in Ahab's case, yielding up\nall his thoughts and fancies to his one supreme purpose; that\npurpose, by its own sheer inveteracy of will, forced itself against\ngods and devils into a kind of self-assumed, independent being of its\nown.  Nay, could grimly live and burn, while the common vitality to\nwhich it was conjoined, fled horror-stricken from the unbidden and\nunfathered birth.  Therefore, the tormented spirit that glared out of\nbodily eyes, when what seemed Ahab rushed from his room, was for the\ntime but a vacated thing, a formless somnambulistic being, a ray of\nliving light, to be sure, but without an object to colour, and\ntherefore a blankness in itself.  God help thee, old man, thy\nthoughts have created a creature in thee; and he whose intense\nthinking thus makes him a Prometheus; a vulture feeds upon that heart\nfor ever; that vulture the very creature he creates.\n\n\n\nCHAPTER 45\n\nThe Affidavit.\n\n\nSo far as what there may be of a narrative in this book; and, indeed,\nas indirectly touching one or two very interesting and curious\nparticulars in the habits of sperm whales, the foregoing chapter, in\nits earlier part, is as important a one as will be found in this\nvolume; but the leading matter of it requires to be still further and\nmore familiarly enlarged upon, in order to be adequately understood,\nand moreover to take away any incredulity which a profound ignorance\nof the entire subject may induce in some minds, as to the natural\nverity of the main points of this affair.\n\nI care not to perform this part of my task methodically; but shall be\ncontent to produce the desired impression by separate citations of\nitems, practically or reliably known to me as a whaleman; and from\nthese citations, I take it--the conclusion aimed at will naturally\nfollow of itself.\n\nFirst: I have personally known three instances where a whale, after\nreceiving a harpoon, has effected a complete escape; and, after an\ninterval (in one instance of three years), has been again struck by\nthe same hand, and slain; when the two irons, both marked by the same\nprivate cypher, have been taken from the body.  In the instance where\nthree years intervened between the flinging of the two harpoons; and\nI think it may have been something more than that; the man who darted\nthem happening, in the interval, to go in a trading ship on a voyage\nto Africa, went ashore there, joined a discovery party, and\npenetrated far into the interior, where he travelled for a period of\nnearly two years, often endangered by serpents, savages, tigers,\npoisonous miasmas, with all the other common perils incident to\nwandering in the heart of unknown regions.  Meanwhile, the whale he\nhad struck must also have been on its travels; no doubt it had thrice\ncircumnavigated the globe, brushing with its flanks all the coasts of\nAfrica; but to no purpose.  This man and this whale again came\ntogether, and the one vanquished the other.  I say I, myself, have\nknown three instances similar to this; that is in two of them I saw\nthe whales struck; and, upon the second attack, saw the two irons\nwith the respective marks cut in them, afterwards taken from the dead\nfish.  In the three-year instance, it so fell out that I was in the\nboat both times, first and last, and the last time distinctly\nrecognised a peculiar sort of huge mole under the whale's eye, which\nI had observed there three years previous.  I say three years, but I\nam pretty sure it was more than that.  Here are three instances,\nthen, which I personally know the truth of; but I have heard of many\nother instances from persons whose veracity in the matter there is no\ngood ground to impeach.\n\nSecondly: It is well known in the Sperm Whale Fishery, however\nignorant the world ashore may be of it, that there have been several\nmemorable historical instances where a particular whale in the ocean\nhas been at distant times and places popularly cognisable.  Why such\na whale became thus marked was not altogether and originally owing to\nhis bodily peculiarities as distinguished from other whales; for\nhowever peculiar in that respect any chance whale may be, they soon\nput an end to his peculiarities by killing him, and boiling him down\ninto a peculiarly valuable oil.  No: the reason was this: that from\nthe fatal experiences of the fishery there hung a terrible prestige\nof perilousness about such a whale as there did about Rinaldo\nRinaldini, insomuch that most fishermen were content to recognise him\nby merely touching their tarpaulins when he would be discovered\nlounging by them on the sea, without seeking to cultivate a more\nintimate acquaintance.  Like some poor devils ashore that happen to\nknow an irascible great man, they make distant unobtrusive\nsalutations to him in the street, lest if they pursued the\nacquaintance further, they might receive a summary thump for their\npresumption.\n\nBut not only did each of these famous whales enjoy great individual\ncelebrity--Nay, you may call it an ocean-wide renown; not only was he\nfamous in life and now is immortal in forecastle stories after death,\nbut he was admitted into all the rights, privileges, and distinctions\nof a name; had as much a name indeed as Cambyses or Caesar.  Was it\nnot so, O Timor Tom! thou famed leviathan, scarred like an iceberg,\nwho so long did'st lurk in the Oriental straits of that name, whose\nspout was oft seen from the palmy beach of Ombay?  Was it not so, O\nNew Zealand Jack! thou terror of all cruisers that crossed their\nwakes in the vicinity of the Tattoo Land?  Was it not so, O Morquan!\nKing of Japan, whose lofty jet they say at times assumed the\nsemblance of a snow-white cross against the sky?  Was it not so, O\nDon Miguel! thou Chilian whale, marked like an old tortoise with\nmystic hieroglyphics upon the back!  In plain prose, here are four\nwhales as well known to the students of Cetacean History as Marius or\nSylla to the classic scholar.\n\nBut this is not all.  New Zealand Tom and Don Miguel, after at\nvarious times creating great havoc among the boats of different\nvessels, were finally gone in quest of, systematically hunted out,\nchased and killed by valiant whaling captains, who heaved up their\nanchors with that express object as much in view, as in setting out\nthrough the Narragansett Woods, Captain Butler of old had it in his\nmind to capture that notorious murderous savage Annawon, the headmost\nwarrior of the Indian King Philip.\n\nI do not know where I can find a better place than just here, to make\nmention of one or two other things, which to me seem important, as in\nprinted form establishing in all respects the reasonableness of the\nwhole story of the White Whale, more especially the catastrophe.  For\nthis is one of those disheartening instances where truth requires\nfull as much bolstering as error.  So ignorant are most landsmen of\nsome of the plainest and most palpable wonders of the world, that\nwithout some hints touching the plain facts, historical and\notherwise, of the fishery, they might scout at Moby Dick as a\nmonstrous fable, or still worse and more detestable, a hideous and\nintolerable allegory.\n\nFirst: Though most men have some vague flitting ideas of the general\nperils of the grand fishery, yet they have nothing like a fixed,\nvivid conception of those perils, and the frequency with which they\nrecur.  One reason perhaps is, that not one in fifty of the actual\ndisasters and deaths by casualties in the fishery, ever finds a\npublic record at home, however transient and immediately forgotten\nthat record.  Do you suppose that that poor fellow there, who this\nmoment perhaps caught by the whale-line off the coast of New Guinea,\nis being carried down to the bottom of the sea by the sounding\nleviathan--do you suppose that that poor fellow's name will appear in\nthe newspaper obituary you will read to-morrow at your breakfast?\nNo: because the mails are very irregular between here and New Guinea.\nIn fact, did you ever hear what might be called regular news direct\nor indirect from New Guinea?  Yet I tell you that upon one particular\nvoyage which I made to the Pacific, among many others we spoke thirty\ndifferent ships, every one of which had had a death by a whale, some\nof them more than one, and three that had each lost a boat's crew.\nFor God's sake, be economical with your lamps and candles! not a\ngallon you burn, but at least one drop of man's blood was spilled for\nit.\n\nSecondly: People ashore have indeed some indefinite idea that a whale\nis an enormous creature of enormous power; but I have ever found that\nwhen narrating to them some specific example of this two-fold\nenormousness, they have significantly complimented me upon my\nfacetiousness; when, I declare upon my soul, I had no more idea of\nbeing facetious than Moses, when he wrote the history of the plagues\nof Egypt.\n\nBut fortunately the special point I here seek can be established upon\ntestimony entirely independent of my own.  That point is this: The\nSperm Whale is in some cases sufficiently powerful, knowing, and\njudiciously malicious, as with direct aforethought to stave in,\nutterly destroy, and sink a large ship; and what is more, the Sperm\nWhale HAS done it.\n\nFirst: In the year 1820 the ship Essex, Captain Pollard, of\nNantucket, was cruising in the Pacific Ocean.  One day she saw\nspouts, lowered her boats, and gave chase to a shoal of sperm whales.\nEre long, several of the whales were wounded; when, suddenly, a very\nlarge whale escaping from the boats, issued from the shoal, and bore\ndirectly down upon the ship.  Dashing his forehead against her hull,\nhe so stove her in, that in less than \"ten minutes\" she settled down\nand fell over.  Not a surviving plank of her has been seen since.\nAfter the severest exposure, part of the crew reached the land in\ntheir boats.  Being returned home at last, Captain Pollard once more\nsailed for the Pacific in command of another ship, but the gods\nshipwrecked him again upon unknown rocks and breakers; for the second\ntime his ship was utterly lost, and forthwith forswearing the sea, he\nhas never tempted it since.  At this day Captain Pollard is a\nresident of Nantucket.  I have seen Owen Chace, who was chief mate of\nthe Essex at the time of the tragedy; I have read his plain and\nfaithful narrative; I have conversed with his son; and all this\nwithin a few miles of the scene of the catastrophe.*\n\n\n*The following are extracts from Chace's narrative: \"Every fact\nseemed to warrant me in concluding that it was anything but chance\nwhich directed his operations; he made two several attacks upon the\nship, at a short interval between them, both of which, according to\ntheir direction, were calculated to do us the most injury, by being\nmade ahead, and thereby combining the speed of the two objects for\nthe shock; to effect which, the exact manoeuvres which he made were\nnecessary.  His aspect was most horrible, and such as indicated\nresentment and fury.  He came directly from the shoal which we had\njust before entered, and in which we had struck three of his\ncompanions, as if fired with revenge for their sufferings.\"  Again:\n\"At all events, the whole circumstances taken together, all happening\nbefore my own eyes, and producing, at the time, impressions in my\nmind of decided, calculating mischief, on the part of the whale (many\nof which impressions I cannot now recall), induce me to be satisfied\nthat I am correct in my opinion.\"\n\nHere are his reflections some time after quitting the ship, during a\nblack night an open boat, when almost despairing of reaching any\nhospitable shore.  \"The dark ocean and swelling waters were nothing;\nthe fears of being swallowed up by some dreadful tempest, or dashed\nupon hidden rocks, with all the other ordinary subjects of fearful\ncontemplation, seemed scarcely entitled to a moment's thought; the\ndismal looking wreck, and THE HORRID ASPECT AND REVENGE OF THE WHALE,\nwholly engrossed my reflections, until day again made its\nappearance.\"\n\nIn another place--p. 45,--he speaks of \"THE MYSTERIOUS AND MORTAL\nATTACK OF THE ANIMAL.\"\n\n\nSecondly: The ship Union, also of Nantucket, was in the year 1807\ntotally lost off the Azores by a similar onset, but the authentic\nparticulars of this catastrophe I have never chanced to encounter,\nthough from the whale hunters I have now and then heard casual\nallusions to it.\n\nThirdly: Some eighteen or twenty years ago Commodore J---, then\ncommanding an American sloop-of-war of the first class, happened to\nbe dining with a party of whaling captains, on board a Nantucket ship\nin the harbor of Oahu, Sandwich Islands.  Conversation turning upon\nwhales, the Commodore was pleased to be sceptical touching the\namazing strength ascribed to them by the professional gentlemen\npresent.  He peremptorily denied for example, that any whale could so\nsmite his stout sloop-of-war as to cause her to leak so much as a\nthimbleful.  Very good; but there is more coming.  Some weeks after,\nthe Commodore set sail in this impregnable craft for Valparaiso.  But\nhe was stopped on the way by a portly sperm whale, that begged a few\nmoments' confidential business with him.  That business consisted in\nfetching the Commodore's craft such a thwack, that with all his pumps\ngoing he made straight for the nearest port to heave down and repair.\nI am not superstitious, but I consider the Commodore's interview\nwith that whale as providential.  Was not Saul of Tarsus converted\nfrom unbelief by a similar fright?  I tell you, the sperm whale will\nstand no nonsense.\n\nI will now refer you to Langsdorff's Voyages for a little\ncircumstance in point, peculiarly interesting to the writer hereof.\nLangsdorff, you must know by the way, was attached to the Russian\nAdmiral Krusenstern's famous Discovery Expedition in the beginning of\nthe present century.  Captain Langsdorff thus begins his seventeenth\nchapter:\n\n\"By the thirteenth of May our ship was ready to sail, and the next\nday we were out in the open sea, on our way to Ochotsh.  The weather\nwas very clear and fine, but so intolerably cold that we were obliged\nto keep on our fur clothing.  For some days we had very little wind;\nit was not till the nineteenth that a brisk gale from the northwest\nsprang up.  An uncommon large whale, the body of which was larger\nthan the ship itself, lay almost at the surface of the water, but was\nnot perceived by any one on board till the moment when the ship,\nwhich was in full sail, was almost upon him, so that it was\nimpossible to prevent its striking against him.  We were thus placed\nin the most imminent danger, as this gigantic creature, setting up\nits back, raised the ship three feet at least out of the water.  The\nmasts reeled, and the sails fell altogether, while we who were below\nall sprang instantly upon the deck, concluding that we had struck\nupon some rock; instead of this we saw the monster sailing off with\nthe utmost gravity and solemnity.  Captain D'Wolf applied immediately\nto the pumps to examine whether or not the vessel had received any\ndamage from the shock, but we found that very happily it had escaped\nentirely uninjured.\"\n\nNow, the Captain D'Wolf here alluded to as commanding the ship in\nquestion, is a New Englander, who, after a long life of unusual\nadventures as a sea-captain, this day resides in the village of\nDorchester near Boston.  I have the honour of being a nephew of his.\nI have particularly questioned him concerning this passage in\nLangsdorff.  He substantiates every word.  The ship, however, was by\nno means a large one: a Russian craft built on the Siberian coast,\nand purchased by my uncle after bartering away the vessel in which he\nsailed from home.\n\nIn that up and down manly book of old-fashioned adventure, so full,\ntoo, of honest wonders--the voyage of Lionel Wafer, one of ancient\nDampier's old chums--I found a little matter set down so like that\njust quoted from Langsdorff, that I cannot forbear inserting it here\nfor a corroborative example, if such be needed.\n\nLionel, it seems, was on his way to \"John Ferdinando,\" as he calls\nthe modern Juan Fernandes.  \"In our way thither,\" he says, \"about\nfour o'clock in the morning, when we were about one hundred and fifty\nleagues from the Main of America, our ship felt a terrible shock,\nwhich put our men in such consternation that they could hardly tell\nwhere they were or what to think; but every one began to prepare for\ndeath.  And, indeed, the shock was so sudden and violent, that we\ntook it for granted the ship had struck against a rock; but when the\namazement was a little over, we cast the lead, and sounded, but found\nno ground.  ....  The suddenness of the shock made the guns leap in\ntheir carriages, and several of the men were shaken out of their\nhammocks.  Captain Davis, who lay with his head on a gun, was thrown\nout of his cabin!\"  Lionel then goes on to impute the shock to an\nearthquake, and seems to substantiate the imputation by stating that\na great earthquake, somewhere about that time, did actually do great\nmischief along the Spanish land.  But I should not much wonder if, in\nthe darkness of that early hour of the morning, the shock was after\nall caused by an unseen whale vertically bumping the hull from\nbeneath.\n\nI might proceed with several more examples, one way or another known\nto me, of the great power and malice at times of the sperm whale.  In\nmore than one instance, he has been known, not only to chase the\nassailing boats back to their ships, but to pursue the ship itself,\nand long withstand all the lances hurled at him from its decks.  The\nEnglish ship Pusie Hall can tell a story on that head; and, as for\nhis strength, let me say, that there have been examples where the\nlines attached to a running sperm whale have, in a calm, been\ntransferred to the ship, and secured there; the whale towing her\ngreat hull through the water, as a horse walks off with a cart.\nAgain, it is very often observed that, if the sperm whale, once\nstruck, is allowed time to rally, he then acts, not so often with\nblind rage, as with wilful, deliberate designs of destruction to his\npursuers; nor is it without conveying some eloquent indication of his\ncharacter, that upon being attacked he will frequently open his\nmouth, and retain it in that dread expansion for several consecutive\nminutes.  But I must be content with only one more and a concluding\nillustration; a remarkable and most significant one, by which you\nwill not fail to see, that not only is the most marvellous event in\nthis book corroborated by plain facts of the present day, but that\nthese marvels (like all marvels) are mere repetitions of the ages; so\nthat for the millionth time we say amen with Solomon--Verily there is\nnothing new under the sun.\n\nIn the sixth Christian century lived Procopius, a Christian\nmagistrate of Constantinople, in the days when Justinian was Emperor\nand Belisarius general.  As many know, he wrote the history of his\nown times, a work every way of uncommon value.  By the best\nauthorities, he has always been considered a most trustworthy and\nunexaggerating historian, except in some one or two particulars, not\nat all affecting the matter presently to be mentioned.\n\nNow, in this history of his, Procopius mentions that, during the term\nof his prefecture at Constantinople, a great sea-monster was captured\nin the neighboring Propontis, or Sea of Marmora, after having\ndestroyed vessels at intervals in those waters for a period of more\nthan fifty years.  A fact thus set down in substantial history cannot\neasily be gainsaid.  Nor is there any reason it should be.  Of what\nprecise species this sea-monster was, is not mentioned.  But as he\ndestroyed ships, as well as for other reasons, he must have been a\nwhale; and I am strongly inclined to think a sperm whale.  And I will\ntell you why.  For a long time I fancied that the sperm whale had\nbeen always unknown in the Mediterranean and the deep waters\nconnecting with it.  Even now I am certain that those seas are not,\nand perhaps never can be, in the present constitution of things, a\nplace for his habitual gregarious resort.  But further investigations\nhave recently proved to me, that in modern times there have been\nisolated instances of the presence of the sperm whale in the\nMediterranean.  I am told, on good authority, that on the Barbary\ncoast, a Commodore Davis of the British navy found the skeleton of a\nsperm whale.  Now, as a vessel of war readily passes through the\nDardanelles, hence a sperm whale could, by the same route, pass out\nof the Mediterranean into the Propontis.\n\nIn the Propontis, as far as I can learn, none of that peculiar\nsubstance called BRIT is to be found, the aliment of the right whale.\nBut I have every reason to believe that the food of the sperm\nwhale--squid or cuttle-fish--lurks at the bottom of that sea, because\nlarge creatures, but by no means the largest of that sort, have been\nfound at its surface.  If, then, you properly put these statements\ntogether, and reason upon them a bit, you will clearly perceive that,\naccording to all human reasoning, Procopius's sea-monster, that for\nhalf a century stove the ships of a Roman Emperor, must in all\nprobability have been a sperm whale.\n\n\n\nCHAPTER 46\n\nSurmises.\n\n\nThough, consumed with the hot fire of his purpose, Ahab in all his\nthoughts and actions ever had in view the ultimate capture of Moby\nDick; though he seemed ready to sacrifice all mortal interests to\nthat one passion; nevertheless it may have been that he was by nature\nand long habituation far too wedded to a fiery whaleman's ways,\naltogether to abandon the collateral prosecution of the voyage.  Or\nat least if this were otherwise, there were not wanting other motives\nmuch more influential with him.  It would be refining too much,\nperhaps, even considering his monomania, to hint that his\nvindictiveness towards the White Whale might have possibly extended\nitself in some degree to all sperm whales, and that the more monsters\nhe slew by so much the more he multiplied the chances that each\nsubsequently encountered whale would prove to be the hated one he\nhunted.  But if such an hypothesis be indeed exceptionable, there\nwere still additional considerations which, though not so strictly\naccording with the wildness of his ruling passion, yet were by no\nmeans incapable of swaying him.\n\nTo accomplish his object Ahab must use tools; and of all tools used\nin the shadow of the moon, men are most apt to get out of order.  He\nknew, for example, that however magnetic his ascendency in some\nrespects was over Starbuck, yet that ascendency did not cover the\ncomplete spiritual man any more than mere corporeal superiority\ninvolves intellectual mastership; for to the purely spiritual, the\nintellectual but stand in a sort of corporeal relation.  Starbuck's\nbody and Starbuck's coerced will were Ahab's, so long as Ahab kept\nhis magnet at Starbuck's brain; still he knew that for all this the\nchief mate, in his soul, abhorred his captain's quest, and could he,\nwould joyfully disintegrate himself from it, or even frustrate it.\nIt might be that a long interval would elapse ere the White Whale was\nseen.  During that long interval Starbuck would ever be apt to fall\ninto open relapses of rebellion against his captain's leadership,\nunless some ordinary, prudential, circumstantial influences were\nbrought to bear upon him.  Not only that, but the subtle insanity of\nAhab respecting Moby Dick was noways more significantly manifested\nthan in his superlative sense and shrewdness in foreseeing that, for\nthe present, the hunt should in some way be stripped of that strange\nimaginative impiousness which naturally invested it; that the full\nterror of the voyage must be kept withdrawn into the obscure\nbackground (for few men's courage is proof against protracted\nmeditation unrelieved by action); that when they stood their long\nnight watches, his officers and men must have some nearer things to\nthink of than Moby Dick.  For however eagerly and impetuously the\nsavage crew had hailed the announcement of his quest; yet all sailors\nof all sorts are more or less capricious and unreliable--they live in\nthe varying outer weather, and they inhale its fickleness--and when\nretained for any object remote and blank in the pursuit, however\npromissory of life and passion in the end, it is above all things\nrequisite that temporary interests and employments should intervene\nand hold them healthily suspended for the final dash.\n\nNor was Ahab unmindful of another thing.  In times of strong emotion\nmankind disdain all base considerations; but such times are\nevanescent.  The permanent constitutional condition of the\nmanufactured man, thought Ahab, is sordidness.  Granting that the\nWhite Whale fully incites the hearts of this my savage crew, and\nplaying round their savageness even breeds a certain generous\nknight-errantism in them, still, while for the love of it they give\nchase to Moby Dick, they must also have food for their more common,\ndaily appetites.  For even the high lifted and chivalric Crusaders of\nold times were not content to traverse two thousand miles of land to\nfight for their holy sepulchre, without committing burglaries,\npicking pockets, and gaining other pious perquisites by the way.  Had\nthey been strictly held to their one final and romantic object--that\nfinal and romantic object, too many would have turned from in\ndisgust.  I will not strip these men, thought Ahab, of all hopes of\ncash--aye, cash.  They may scorn cash now; but let some months go by,\nand no perspective promise of it to them, and then this same\nquiescent cash all at once mutinying in them, this same cash would\nsoon cashier Ahab.\n\nNor was there wanting still another precautionary motive more related\nto Ahab personally.  Having impulsively, it is probable, and perhaps\nsomewhat prematurely revealed the prime but private purpose of the\nPequod's voyage, Ahab was now entirely conscious that, in so doing,\nhe had indirectly laid himself open to the unanswerable charge of\nusurpation; and with perfect impunity, both moral and legal, his crew\nif so disposed, and to that end competent, could refuse all further\nobedience to him, and even violently wrest from him the command.\nFrom even the barely hinted imputation of usurpation, and the\npossible consequences of such a suppressed impression gaining ground,\nAhab must of course have been most anxious to protect himself.  That\nprotection could only consist in his own predominating brain and\nheart and hand, backed by a heedful, closely calculating attention to\nevery minute atmospheric influence which it was possible for his crew\nto be subjected to.\n\nFor all these reasons then, and others perhaps too analytic to be\nverbally developed here, Ahab plainly saw that he must still in a\ngood degree continue true to the natural, nominal purpose of the\nPequod's voyage; observe all customary usages; and not only that, but\nforce himself to evince all his well known passionate interest in the\ngeneral pursuit of his profession.\n\nBe all this as it may, his voice was now often heard hailing the\nthree mast-heads and admonishing them to keep a bright look-out, and\nnot omit reporting even a porpoise.  This vigilance was not long\nwithout reward.\n\n\n\nCHAPTER 47\n\nThe Mat-Maker.\n\n\nIt was a cloudy, sultry afternoon; the seamen were lazily lounging\nabout the decks, or vacantly gazing over into the lead-coloured\nwaters.  Queequeg and I were mildly employed weaving what is called a\nsword-mat, for an additional lashing to our boat.  So still and\nsubdued and yet somehow preluding was all the scene, and such an\nincantation of reverie lurked in the air, that each silent sailor\nseemed resolved into his own invisible self.\n\nI was the attendant or page of Queequeg, while busy at the mat.  As I\nkept passing and repassing the filling or woof of marline between the\nlong yarns of the warp, using my own hand for the shuttle, and as\nQueequeg, standing sideways, ever and anon slid his heavy oaken sword\nbetween the threads, and idly looking off upon the water, carelessly\nand unthinkingly drove home every yarn: I say so strange a\ndreaminess did there then reign all over the ship and all over the\nsea, only broken by the intermitting dull sound of the sword, that it\nseemed as if this were the Loom of Time, and I myself were a shuttle\nmechanically weaving and weaving away at the Fates.  There lay the\nfixed threads of the warp subject to but one single, ever returning,\nunchanging vibration, and that vibration merely enough to admit of\nthe crosswise interblending of other threads with its own.  This warp\nseemed necessity; and here, thought I, with my own hand I ply my own\nshuttle and weave my own destiny into these unalterable threads.\nMeantime, Queequeg's impulsive, indifferent sword, sometimes hitting\nthe woof slantingly, or crookedly, or strongly, or weakly, as the\ncase might be; and by this difference in the concluding blow\nproducing a corresponding contrast in the final aspect of the\ncompleted fabric; this savage's sword, thought I, which thus finally\nshapes and fashions both warp and woof; this easy, indifferent sword\nmust be chance--aye, chance, free will, and necessity--nowise\nincompatible--all interweavingly working together.  The straight warp\nof necessity, not to be swerved from its ultimate course--its every\nalternating vibration, indeed, only tending to that; free will still\nfree to ply her shuttle between given threads; and chance, though\nrestrained in its play within the right lines of necessity, and\nsideways in its motions directed by free will, though thus prescribed\nto by both, chance by turns rules either, and has the last featuring\nblow at events.\n\n\nThus we were weaving and weaving away when I started at a sound so\nstrange, long drawn, and musically wild and unearthly, that the ball\nof free will dropped from my hand, and I stood gazing up at the\nclouds whence that voice dropped like a wing.  High aloft in the\ncross-trees was that mad Gay-Header, Tashtego.  His body was reaching\neagerly forward, his hand stretched out like a wand, and at brief\nsudden intervals he continued his cries.  To be sure the same sound\nwas that very moment perhaps being heard all over the seas, from\nhundreds of whalemen's look-outs perched as high in the air; but from\nfew of those lungs could that accustomed old cry have derived such a\nmarvellous cadence as from Tashtego the Indian's.\n\nAs he stood hovering over you half suspended in air, so wildly and\neagerly peering towards the horizon, you would have thought him some\nprophet or seer beholding the shadows of Fate, and by those wild\ncries announcing their coming.\n\n\"There she blows! there! there! there! she blows! she blows!\"\n\n\"Where-away?\"\n\n\"On the lee-beam, about two miles off! a school of them!\"\n\nInstantly all was commotion.\n\nThe Sperm Whale blows as a clock ticks, with the same undeviating and\nreliable uniformity.  And thereby whalemen distinguish this fish from\nother tribes of his genus.\n\n\"There go flukes!\" was now the cry from Tashtego; and the whales\ndisappeared.\n\n\"Quick, steward!\" cried Ahab.  \"Time! time!\"\n\nDough-Boy hurried below, glanced at the watch, and reported the exact\nminute to Ahab.\n\nThe ship was now kept away from the wind, and she went gently rolling\nbefore it.  Tashtego reporting that the whales had gone down heading\nto leeward, we confidently looked to see them again directly in\nadvance of our bows.  For that singular craft at times evinced by the\nSperm Whale when, sounding with his head in one direction, he\nnevertheless, while concealed beneath the surface, mills round, and\nswiftly swims off in the opposite quarter--this deceitfulness of his\ncould not now be in action; for there was no reason to suppose that\nthe fish seen by Tashtego had been in any way alarmed, or indeed knew\nat all of our vicinity.  One of the men selected for\nshipkeepers--that is, those not appointed to the boats, by this time\nrelieved the Indian at the main-mast head.  The sailors at the fore\nand mizzen had come down; the line tubs were fixed in their places;\nthe cranes were thrust out; the mainyard was backed, and the three\nboats swung over the sea like three samphire baskets over high\ncliffs.  Outside of the bulwarks their eager crews with one hand\nclung to the rail, while one foot was expectantly poised on the\ngunwale.  So look the long line of man-of-war's men about to throw\nthemselves on board an enemy's ship.\n\nBut at this critical instant a sudden exclamation was heard that took\nevery eye from the whale.  With a start all glared at dark Ahab, who\nwas surrounded by five dusky phantoms that seemed fresh formed out of\nair.\n\n\n\nCHAPTER 48\n\nThe First Lowering.\n\n\nThe phantoms, for so they then seemed, were flitting on the other\nside of the deck, and, with a noiseless celerity, were casting loose\nthe tackles and bands of the boat which swung there.  This boat had\nalways been deemed one of the spare boats, though technically called\nthe captain's, on account of its hanging from the starboard quarter.\nThe figure that now stood by its bows was tall and swart, with one\nwhite tooth evilly protruding from its steel-like lips.  A rumpled\nChinese jacket of black cotton funereally invested him, with wide\nblack trowsers of the same dark stuff.  But strangely crowning this\nebonness was a glistening white plaited turban, the living hair\nbraided and coiled round and round upon his head.  Less swart in\naspect, the companions of this figure were of that vivid,\ntiger-yellow complexion peculiar to some of the aboriginal natives of\nthe Manillas;--a race notorious for a certain diabolism of subtilty,\nand by some honest white mariners supposed to be the paid spies and\nsecret confidential agents on the water of the devil, their lord,\nwhose counting-room they suppose to be elsewhere.\n\nWhile yet the wondering ship's company were gazing upon these\nstrangers, Ahab cried out to the white-turbaned old man at their\nhead, \"All ready there, Fedallah?\"\n\n\"Ready,\" was the half-hissed reply.\n\n\"Lower away then; d'ye hear?\" shouting across the deck.  \"Lower away\nthere, I say.\"\n\nSuch was the thunder of his voice, that spite of their amazement the\nmen sprang over the rail; the sheaves whirled round in the blocks;\nwith a wallow, the three boats dropped into the sea; while, with a\ndexterous, off-handed daring, unknown in any other vocation, the\nsailors, goat-like, leaped down the rolling ship's side into the\ntossed boats below.\n\nHardly had they pulled out from under the ship's lee, when a fourth\nkeel, coming from the windward side, pulled round under the stern,\nand showed the five strangers rowing Ahab, who, standing erect in the\nstern, loudly hailed Starbuck, Stubb, and Flask, to spread themselves\nwidely, so as to cover a large expanse of water.  But with all their\neyes again riveted upon the swart Fedallah and his crew, the inmates\nof the other boats obeyed not the command.\n\n\"Captain Ahab?--\" said Starbuck.\n\n\"Spread yourselves,\" cried Ahab; \"give way, all four boats.  Thou,\nFlask, pull out more to leeward!\"\n\n\"Aye, aye, sir,\" cheerily cried little King-Post, sweeping round his\ngreat steering oar.  \"Lay back!\" addressing his crew.\n\"There!--there!--there again!  There she blows right ahead,\nboys!--lay back!\"\n\n\"Never heed yonder yellow boys, Archy.\"\n\n\"Oh, I don't mind'em, sir,\" said Archy; \"I knew it all before now.\nDidn't I hear 'em in the hold?  And didn't I tell Cabaco here of it?\nWhat say ye, Cabaco?  They are stowaways, Mr. Flask.\"\n\n\"Pull, pull, my fine hearts-alive; pull, my children; pull, my little\nones,\" drawlingly and soothingly sighed Stubb to his crew, some of\nwhom still showed signs of uneasiness.  \"Why don't you break your\nbackbones, my boys?  What is it you stare at?  Those chaps in yonder\nboat?  Tut!  They are only five more hands come to help us--never\nmind from where--the more the merrier.  Pull, then, do pull; never\nmind the brimstone--devils are good fellows enough.  So, so; there\nyou are now; that's the stroke for a thousand pounds; that's the\nstroke to sweep the stakes!  Hurrah for the gold cup of sperm oil, my\nheroes!  Three cheers, men--all hearts alive!  Easy, easy; don't be\nin a hurry--don't be in a hurry.  Why don't you snap your oars, you\nrascals?  Bite something, you dogs!  So, so, so, then:--softly,\nsoftly!  That's it--that's it! long and strong.  Give way there, give\nway!  The devil fetch ye, ye ragamuffin rapscallions; ye are all\nasleep.  Stop snoring, ye sleepers, and pull.  Pull, will ye? pull,\ncan't ye? pull, won't ye?  Why in the name of gudgeons and\nginger-cakes don't ye pull?--pull and break something! pull, and\nstart your eyes out!  Here!\" whipping out the sharp knife from his\ngirdle; \"every mother's son of ye draw his knife, and pull with the\nblade between his teeth.  That's it--that's it.  Now ye do something;\nthat looks like it, my steel-bits.  Start her--start her, my\nsilver-spoons!  Start her, marling-spikes!\"\n\nStubb's exordium to his crew is given here at large, because he had\nrather a peculiar way of talking to them in general, and especially\nin inculcating the religion of rowing.  But you must not suppose from\nthis specimen of his sermonizings that he ever flew into downright\npassions with his congregation.  Not at all; and therein consisted\nhis chief peculiarity.  He would say the most terrific things to his\ncrew, in a tone so strangely compounded of fun and fury, and the fury\nseemed so calculated merely as a spice to the fun, that no oarsman\ncould hear such queer invocations without pulling for dear life, and\nyet pulling for the mere joke of the thing.  Besides he all the time\nlooked so easy and indolent himself, so loungingly managed his\nsteering-oar, and so broadly gaped--open-mouthed at times--that the\nmere sight of such a yawning commander, by sheer force of contrast,\nacted like a charm upon the crew.  Then again, Stubb was one of those\nodd sort of humorists, whose jollity is sometimes so curiously\nambiguous, as to put all inferiors on their guard in the matter of\nobeying them.\n\nIn obedience to a sign from Ahab, Starbuck was now pulling obliquely\nacross Stubb's bow; and when for a minute or so the two boats were\npretty near to each other, Stubb hailed the mate.\n\n\"Mr. Starbuck! larboard boat there, ahoy! a word with ye, sir, if ye\nplease!\"\n\n\"Halloa!\" returned Starbuck, turning round not a single inch as he\nspoke; still earnestly but whisperingly urging his crew; his face set\nlike a flint from Stubb's.\n\n\"What think ye of those yellow boys, sir!\n\n\"Smuggled on board, somehow, before the ship sailed. (Strong, strong,\nboys!)\" in a whisper to his crew, then speaking out loud again: \"A\nsad business, Mr. Stubb! (seethe her, seethe her, my lads!) but never\nmind, Mr. Stubb, all for the best.  Let all your crew pull strong,\ncome what will. (Spring, my men, spring!) There's hogsheads of sperm\nahead, Mr. Stubb, and that's what ye came for. (Pull, my boys!)\nSperm, sperm's the play!  This at least is duty; duty and profit hand\nin hand.\"\n\n\"Aye, aye, I thought as much,\" soliloquized Stubb, when the boats\ndiverged, \"as soon as I clapt eye on 'em, I thought so.  Aye, and\nthat's what he went into the after hold for, so often, as Dough-Boy\nlong suspected.  They were hidden down there.  The White Whale's at\nthe bottom of it.  Well, well, so be it!  Can't be helped!  All\nright!  Give way, men!  It ain't the White Whale to-day!  Give way!\"\n\nNow the advent of these outlandish strangers at such a critical\ninstant as the lowering of the boats from the deck, this had not\nunreasonably awakened a sort of superstitious amazement in some of\nthe ship's company; but Archy's fancied discovery having some time\nprevious got abroad among them, though indeed not credited then, this\nhad in some small measure prepared them for the event.  It took off\nthe extreme edge of their wonder; and so what with all this and\nStubb's confident way of accounting for their appearance, they were\nfor the time freed from superstitious surmisings; though the affair\nstill left abundant room for all manner of wild conjectures as to\ndark Ahab's precise agency in the matter from the beginning.  For me,\nI silently recalled the mysterious shadows I had seen creeping on\nboard the Pequod during the dim Nantucket dawn, as well as the\nenigmatical hintings of the unaccountable Elijah.\n\nMeantime, Ahab, out of hearing of his officers, having sided the\nfurthest to windward, was still ranging ahead of the other boats; a\ncircumstance bespeaking how potent a crew was pulling him.  Those\ntiger yellow creatures of his seemed all steel and whalebone; like\nfive trip-hammers they rose and fell with regular strokes of\nstrength, which periodically started the boat along the water like a\nhorizontal burst boiler out of a Mississippi steamer.  As for\nFedallah, who was seen pulling the harpooneer oar, he had thrown\naside his black jacket, and displayed his naked chest with the whole\npart of his body above the gunwale, clearly cut against the\nalternating depressions of the watery horizon; while at the other end\nof the boat Ahab, with one arm, like a fencer's, thrown half backward\ninto the air, as if to counterbalance any tendency to trip; Ahab was\nseen steadily managing his steering oar as in a thousand boat\nlowerings ere the White Whale had torn him.  All at once the\noutstretched arm gave a peculiar motion and then remained fixed,\nwhile the boat's five oars were seen simultaneously peaked.  Boat and\ncrew sat motionless on the sea.  Instantly the three spread boats in\nthe rear paused on their way.  The whales had irregularly settled\nbodily down into the blue, thus giving no distantly discernible token\nof the movement, though from his closer vicinity Ahab had observed\nit.\n\n\"Every man look out along his oars!\" cried Starbuck.  \"Thou,\nQueequeg, stand up!\"\n\nNimbly springing up on the triangular raised box in the bow, the\nsavage stood erect there, and with intensely eager eyes gazed off\ntowards the spot where the chase had last been descried.  Likewise\nupon the extreme stern of the boat where it was also triangularly\nplatformed level with the gunwale, Starbuck himself was seen coolly\nand adroitly balancing himself to the jerking tossings of his chip of\na craft, and silently eyeing the vast blue eye of the sea.\n\nNot very far distant Flask's boat was also lying breathlessly still;\nits commander recklessly standing upon the top of the loggerhead, a\nstout sort of post rooted in the keel, and rising some two feet above\nthe level of the stern platform.  It is used for catching turns with\nthe whale line.  Its top is not more spacious than the palm of a\nman's hand, and standing upon such a base as that, Flask seemed\nperched at the mast-head of some ship which had sunk to all but her\ntrucks.  But little King-Post was small and short, and at the same\ntime little King-Post was full of a large and tall ambition, so that\nthis loggerhead stand-point of his did by no means satisfy King-Post.\n\n\"I can't see three seas off; tip us up an oar there, and let me on to\nthat.\"\n\nUpon this, Daggoo, with either hand upon the gunwale to steady his\nway, swiftly slid aft, and then erecting himself volunteered his\nlofty shoulders for a pedestal.\n\n\"Good a mast-head as any, sir.  Will you mount?\"\n\n\"That I will, and thank ye very much, my fine fellow; only I wish you\nfifty feet taller.\"\n\nWhereupon planting his feet firmly against two opposite planks of the\nboat, the gigantic negro, stooping a little, presented his flat palm\nto Flask's foot, and then putting Flask's hand on his hearse-plumed\nhead and bidding him spring as he himself should toss, with one\ndexterous fling landed the little man high and dry on his shoulders.\nAnd here was Flask now standing, Daggoo with one lifted arm\nfurnishing him with a breastband to lean against and steady himself\nby.\n\nAt any time it is a strange sight to the tyro to see with what\nwondrous habitude of unconscious skill the whaleman will maintain an\nerect posture in his boat, even when pitched about by the most\nriotously perverse and cross-running seas.  Still more strange to see\nhim giddily perched upon the loggerhead itself, under such\ncircumstances.  But the sight of little Flask mounted upon gigantic\nDaggoo was yet more curious; for sustaining himself with a cool,\nindifferent, easy, unthought of, barbaric majesty, the noble negro to\nevery roll of the sea harmoniously rolled his fine form.  On his\nbroad back, flaxen-haired Flask seemed a snow-flake.  The bearer\nlooked nobler than the rider.  Though truly vivacious, tumultuous,\nostentatious little Flask would now and then stamp with impatience;\nbut not one added heave did he thereby give to the negro's lordly\nchest.  So have I seen Passion and Vanity stamping the living\nmagnanimous earth, but the earth did not alter her tides and her\nseasons for that.\n\nMeanwhile Stubb, the third mate, betrayed no such far-gazing\nsolicitudes.  The whales might have made one of their regular\nsoundings, not a temporary dive from mere fright; and if that were\nthe case, Stubb, as his wont in such cases, it seems, was resolved to\nsolace the languishing interval with his pipe.  He withdrew it from\nhis hatband, where he always wore it aslant like a feather.  He\nloaded it, and rammed home the loading with his thumb-end; but hardly\nhad he ignited his match across the rough sandpaper of his hand,\nwhen Tashtego, his harpooneer, whose eyes had been setting to\nwindward like two fixed stars, suddenly dropped like light from his\nerect attitude to his seat, crying out in a quick phrensy of hurry,\n\"Down, down all, and give way!--there they are!\"\n\nTo a landsman, no whale, nor any sign of a herring, would have been\nvisible at that moment; nothing but a troubled bit of greenish white\nwater, and thin scattered puffs of vapour hovering over it, and\nsuffusingly blowing off to leeward, like the confused scud from white\nrolling billows.  The air around suddenly vibrated and tingled, as it\nwere, like the air over intensely heated plates of iron.  Beneath\nthis atmospheric waving and curling, and partially beneath a thin\nlayer of water, also, the whales were swimming.  Seen in advance of\nall the other indications, the puffs of vapour they spouted, seemed\ntheir forerunning couriers and detached flying outriders.\n\nAll four boats were now in keen pursuit of that one spot of troubled\nwater and air.  But it bade fair to outstrip them; it flew on and on,\nas a mass of interblending bubbles borne down a rapid stream from the\nhills.\n\n\"Pull, pull, my good boys,\" said Starbuck, in the lowest possible but\nintensest concentrated whisper to his men; while the sharp fixed\nglance from his eyes darted straight ahead of the bow, almost seemed\nas two visible needles in two unerring binnacle compasses.  He did\nnot say much to his crew, though, nor did his crew say anything to\nhim.  Only the silence of the boat was at intervals startlingly\npierced by one of his peculiar whispers, now harsh with command, now\nsoft with entreaty.\n\nHow different the loud little King-Post.  \"Sing out and say\nsomething, my hearties.  Roar and pull, my thunderbolts!  Beach me,\nbeach me on their black backs, boys; only do that for me, and I'll\nsign over to you my Martha's Vineyard plantation, boys; including\nwife and children, boys.  Lay me on--lay me on!  O Lord, Lord! but I\nshall go stark, staring mad!  See! see that white water!\"  And so\nshouting, he pulled his hat from his head, and stamped up and down on\nit; then picking it up, flirted it far off upon the sea; and finally\nfell to rearing and plunging in the boat's stern like a crazed colt\nfrom the prairie.\n\n\"Look at that chap now,\" philosophically drawled Stubb, who, with his\nunlighted short pipe, mechanically retained between his teeth, at a\nshort distance, followed after--\"He's got fits, that Flask has.\nFits? yes, give him fits--that's the very word--pitch fits into 'em.\nMerrily, merrily, hearts-alive.  Pudding for supper, you\nknow;--merry's the word.  Pull, babes--pull, sucklings--pull, all.\nBut what the devil are you hurrying about?  Softly, softly, and\nsteadily, my men.  Only pull, and keep pulling; nothing more.  Crack\nall your backbones, and bite your knives in two--that's all.  Take it\neasy--why don't ye take it easy, I say, and burst all your livers and\nlungs!\"\n\nBut what it was that inscrutable Ahab said to that tiger-yellow crew\nof his--these were words best omitted here; for you live under the\nblessed light of the evangelical land.  Only the infidel sharks in\nthe audacious seas may give ear to such words, when, with tornado\nbrow, and eyes of red murder, and foam-glued lips, Ahab leaped after\nhis prey.\n\nMeanwhile, all the boats tore on.  The repeated specific allusions of\nFlask to \"that whale,\" as he called the fictitious monster which he\ndeclared to be incessantly tantalizing his boat's bow with its\ntail--these allusions of his were at times so vivid and life-like,\nthat they would cause some one or two of his men to snatch a fearful\nlook over the shoulder.  But this was against all rule; for the\noarsmen must put out their eyes, and ram a skewer through their\nnecks; usage pronouncing that they must have no organs but ears, and\nno limbs but arms, in these critical moments.\n\nIt was a sight full of quick wonder and awe!  The vast swells of the\nomnipotent sea; the surging, hollow roar they made, as they rolled\nalong the eight gunwales, like gigantic bowls in a boundless\nbowling-green; the brief suspended agony of the boat, as it would tip\nfor an instant on the knife-like edge of the sharper waves, that\nalmost seemed threatening to cut it in two; the sudden profound dip\ninto the watery glens and hollows; the keen spurrings and goadings to\ngain the top of the opposite hill; the headlong, sled-like slide down\nits other side;--all these, with the cries of the headsmen and\nharpooneers, and the shuddering gasps of the oarsmen, with the\nwondrous sight of the ivory Pequod bearing down upon her boats with\noutstretched sails, like a wild hen after her screaming brood;--all\nthis was thrilling.\n\nNot the raw recruit, marching from the bosom of his wife into the\nfever heat of his first battle; not the dead man's ghost encountering\nthe first unknown phantom in the other world;--neither of these can\nfeel stranger and stronger emotions than that man does, who for the\nfirst time finds himself pulling into the charmed, churned circle of\nthe hunted sperm whale.\n\nThe dancing white water made by the chase was now becoming more and\nmore visible, owing to the increasing darkness of the dun\ncloud-shadows flung upon the sea.  The jets of vapour no longer\nblended, but tilted everywhere to right and left; the whales seemed\nseparating their wakes.  The boats were pulled more apart; Starbuck\ngiving chase to three whales running dead to leeward.  Our sail was\nnow set, and, with the still rising wind, we rushed along; the boat\ngoing with such madness through the water, that the lee oars could\nscarcely be worked rapidly enough to escape being torn from the\nrow-locks.\n\nSoon we were running through a suffusing wide veil of mist; neither\nship nor boat to be seen.\n\n\"Give way, men,\" whispered Starbuck, drawing still further aft the\nsheet of his sail; \"there is time to kill a fish yet before the\nsquall comes.  There's white water again!--close to!  Spring!\"\n\nSoon after, two cries in quick succession on each side of us denoted\nthat the other boats had got fast; but hardly were they overheard,\nwhen with a lightning-like hurtling whisper Starbuck said: \"Stand\nup!\" and Queequeg, harpoon in hand, sprang to his feet.\n\nThough not one of the oarsmen was then facing the life and death\nperil so close to them ahead, yet with their eyes on the intense\ncountenance of the mate in the stern of the boat, they knew that the\nimminent instant had come; they heard, too, an enormous wallowing\nsound as of fifty elephants stirring in their litter.  Meanwhile the\nboat was still booming through the mist, the waves curling and\nhissing around us like the erected crests of enraged serpents.\n\n\"That's his hump.  THERE, THERE, give it to him!\" whispered Starbuck.\n\nA short rushing sound leaped out of the boat; it was the darted iron\nof Queequeg.  Then all in one welded commotion came an invisible push\nfrom astern, while forward the boat seemed striking on a ledge; the\nsail collapsed and exploded; a gush of scalding vapour shot up near\nby; something rolled and tumbled like an earthquake beneath us.  The\nwhole crew were half suffocated as they were tossed helter-skelter\ninto the white curdling cream of the squall.  Squall, whale, and\nharpoon had all blended together; and the whale, merely grazed by the\niron, escaped.\n\nThough completely swamped, the boat was nearly unharmed.  Swimming\nround it we picked up the floating oars, and lashing them across the\ngunwale, tumbled back to our places.  There we sat up to our knees in\nthe sea, the water covering every rib and plank, so that to our\ndownward gazing eyes the suspended craft seemed a coral boat grown up\nto us from the bottom of the ocean.\n\nThe wind increased to a howl; the waves dashed their bucklers\ntogether; the whole squall roared, forked, and crackled around us\nlike a white fire upon the prairie, in which, unconsumed, we were\nburning; immortal in these jaws of death!  In vain we hailed the\nother boats; as well roar to the live coals down the chimney of a\nflaming furnace as hail those boats in that storm.  Meanwhile the\ndriving scud, rack, and mist, grew darker with the shadows of night;\nno sign of the ship could be seen.  The rising sea forbade all\nattempts to bale out the boat.  The oars were useless as propellers,\nperforming now the office of life-preservers.  So, cutting the\nlashing of the waterproof match keg, after many failures Starbuck\ncontrived to ignite the lamp in the lantern; then stretching it on a\nwaif pole, handed it to Queequeg as the standard-bearer of this\nforlorn hope.  There, then, he sat, holding up that imbecile candle\nin the heart of that almighty forlornness.  There, then, he sat, the\nsign and symbol of a man without faith, hopelessly holding up hope in\nthe midst of despair.\n\nWet, drenched through, and shivering cold, despairing of ship or\nboat, we lifted up our eyes as the dawn came on.  The mist still\nspread over the sea, the empty lantern lay crushed in the bottom of\nthe boat.  Suddenly Queequeg started to his feet, hollowing his hand\nto his ear.  We all heard a faint creaking, as of ropes and yards\nhitherto muffled by the storm.  The sound came nearer and nearer; the\nthick mists were dimly parted by a huge, vague form.  Affrighted, we\nall sprang into the sea as the ship at last loomed into view, bearing\nright down upon us within a distance of not much more than its\nlength.\n\nFloating on the waves we saw the abandoned boat, as for one instant\nit tossed and gaped beneath the ship's bows like a chip at the base\nof a cataract; and then the vast hull rolled over it, and it was seen\nno more till it came up weltering astern.  Again we swam for it, were\ndashed against it by the seas, and were at last taken up and safely\nlanded on board.  Ere the squall came close to, the other boats had\ncut loose from their fish and returned to the ship in good time.  The\nship had given us up, but was still cruising, if haply it might light\nupon some token of our perishing,--an oar or a lance pole.\n\n\n\nCHAPTER 49\n\nThe Hyena.\n\n\nThere are certain queer times and occasions in this strange mixed\naffair we call life when a man takes this whole universe for a vast\npractical joke, though the wit thereof he but dimly discerns, and\nmore than suspects that the joke is at nobody's expense but his own.\nHowever, nothing dispirits, and nothing seems worth while disputing.\nHe bolts down all events, all creeds, and beliefs, and persuasions,\nall hard things visible and invisible, never mind how knobby; as an\nostrich of potent digestion gobbles down bullets and gun flints.  And\nas for small difficulties and worryings, prospects of sudden\ndisaster, peril of life and limb; all these, and death itself, seem\nto him only sly, good-natured hits, and jolly punches in the side\nbestowed by the unseen and unaccountable old joker.  That odd sort of\nwayward mood I am speaking of, comes over a man only in some time of\nextreme tribulation; it comes in the very midst of his earnestness,\nso that what just before might have seemed to him a thing most\nmomentous, now seems but a part of the general joke.  There is\nnothing like the perils of whaling to breed this free and easy sort\nof genial, desperado philosophy; and with it I now regarded this\nwhole voyage of the Pequod, and the great White Whale its object.\n\n\"Queequeg,\" said I, when they had dragged me, the last man, to the\ndeck, and I was still shaking myself in my jacket to fling off the\nwater; \"Queequeg, my fine friend, does this sort of thing often\nhappen?\"  Without much emotion, though soaked through just like me,\nhe gave me to understand that such things did often happen.\n\n\"Mr. Stubb,\" said I, turning to that worthy, who, buttoned up in his\noil-jacket, was now calmly smoking his pipe in the rain; \"Mr. Stubb,\nI think I have heard you say that of all whalemen you ever met, our\nchief mate, Mr. Starbuck, is by far the most careful and prudent.  I\nsuppose then, that going plump on a flying whale with your sail set\nin a foggy squall is the height of a whaleman's discretion?\"\n\n\"Certain.  I've lowered for whales from a leaking ship in a gale off\nCape Horn.\"\n\n\"Mr. Flask,\" said I, turning to little King-Post, who was standing\nclose by; \"you are experienced in these things, and I am not.  Will\nyou tell me whether it is an unalterable law in this fishery, Mr.\nFlask, for an oarsman to break his own back pulling himself\nback-foremost into death's jaws?\"\n\n\"Can't you twist that smaller?\" said Flask.  \"Yes, that's the law.  I\nshould like to see a boat's crew backing water up to a whale face\nforemost.  Ha, ha! the whale would give them squint for squint, mind\nthat!\"\n\nHere then, from three impartial witnesses, I had a deliberate\nstatement of the entire case.  Considering, therefore, that squalls\nand capsizings in the water and consequent bivouacks on the deep,\nwere matters of common occurrence in this kind of life; considering\nthat at the superlatively critical instant of going on to the whale I\nmust resign my life into the hands of him who steered the\nboat--oftentimes a fellow who at that very moment is in his\nimpetuousness upon the point of scuttling the craft with his own\nfrantic stampings; considering that the particular disaster to our\nown particular boat was chiefly to be imputed to Starbuck's driving\non to his whale almost in the teeth of a squall, and considering that\nStarbuck, notwithstanding, was famous for his great heedfulness in\nthe fishery; considering that I belonged to this uncommonly prudent\nStarbuck's boat; and finally considering in what a devil's chase I\nwas implicated, touching the White Whale: taking all things together,\nI say, I thought I might as well go below and make a rough draft of\nmy will.  \"Queequeg,\" said I, \"come along, you shall be my lawyer,\nexecutor, and legatee.\"\n\nIt may seem strange that of all men sailors should be tinkering at\ntheir last wills and testaments, but there are no people in the world\nmore fond of that diversion.  This was the fourth time in my nautical\nlife that I had done the same thing.  After the ceremony was\nconcluded upon the present occasion, I felt all the easier; a stone\nwas rolled away from my heart.  Besides, all the days I should now\nlive would be as good as the days that Lazarus lived after his\nresurrection; a supplementary clean gain of so many months or weeks\nas the case might be.  I survived myself; my death and burial were\nlocked up in my chest.  I looked round me tranquilly and contentedly,\nlike a quiet ghost with a clean conscience sitting inside the bars of\na snug family vault.\n\nNow then, thought I, unconsciously rolling up the sleeves of my\nfrock, here goes for a cool, collected dive at death and destruction,\nand the devil fetch the hindmost.\n\n\n\nCHAPTER 50\n\nAhab's Boat and Crew.  Fedallah.\n\n\n\"Who would have thought it, Flask!\" cried Stubb; \"if I had but one\nleg you would not catch me in a boat, unless maybe to stop the\nplug-hole with my timber toe.  Oh! he's a wonderful old man!\"\n\n\"I don't think it so strange, after all, on that account,\" said\nFlask.  \"If his leg were off at the hip, now, it would be a different\nthing.  That would disable him; but he has one knee, and good part of\nthe other left, you know.\"\n\n\"I don't know that, my little man; I never yet saw him kneel.\"\n\n\nAmong whale-wise people it has often been argued whether, considering\nthe paramount importance of his life to the success of the voyage, it\nis right for a whaling captain to jeopardize that life in the active\nperils of the chase.  So Tamerlane's soldiers often argued with tears\nin their eyes, whether that invaluable life of his ought to be\ncarried into the thickest of the fight.\n\nBut with Ahab the question assumed a modified aspect.  Considering\nthat with two legs man is but a hobbling wight in all times of\ndanger; considering that the pursuit of whales is always under great\nand extraordinary difficulties; that every individual moment, indeed,\nthen comprises a peril; under these circumstances is it wise for any\nmaimed man to enter a whale-boat in the hunt?  As a general thing,\nthe joint-owners of the Pequod must have plainly thought not.\n\nAhab well knew that although his friends at home would think little\nof his entering a boat in certain comparatively harmless vicissitudes\nof the chase, for the sake of being near the scene of action and\ngiving his orders in person, yet for Captain Ahab to have a boat\nactually apportioned to him as a regular headsman in the hunt--above\nall for Captain Ahab to be supplied with five extra men, as that same\nboat's crew, he well knew that such generous conceits never entered the\nheads of the owners of the Pequod.  Therefore he had not solicited a\nboat's crew from them, nor had he in any way hinted his desires on\nthat head.  Nevertheless he had taken private measures of his own\ntouching all that matter.  Until Cabaco's published discovery, the\nsailors had little foreseen it, though to be sure when, after being a\nlittle while out of port, all hands had concluded the customary\nbusiness of fitting the whaleboats for service; when some time after\nthis Ahab was now and then found bestirring himself in the matter of\nmaking thole-pins with his own hands for what was thought to be one\nof the spare boats, and even solicitously cutting the small wooden\nskewers, which when the line is running out are pinned over the\ngroove in the bow: when all this was observed in him, and\nparticularly his solicitude in having an extra coat of sheathing in\nthe bottom of the boat, as if to make it better withstand the pointed\npressure of his ivory limb; and also the anxiety he evinced in\nexactly shaping the thigh board, or clumsy cleat, as it is sometimes\ncalled, the horizontal piece in the boat's bow for bracing the knee\nagainst in darting or stabbing at the whale; when it was observed how\noften he stood up in that boat with his solitary knee fixed in the\nsemi-circular depression in the cleat, and with the carpenter's\nchisel gouged out a little here and straightened it a little there;\nall these things, I say, had awakened much interest and curiosity at\nthe time.  But almost everybody supposed that this particular\npreparative heedfulness in Ahab must only be with a view to the\nultimate chase of Moby Dick; for he had already revealed his\nintention to hunt that mortal monster in person.  But such a\nsupposition did by no means involve the remotest suspicion as to any\nboat's crew being assigned to that boat.\n\nNow, with the subordinate phantoms, what wonder remained soon waned\naway; for in a whaler wonders soon wane.  Besides, now and then such\nunaccountable odds and ends of strange nations come up from the\nunknown nooks and ash-holes of the earth to man these floating\noutlaws of whalers; and the ships themselves often pick up such queer\ncastaway creatures found tossing about the open sea on planks, bits\nof wreck, oars, whaleboats, canoes, blown-off Japanese junks, and\nwhat not; that Beelzebub himself might climb up the side and step\ndown into the cabin to chat with the captain, and it would not create\nany unsubduable excitement in the forecastle.\n\nBut be all this as it may, certain it is that while the subordinate\nphantoms soon found their place among the crew, though still as it\nwere somehow distinct from them, yet that hair-turbaned Fedallah\nremained a muffled mystery to the last.  Whence he came in a mannerly\nworld like this, by what sort of unaccountable tie he soon evinced\nhimself to be linked with Ahab's peculiar fortunes; nay, so far as to\nhave some sort of a half-hinted influence; Heaven knows, but it might\nhave been even authority over him; all this none knew.  But one\ncannot sustain an indifferent air concerning Fedallah.  He was such a\ncreature as civilized, domestic people in the temperate zone only see\nin their dreams, and that but dimly; but the like of whom now and\nthen glide among the unchanging Asiatic communities, especially the\nOriental isles to the east of the continent--those insulated,\nimmemorial, unalterable countries, which even in these modern days\nstill preserve much of the ghostly aboriginalness of earth's primal\ngenerations, when the memory of the first man was a distinct\nrecollection, and all men his descendants, unknowing whence he came,\neyed each other as real phantoms, and asked of the sun and the moon\nwhy they were created and to what end; when though, according to\nGenesis, the angels indeed consorted with the daughters of men, the\ndevils also, add the uncanonical Rabbins, indulged in mundane amours.\n\n\n\nCHAPTER 51\n\nThe Spirit-Spout.\n\n\nDays, weeks passed, and under easy sail, the ivory Pequod had slowly\nswept across four several cruising-grounds; that off the Azores; off\nthe Cape de Verdes; on the Plate (so called), being off the mouth of\nthe Rio de la Plata; and the Carrol Ground, an unstaked, watery\nlocality, southerly from St. Helena.\n\nIt was while gliding through these latter waters that one serene and\nmoonlight night, when all the waves rolled by like scrolls of silver;\nand, by their soft, suffusing seethings, made what seemed a silvery\nsilence, not a solitude; on such a silent night a silvery jet was\nseen far in advance of the white bubbles at the bow.  Lit up by the\nmoon, it looked celestial; seemed some plumed and glittering god\nuprising from the sea.  Fedallah first descried this jet.  For of\nthese moonlight nights, it was his wont to mount to the main-mast\nhead, and stand a look-out there, with the same precision as if it\nhad been day.  And yet, though herds of whales were seen by night,\nnot one whaleman in a hundred would venture a lowering for them.  You\nmay think with what emotions, then, the seamen beheld this old\nOriental perched aloft at such unusual hours; his turban and the\nmoon, companions in one sky.  But when, after spending his uniform\ninterval there for several successive nights without uttering a\nsingle sound; when, after all this silence, his unearthly voice was\nheard announcing that silvery, moon-lit jet, every reclining mariner\nstarted to his feet as if some winged spirit had lighted in the\nrigging, and hailed the mortal crew.  \"There she blows!\"  Had the\ntrump of judgment blown, they could not have quivered more; yet still\nthey felt no terror; rather pleasure.  For though it was a most\nunwonted hour, yet so impressive was the cry, and so deliriously\nexciting, that almost every soul on board instinctively desired a\nlowering.\n\nWalking the deck with quick, side-lunging strides, Ahab commanded the\nt'gallant sails and royals to be set, and every stunsail spread.  The\nbest man in the ship must take the helm.  Then, with every mast-head\nmanned, the piled-up craft rolled down before the wind.  The strange,\nupheaving, lifting tendency of the taffrail breeze filling the\nhollows of so many sails, made the buoyant, hovering deck to feel\nlike air beneath the feet; while still she rushed along, as if two\nantagonistic influences were struggling in her--one to mount direct\nto heaven, the other to drive yawingly to some horizontal goal.  And\nhad you watched Ahab's face that night, you would have thought that\nin him also two different things were warring.  While his one live\nleg made lively echoes along the deck, every stroke of his dead limb\nsounded like a coffin-tap.  On life and death this old man walked.\nBut though the ship so swiftly sped, and though from every eye, like\narrows, the eager glances shot, yet the silvery jet was no more seen\nthat night.  Every sailor swore he saw it once, but not a second\ntime.\n\nThis midnight-spout had almost grown a forgotten thing, when, some\ndays after, lo! at the same silent hour, it was again announced:\nagain it was descried by all; but upon making sail to overtake it,\nonce more it disappeared as if it had never been.  And so it served\nus night after night, till no one heeded it but to wonder at it.\nMysteriously jetted into the clear moonlight, or starlight, as the\ncase might be; disappearing again for one whole day, or two days, or\nthree; and somehow seeming at every distinct repetition to be\nadvancing still further and further in our van, this solitary jet\nseemed for ever alluring us on.\n\nNor with the immemorial superstition of their race, and in accordance\nwith the preternaturalness, as it seemed, which in many things\ninvested the Pequod, were there wanting some of the seamen who swore\nthat whenever and wherever descried; at however remote times, or in\nhowever far apart latitudes and longitudes, that unnearable spout was\ncast by one self-same whale; and that whale, Moby Dick.  For a time,\nthere reigned, too, a sense of peculiar dread at this flitting\napparition, as if it were treacherously beckoning us on and on, in\norder that the monster might turn round upon us, and rend us at last\nin the remotest and most savage seas.\n\nThese temporary apprehensions, so vague but so awful, derived a\nwondrous potency from the contrasting serenity of the weather, in\nwhich, beneath all its blue blandness, some thought there lurked a\ndevilish charm, as for days and days we voyaged along, through seas\nso wearily, lonesomely mild, that all space, in repugnance to our\nvengeful errand, seemed vacating itself of life before our urn-like\nprow.\n\nBut, at last, when turning to the eastward, the Cape winds began\nhowling around us, and we rose and fell upon the long, troubled seas\nthat are there; when the ivory-tusked Pequod sharply bowed to the\nblast, and gored the dark waves in her madness, till, like showers of\nsilver chips, the foam-flakes flew over her bulwarks; then all this\ndesolate vacuity of life went away, but gave place to sights more\ndismal than before.\n\nClose to our bows, strange forms in the water darted hither and\nthither before us; while thick in our rear flew the inscrutable\nsea-ravens.  And every morning, perched on our stays, rows of these\nbirds were seen; and spite of our hootings, for a long time\nobstinately clung to the hemp, as though they deemed our ship some\ndrifting, uninhabited craft; a thing appointed to desolation, and\ntherefore fit roosting-place for their homeless selves.  And heaved\nand heaved, still unrestingly heaved the black sea, as if its vast\ntides were a conscience; and the great mundane soul were in anguish\nand remorse for the long sin and suffering it had bred.\n\nCape of Good Hope, do they call ye?  Rather Cape Tormentoto, as\ncalled of yore; for long allured by the perfidious silences that\nbefore had attended us, we found ourselves launched into this\ntormented sea, where guilty beings transformed into those fowls and\nthese fish, seemed condemned to swim on everlastingly without any\nhaven in store, or beat that black air without any horizon.  But\ncalm, snow-white, and unvarying; still directing its fountain of\nfeathers to the sky; still beckoning us on from before, the solitary\njet would at times be descried.\n\nDuring all this blackness of the elements, Ahab, though assuming for\nthe time the almost continual command of the drenched and dangerous\ndeck, manifested the gloomiest reserve; and more seldom than ever\naddressed his mates.  In tempestuous times like these, after\neverything above and aloft has been secured, nothing more can be done\nbut passively to await the issue of the gale.  Then Captain and crew\nbecome practical fatalists.  So, with his ivory leg inserted into its\naccustomed hole, and with one hand firmly grasping a shroud, Ahab for\nhours and hours would stand gazing dead to windward, while an\noccasional squall of sleet or snow would all but congeal his very\neyelashes together.  Meantime, the crew driven from the forward part\nof the ship by the perilous seas that burstingly broke over its bows,\nstood in a line along the bulwarks in the waist; and the better to\nguard against the leaping waves, each man had slipped himself into a\nsort of bowline secured to the rail, in which he swung as in a\nloosened belt.  Few or no words were spoken; and the silent ship, as\nif manned by painted sailors in wax, day after day tore on through\nall the swift madness and gladness of the demoniac waves.  By night\nthe same muteness of humanity before the shrieks of the ocean\nprevailed; still in silence the men swung in the bowlines; still\nwordless Ahab stood up to the blast.  Even when wearied nature seemed\ndemanding repose he would not seek that repose in his hammock.\nNever could Starbuck forget the old man's aspect, when one night\ngoing down into the cabin to mark how the barometer stood, he saw him\nwith closed eyes sitting straight in his floor-screwed chair; the\nrain and half-melted sleet of the storm from which he had some time\nbefore emerged, still slowly dripping from the unremoved hat and\ncoat.  On the table beside him lay unrolled one of those charts of\ntides and currents which have previously been spoken of.  His lantern\nswung from his tightly clenched hand.  Though the body was erect, the\nhead was thrown back so that the closed eyes were pointed towards the\nneedle of the tell-tale that swung from a beam in the ceiling.*\n\n\n*The cabin-compass is called the tell-tale, because without going to\nthe compass at the helm, the Captain, while below, can inform himself\nof the course of the ship.\n\n\nTerrible old man! thought Starbuck with a shudder, sleeping in this\ngale, still thou steadfastly eyest thy purpose.\n\n\n\nCHAPTER 52\n\nThe Albatross.\n\n\nSouth-eastward from the Cape, off the distant Crozetts, a good\ncruising ground for Right Whalemen, a sail loomed ahead, the Goney\n(Albatross) by name.  As she slowly drew nigh, from my lofty perch at\nthe fore-mast-head, I had a good view of that sight so remarkable to\na tyro in the far ocean fisheries--a whaler at sea, and long absent\nfrom home.\n\nAs if the waves had been fullers, this craft was bleached like the\nskeleton of a stranded walrus.  All down her sides, this spectral\nappearance was traced with long channels of reddened rust, while all\nher spars and her rigging were like the thick branches of trees\nfurred over with hoar-frost.  Only her lower sails were set.  A wild\nsight it was to see her long-bearded look-outs at those three\nmast-heads.  They seemed clad in the skins of beasts, so torn and\nbepatched the raiment that had survived nearly four years of\ncruising.  Standing in iron hoops nailed to the mast, they swayed and\nswung over a fathomless sea; and though, when the ship slowly glided\nclose under our stern, we six men in the air came so nigh to each\nother that we might almost have leaped from the mast-heads of one\nship to those of the other; yet, those forlorn-looking fishermen,\nmildly eyeing us as they passed, said not one word to our own\nlook-outs, while the quarter-deck hail was being heard from below.\n\n\"Ship ahoy!  Have ye seen the White Whale?\"\n\nBut as the strange captain, leaning over the pallid bulwarks, was in\nthe act of putting his trumpet to his mouth, it somehow fell from his\nhand into the sea; and the wind now rising amain, he in vain strove\nto make himself heard without it.  Meantime his ship was still\nincreasing the distance between.  While in various silent ways\nthe seamen of the Pequod were evincing their observance of this\nominous incident at the first mere mention of the White Whale's name\nto another ship, Ahab for a moment paused; it almost seemed as though\nhe would have lowered a boat to board the stranger, had not the\nthreatening wind forbade.  But taking advantage of his windward\nposition, he again seized his trumpet, and knowing by her aspect that\nthe stranger vessel was a Nantucketer and shortly bound home, he\nloudly hailed--\"Ahoy there!  This is the Pequod, bound round the\nworld!  Tell them to address all future letters to the Pacific ocean!\nand this time three years, if I am not at home, tell them to address\nthem to--\"\n\nAt that moment the two wakes were fairly crossed, and instantly,\nthen, in accordance with their singular ways, shoals of small\nharmless fish, that for some days before had been placidly swimming\nby our side, darted away with what seemed shuddering fins, and ranged\nthemselves fore and aft with the stranger's flanks.  Though in the\ncourse of his continual voyagings Ahab must often before have noticed\na similar sight, yet, to any monomaniac man, the veriest trifles\ncapriciously carry meanings.\n\n\"Swim away from me, do ye?\" murmured Ahab, gazing over into the\nwater.  There seemed but little in the words, but the tone conveyed\nmore of deep helpless sadness than the insane old man had ever before\nevinced.  But turning to the steersman, who thus far had been holding\nthe ship in the wind to diminish her headway, he cried out in his old\nlion voice,--\"Up helm!  Keep her off round the world!\"\n\nRound the world!  There is much in that sound to inspire proud\nfeelings; but whereto does all that circumnavigation conduct?  Only\nthrough numberless perils to the very point whence we started, where\nthose that we left behind secure, were all the time before us.\n\nWere this world an endless plain, and by sailing eastward we could\nfor ever reach new distances, and discover sights more sweet and\nstrange than any Cyclades or Islands of King Solomon, then there were\npromise in the voyage.  But in pursuit of those far mysteries we\ndream of, or in tormented chase of that demon phantom that, some time\nor other, swims before all human hearts; while chasing such over this\nround globe, they either lead us on in barren mazes or midway leave\nus whelmed.\n\n\n\nCHAPTER 53\n\nThe Gam.\n\n\nThe ostensible reason why Ahab did not go on board of the whaler we\nhad spoken was this: the wind and sea betokened storms.  But even had\nthis not been the case, he would not after all, perhaps, have boarded\nher--judging by his subsequent conduct on similar occasions--if so it\nhad been that, by the process of hailing, he had obtained a negative\nanswer to the question he put.  For, as it eventually turned out, he\ncared not to consort, even for five minutes, with any stranger\ncaptain, except he could contribute some of that information he so\nabsorbingly sought.  But all this might remain inadequately\nestimated, were not something said here of the peculiar usages of\nwhaling-vessels when meeting each other in foreign seas, and\nespecially on a common cruising-ground.\n\nIf two strangers crossing the Pine Barrens in New York State, or the\nequally desolate Salisbury Plain in England; if casually encountering\neach other in such inhospitable wilds, these twain, for the life of\nthem, cannot well avoid a mutual salutation; and stopping for a\nmoment to interchange the news; and, perhaps, sitting down for a\nwhile and resting in concert: then, how much more natural that upon\nthe illimitable Pine Barrens and Salisbury Plains of the sea, two\nwhaling vessels descrying each other at the ends of the earth--off\nlone Fanning's Island, or the far away King's Mills; how much more\nnatural, I say, that under such circumstances these ships should not\nonly interchange hails, but come into still closer, more friendly and\nsociable contact.  And especially would this seem to be a matter of\ncourse, in the case of vessels owned in one seaport, and whose\ncaptains, officers, and not a few of the men are personally known to\neach other; and consequently, have all sorts of dear domestic things\nto talk about.\n\nFor the long absent ship, the outward-bounder, perhaps, has letters\non board; at any rate, she will be sure to let her have some papers\nof a date a year or two later than the last one on her blurred and\nthumb-worn files.  And in return for that courtesy, the outward-bound\nship would receive the latest whaling intelligence from the\ncruising-ground to which she may be destined, a thing of the utmost\nimportance to her.  And in degree, all this will hold true concerning\nwhaling vessels crossing each other's track on the cruising-ground\nitself, even though they are equally long absent from home.  For one\nof them may have received a transfer of letters from some third, and\nnow far remote vessel; and some of those letters may be for the\npeople of the ship she now meets.  Besides, they would exchange the\nwhaling news, and have an agreeable chat.  For not only would they\nmeet with all the sympathies of sailors, but likewise with all the\npeculiar congenialities arising from a common pursuit and mutually\nshared privations and perils.\n\nNor would difference of country make any very essential difference;\nthat is, so long as both parties speak one language, as is the case\nwith Americans and English.  Though, to be sure, from the small\nnumber of English whalers, such meetings do not very often occur, and\nwhen they do occur there is too apt to be a sort of shyness between\nthem; for your Englishman is rather reserved, and your Yankee, he\ndoes not fancy that sort of thing in anybody but himself.  Besides,\nthe English whalers sometimes affect a kind of metropolitan\nsuperiority over the American whalers; regarding the long, lean\nNantucketer, with his nondescript provincialisms, as a sort of\nsea-peasant.  But where this superiority in the English whalemen\ndoes really consist, it would be hard to say, seeing that the Yankees\nin one day, collectively, kill more whales than all the English,\ncollectively, in ten years.  But this is a harmless little foible in\nthe English whale-hunters, which the Nantucketer does not take much\nto heart; probably, because he knows that he has a few foibles\nhimself.\n\nSo, then, we see that of all ships separately sailing the sea, the\nwhalers have most reason to be sociable--and they are so.  Whereas,\nsome merchant ships crossing each other's wake in the mid-Atlantic,\nwill oftentimes pass on without so much as a single word of\nrecognition, mutually cutting each other on the high seas, like a\nbrace of dandies in Broadway; and all the time indulging, perhaps, in\nfinical criticism upon each other's rig.  As for Men-of-War, when\nthey chance to meet at sea, they first go through such a string of\nsilly bowings and scrapings, such a ducking of ensigns, that there\ndoes not seem to be much right-down hearty good-will and brotherly\nlove about it at all.  As touching Slave-ships meeting, why, they are\nin such a prodigious hurry, they run away from each other as soon as\npossible.  And as for Pirates, when they chance to cross each other's\ncross-bones, the first hail is--\"How many skulls?\"--the same way that\nwhalers hail--\"How many barrels?\"  And that question once answered,\npirates straightway steer apart, for they are infernal villains on\nboth sides, and don't like to see overmuch of each other's villanous\nlikenesses.\n\nBut look at the godly, honest, unostentatious, hospitable, sociable,\nfree-and-easy whaler!  What does the whaler do when she meets another\nwhaler in any sort of decent weather?  She has a \"GAM,\" a thing so\nutterly unknown to all other ships that they never heard of the name\neven; and if by chance they should hear of it, they only grin at it,\nand repeat gamesome stuff about \"spouters\" and \"blubber-boilers,\" and\nsuch like pretty exclamations.  Why it is that all Merchant-seamen,\nand also all Pirates and Man-of-War's men, and Slave-ship sailors,\ncherish such a scornful feeling towards Whale-ships; this is a\nquestion it would be hard to answer.  Because, in the case of\npirates, say, I should like to know whether that profession of theirs\nhas any peculiar glory about it.  It sometimes ends in uncommon\nelevation, indeed; but only at the gallows.  And besides, when a man\nis elevated in that odd fashion, he has no proper foundation for his\nsuperior altitude.  Hence, I conclude, that in boasting himself to be\nhigh lifted above a whaleman, in that assertion the pirate has no\nsolid basis to stand on.\n\nBut what is a GAM?  You might wear out your index-finger running up\nand down the columns of dictionaries, and never find the word.  Dr.\nJohnson never attained to that erudition; Noah Webster's ark does not\nhold it.  Nevertheless, this same expressive word has now for many\nyears been in constant use among some fifteen thousand true born\nYankees.  Certainly, it needs a definition, and should be\nincorporated into the Lexicon.  With that view, let me learnedly\ndefine it.\n\nGAM.  NOUN--A SOCIAL MEETING OF TWO (OR MORE) WHALESHIPS, GENERALLY\nON A CRUISING-GROUND; WHEN, AFTER EXCHANGING HAILS, THEY EXCHANGE\nVISITS BY BOATS' CREWS; THE TWO CAPTAINS REMAINING, FOR THE TIME, ON\nBOARD OF ONE SHIP, AND THE TWO CHIEF MATES ON THE OTHER.\n\nThere is another little item about Gamming which must not be\nforgotten here.  All professions have their own little peculiarities\nof detail; so has the whale fishery.  In a pirate, man-of-war, or\nslave ship, when the captain is rowed anywhere in his boat, he always\nsits in the stern sheets on a comfortable, sometimes cushioned seat\nthere, and often steers himself with a pretty little milliner's\ntiller decorated with gay cords and ribbons.  But the whale-boat has\nno seat astern, no sofa of that sort whatever, and no tiller at all.\nHigh times indeed, if whaling captains were wheeled about the water\non castors like gouty old aldermen in patent chairs.  And as for a\ntiller, the whale-boat never admits of any such effeminacy; and\ntherefore as in gamming a complete boat's crew must leave the ship,\nand hence as the boat steerer or harpooneer is of the number, that\nsubordinate is the steersman upon the occasion, and the captain,\nhaving no place to sit in, is pulled off to his visit all standing\nlike a pine tree.  And often you will notice that being conscious of\nthe eyes of the whole visible world resting on him from the sides of\nthe two ships, this standing captain is all alive to the importance\nof sustaining his dignity by maintaining his legs.  Nor is this any\nvery easy matter; for in his rear is the immense projecting steering\noar hitting him now and then in the small of his back, the after-oar\nreciprocating by rapping his knees in front.  He is thus completely\nwedged before and behind, and can only expand himself sideways by\nsettling down on his stretched legs; but a sudden, violent pitch of\nthe boat will often go far to topple him, because length of\nfoundation is nothing without corresponding breadth.  Merely make a\nspread angle of two poles, and you cannot stand them up.  Then,\nagain, it would never do in plain sight of the world's riveted eyes,\nit would never do, I say, for this straddling captain to be seen\nsteadying himself the slightest particle by catching hold of anything\nwith his hands; indeed, as token of his entire, buoyant self-command,\nhe generally carries his hands in his trowsers' pockets; but perhaps\nbeing generally very large, heavy hands, he carries them there for\nballast.  Nevertheless there have occurred instances, well\nauthenticated ones too, where the captain has been known for an\nuncommonly critical moment or two, in a sudden squall say--to seize\nhold of the nearest oarsman's hair, and hold on there like grim\ndeath.\n\n\n\nCHAPTER 54\n\nThe Town-Ho's Story.\n\n\n(AS TOLD AT THE GOLDEN INN)\n\n\nThe Cape of Good Hope, and all the watery region round about there,\nis much like some noted four corners of a great highway, where you\nmeet more travellers than in any other part.\n\nIt was not very long after speaking the Goney that another\nhomeward-bound whaleman, the Town-Ho,* was encountered.  She was\nmanned almost wholly by Polynesians.  In the short gam that ensued\nshe gave us strong news of Moby Dick.  To some the general interest\nin the White Whale was now wildly heightened by a circumstance of the\nTown-Ho's story, which seemed obscurely to involve with the whale a\ncertain wondrous, inverted visitation of one of those so called\njudgments of God which at times are said to overtake some men.  This\nlatter circumstance, with its own particular accompaniments, forming\nwhat may be called the secret part of the tragedy about to be\nnarrated, never reached the ears of Captain Ahab or his mates.  For\nthat secret part of the story was unknown to the captain of the\nTown-Ho himself.  It was the private property of three confederate\nwhite seamen of that ship, one of whom, it seems, communicated it to\nTashtego with Romish injunctions of secrecy, but the following night\nTashtego rambled in his sleep, and revealed so much of it in that\nway, that when he was wakened he could not well withhold the rest.\nNevertheless, so potent an influence did this thing have on those\nseamen in the Pequod who came to the full knowledge of it, and by\nsuch a strange delicacy, to call it so, were they governed in this\nmatter, that they kept the secret among themselves so that it never\ntranspired abaft the Pequod's main-mast.  Interweaving in its proper\nplace this darker thread with the story as publicly narrated on the\nship, the whole of this strange affair I now proceed to put on\nlasting record.\n\n\n*The ancient whale-cry upon first sighting a whale from the\nmast-head, still used by whalemen in hunting the famous Gallipagos\nterrapin.\n\n\nFor my humor's sake, I shall preserve the style in which I once\nnarrated it at Lima, to a lounging circle of my Spanish friends, one\nsaint's eve, smoking upon the thick-gilt tiled piazza of the Golden\nInn.  Of those fine cavaliers, the young Dons, Pedro and Sebastian,\nwere on the closer terms with me; and hence the interluding questions\nthey occasionally put, and which are duly answered at the time.\n\n\"Some two years prior to my first learning the events which I am\nabout rehearsing to you, gentlemen, the Town-Ho, Sperm Whaler of\nNantucket, was cruising in your Pacific here, not very many days'\nsail eastward from the eaves of this good Golden Inn.  She was\nsomewhere to the northward of the Line.  One morning upon handling\nthe pumps, according to daily usage, it was observed that she made\nmore water in her hold than common.  They supposed a sword-fish had\nstabbed her, gentlemen.  But the captain, having some unusual reason\nfor believing that rare good luck awaited him in those latitudes; and\ntherefore being very averse to quit them, and the leak not being then\nconsidered at all dangerous, though, indeed, they could not find it\nafter searching the hold as low down as was possible in rather heavy\nweather, the ship still continued her cruisings, the mariners working\nat the pumps at wide and easy intervals; but no good luck came; more\ndays went by, and not only was the leak yet undiscovered, but it\nsensibly increased.  So much so, that now taking some alarm, the\ncaptain, making all sail, stood away for the nearest harbor among the\nislands, there to have his hull hove out and repaired.\n\n\"Though no small passage was before her, yet, if the commonest chance\nfavoured, he did not at all fear that his ship would founder by the\nway, because his pumps were of the best, and being periodically\nrelieved at them, those six-and-thirty men of his could easily keep\nthe ship free; never mind if the leak should double on her.  In\ntruth, well nigh the whole of this passage being attended by very\nprosperous breezes, the Town-Ho had all but certainly arrived in\nperfect safety at her port without the occurrence of the least\nfatality, had it not been for the brutal overbearing of Radney, the\nmate, a Vineyarder, and the bitterly provoked vengeance of Steelkilt,\na Lakeman and desperado from Buffalo.\n\n\"'Lakeman!--Buffalo!  Pray, what is a Lakeman, and where is Buffalo?'\nsaid Don Sebastian, rising in his swinging mat of grass.\n\n\"On the eastern shore of our Lake Erie, Don; but--I crave your\ncourtesy--may be, you shall soon hear further of all that.  Now,\ngentlemen, in square-sail brigs and three-masted ships, well-nigh as\nlarge and stout as any that ever sailed out of your old Callao to far\nManilla; this Lakeman, in the land-locked heart of our America, had\nyet been nurtured by all those agrarian freebooting impressions\npopularly connected with the open ocean.  For in their interflowing\naggregate, those grand fresh-water seas of ours,--Erie, and Ontario,\nand Huron, and Superior, and Michigan,--possess an ocean-like\nexpansiveness, with many of the ocean's noblest traits; with many of\nits rimmed varieties of races and of climes.  They contain round\narchipelagoes of romantic isles, even as the Polynesian waters do; in\nlarge part, are shored by two great contrasting nations, as the\nAtlantic is; they furnish long maritime approaches to our numerous\nterritorial colonies from the East, dotted all round their banks;\nhere and there are frowned upon by batteries, and by the goat-like\ncraggy guns of lofty Mackinaw; they have heard the fleet thunderings\nof naval victories; at intervals, they yield their beaches to wild\nbarbarians, whose red painted faces flash from out their peltry\nwigwams; for leagues and leagues are flanked by ancient and unentered\nforests, where the gaunt pines stand like serried lines of kings in\nGothic genealogies; those same woods harboring wild Afric beasts of\nprey, and silken creatures whose exported furs give robes to Tartar\nEmperors; they mirror the paved capitals of Buffalo and Cleveland, as\nwell as Winnebago villages; they float alike the full-rigged merchant\nship, the armed cruiser of the State, the steamer, and the beech\ncanoe; they are swept by Borean and dismasting blasts as direful as\nany that lash the salted wave; they know what shipwrecks are, for out\nof sight of land, however inland, they have drowned full many a\nmidnight ship with all its shrieking crew.  Thus, gentlemen, though\nan inlander, Steelkilt was wild-ocean born, and wild-ocean nurtured;\nas much of an audacious mariner as any.  And for Radney, though in\nhis infancy he may have laid him down on the lone Nantucket beach, to\nnurse at his maternal sea; though in after life he had long followed\nour austere Atlantic and your contemplative Pacific; yet was he quite\nas vengeful and full of social quarrel as the backwoods seaman, fresh\nfrom the latitudes of buck-horn handled bowie-knives.  Yet was this\nNantucketer a man with some good-hearted traits; and this Lakeman, a\nmariner, who though a sort of devil indeed, might yet by inflexible\nfirmness, only tempered by that common decency of human recognition\nwhich is the meanest slave's right; thus treated, this Steelkilt had\nlong been retained harmless and docile.  At all events, he had proved\nso thus far; but Radney was doomed and made mad, and Steelkilt--but,\ngentlemen, you shall hear.\n\n\"It was not more than a day or two at the furthest after pointing her\nprow for her island haven, that the Town-Ho's leak seemed again\nincreasing, but only so as to require an hour or more at the pumps\nevery day.  You must know that in a settled and civilized ocean like\nour Atlantic, for example, some skippers think little of pumping\ntheir whole way across it; though of a still, sleepy night, should\nthe officer of the deck happen to forget his duty in that respect,\nthe probability would be that he and his shipmates would never again\nremember it, on account of all hands gently subsiding to the bottom.\nNor in the solitary and savage seas far from you to the westward,\ngentlemen, is it altogether unusual for ships to keep clanging at\ntheir pump-handles in full chorus even for a voyage of considerable\nlength; that is, if it lie along a tolerably accessible coast, or if\nany other reasonable retreat is afforded them.  It is only when a\nleaky vessel is in some very out of the way part of those waters,\nsome really landless latitude, that her captain begins to feel a\nlittle anxious.\n\n\"Much this way had it been with the Town-Ho; so when her leak was\nfound gaining once more, there was in truth some small concern\nmanifested by several of her company; especially by Radney the mate.\nHe commanded the upper sails to be well hoisted, sheeted home anew,\nand every way expanded to the breeze.  Now this Radney, I suppose,\nwas as little of a coward, and as little inclined to any sort of\nnervous apprehensiveness touching his own person as any fearless,\nunthinking creature on land or on sea that you can conveniently\nimagine, gentlemen.  Therefore when he betrayed this solicitude about\nthe safety of the ship, some of the seamen declared that it was only\non account of his being a part owner in her.  So when they were\nworking that evening at the pumps, there was on this head no small\ngamesomeness slily going on among them, as they stood with their feet\ncontinually overflowed by the rippling clear water; clear as any\nmountain spring, gentlemen--that bubbling from the pumps ran across\nthe deck, and poured itself out in steady spouts at the lee\nscupper-holes.\n\n\"Now, as you well know, it is not seldom the case in this\nconventional world of ours--watery or otherwise; that when a person\nplaced in command over his fellow-men finds one of them to be very\nsignificantly his superior in general pride of manhood, straightway\nagainst that man he conceives an unconquerable dislike and\nbitterness; and if he have a chance he will pull down and pulverize\nthat subaltern's tower, and make a little heap of dust of it.  Be\nthis conceit of mine as it may, gentlemen, at all events Steelkilt\nwas a tall and noble animal with a head like a Roman, and a flowing\ngolden beard like the tasseled housings of your last viceroy's\nsnorting charger; and a brain, and a heart, and a soul in him,\ngentlemen, which had made Steelkilt Charlemagne, had he been born son\nto Charlemagne's father.  But Radney, the mate, was ugly as a mule;\nyet as hardy, as stubborn, as malicious.  He did not love Steelkilt,\nand Steelkilt knew it.\n\n\"Espying the mate drawing near as he was toiling at the pump with the\nrest, the Lakeman affected not to notice him, but unawed, went on\nwith his gay banterings.\n\n\"'Aye, aye, my merry lads, it's a lively leak this; hold a cannikin,\none of ye, and let's have a taste.  By the Lord, it's worth bottling!\nI tell ye what, men, old Rad's investment must go for it! he had\nbest cut away his part of the hull and tow it home.  The fact is,\nboys, that sword-fish only began the job; he's come back again with a\ngang of ship-carpenters, saw-fish, and file-fish, and what not; and\nthe whole posse of 'em are now hard at work cutting and slashing at\nthe bottom; making improvements, I suppose.  If old Rad were here\nnow, I'd tell him to jump overboard and scatter 'em.  They're playing\nthe devil with his estate, I can tell him.  But he's a simple old\nsoul,--Rad, and a beauty too.  Boys, they say the rest of his\nproperty is invested in looking-glasses.  I wonder if he'd give a\npoor devil like me the model of his nose.'\n\n\"'Damn your eyes! what's that pump stopping for?' roared Radney,\npretending not to have heard the sailors' talk.  'Thunder away at\nit!'\n\n'Aye, aye, sir,' said Steelkilt, merry as a cricket.  'Lively, boys,\nlively, now!'  And with that the pump clanged like fifty\nfire-engines; the men tossed their hats off to it, and ere long that\npeculiar gasping of the lungs was heard which denotes the fullest\ntension of life's utmost energies.\n\n\"Quitting the pump at last, with the rest of his band, the Lakeman\nwent forward all panting, and sat himself down on the windlass; his\nface fiery red, his eyes bloodshot, and wiping the profuse sweat from\nhis brow.  Now what cozening fiend it was, gentlemen, that possessed\nRadney to meddle with such a man in that corporeally exasperated\nstate, I know not; but so it happened.  Intolerably striding along\nthe deck, the mate commanded him to get a broom and sweep down the\nplanks, and also a shovel, and remove some offensive matters\nconsequent upon allowing a pig to run at large.\n\n\"Now, gentlemen, sweeping a ship's deck at sea is a piece of\nhousehold work which in all times but raging gales is regularly\nattended to every evening; it has been known to be done in the case\nof ships actually foundering at the time.  Such, gentlemen, is the\ninflexibility of sea-usages and the instinctive love of neatness in\nseamen; some of whom would not willingly drown without first washing\ntheir faces.  But in all vessels this broom business is the\nprescriptive province of the boys, if boys there be aboard.  Besides,\nit was the stronger men in the Town-Ho that had been divided into\ngangs, taking turns at the pumps; and being the most athletic seaman\nof them all, Steelkilt had been regularly assigned captain of one of\nthe gangs; consequently he should have been freed from any trivial\nbusiness not connected with truly nautical duties, such being the\ncase with his comrades.  I mention all these particulars so that you\nmay understand exactly how this affair stood between the two men.\n\n\"But there was more than this: the order about the shovel was almost\nas plainly meant to sting and insult Steelkilt, as though Radney had\nspat in his face.  Any man who has gone sailor in a whale-ship will\nunderstand this; and all this and doubtless much more, the Lakeman\nfully comprehended when the mate uttered his command.  But as he sat\nstill for a moment, and as he steadfastly looked into the mate's\nmalignant eye and perceived the stacks of powder-casks heaped up in\nhim and the slow-match silently burning along towards them; as he\ninstinctively saw all this, that strange forbearance and\nunwillingness to stir up the deeper passionateness in any already\nireful being--a repugnance most felt, when felt at all, by really\nvaliant men even when aggrieved--this nameless phantom feeling,\ngentlemen, stole over Steelkilt.\n\n\"Therefore, in his ordinary tone, only a little broken by the bodily\nexhaustion he was temporarily in, he answered him saying that\nsweeping the deck was not his business, and he would not do it.  And\nthen, without at all alluding to the shovel, he pointed to three\nlads as the customary sweepers; who, not being billeted at the\npumps, had done little or nothing all day.  To this, Radney replied\nwith an oath, in a most domineering and outrageous manner\nunconditionally reiterating his command; meanwhile advancing upon the\nstill seated Lakeman, with an uplifted cooper's club hammer which he\nhad snatched from a cask near by.\n\n\"Heated and irritated as he was by his spasmodic toil at the pumps,\nfor all his first nameless feeling of forbearance the sweating\nSteelkilt could but ill brook this bearing in the mate; but somehow\nstill smothering the conflagration within him, without speaking he\nremained doggedly rooted to his seat, till at last the incensed\nRadney shook the hammer within a few inches of his face, furiously\ncommanding him to do his bidding.\n\n\"Steelkilt rose, and slowly retreating round the windlass, steadily\nfollowed by the mate with his menacing hammer, deliberately repeated\nhis intention not to obey.  Seeing, however, that his forbearance had\nnot the slightest effect, by an awful and unspeakable intimation with\nhis twisted hand he warned off the foolish and infatuated man; but it\nwas to no purpose.  And in this way the two went once slowly round\nthe windlass; when, resolved at last no longer to retreat, bethinking\nhim that he had now forborne as much as comported with his humor, the\nLakeman paused on the hatches and thus spoke to the officer:\n\n\"'Mr. Radney, I will not obey you.  Take that hammer away, or look to\nyourself.'  But the predestinated mate coming still closer to him,\nwhere the Lakeman stood fixed, now shook the heavy hammer within an\ninch of his teeth; meanwhile repeating a string of insufferable\nmaledictions.  Retreating not the thousandth part of an inch;\nstabbing him in the eye with the unflinching poniard of his glance,\nSteelkilt, clenching his right hand behind him and creepingly drawing\nit back, told his persecutor that if the hammer but grazed his cheek\nhe (Steelkilt) would murder him.  But, gentlemen, the fool had been\nbranded for the slaughter by the gods.  Immediately the hammer\ntouched the cheek; the next instant the lower jaw of the mate was\nstove in his head; he fell on the hatch spouting blood like a whale.\n\n\"Ere the cry could go aft Steelkilt was shaking one of the backstays\nleading far aloft to where two of his comrades were standing their\nmastheads.  They were both Canallers.\n\n\"'Canallers!' cried Don Pedro.  'We have seen many whale-ships in our\nharbours, but never heard of your Canallers.  Pardon: who and what are\nthey?'\n\n\"'Canallers, Don, are the boatmen belonging to our grand Erie Canal.\nYou must have heard of it.'\n\n\"'Nay, Senor; hereabouts in this dull, warm, most lazy, and\nhereditary land, we know but little of your vigorous North.'\n\n\"'Aye?  Well then, Don, refill my cup.  Your chicha's very fine; and\nere proceeding further I will tell ye what our Canallers are; for\nsuch information may throw side-light upon my story.'\n\n\"For three hundred and sixty miles, gentlemen, through the entire\nbreadth of the state of New York; through numerous populous cities\nand most thriving villages; through long, dismal, uninhabited swamps,\nand affluent, cultivated fields, unrivalled for fertility; by\nbilliard-room and bar-room; through the holy-of-holies of great\nforests; on Roman arches over Indian rivers; through sun and shade;\nby happy hearts or broken; through all the wide contrasting scenery\nof those noble Mohawk counties; and especially, by rows of snow-white\nchapels, whose spires stand almost like milestones, flows one\ncontinual stream of Venetianly corrupt and often lawless life.\nThere's your true Ashantee, gentlemen; there howl your pagans; where\nyou ever find them, next door to you; under the long-flung shadow,\nand the snug patronising lee of churches.  For by some curious\nfatality, as it is often noted of your metropolitan freebooters that\nthey ever encamp around the halls of justice, so sinners, gentlemen,\nmost abound in holiest vicinities.\n\n\"'Is that a friar passing?' said Don Pedro, looking downwards into\nthe crowded plazza, with humorous concern.\n\n\"'Well for our northern friend, Dame Isabella's Inquisition wanes in\nLima,' laughed Don Sebastian.  'Proceed, Senor.'\n\n\"'A moment!  Pardon!' cried another of the company.  'In the name of\nall us Limeese, I but desire to express to you, sir sailor, that we\nhave by no means overlooked your delicacy in not substituting present\nLima for distant Venice in your corrupt comparison.  Oh! do not bow\nand look surprised; you know the proverb all along this\ncoast--\"Corrupt as Lima.\"  It but bears out your saying, too;\nchurches more plentiful than billiard-tables, and for ever open--and\n\"Corrupt as Lima.\"  So, too, Venice; I have been there; the holy city\nof the blessed evangelist, St. Mark!--St. Dominic, purge it!  Your\ncup!  Thanks: here I refill; now, you pour out again.'\n\n\"Freely depicted in his own vocation, gentlemen, the Canaller would\nmake a fine dramatic hero, so abundantly and picturesquely wicked is\nhe.  Like Mark Antony, for days and days along his green-turfed,\nflowery Nile, he indolently floats, openly toying with his\nred-cheeked Cleopatra, ripening his apricot thigh upon the sunny\ndeck.  But ashore, all this effeminacy is dashed.  The brigandish\nguise which the Canaller so proudly sports; his slouched and\ngaily-ribboned hat betoken his grand features.  A terror to the\nsmiling innocence of the villages through which he floats; his swart\nvisage and bold swagger are not unshunned in cities.  Once a vagabond\non his own canal, I have received good turns from one of these\nCanallers; I thank him heartily; would fain be not ungrateful; but it\nis often one of the prime redeeming qualities of your man of\nviolence, that at times he has as stiff an arm to back a poor\nstranger in a strait, as to plunder a wealthy one.  In sum,\ngentlemen, what the wildness of this canal life is, is emphatically\nevinced by this; that our wild whale-fishery contains so many of its\nmost finished graduates, and that scarce any race of mankind, except\nSydney men, are so much distrusted by our whaling captains.  Nor does\nit at all diminish the curiousness of this matter, that to many\nthousands of our rural boys and young men born along its line, the\nprobationary life of the Grand Canal furnishes the sole transition\nbetween quietly reaping in a Christian corn-field, and recklessly\nploughing the waters of the most barbaric seas.\n\n\"'I see!  I see!' impetuously exclaimed Don Pedro, spilling his\nchicha upon his silvery ruffles.  'No need to travel!  The world's\none Lima.  I had thought, now, that at your temperate North the\ngenerations were cold and holy as the hills.--But the story.'\n\n\"I left off, gentlemen, where the Lakeman shook the backstay.\nHardly had he done so, when he was surrounded by the three junior\nmates and the four harpooneers, who all crowded him to the deck.  But\nsliding down the ropes like baleful comets, the two Canallers rushed\ninto the uproar, and sought to drag their man out of it towards the\nforecastle.  Others of the sailors joined with them in this attempt,\nand a twisted turmoil ensued; while standing out of harm's way, the\nvaliant captain danced up and down with a whale-pike, calling upon\nhis officers to manhandle that atrocious scoundrel, and smoke him\nalong to the quarter-deck.  At intervals, he ran close up to the\nrevolving border of the confusion, and prying into the heart of it\nwith his pike, sought to prick out the object of his resentment.  But\nSteelkilt and his desperadoes were too much for them all; they\nsucceeded in gaining the forecastle deck, where, hastily slewing\nabout three or four large casks in a line with the windlass, these\nsea-Parisians entrenched themselves behind the barricade.\n\n\"'Come out of that, ye pirates!' roared the captain, now menacing\nthem with a pistol in each hand, just brought to him by the steward.\n'Come out of that, ye cut-throats!'\n\n\"Steelkilt leaped on the barricade, and striding up and down there,\ndefied the worst the pistols could do; but gave the captain to\nunderstand distinctly, that his (Steelkilt's) death would be the\nsignal for a murderous mutiny on the part of all hands.  Fearing in\nhis heart lest this might prove but too true, the captain a little\ndesisted, but still commanded the insurgents instantly to return to\ntheir duty.\n\n\"'Will you promise not to touch us, if we do?' demanded their\nringleader.\n\n\"'Turn to! turn to!--I make no promise;--to your duty!  Do you want\nto sink the ship, by knocking off at a time like this?  Turn to!' and\nhe once more raised a pistol.\n\n\"'Sink the ship?' cried Steelkilt.  'Aye, let her sink.  Not a man of\nus turns to, unless you swear not to raise a rope-yarn against us.\nWhat say ye, men?' turning to his comrades.  A fierce cheer was their\nresponse.\n\n\"The Lakeman now patrolled the barricade, all the while keeping his\neye on the Captain, and jerking out such sentences as these:--'It's\nnot our fault; we didn't want it; I told him to take his hammer away;\nit was boy's business; he might have known me before this; I told him\nnot to prick the buffalo; I believe I have broken a finger here\nagainst his cursed jaw; ain't those mincing knives down in the\nforecastle there, men? look to those handspikes, my hearties.\nCaptain, by God, look to yourself; say the word; don't be a fool;\nforget it all; we are ready to turn to; treat us decently, and we're\nyour men; but we won't be flogged.'\n\n\"'Turn to!  I make no promises, turn to, I say!'\n\n\"'Look ye, now,' cried the Lakeman, flinging out his arm towards him,\n'there are a few of us here (and I am one of them) who have shipped\nfor the cruise, d'ye see; now as you well know, sir, we can claim our\ndischarge as soon as the anchor is down; so we don't want a row; it's\nnot our interest; we want to be peaceable; we are ready to work, but\nwe won't be flogged.'\n\n\"'Turn to!' roared the Captain.\n\n\"Steelkilt glanced round him a moment, and then said:--'I tell you\nwhat it is now, Captain, rather than kill ye, and be hung for such a\nshabby rascal, we won't lift a hand against ye unless ye attack us;\nbut till you say the word about not flogging us, we don't do a hand's\nturn.'\n\n\"'Down into the forecastle then, down with ye, I'll keep ye there\ntill ye're sick of it.  Down ye go.'\n\n\"'Shall we?' cried the ringleader to his men.  Most of them were\nagainst it; but at length, in obedience to Steelkilt, they preceded\nhim down into their dark den, growlingly disappearing, like bears\ninto a cave.\n\n\"As the Lakeman's bare head was just level with the planks, the\nCaptain and his posse leaped the barricade, and rapidly drawing over\nthe slide of the scuttle, planted their group of hands upon it, and\nloudly called for the steward to bring the heavy brass padlock\nbelonging to the companionway.\n\nThen opening the slide a little, the Captain whispered something down\nthe crack, closed it, and turned the key upon them--ten in\nnumber--leaving on deck some twenty or more, who thus far had\nremained neutral.\n\n\"All night a wide-awake watch was kept by all the officers, forward\nand aft, especially about the forecastle scuttle and fore hatchway;\nat which last place it was feared the insurgents might emerge, after\nbreaking through the bulkhead below.  But the hours of darkness\npassed in peace; the men who still remained at their duty toiling\nhard at the pumps, whose clinking and clanking at intervals through\nthe dreary night dismally resounded through the ship.\n\n\"At sunrise the Captain went forward, and knocking on the deck,\nsummoned the prisoners to work; but with a yell they refused.  Water\nwas then lowered down to them, and a couple of handfuls of biscuit\nwere tossed after it; when again turning the key upon them and\npocketing it, the Captain returned to the quarter-deck.  Twice every\nday for three days this was repeated; but on the fourth morning a\nconfused wrangling, and then a scuffling was heard, as the customary\nsummons was delivered; and suddenly four men burst up from the\nforecastle, saying they were ready to turn to.  The fetid closeness\nof the air, and a famishing diet, united perhaps to some fears of\nultimate retribution, had constrained them to surrender at\ndiscretion.  Emboldened by this, the Captain reiterated his demand to\nthe rest, but Steelkilt shouted up to him a terrific hint to stop his\nbabbling and betake himself where he belonged.  On the fifth morning\nthree others of the mutineers bolted up into the air from the\ndesperate arms below that sought to restrain them.  Only three were\nleft.\n\n\"'Better turn to, now?' said the Captain with a heartless jeer.\n\n\"'Shut us up again, will ye!' cried Steelkilt.\n\n\"'Oh certainly,' the Captain, and the key clicked.\n\n\"It was at this point, gentlemen, that enraged by the defection of\nseven of his former associates, and stung by the mocking voice that\nhad last hailed him, and maddened by his long entombment in a place\nas black as the bowels of despair; it was then that Steelkilt\nproposed to the two Canallers, thus far apparently of one mind with\nhim, to burst out of their hole at the next summoning of the\ngarrison; and armed with their keen mincing knives (long, crescentic,\nheavy implements with a handle at each end) run amuck from the\nbowsprit to the taffrail; and if by any devilishness of desperation\npossible, seize the ship.  For himself, he would do this, he said,\nwhether they joined him or not.  That was the last night he should\nspend in that den.  But the scheme met with no opposition on the part\nof the other two; they swore they were ready for that, or for any\nother mad thing, for anything in short but a surrender.  And what was\nmore, they each insisted upon being the first man on deck, when the\ntime to make the rush should come.  But to this their leader as\nfiercely objected, reserving that priority for himself; particularly\nas his two comrades would not yield, the one to the other, in the\nmatter; and both of them could not be first, for the ladder would but\nadmit one man at a time.  And here, gentlemen, the foul play of these\nmiscreants must come out.\n\n\"Upon hearing the frantic project of their leader, each in his own\nseparate soul had suddenly lighted, it would seem, upon the same\npiece of treachery, namely: to be foremost in breaking out, in\norder to be the first of the three, though the last of the ten, to\nsurrender; and thereby secure whatever small chance of pardon such\nconduct might merit.  But when Steelkilt made known his determination\nstill to lead them to the last, they in some way, by some subtle\nchemistry of villany, mixed their before secret treacheries together;\nand when their leader fell into a doze, verbally opened their souls\nto each other in three sentences; and bound the sleeper with cords,\nand gagged him with cords; and shrieked out for the Captain at\nmidnight.\n\n\"Thinking murder at hand, and smelling in the dark for the blood, he\nand all his armed mates and harpooneers rushed for the forecastle.\nIn a few minutes the scuttle was opened, and, bound hand and foot,\nthe still struggling ringleader was shoved up into the air by his\nperfidious allies, who at once claimed the honour of securing a man\nwho had been fully ripe for murder.  But all these were collared, and\ndragged along the deck like dead cattle; and, side by side, were\nseized up into the mizzen rigging, like three quarters of meat, and\nthere they hung till morning.  'Damn ye,' cried the Captain, pacing\nto and fro before them, 'the vultures would not touch ye, ye\nvillains!'\n\n\"At sunrise he summoned all hands; and separating those who had\nrebelled from those who had taken no part in the mutiny, he told the\nformer that he had a good mind to flog them all round--thought, upon\nthe whole, he would do so--he ought to--justice demanded it; but for\nthe present, considering their timely surrender, he would let them go\nwith a reprimand, which he accordingly administered in the vernacular.\n\n\"'But as for you, ye carrion rogues,' turning to the three men in the\nrigging--'for you, I mean to mince ye up for the try-pots;' and,\nseizing a rope, he applied it with all his might to the backs of the\ntwo traitors, till they yelled no more, but lifelessly hung their\nheads sideways, as the two crucified thieves are drawn.\n\n\"'My wrist is sprained with ye!' he cried, at last; 'but there is\nstill rope enough left for you, my fine bantam, that wouldn't give\nup.  Take that gag from his mouth, and let us hear what he can say\nfor himself.'\n\n\"For a moment the exhausted mutineer made a tremulous motion of his\ncramped jaws, and then painfully twisting round his head, said in a\nsort of hiss, 'What I say is this--and mind it well--if you flog me,\nI murder you!'\n\n\"'Say ye so? then see how ye frighten me'--and the Captain drew off\nwith the rope to strike.\n\n\"'Best not,' hissed the Lakeman.\n\n\"'But I must,'--and the rope was once more drawn back for the stroke.\n\n\"Steelkilt here hissed out something, inaudible to all but the\nCaptain; who, to the amazement of all hands, started back, paced the\ndeck rapidly two or three times, and then suddenly throwing down his\nrope, said, 'I won't do it--let him go--cut him down: d'ye hear?'\n\nBut as the junior mates were hurrying to execute the order, a pale\nman, with a bandaged head, arrested them--Radney the chief mate.\nEver since the blow, he had lain in his berth; but that morning,\nhearing the tumult on the deck, he had crept out, and thus far had\nwatched the whole scene.  Such was the state of his mouth, that he\ncould hardly speak; but mumbling something about his being willing\nand able to do what the captain dared not attempt, he snatched the\nrope and advanced to his pinioned foe.\n\n\"'You are a coward!' hissed the Lakeman.\n\n\"'So I am, but take that.'  The mate was in the very act of striking,\nwhen another hiss stayed his uplifted arm.  He paused: and then\npausing no more, made good his word, spite of Steelkilt's threat,\nwhatever that might have been.  The three men were then cut down, all\nhands were turned to, and, sullenly worked by the moody seamen, the\niron pumps clanged as before.\n\n\"Just after dark that day, when one watch had retired below, a clamor\nwas heard in the forecastle; and the two trembling traitors running\nup, besieged the cabin door, saying they durst not consort with the\ncrew.  Entreaties, cuffs, and kicks could not drive them back, so at\ntheir own instance they were put down in the ship's run for\nsalvation.  Still, no sign of mutiny reappeared among the rest.  On\nthe contrary, it seemed, that mainly at Steelkilt's instigation, they\nhad resolved to maintain the strictest peacefulness, obey all orders\nto the last, and, when the ship reached port, desert her in a body.\nBut in order to insure the speediest end to the voyage, they all\nagreed to another thing--namely, not to sing out for whales, in case\nany should be discovered.  For, spite of her leak, and spite of all her\nother perils, the Town-Ho still maintained her mast-heads, and her\ncaptain was just as willing to lower for a fish that moment, as on\nthe day his craft first struck the cruising ground; and Radney the mate\nwas quite as ready to change his berth for a boat, and with his\nbandaged mouth seek to gag in death the vital jaw of the whale.\n\n\"But though the Lakeman had induced the seamen to adopt this sort of\npassiveness in their conduct, he kept his own counsel (at least till\nall was over) concerning his own proper and private revenge upon the\nman who had stung him in the ventricles of his heart.  He was in\nRadney the chief mate's watch; and as if the infatuated man sought to\nrun more than half way to meet his doom, after the scene at the\nrigging, he insisted, against the express counsel of the captain,\nupon resuming the head of his watch at night.  Upon this, and one or\ntwo other circumstances, Steelkilt systematically built the plan of\nhis revenge.\n\n\"During the night, Radney had an unseamanlike way of sitting on the\nbulwarks of the quarter-deck, and leaning his arm upon the gunwale of\nthe boat which was hoisted up there, a little above the ship's side.\nIn this attitude, it was well known, he sometimes dozed.  There was a\nconsiderable vacancy between the boat and the ship, and down between\nthis was the sea.  Steelkilt calculated his time, and found that his\nnext trick at the helm would come round at two o'clock, in the\nmorning of the third day from that in which he had been betrayed.  At\nhis leisure, he employed the interval in braiding something very\ncarefully in his watches below.\n\n\"'What are you making there?' said a shipmate.\n\n\"'What do you think? what does it look like?'\n\n\"'Like a lanyard for your bag; but it's an odd one, seems to me.'\n\n'Yes, rather oddish,' said the Lakeman, holding it at arm's length\nbefore him; 'but I think it will answer.  Shipmate, I haven't enough\ntwine,--have you any?'\n\n\"But there was none in the forecastle.\n\n\"'Then I must get some from old Rad;' and he rose to go aft.\n\n\"'You don't mean to go a begging to HIM!' said a sailor.\n\n\"'Why not?  Do you think he won't do me a turn, when it's to help\nhimself in the end, shipmate?' and going to the mate, he looked at\nhim quietly, and asked him for some twine to mend his hammock.  It\nwas given him--neither twine nor lanyard were seen again; but the\nnext night an iron ball, closely netted, partly rolled from the\npocket of the Lakeman's monkey jacket, as he was tucking the coat\ninto his hammock for a pillow.  Twenty-four hours after, his trick at\nthe silent helm--nigh to the man who was apt to doze over the grave\nalways ready dug to the seaman's hand--that fatal hour was then to\ncome; and in the fore-ordaining soul of Steelkilt, the mate was\nalready stark and stretched as a corpse, with his forehead crushed\nin.\n\n\"But, gentlemen, a fool saved the would-be murderer from the bloody\ndeed he had planned.  Yet complete revenge he had, and without being\nthe avenger.  For by a mysterious fatality, Heaven itself seemed to\nstep in to take out of his hands into its own the damning thing he\nwould have done.\n\n\"It was just between daybreak and sunrise of the morning of the\nsecond day, when they were washing down the decks, that a stupid\nTeneriffe man, drawing water in the main-chains, all at once shouted\nout, 'There she rolls! there she rolls!'  Jesu, what a whale!  It was\nMoby Dick.\n\n\"'Moby Dick!' cried Don Sebastian; 'St. Dominic!  Sir sailor, but do\nwhales have christenings?  Whom call you Moby Dick?'\n\n\"'A very white, and famous, and most deadly immortal monster,\nDon;--but that would be too long a story.'\n\n\"'How? how?' cried all the young Spaniards, crowding.\n\n\"'Nay, Dons, Dons--nay, nay!  I cannot rehearse that now.  Let me get\nmore into the air, Sirs.'\n\n\"'The chicha! the chicha!' cried Don Pedro; 'our vigorous friend looks\nfaint;--fill up his empty glass!'\n\n\"No need, gentlemen; one moment, and I proceed.--Now, gentlemen, so\nsuddenly perceiving the snowy whale within fifty yards of the\nship--forgetful of the compact among the crew--in the excitement of\nthe moment, the Teneriffe man had instinctively and involuntarily\nlifted his voice for the monster, though for some little time past it\nhad been plainly beheld from the three sullen mast-heads.  All was\nnow a phrensy.  'The White Whale--the White Whale!' was the cry from\ncaptain, mates, and harpooneers, who, undeterred by fearful rumours,\nwere all anxious to capture so famous and precious a fish; while the\ndogged crew eyed askance, and with curses, the appalling beauty of\nthe vast milky mass, that lit up by a horizontal spangling sun,\nshifted and glistened like a living opal in the blue morning sea.\nGentlemen, a strange fatality pervades the whole career of these\nevents, as if verily mapped out before the world itself was charted.\nThe mutineer was the bowsman of the mate, and when fast to a fish, it\nwas his duty to sit next him, while Radney stood up with his lance in\nthe prow, and haul in or slacken the line, at the word of command.\nMoreover, when the four boats were lowered, the mate's got the start;\nand none howled more fiercely with delight than did Steelkilt, as he\nstrained at his oar.  After a stiff pull, their harpooneer got fast,\nand, spear in hand, Radney sprang to the bow.  He was always a\nfurious man, it seems, in a boat.  And now his bandaged cry was, to\nbeach him on the whale's topmost back.  Nothing loath, his bowsman\nhauled him up and up, through a blinding foam that blent two\nwhitenesses together; till of a sudden the boat struck as against a\nsunken ledge, and keeling over, spilled out the standing mate.  That\ninstant, as he fell on the whale's slippery back, the boat righted,\nand was dashed aside by the swell, while Radney was tossed over into\nthe sea, on the other flank of the whale.  He struck out through the\nspray, and, for an instant, was dimly seen through that veil, wildly\nseeking to remove himself from the eye of Moby Dick.  But the whale\nrushed round in a sudden maelstrom; seized the swimmer between his\njaws; and rearing high up with him, plunged headlong again, and went\ndown.\n\n\"Meantime, at the first tap of the boat's bottom, the Lakeman had\nslackened the line, so as to drop astern from the whirlpool; calmly\nlooking on, he thought his own thoughts.  But a sudden, terrific,\ndownward jerking of the boat, quickly brought his knife to the line.\nHe cut it; and the whale was free.  But, at some distance, Moby Dick\nrose again, with some tatters of Radney's red woollen shirt, caught\nin the teeth that had destroyed him.  All four boats gave chase\nagain; but the whale eluded them, and finally wholly disappeared.\n\n\"In good time, the Town-Ho reached her port--a savage, solitary\nplace--where no civilized creature resided.  There, headed by the\nLakeman, all but five or six of the foremastmen deliberately\ndeserted among the palms; eventually, as it turned out, seizing a\nlarge double war-canoe of the savages, and setting sail for some\nother harbor.\n\n\"The ship's company being reduced to but a handful, the captain\ncalled upon the Islanders to assist him in the laborious business of\nheaving down the ship to stop the leak.  But to such unresting\nvigilance over their dangerous allies was this small band of whites\nnecessitated, both by night and by day, and so extreme was the hard\nwork they underwent, that upon the vessel being ready again for sea,\nthey were in such a weakened condition that the captain durst not put\noff with them in so heavy a vessel.  After taking counsel with his\nofficers, he anchored the ship as far off shore as possible; loaded\nand ran out his two cannon from the bows; stacked his muskets on the\npoop; and warning the Islanders not to approach the ship at their\nperil, took one man with him, and setting the sail of his best\nwhale-boat, steered straight before the wind for Tahiti, five hundred\nmiles distant, to procure a reinforcement to his crew.\n\n\"On the fourth day of the sail, a large canoe was descried, which\nseemed to have touched at a low isle of corals.  He steered away from\nit; but the savage craft bore down on him; and soon the voice of\nSteelkilt hailed him to heave to, or he would run him under water.\nThe captain presented a pistol.  With one foot on each prow of the\nyoked war-canoes, the Lakeman laughed him to scorn; assuring him that\nif the pistol so much as clicked in the lock, he would bury him in\nbubbles and foam.\n\n\"'What do you want of me?' cried the captain.\n\n\"'Where are you bound? and for what are you bound?' demanded\nSteelkilt; 'no lies.'\n\n\"'I am bound to Tahiti for more men.'\n\n\"'Very good.  Let me board you a moment--I come in peace.'  With that\nhe leaped from the canoe, swam to the boat; and climbing the gunwale,\nstood face to face with the captain.\n\n\"'Cross your arms, sir; throw back your head.  Now, repeat after me.\nAs soon as Steelkilt leaves me, I swear to beach this boat on yonder\nisland, and remain there six days.  If I do not, may lightning strike\nme!'\n\n\"'A pretty scholar,' laughed the Lakeman.  'Adios, Senor!' and\nleaping into the sea, he swam back to his comrades.\n\n\"Watching the boat till it was fairly beached, and drawn up to the\nroots of the cocoa-nut trees, Steelkilt made sail again, and in due\ntime arrived at Tahiti, his own place of destination.  There, luck\nbefriended him; two ships were about to sail for France, and were\nprovidentially in want of precisely that number of men which the\nsailor headed.  They embarked; and so for ever got the start of\ntheir former captain, had he been at all minded to work them legal\nretribution.\n\n\"Some ten days after the French ships sailed, the whale-boat arrived,\nand the captain was forced to enlist some of the more civilized\nTahitians, who had been somewhat used to the sea.  Chartering a small\nnative schooner, he returned with them to his vessel; and finding all\nright there, again resumed his cruisings.\n\n\"Where Steelkilt now is, gentlemen, none know; but upon the island of\nNantucket, the widow of Radney still turns to the sea which refuses\nto give up its dead; still in dreams sees the awful white whale that\ndestroyed him.\n\n\"'Are you through?' said Don Sebastian, quietly.\n\n\"'I am, Don.'\n\n\"'Then I entreat you, tell me if to the best of your own convictions,\nthis your story is in substance really true?  It is so passing\nwonderful!  Did you get it from an unquestionable source?  Bear with\nme if I seem to press.'\n\n\"'Also bear with all of us, sir sailor; for we all join in Don\nSebastian's suit,' cried the company, with exceeding interest.\n\n\"'Is there a copy of the Holy Evangelists in the Golden Inn,\ngentlemen?'\n\n\"'Nay,' said Don Sebastian; 'but I know a worthy priest near by, who\nwill quickly procure one for me.  I go for it; but are you well\nadvised? this may grow too serious.'\n\n\"'Will you be so good as to bring the priest also, Don?'\n\n\"'Though there are no Auto-da-Fe's in Lima now,' said one of the\ncompany to another; 'I fear our sailor friend runs risk of the\narchiepiscopacy.  Let us withdraw more out of the moonlight.  I see\nno need of this.'\n\n\"'Excuse me for running after you, Don Sebastian; but may I also beg\nthat you will be particular in procuring the largest sized\nEvangelists you can.'\n\n\n'This is the priest, he brings you the Evangelists,' said Don\nSebastian, gravely, returning with a tall and solemn figure.\n\n\"'Let me remove my hat.  Now, venerable priest, further into the\nlight, and hold the Holy Book before me that I may touch it.\n\n\"'So help me Heaven, and on my honour the story I have told ye,\ngentlemen, is in substance and its great items, true.  I know it to\nbe true; it happened on this ball; I trod the ship; I knew the crew;\nI have seen and talked with Steelkilt since the death of Radney.'\"\n\n\n\nCHAPTER 55\n\nOf the Monstrous Pictures of Whales.\n\n\nI shall ere long paint to you as well as one can without canvas,\nsomething like the true form of the whale as he actually appears to\nthe eye of the whaleman when in his own absolute body the whale is\nmoored alongside the whale-ship so that he can be fairly stepped upon\nthere.  It may be worth while, therefore, previously to advert to\nthose curious imaginary portraits of him which even down to the\npresent day confidently challenge the faith of the landsman.  It is\ntime to set the world right in this matter, by proving such pictures\nof the whale all wrong.\n\nIt may be that the primal source of all those pictorial delusions\nwill be found among the oldest Hindoo, Egyptian, and Grecian\nsculptures.  For ever since those inventive but unscrupulous times\nwhen on the marble panellings of temples, the pedestals of statues,\nand on shields, medallions, cups, and coins, the dolphin was drawn in\nscales of chain-armor like Saladin's, and a helmeted head like St.\nGeorge's; ever since then has something of the same sort of license\nprevailed, not only in most popular pictures of the whale, but in\nmany scientific presentations of him.\n\nNow, by all odds, the most ancient extant portrait anyways purporting\nto be the whale's, is to be found in the famous cavern-pagoda of\nElephanta, in India.  The Brahmins maintain that in the almost\nendless sculptures of that immemorial pagoda, all the trades and\npursuits, every conceivable avocation of man, were prefigured ages\nbefore any of them actually came into being.  No wonder then, that in\nsome sort our noble profession of whaling should have been there\nshadowed forth.  The Hindoo whale referred to, occurs in a separate\ndepartment of the wall, depicting the incarnation of Vishnu in the\nform of leviathan, learnedly known as the Matse Avatar.  But though\nthis sculpture is half man and half whale, so as only to give the\ntail of the latter, yet that small section of him is all wrong.  It\nlooks more like the tapering tail of an anaconda, than the broad palms\nof the true whale's majestic flukes.\n\nBut go to the old Galleries, and look now at a great Christian\npainter's portrait of this fish; for he succeeds no better than the\nantediluvian Hindoo.  It is Guido's picture of Perseus rescuing\nAndromeda from the sea-monster or whale.  Where did Guido get the\nmodel of such a strange creature as that?  Nor does Hogarth, in\npainting the same scene in his own \"Perseus Descending,\" make out one\nwhit better.  The huge corpulence of that Hogarthian monster\nundulates on the surface, scarcely drawing one inch of water.  It has\na sort of howdah on its back, and its distended tusked mouth into\nwhich the billows are rolling, might be taken for the Traitors' Gate\nleading from the Thames by water into the Tower.  Then, there are the\nProdromus whales of old Scotch Sibbald, and Jonah's whale, as\ndepicted in the prints of old Bibles and the cuts of old primers.\nWhat shall be said of these?  As for the book-binder's whale winding\nlike a vine-stalk round the stock of a descending anchor--as stamped\nand gilded on the backs and title-pages of many books both old and\nnew--that is a very picturesque but purely fabulous creature,\nimitated, I take it, from the like figures on antique vases.  Though\nuniversally denominated a dolphin, I nevertheless call this\nbook-binder's fish an attempt at a whale; because it was so intended\nwhen the device was first introduced.  It was introduced by an old\nItalian publisher somewhere about the 15th century, during the\nRevival of Learning; and in those days, and even down to a\ncomparatively late period, dolphins were popularly supposed to be a\nspecies of the Leviathan.\n\nIn the vignettes and other embellishments of some ancient books you\nwill at times meet with very curious touches at the whale, where all\nmanner of spouts, jets d'eau, hot springs and cold, Saratoga and\nBaden-Baden, come bubbling up from his unexhausted brain.  In the\ntitle-page of the original edition of the \"Advancement of Learning\"\nyou will find some curious whales.\n\nBut quitting all these unprofessional attempts, let us glance at\nthose pictures of leviathan purporting to be sober, scientific\ndelineations, by those who know.  In old Harris's collection of\nvoyages there are some plates of whales extracted from a Dutch book\nof voyages, A.D. 1671, entitled \"A Whaling Voyage to Spitzbergen in\nthe ship Jonas in the Whale, Peter Peterson of Friesland, master.\"\nIn one of those plates the whales, like great rafts of logs, are\nrepresented lying among ice-isles, with white bears running over\ntheir living backs.  In another plate, the prodigious blunder is made\nof representing the whale with perpendicular flukes.\n\nThen again, there is an imposing quarto, written by one Captain\nColnett, a Post Captain in the English navy, entitled \"A Voyage round\nCape Horn into the South Seas, for the purpose of extending the\nSpermaceti Whale Fisheries.\"  In this book is an outline purporting\nto be a \"Picture of a Physeter or Spermaceti whale, drawn by scale\nfrom one killed on the coast of Mexico, August, 1793, and hoisted on\ndeck.\"  I doubt not the captain had this veracious picture taken for\nthe benefit of his marines.  To mention but one thing about it, let\nme say that it has an eye which applied, according to the\naccompanying scale, to a full grown sperm whale, would make the eye\nof that whale a bow-window some five feet long.  Ah, my gallant\ncaptain, why did ye not give us Jonah looking out of that eye!\n\nNor are the most conscientious compilations of Natural History for\nthe benefit of the young and tender, free from the same heinousness\nof mistake.  Look at that popular work \"Goldsmith's Animated Nature.\"\nIn the abridged London edition of 1807, there are plates of an\nalleged \"whale\" and a \"narwhale.\"  I do not wish to seem inelegant,\nbut this unsightly whale looks much like an amputated sow; and, as\nfor the narwhale, one glimpse at it is enough to amaze one, that in\nthis nineteenth century such a hippogriff could be palmed for genuine\nupon any intelligent public of schoolboys.\n\nThen, again, in 1825, Bernard Germain, Count de Lacepede, a great\nnaturalist, published a scientific systemized whale book, wherein are\nseveral pictures of the different species of the Leviathan.  All\nthese are not only incorrect, but the picture of the Mysticetus or\nGreenland whale (that is to say, the Right whale), even Scoresby, a\nlong experienced man as touching that species, declares not to have\nits counterpart in nature.\n\nBut the placing of the cap-sheaf to all this blundering business was\nreserved for the scientific Frederick Cuvier, brother to the famous\nBaron.  In 1836, he published a Natural History of Whales, in which\nhe gives what he calls a picture of the Sperm Whale.  Before showing\nthat picture to any Nantucketer, you had best provide for your\nsummary retreat from Nantucket.  In a word, Frederick Cuvier's Sperm\nWhale is not a Sperm Whale, but a squash.  Of course, he never had\nthe benefit of a whaling voyage (such men seldom have), but whence he\nderived that picture, who can tell?  Perhaps he got it as his\nscientific predecessor in the same field, Desmarest, got one of his\nauthentic abortions; that is, from a Chinese drawing.  And what sort\nof lively lads with the pencil those Chinese are, many queer cups and\nsaucers inform us.\n\nAs for the sign-painters' whales seen in the streets hanging over the\nshops of oil-dealers, what shall be said of them?  They are generally\nRichard III. whales, with dromedary humps, and very savage;\nbreakfasting on three or four sailor tarts, that is whaleboats full\nof mariners: their deformities floundering in seas of blood and blue\npaint.\n\nBut these manifold mistakes in depicting the whale are not so very\nsurprising after all.  Consider!  Most of the scientific drawings\nhave been taken from the stranded fish; and these are about as\ncorrect as a drawing of a wrecked ship, with broken back, would\ncorrectly represent the noble animal itself in all its undashed pride\nof hull and spars.  Though elephants have stood for their\nfull-lengths, the living Leviathan has never yet fairly floated\nhimself for his portrait.  The living whale, in his full majesty and\nsignificance, is only to be seen at sea in unfathomable waters; and\nafloat the vast bulk of him is out of sight, like a launched\nline-of-battle ship; and out of that element it is a thing eternally\nimpossible for mortal man to hoist him bodily into the air, so as to\npreserve all his mighty swells and undulations.  And, not to speak of\nthe highly presumable difference of contour between a young sucking\nwhale and a full-grown Platonian Leviathan; yet, even in the case of\none of those young sucking whales hoisted to a ship's deck, such is\nthen the outlandish, eel-like, limbered, varying shape of him, that\nhis precise expression the devil himself could not catch.\n\nBut it may be fancied, that from the naked skeleton of the stranded\nwhale, accurate hints may be derived touching his true form.  Not at\nall.  For it is one of the more curious things about this Leviathan,\nthat his skeleton gives very little idea of his general shape.\nThough Jeremy Bentham's skeleton, which hangs for candelabra in the\nlibrary of one of his executors, correctly conveys the idea of a\nburly-browed utilitarian old gentleman, with all Jeremy's other\nleading personal characteristics; yet nothing of this kind could be\ninferred from any leviathan's articulated bones.  In fact, as the\ngreat Hunter says, the mere skeleton of the whale bears the same\nrelation to the fully invested and padded animal as the insect does\nto the chrysalis that so roundingly envelopes it.  This peculiarity\nis strikingly evinced in the head, as in some part of this book will\nbe incidentally shown.  It is also very curiously displayed in the\nside fin, the bones of which almost exactly answer to the bones of the\nhuman hand, minus only the thumb.  This fin has four regular\nbone-fingers, the index, middle, ring, and little finger.  But all\nthese are permanently lodged in their fleshy covering, as the human\nfingers in an artificial covering.  \"However recklessly the whale may\nsometimes serve us,\" said humorous Stubb one day, \"he can never be\ntruly said to handle us without mittens.\"\n\nFor all these reasons, then, any way you may look at it, you must\nneeds conclude that the great Leviathan is that one creature in the\nworld which must remain unpainted to the last.  True, one portrait\nmay hit the mark much nearer than another, but none can hit it with\nany very considerable degree of exactness.  So there is no earthly\nway of finding out precisely what the whale really looks like.  And\nthe only mode in which you can derive even a tolerable idea of his\nliving contour, is by going a whaling yourself; but by so doing, you\nrun no small risk of being eternally stove and sunk by him.\nWherefore, it seems to me you had best not be too fastidious in your\ncuriosity touching this Leviathan.\n\n\n\nCHAPTER 56\n\nOf the Less Erroneous Pictures of Whales, and the True Pictures of\nWhaling Scenes.\n\n\nIn connexion with the monstrous pictures of whales, I am strongly\ntempted here to enter upon those still more monstrous stories of them\nwhich are to be found in certain books, both ancient and modern,\nespecially in Pliny, Purchas, Hackluyt, Harris, Cuvier, etc.  But I\npass that matter by.\n\nI know of only four published outlines of the great Sperm Whale;\nColnett's, Huggins's, Frederick Cuvier's, and Beale's.  In the\nprevious chapter Colnett and Cuvier have been referred to.  Huggins's\nis far better than theirs; but, by great odds, Beale's is the best.\nAll Beale's drawings of this whale are good, excepting the middle\nfigure in the picture of three whales in various attitudes, capping\nhis second chapter.  His frontispiece, boats attacking Sperm Whales,\nthough no doubt calculated to excite the civil scepticism of some\nparlor men, is admirably correct and life-like in its general effect.\nSome of the Sperm Whale drawings in J.  Ross Browne are pretty\ncorrect in contour; but they are wretchedly engraved.  That is not\nhis fault though.\n\nOf the Right Whale, the best outline pictures are in Scoresby; but\nthey are drawn on too small a scale to convey a desirable impression.\nHe has but one picture of whaling scenes, and this is a sad\ndeficiency, because it is by such pictures only, when at all well\ndone, that you can derive anything like a truthful idea of the living\nwhale as seen by his living hunters.\n\nBut, taken for all in all, by far the finest, though in some details\nnot the most correct, presentations of whales and whaling scenes to\nbe anywhere found, are two large French engravings, well executed,\nand taken from paintings by one Garnery.  Respectively, they\nrepresent attacks on the Sperm and Right Whale.  In the first\nengraving a noble Sperm Whale is depicted in full majesty of might,\njust risen beneath the boat from the profundities of the ocean, and\nbearing high in the air upon his back the terrific wreck of the\nstoven planks.  The prow of the boat is partially unbroken, and is\ndrawn just balancing upon the monster's spine; and standing in that\nprow, for that one single incomputable flash of time, you behold an\noarsman, half shrouded by the incensed boiling spout of the whale,\nand in the act of leaping, as if from a precipice.  The action of the\nwhole thing is wonderfully good and true.  The half-emptied line-tub\nfloats on the whitened sea; the wooden poles of the spilled harpoons\nobliquely bob in it; the heads of the swimming crew are scattered\nabout the whale in contrasting expressions of affright; while in the\nblack stormy distance the ship is bearing down upon the scene.\nSerious fault might be found with the anatomical details of this\nwhale, but let that pass; since, for the life of me, I could not draw\nso good a one.\n\nIn the second engraving, the boat is in the act of drawing alongside\nthe barnacled flank of a large running Right Whale, that rolls his\nblack weedy bulk in the sea like some mossy rock-slide from the\nPatagonian cliffs.  His jets are erect, full, and black like soot; so\nthat from so abounding a smoke in the chimney, you would think there\nmust be a brave supper cooking in the great bowels below.  Sea fowls\nare pecking at the small crabs, shell-fish, and other sea candies and\nmaccaroni, which the Right Whale sometimes carries on his pestilent\nback.  And all the while the thick-lipped leviathan is rushing\nthrough the deep, leaving tons of tumultuous white curds in his wake,\nand causing the slight boat to rock in the swells like a skiff caught\nnigh the paddle-wheels of an ocean steamer.  Thus, the foreground is\nall raging commotion; but behind, in admirable artistic contrast, is\nthe glassy level of a sea becalmed, the drooping unstarched sails of\nthe powerless ship, and the inert mass of a dead whale, a conquered\nfortress, with the flag of capture lazily hanging from the whale-pole\ninserted into his spout-hole.\n\nWho Garnery the painter is, or was, I know not.  But my life for it\nhe was either practically conversant with his subject, or else\nmarvellously tutored by some experienced whaleman.  The French are\nthe lads for painting action.  Go and gaze upon all the paintings of\nEurope, and where will you find such a gallery of living and\nbreathing commotion on canvas, as in that triumphal hall at\nVersailles; where the beholder fights his way, pell-mell, through the\nconsecutive great battles of France; where every sword seems a flash\nof the Northern Lights, and the successive armed kings and Emperors\ndash by, like a charge of crowned centaurs?  Not wholly unworthy of a\nplace in that gallery, are these sea battle-pieces of Garnery.\n\nThe natural aptitude of the French for seizing the picturesqueness of\nthings seems to be peculiarly evinced in what paintings and\nengravings they have of their whaling scenes.  With not one tenth of\nEngland's experience in the fishery, and not the thousandth part of\nthat of the Americans, they have nevertheless furnished both nations\nwith the only finished sketches at all capable of conveying the real\nspirit of the whale hunt.  For the most part, the English and\nAmerican whale draughtsmen seem entirely content with presenting the\nmechanical outline of things, such as the vacant profile of the\nwhale; which, so far as picturesqueness of effect is concerned, is\nabout tantamount to sketching the profile of a pyramid.  Even\nScoresby, the justly renowned Right whaleman, after giving us a stiff\nfull length of the Greenland whale, and three or four delicate\nminiatures of narwhales and porpoises, treats us to a series of\nclassical engravings of boat hooks, chopping knives, and grapnels;\nand with the microscopic diligence of a Leuwenhoeck submits to the\ninspection of a shivering world ninety-six fac-similes of magnified\nArctic snow crystals.  I mean no disparagement to the excellent\nvoyager (I honour him for a veteran), but in so important a matter it\nwas certainly an oversight not to have procured for every crystal a\nsworn affidavit taken before a Greenland Justice of the Peace.\n\nIn addition to those fine engravings from Garnery, there are two\nother French engravings worthy of note, by some one who subscribes\nhimself \"H.  Durand.\"  One of them, though not precisely adapted to\nour present purpose, nevertheless deserves mention on other accounts.\nIt is a quiet noon-scene among the isles of the Pacific; a French\nwhaler anchored, inshore, in a calm, and lazily taking water on\nboard; the loosened sails of the ship, and the long leaves of the\npalms in the background, both drooping together in the breezeless\nair.  The effect is very fine, when considered with reference to its\npresenting the hardy fishermen under one of their few aspects of\noriental repose.  The other engraving is quite a different affair:\nthe ship hove-to upon the open sea, and in the very heart of the\nLeviathanic life, with a Right Whale alongside; the vessel (in the\nact of cutting-in) hove over to the monster as if to a quay; and a\nboat, hurriedly pushing off from this scene of activity, is about\ngiving chase to whales in the distance.  The harpoons and lances lie\nlevelled for use; three oarsmen are just setting the mast in its\nhole; while from a sudden roll of the sea, the little craft stands\nhalf-erect out of the water, like a rearing horse.  From the ship,\nthe smoke of the torments of the boiling whale is going up like the\nsmoke over a village of smithies; and to windward, a black cloud,\nrising up with earnest of squalls and rains, seems to quicken the\nactivity of the excited seamen.\n\n\n\nCHAPTER 57\n\nOf Whales in Paint; in Teeth; in Wood; in Sheet-Iron; in Stone; in\nMountains; in Stars.\n\n\nOn Tower-hill, as you go down to the London docks, you may have seen\na crippled beggar (or KEDGER, as the sailors say) holding a painted\nboard before him, representing the tragic scene in which he lost his\nleg.  There are three whales and three boats; and one of the boats\n(presumed to contain the missing leg in all its original integrity)\nis being crunched by the jaws of the foremost whale.  Any time these\nten years, they tell me, has that man held up that picture, and\nexhibited that stump to an incredulous world.  But the time of his\njustification has now come.  His three whales are as good whales as\nwere ever published in Wapping, at any rate; and his stump as\nunquestionable a stump as any you will find in the western clearings.\nBut, though for ever mounted on that stump, never a stump-speech\ndoes the poor whaleman make; but, with downcast eyes, stands ruefully\ncontemplating his own amputation.\n\nThroughout the Pacific, and also in Nantucket, and New Bedford, and\nSag Harbor, you will come across lively sketches of whales and\nwhaling-scenes, graven by the fishermen themselves on Sperm\nWhale-teeth, or ladies' busks wrought out of the Right Whale-bone,\nand other like skrimshander articles, as the whalemen call the\nnumerous little ingenious contrivances they elaborately carve out of\nthe rough material, in their hours of ocean leisure.  Some of them\nhave little boxes of dentistical-looking implements, specially\nintended for the skrimshandering business.  But, in general, they\ntoil with their jack-knives alone; and, with that almost omnipotent\ntool of the sailor, they will turn you out anything you please, in\nthe way of a mariner's fancy.\n\nLong exile from Christendom and civilization inevitably restores a\nman to that condition in which God placed him, i.e. what is called\nsavagery.  Your true whale-hunter is as much a savage as an Iroquois.\nI myself am a savage, owning no allegiance but to the King of the\nCannibals; and ready at any moment to rebel against him.\n\nNow, one of the peculiar characteristics of the savage in his\ndomestic hours, is his wonderful patience of industry.  An ancient\nHawaiian war-club or spear-paddle, in its full multiplicity and\nelaboration of carving, is as great a trophy of human perseverance as\na Latin lexicon.  For, with but a bit of broken sea-shell or a\nshark's tooth, that miraculous intricacy of wooden net-work has been\nachieved; and it has cost steady years of steady application.\n\nAs with the Hawaiian savage, so with the white sailor-savage.  With\nthe same marvellous patience, and with the same single shark's tooth,\nof his one poor jack-knife, he will carve you a bit of bone\nsculpture, not quite as workmanlike, but as close packed in its\nmaziness of design, as the Greek savage, Achilles's shield; and full\nof barbaric spirit and suggestiveness, as the prints of that fine old\nDutch savage, Albert Durer.\n\nWooden whales, or whales cut in profile out of the small dark slabs\nof the noble South Sea war-wood, are frequently met with in the\nforecastles of American whalers.  Some of them are done with much\naccuracy.\n\nAt some old gable-roofed country houses you will see brass whales\nhung by the tail for knockers to the road-side door.  When the porter\nis sleepy, the anvil-headed whale would be best.  But these knocking\nwhales are seldom remarkable as faithful essays.  On the spires of\nsome old-fashioned churches you will see sheet-iron whales placed\nthere for weather-cocks; but they are so elevated, and besides that\nare to all intents and purposes so labelled with \"HANDS OFF!\" you\ncannot examine them closely enough to decide upon their merit.\n\nIn bony, ribby regions of the earth, where at the base of high broken\ncliffs masses of rock lie strewn in fantastic groupings upon the\nplain, you will often discover images as of the petrified forms of\nthe Leviathan partly merged in grass, which of a windy day breaks\nagainst them in a surf of green surges.\n\nThen, again, in mountainous countries where the traveller is\ncontinually girdled by amphitheatrical heights; here and there from\nsome lucky point of view you will catch passing glimpses of the\nprofiles of whales defined along the undulating ridges.  But you must\nbe a thorough whaleman, to see these sights; and not only that, but\nif you wish to return to such a sight again, you must be sure and\ntake the exact intersecting latitude and longitude of your first\nstand-point, else so chance-like are such observations of the hills,\nthat your precise, previous stand-point would require a laborious\nre-discovery; like the Soloma Islands, which still remain incognita,\nthough once high-ruffed Mendanna trod them and old Figuera\nchronicled them.\n\nNor when expandingly lifted by your subject, can you fail to trace\nout great whales in the starry heavens, and boats in pursuit of them;\nas when long filled with thoughts of war the Eastern nations saw\narmies locked in battle among the clouds.  Thus at the North have I\nchased Leviathan round and round the Pole with the revolutions of the\nbright points that first defined him to me.  And beneath the\neffulgent Antarctic skies I have boarded the Argo-Navis, and joined\nthe chase against the starry Cetus far beyond the utmost stretch of\nHydrus and the Flying Fish.\n\nWith a frigate's anchors for my bridle-bitts and fasces of harpoons\nfor spurs, would I could mount that whale and leap the topmost skies,\nto see whether the fabled heavens with all their countless tents\nreally lie encamped beyond my mortal sight!\n\n\n\nCHAPTER 58\n\nBrit.\n\n\nSteering north-eastward from the Crozetts, we fell in with vast\nmeadows of brit, the minute, yellow substance, upon which the Right\nWhale largely feeds.  For leagues and leagues it undulated round us,\nso that we seemed to be sailing through boundless fields of ripe and\ngolden wheat.\n\nOn the second day, numbers of Right Whales were seen, who, secure\nfrom the attack of a Sperm Whaler like the Pequod, with open jaws\nsluggishly swam through the brit, which, adhering to the fringing\nfibres of that wondrous Venetian blind in their mouths, was in that\nmanner separated from the water that escaped at the lip.\n\nAs morning mowers, who side by side slowly and seethingly advance\ntheir scythes through the long wet grass of marshy meads; even so\nthese monsters swam, making a strange, grassy, cutting sound; and\nleaving behind them endless swaths of blue upon the yellow sea.*\n\n\n*That part of the sea known among whalemen as the \"Brazil Banks\" does\nnot bear that name as the Banks of Newfoundland do, because of there\nbeing shallows and soundings there, but because of this remarkable\nmeadow-like appearance, caused by the vast drifts of brit continually\nfloating in those latitudes, where the Right Whale is often chased.\n\n\nBut it was only the sound they made as they parted the brit which at\nall reminded one of mowers.  Seen from the mast-heads, especially\nwhen they paused and were stationary for a while, their vast black\nforms looked more like lifeless masses of rock than anything else.\nAnd as in the great hunting countries of India, the stranger at a\ndistance will sometimes pass on the plains recumbent elephants\nwithout knowing them to be such, taking them for bare, blackened\nelevations of the soil; even so, often, with him, who for the first\ntime beholds this species of the leviathans of the sea.  And even\nwhen recognised at last, their immense magnitude renders it very\nhard really to believe that such bulky masses of overgrowth can\npossibly be instinct, in all parts, with the same sort of life that\nlives in a dog or a horse.\n\nIndeed, in other respects, you can hardly regard any creatures of the\ndeep with the same feelings that you do those of the shore.  For\nthough some old naturalists have maintained that all creatures of the\nland are of their kind in the sea; and though taking a broad general\nview of the thing, this may very well be; yet coming to specialties,\nwhere, for example, does the ocean furnish any fish that in\ndisposition answers to the sagacious kindness of the dog?  The\naccursed shark alone can in any generic respect be said to bear\ncomparative analogy to him.\n\nBut though, to landsmen in general, the native inhabitants of the\nseas have ever been regarded with emotions unspeakably unsocial and\nrepelling; though we know the sea to be an everlasting terra\nincognita, so that Columbus sailed over numberless unknown worlds to\ndiscover his one superficial western one; though, by vast odds, the\nmost terrific of all mortal disasters have immemorially and\nindiscriminately befallen tens and hundreds of thousands of those who\nhave gone upon the waters; though but a moment's consideration will\nteach, that however baby man may brag of his science and skill, and\nhowever much, in a flattering future, that science and skill may\naugment; yet for ever and for ever, to the crack of doom, the sea\nwill insult and murder him, and pulverize the stateliest, stiffest\nfrigate he can make; nevertheless, by the continual repetition of\nthese very impressions, man has lost that sense of the full awfulness\nof the sea which aboriginally belongs to it.\n\nThe first boat we read of, floated on an ocean, that with Portuguese\nvengeance had whelmed a whole world without leaving so much as a\nwidow.  That same ocean rolls now; that same ocean destroyed the\nwrecked ships of last year.  Yea, foolish mortals, Noah's flood is\nnot yet subsided; two thirds of the fair world it yet covers.\n\nWherein differ the sea and the land, that a miracle upon one is not a\nmiracle upon the other?  Preternatural terrors rested upon the\nHebrews, when under the feet of Korah and his company the live ground\nopened and swallowed them up for ever; yet not a modern sun ever\nsets, but in precisely the same manner the live sea swallows up ships\nand crews.\n\nBut not only is the sea such a foe to man who is an alien to it, but\nit is also a fiend to its own off-spring; worse than the Persian host\nwho murdered his own guests; sparing not the creatures which itself\nhath spawned.  Like a savage tigress that tossing in the jungle\noverlays her own cubs, so the sea dashes even the mightiest whales\nagainst the rocks, and leaves them there side by side with the split\nwrecks of ships.  No mercy, no power but its own controls it.\nPanting and snorting like a mad battle steed that has lost its rider,\nthe masterless ocean overruns the globe.\n\nConsider the subtleness of the sea; how its most dreaded creatures\nglide under water, unapparent for the most part, and treacherously\nhidden beneath the loveliest tints of azure.  Consider also the\ndevilish brilliance and beauty of many of its most remorseless\ntribes, as the dainty embellished shape of many species of sharks.\nConsider, once more, the universal cannibalism of the sea; all whose\ncreatures prey upon each other, carrying on eternal war since the\nworld began.\n\nConsider all this; and then turn to this green, gentle, and most\ndocile earth; consider them both, the sea and the land; and do you\nnot find a strange analogy to something in yourself?  For as this\nappalling ocean surrounds the verdant land, so in the soul of man\nthere lies one insular Tahiti, full of peace and joy, but encompassed\nby all the horrors of the half known life.  God keep thee!  Push not\noff from that isle, thou canst never return!\n\n\nCHAPTER 59\n\nSquid.\n\n\nSlowly wading through the meadows of brit, the Pequod still held on\nher way north-eastward towards the island of Java; a gentle air\nimpelling her keel, so that in the surrounding serenity her three\ntall tapering masts mildly waved to that languid breeze, as three\nmild palms on a plain.  And still, at wide intervals in the silvery\nnight, the lonely, alluring jet would be seen.\n\nBut one transparent blue morning, when a stillness almost\npreternatural spread over the sea, however unattended with any\nstagnant calm; when the long burnished sun-glade on the waters seemed\na golden finger laid across them, enjoining some secrecy; when the\nslippered waves whispered together as they softly ran on; in this\nprofound hush of the visible sphere a strange spectre was seen by\nDaggoo from the main-mast-head.\n\nIn the distance, a great white mass lazily rose, and rising higher\nand higher, and disentangling itself from the azure, at last gleamed\nbefore our prow like a snow-slide, new slid from the hills.  Thus\nglistening for a moment, as slowly it subsided, and sank.  Then once\nmore arose, and silently gleamed.  It seemed not a whale; and yet is\nthis Moby Dick? thought Daggoo.  Again the phantom went down, but on\nre-appearing once more, with a stiletto-like cry that startled every\nman from his nod, the negro yelled out--\"There! there again! there\nshe breaches! right ahead!  The White Whale, the White Whale!\"\n\nUpon this, the seamen rushed to the yard-arms, as in swarming-time\nthe bees rush to the boughs.  Bare-headed in the sultry sun, Ahab\nstood on the bowsprit, and with one hand pushed far behind in\nreadiness to wave his orders to the helmsman, cast his eager glance\nin the direction indicated aloft by the outstretched motionless arm\nof Daggoo.\n\nWhether the flitting attendance of the one still and solitary jet had\ngradually worked upon Ahab, so that he was now prepared to connect\nthe ideas of mildness and repose with the first sight of the\nparticular whale he pursued; however this was, or whether his\neagerness betrayed him; whichever way it might have been, no sooner\ndid he distinctly perceive the white mass, than with a quick\nintensity he instantly gave orders for lowering.\n\nThe four boats were soon on the water; Ahab's in advance, and all\nswiftly pulling towards their prey.  Soon it went down, and while,\nwith oars suspended, we were awaiting its reappearance, lo! in the\nsame spot where it sank, once more it slowly rose.  Almost forgetting\nfor the moment all thoughts of Moby Dick, we now gazed at the most\nwondrous phenomenon which the secret seas have hitherto revealed to\nmankind.  A vast pulpy mass, furlongs in length and breadth, of a\nglancing cream-colour, lay floating on the water, innumerable long\narms radiating from its centre, and curling and twisting like a nest\nof anacondas, as if blindly to clutch at any hapless object within\nreach.  No perceptible face or front did it have; no conceivable\ntoken of either sensation or instinct; but undulated there on the\nbillows, an unearthly, formless, chance-like apparition of life.\n\nAs with a low sucking sound it slowly disappeared again, Starbuck\nstill gazing at the agitated waters where it had sunk, with a wild\nvoice exclaimed--\"Almost rather had I seen Moby Dick and fought him,\nthan to have seen thee, thou white ghost!\"\n\n\"What was it, Sir?\" said Flask.\n\n\"The great live squid, which, they say, few whale-ships ever beheld,\nand returned to their ports to tell of it.\"\n\nBut Ahab said nothing; turning his boat, he sailed back to the\nvessel; the rest as silently following.\n\nWhatever superstitions the sperm whalemen in general have connected\nwith the sight of this object, certain it is, that a glimpse of it\nbeing so very unusual, that circumstance has gone far to invest it\nwith portentousness.  So rarely is it beheld, that though one and all\nof them declare it to be the largest animated thing in the ocean, yet\nvery few of them have any but the most vague ideas concerning its\ntrue nature and form; notwithstanding, they believe it to furnish to\nthe sperm whale his only food.  For though other species of whales\nfind their food above water, and may be seen by man in the act of\nfeeding, the spermaceti whale obtains his whole food in unknown zones\nbelow the surface; and only by inference is it that any one can tell\nof what, precisely, that food consists.  At times, when closely\npursued, he will disgorge what are supposed to be the detached arms\nof the squid; some of them thus exhibited exceeding twenty and thirty\nfeet in length.  They fancy that the monster to which these arms\nbelonged ordinarily clings by them to the bed of the ocean; and that\nthe sperm whale, unlike other species, is supplied with teeth in\norder to attack and tear it.\n\nThere seems some ground to imagine that the great Kraken of Bishop\nPontoppodan may ultimately resolve itself into Squid.  The manner in\nwhich the Bishop describes it, as alternately rising and sinking,\nwith some other particulars he narrates, in all this the two\ncorrespond.  But much abatement is necessary with respect to the\nincredible bulk he assigns it.\n\nBy some naturalists who have vaguely heard rumors of the mysterious\ncreature, here spoken of, it is included among the class of\ncuttle-fish, to which, indeed, in certain external respects it would\nseem to belong, but only as the Anak of the tribe.\n\n\n\nCHAPTER 60\n\nThe Line.\n\n\nWith reference to the whaling scene shortly to be described, as well\nas for the better understanding of all similar scenes elsewhere\npresented, I have here to speak of the magical, sometimes horrible\nwhale-line.\n\nThe line originally used in the fishery was of the best hemp,\nslightly vapoured with tar, not impregnated with it, as in the case of\nordinary ropes; for while tar, as ordinarily used, makes the hemp\nmore pliable to the rope-maker, and also renders the rope itself more\nconvenient to the sailor for common ship use; yet, not only would the\nordinary quantity too much stiffen the whale-line for the close\ncoiling to which it must be subjected; but as most seamen are\nbeginning to learn, tar in general by no means adds to the rope's\ndurability or strength, however much it may give it compactness and\ngloss.\n\nOf late years the Manilla rope has in the American fishery almost\nentirely superseded hemp as a material for whale-lines; for, though\nnot so durable as hemp, it is stronger, and far more soft and\nelastic; and I will add (since there is an aesthetics in all things),\nis much more handsome and becoming to the boat, than hemp.  Hemp is a\ndusky, dark fellow, a sort of Indian; but Manilla is as a\ngolden-haired Circassian to behold.\n\nThe whale-line is only two-thirds of an inch in thickness.  At first\nsight, you would not think it so strong as it really is.  By\nexperiment its one and fifty yarns will each suspend a weight of one\nhundred and twenty pounds; so that the whole rope will bear a strain\nnearly equal to three tons.  In length, the common sperm whale-line\nmeasures something over two hundred fathoms.  Towards the stern of\nthe boat it is spirally coiled away in the tub, not like the\nworm-pipe of a still though, but so as to form one round,\ncheese-shaped mass of densely bedded \"sheaves,\" or layers of\nconcentric spiralizations, without any hollow but the \"heart,\" or\nminute vertical tube formed at the axis of the cheese.  As the least\ntangle or kink in the coiling would, in running out, infallibly take\nsomebody's arm, leg, or entire body off, the utmost precaution is\nused in stowing the line in its tub.  Some harpooneers will consume\nalmost an entire morning in this business, carrying the line high\naloft and then reeving it downwards through a block towards the tub,\nso as in the act of coiling to free it from all possible wrinkles and\ntwists.\n\nIn the English boats two tubs are used instead of one; the same line\nbeing continuously coiled in both tubs.  There is some advantage in\nthis; because these twin-tubs being so small they fit more readily\ninto the boat, and do not strain it so much; whereas, the American\ntub, nearly three feet in diameter and of proportionate depth, makes\na rather bulky freight for a craft whose planks are but one half-inch\nin thickness; for the bottom of the whale-boat is like critical ice,\nwhich will bear up a considerable distributed weight, but not very\nmuch of a concentrated one.  When the painted canvas cover is clapped\non the American line-tub, the boat looks as if it were pulling off\nwith a prodigious great wedding-cake to present to the whales.\n\nBoth ends of the line are exposed; the lower end terminating in an\neye-splice or loop coming up from the bottom against the side of the\ntub, and hanging over its edge completely disengaged from everything.\nThis arrangement of the lower end is necessary on two accounts.\nFirst: In order to facilitate the fastening to it of an additional\nline from a neighboring boat, in case the stricken whale should sound\nso deep as to threaten to carry off the entire line originally\nattached to the harpoon.  In these instances, the whale of course is\nshifted like a mug of ale, as it were, from the one boat to the\nother; though the first boat always hovers at hand to assist its\nconsort.  Second: This arrangement is indispensable for common\nsafety's sake; for were the lower end of the line in any way attached\nto the boat, and were the whale then to run the line out to the end\nalmost in a single, smoking minute as he sometimes does, he would not\nstop there, for the doomed boat would infallibly be dragged down\nafter him into the profundity of the sea; and in that case no\ntown-crier would ever find her again.\n\nBefore lowering the boat for the chase, the upper end of the line is\ntaken aft from the tub, and passing round the loggerhead there, is\nagain carried forward the entire length of the boat, resting\ncrosswise upon the loom or handle of every man's oar, so that it jogs\nagainst his wrist in rowing; and also passing between the men, as\nthey alternately sit at the opposite gunwales, to the leaded chocks\nor grooves in the extreme pointed prow of the boat, where a wooden\npin or skewer the size of a common quill, prevents it from slipping\nout.  From the chocks it hangs in a slight festoon over the bows, and\nis then passed inside the boat again; and some ten or twenty fathoms\n(called box-line) being coiled upon the box in the bows, it continues\nits way to the gunwale still a little further aft, and is then\nattached to the short-warp--the rope which is immediately connected\nwith the harpoon; but previous to that connexion, the short-warp goes\nthrough sundry mystifications too tedious to detail.\n\nThus the whale-line folds the whole boat in its complicated coils,\ntwisting and writhing around it in almost every direction.  All the\noarsmen are involved in its perilous contortions; so that to the\ntimid eye of the landsman, they seem as Indian jugglers, with the\ndeadliest snakes sportively festooning their limbs.  Nor can any son\nof mortal woman, for the first time, seat himself amid those hempen\nintricacies, and while straining his utmost at the oar, bethink him\nthat at any unknown instant the harpoon may be darted, and all these\nhorrible contortions be put in play like ringed lightnings; he cannot\nbe thus circumstanced without a shudder that makes the very marrow in\nhis bones to quiver in him like a shaken jelly.  Yet habit--strange\nthing! what cannot habit accomplish?--Gayer sallies, more merry\nmirth, better jokes, and brighter repartees, you never heard over\nyour mahogany, than you will hear over the half-inch white cedar of\nthe whale-boat, when thus hung in hangman's nooses; and, like the six\nburghers of Calais before King Edward, the six men composing the crew\npull into the jaws of death, with a halter around every neck, as you\nmay say.\n\nPerhaps a very little thought will now enable you to account for\nthose repeated whaling disasters--some few of which are casually\nchronicled--of this man or that man being taken out of the boat by\nthe line, and lost.  For, when the line is darting out, to be seated\nthen in the boat, is like being seated in the midst of the manifold\nwhizzings of a steam-engine in full play, when every flying beam, and\nshaft, and wheel, is grazing you.  It is worse; for you cannot sit\nmotionless in the heart of these perils, because the boat is rocking\nlike a cradle, and you are pitched one way and the other, without the\nslightest warning; and only by a certain self-adjusting buoyancy and\nsimultaneousness of volition and action, can you escape being made a\nMazeppa of, and run away with where the all-seeing sun himself could\nnever pierce you out.\n\nAgain: as the profound calm which only apparently precedes and\nprophesies of the storm, is perhaps more awful than the storm itself;\nfor, indeed, the calm is but the wrapper and envelope of the storm;\nand contains it in itself, as the seemingly harmless rifle holds the\nfatal powder, and the ball, and the explosion; so the graceful repose\nof the line, as it silently serpentines about the oarsmen before\nbeing brought into actual play--this is a thing which carries more of\ntrue terror than any other aspect of this dangerous affair.  But why\nsay more?  All men live enveloped in whale-lines.  All are born with\nhalters round their necks; but it is only when caught in the swift,\nsudden turn of death, that mortals realize the silent, subtle,\never-present perils of life.  And if you be a philosopher, though\nseated in the whale-boat, you would not at heart feel one whit more\nof terror, than though seated before your evening fire with a poker,\nand not a harpoon, by your side.\n\n\n\nCHAPTER 61\n\nStubb Kills a Whale.\n\n\nIf to Starbuck the apparition of the Squid was a thing of portents,\nto Queequeg it was quite a different object.\n\n\"When you see him 'quid,\" said the savage, honing his harpoon in the\nbow of his hoisted boat, \"then you quick see him 'parm whale.\"\n\nThe next day was exceedingly still and sultry, and with nothing\nspecial to engage them, the Pequod's crew could hardly resist the\nspell of sleep induced by such a vacant sea.  For this part of the\nIndian Ocean through which we then were voyaging is not what whalemen\ncall a lively ground; that is, it affords fewer glimpses of\nporpoises, dolphins, flying-fish, and other vivacious denizens of\nmore stirring waters, than those off the Rio de la Plata, or the\nin-shore ground off Peru.\n\nIt was my turn to stand at the foremast-head; and with my shoulders\nleaning against the slackened royal shrouds, to and fro I idly swayed\nin what seemed an enchanted air.  No resolution could withstand it;\nin that dreamy mood losing all consciousness, at last my soul went\nout of my body; though my body still continued to sway as a pendulum\nwill, long after the power which first moved it is withdrawn.\n\nEre forgetfulness altogether came over me, I had noticed that the\nseamen at the main and mizzen-mast-heads were already drowsy.  So\nthat at last all three of us lifelessly swung from the spars, and for\nevery swing that we made there was a nod from below from the\nslumbering helmsman.  The waves, too, nodded their indolent crests;\nand across the wide trance of the sea, east nodded to west, and the\nsun over all.\n\nSuddenly bubbles seemed bursting beneath my closed eyes; like vices\nmy hands grasped the shrouds; some invisible, gracious agency\npreserved me; with a shock I came back to life.  And lo! close under\nour lee, not forty fathoms off, a gigantic Sperm Whale lay rolling in\nthe water like the capsized hull of a frigate, his broad, glossy\nback, of an Ethiopian hue, glistening in the sun's rays like a\nmirror.  But lazily undulating in the trough of the sea, and ever and\nanon tranquilly spouting his vapoury jet, the whale looked like a\nportly burgher smoking his pipe of a warm afternoon.  But that pipe,\npoor whale, was thy last.  As if struck by some enchanter's wand, the\nsleepy ship and every sleeper in it all at once started into\nwakefulness; and more than a score of voices from all parts of the\nvessel, simultaneously with the three notes from aloft, shouted forth\nthe accustomed cry, as the great fish slowly and regularly spouted\nthe sparkling brine into the air.\n\n\"Clear away the boats!  Luff!\" cried Ahab.  And obeying his own\norder, he dashed the helm down before the helmsman could handle the\nspokes.\n\nThe sudden exclamations of the crew must have alarmed the whale; and\nere the boats were down, majestically turning, he swam away to the\nleeward, but with such a steady tranquillity, and making so few\nripples as he swam, that thinking after all he might not as yet be\nalarmed, Ahab gave orders that not an oar should be used, and no man\nmust speak but in whispers.  So seated like Ontario Indians on the\ngunwales of the boats, we swiftly but silently paddled along; the\ncalm not admitting of the noiseless sails being set.  Presently, as\nwe thus glided in chase, the monster perpendicularly flitted his tail\nforty feet into the air, and then sank out of sight like a tower\nswallowed up.\n\n\"There go flukes!\" was the cry, an announcement immediately followed\nby Stubb's producing his match and igniting his pipe, for now a\nrespite was granted.  After the full interval of his sounding had\nelapsed, the whale rose again, and being now in advance of the\nsmoker's boat, and much nearer to it than to any of the others, Stubb\ncounted upon the honour of the capture.  It was obvious, now, that the\nwhale had at length become aware of his pursuers.  All silence of\ncautiousness was therefore no longer of use.  Paddles were dropped,\nand oars came loudly into play.  And still puffing at his pipe, Stubb\ncheered on his crew to the assault.\n\nYes, a mighty change had come over the fish.  All alive to his\njeopardy, he was going \"head out\"; that part obliquely projecting\nfrom the mad yeast which he brewed.*\n\n\n*It will be seen in some other place of what a very light substance\nthe entire interior of the sperm whale's enormous head consists.\nThough apparently the most massive, it is by far the most buoyant\npart about him.  So that with ease he elevates it in the air, and\ninvariably does so when going at his utmost speed.  Besides, such is\nthe breadth of the upper part of the front of his head, and such the\ntapering cut-water formation of the lower part, that by obliquely\nelevating his head, he thereby may be said to transform himself from\na bluff-bowed sluggish galliot into a sharppointed New York\npilot-boat.\n\n\n\"Start her, start her, my men!  Don't hurry yourselves; take plenty\nof time--but start her; start her like thunder-claps, that's all,\"\ncried Stubb, spluttering out the smoke as he spoke.  \"Start her, now;\ngive 'em the long and strong stroke, Tashtego.  Start her, Tash, my\nboy--start her, all; but keep cool, keep cool--cucumbers is the\nword--easy, easy--only start her like grim death and grinning devils,\nand raise the buried dead perpendicular out of their graves,\nboys--that's all.  Start her!\"\n\n\"Woo-hoo!  Wa-hee!\" screamed the Gay-Header in reply, raising some\nold war-whoop to the skies; as every oarsman in the strained boat\ninvoluntarily bounced forward with the one tremendous leading stroke\nwhich the eager Indian gave.\n\nBut his wild screams were answered by others quite as wild.\n\"Kee-hee!  Kee-hee!\" yelled Daggoo, straining forwards and backwards\non his seat, like a pacing tiger in his cage.\n\n\"Ka-la!  Koo-loo!\" howled Queequeg, as if smacking his lips over a\nmouthful of Grenadier's steak.  And thus with oars and yells the\nkeels cut the sea.  Meanwhile, Stubb retaining his place in the\nvan, still encouraged his men to the onset, all the while puffing the\nsmoke from his mouth.  Like desperadoes they tugged and they\nstrained, till the welcome cry was heard--\"Stand up, Tashtego!--give\nit to him!\"  The harpoon was hurled.  \"Stern all!\"  The oarsmen\nbacked water; the same moment something went hot and hissing along\nevery one of their wrists.  It was the magical line.  An instant\nbefore, Stubb had swiftly caught two additional turns with it round\nthe loggerhead, whence, by reason of its increased rapid circlings, a\nhempen blue smoke now jetted up and mingled with the steady fumes\nfrom his pipe.  As the line passed round and round the loggerhead; so\nalso, just before reaching that point, it blisteringly passed through\nand through both of Stubb's hands, from which the hand-cloths, or\nsquares of quilted canvas sometimes worn at these times, had\naccidentally dropped.  It was like holding an enemy's sharp two-edged\nsword by the blade, and that enemy all the time striving to wrest it\nout of your clutch.\n\n\"Wet the line! wet the line!\" cried Stubb to the tub oarsman (him\nseated by the tub) who, snatching off his hat, dashed sea-water into\nit.*  More turns were taken, so that the line began holding its place.\nThe boat now flew through the boiling water like a shark all fins.\nStubb and Tashtego here changed places--stem for stern--a staggering\nbusiness truly in that rocking commotion.\n\n\n*Partly to show the indispensableness of this act, it may here be\nstated, that, in the old Dutch fishery, a mop was used to dash the\nrunning line with water; in many other ships, a wooden piggin, or\nbailer, is set apart for that purpose.  Your hat, however, is the\nmost convenient.\n\n\nFrom the vibrating line extending the entire length of the upper part\nof the boat, and from its now being more tight than a harpstring, you\nwould have thought the craft had two keels--one cleaving the water,\nthe other the air--as the boat churned on through both opposing\nelements at once.  A continual cascade played at the bows; a\nceaseless whirling eddy in her wake; and, at the slightest motion\nfrom within, even but of a little finger, the vibrating, cracking\ncraft canted over her spasmodic gunwale into the sea.  Thus they\nrushed; each man with might and main clinging to his seat, to prevent\nbeing tossed to the foam; and the tall form of Tashtego at the\nsteering oar crouching almost double, in order to bring down his\ncentre of gravity.  Whole Atlantics and Pacifics seemed passed as\nthey shot on their way, till at length the whale somewhat slackened\nhis flight.\n\n\"Haul in--haul in!\" cried Stubb to the bowsman! and, facing round\ntowards the whale, all hands began pulling the boat up to him, while\nyet the boat was being towed on.  Soon ranging up by his flank,\nStubb, firmly planting his knee in the clumsy cleat, darted dart\nafter dart into the flying fish; at the word of command, the boat\nalternately sterning out of the way of the whale's horrible wallow,\nand then ranging up for another fling.\n\nThe red tide now poured from all sides of the monster like brooks\ndown a hill.  His tormented body rolled not in brine but in blood,\nwhich bubbled and seethed for furlongs behind in their wake.  The\nslanting sun playing upon this crimson pond in the sea, sent back\nits reflection into every face, so that they all glowed to each other\nlike red men.  And all the while, jet after jet of white smoke was\nagonizingly shot from the spiracle of the whale, and vehement puff\nafter puff from the mouth of the excited headsman; as at every dart,\nhauling in upon his crooked lance (by the line attached to it), Stubb\nstraightened it again and again, by a few rapid blows against the\ngunwale, then again and again sent it into the whale.\n\n\"Pull up--pull up!\" he now cried to the bowsman, as the waning whale\nrelaxed in his wrath.  \"Pull up!--close to!\" and the boat ranged\nalong the fish's flank.  When reaching far over the bow, Stubb slowly\nchurned his long sharp lance into the fish, and kept it there,\ncarefully churning and churning, as if cautiously seeking to feel\nafter some gold watch that the whale might have swallowed, and which\nhe was fearful of breaking ere he could hook it out.  But that gold\nwatch he sought was the innermost life of the fish.  And now it is\nstruck; for, starting from his trance into that unspeakable thing\ncalled his \"flurry,\" the monster horribly wallowed in his blood,\noverwrapped himself in impenetrable, mad, boiling spray, so that the\nimperilled craft, instantly dropping astern, had much ado blindly to\nstruggle out from that phrensied twilight into the clear air of the\nday.\n\nAnd now abating in his flurry, the whale once more rolled out into\nview; surging from side to side; spasmodically dilating and\ncontracting his spout-hole, with sharp, cracking, agonized\nrespirations.  At last, gush after gush of clotted red gore, as if it\nhad been the purple lees of red wine, shot into the frighted air; and\nfalling back again, ran dripping down his motionless flanks into\nthe sea.  His heart had burst!\n\n\"He's dead, Mr. Stubb,\" said Daggoo.\n\n\"Yes; both pipes smoked out!\" and withdrawing his own from his mouth,\nStubb scattered the dead ashes over the water; and, for a moment,\nstood thoughtfully eyeing the vast corpse he had made.\n\n\n\nCHAPTER 62\n\nThe Dart.\n\n\nA word concerning an incident in the last chapter.\n\nAccording to the invariable usage of the fishery, the whale-boat\npushes off from the ship, with the headsman or whale-killer as\ntemporary steersman, and the harpooneer or whale-fastener pulling the\nforemost oar, the one known as the harpooneer-oar.  Now it needs a\nstrong, nervous arm to strike the first iron into the fish; for\noften, in what is called a long dart, the heavy implement has to be\nflung to the distance of twenty or thirty feet.  But however\nprolonged and exhausting the chase, the harpooneer is expected to\npull his oar meanwhile to the uttermost; indeed, he is expected to\nset an example of superhuman activity to the rest, not only by\nincredible rowing, but by repeated loud and intrepid exclamations;\nand what it is to keep shouting at the top of one's compass, while\nall the other muscles are strained and half started--what that is\nnone know but those who have tried it.  For one, I cannot bawl very\nheartily and work very recklessly at one and the same time.  In this\nstraining, bawling state, then, with his back to the fish, all at\nonce the exhausted harpooneer hears the exciting cry--\"Stand up, and\ngive it to him!\"  He now has to drop and secure his oar, turn round\non his centre half way, seize his harpoon from the crotch, and with\nwhat little strength may remain, he essays to pitch it somehow into\nthe whale.  No wonder, taking the whole fleet of whalemen in a body,\nthat out of fifty fair chances for a dart, not five are successful;\nno wonder that so many hapless harpooneers are madly cursed and\ndisrated; no wonder that some of them actually burst their\nblood-vessels in the boat; no wonder that some sperm whalemen are\nabsent four years with four barrels; no wonder that to many ship\nowners, whaling is but a losing concern; for it is the harpooneer\nthat makes the voyage, and if you take the breath out of his body how\ncan you expect to find it there when most wanted!\n\nAgain, if the dart be successful, then at the second critical\ninstant, that is, when the whale starts to run, the boatheader and\nharpooneer likewise start to running fore and aft, to the imminent\njeopardy of themselves and every one else.  It is then they change\nplaces; and the headsman, the chief officer of the little craft,\ntakes his proper station in the bows of the boat.\n\nNow, I care not who maintains the contrary, but all this is both\nfoolish and unnecessary.  The headsman should stay in the bows from\nfirst to last; he should both dart the harpoon and the lance, and no\nrowing whatever should be expected of him, except under circumstances\nobvious to any fisherman.  I know that this would sometimes involve a\nslight loss of speed in the chase; but long experience in various\nwhalemen of more than one nation has convinced me that in the vast\nmajority of failures in the fishery, it has not by any means been so\nmuch the speed of the whale as the before described exhaustion of the\nharpooneer that has caused them.\n\nTo insure the greatest efficiency in the dart, the harpooneers of\nthis world must start to their feet from out of idleness, and not\nfrom out of toil.\n\n\n\nCHAPTER 63\n\nThe Crotch.\n\n\nOut of the trunk, the branches grow; out of them, the twigs.  So, in\nproductive subjects, grow the chapters.\n\nThe crotch alluded to on a previous page deserves independent\nmention.  It is a notched stick of a peculiar form, some two feet in\nlength, which is perpendicularly inserted into the starboard gunwale\nnear the bow, for the purpose of furnishing a rest for the wooden\nextremity of the harpoon, whose other naked, barbed end slopingly\nprojects from the prow.  Thereby the weapon is instantly at hand to\nits hurler, who snatches it up as readily from its rest as a\nbackwoodsman swings his rifle from the wall.  It is customary to have\ntwo harpoons reposing in the crotch, respectively called the first\nand second irons.\n\nBut these two harpoons, each by its own cord, are both connected with\nthe line; the object being this: to dart them both, if possible, one\ninstantly after the other into the same whale; so that if, in the\ncoming drag, one should draw out, the other may still retain a hold.\nIt is a doubling of the chances.  But it very often happens that\nowing to the instantaneous, violent, convulsive running of the whale\nupon receiving the first iron, it becomes impossible for the\nharpooneer, however lightning-like in his movements, to pitch the\nsecond iron into him.  Nevertheless, as the second iron is already\nconnected with the line, and the line is running, hence that weapon\nmust, at all events, be anticipatingly tossed out of the boat,\nsomehow and somewhere; else the most terrible jeopardy would involve\nall hands.  Tumbled into the water, it accordingly is in such cases;\nthe spare coils of box line (mentioned in a preceding chapter) making\nthis feat, in most instances, prudently practicable.  But this\ncritical act is not always unattended with the saddest and most fatal\ncasualties.\n\nFurthermore: you must know that when the second iron is thrown\noverboard, it thenceforth becomes a dangling, sharp-edged terror,\nskittishly curvetting about both boat and whale, entangling the\nlines, or cutting them, and making a prodigious sensation in all\ndirections.  Nor, in general, is it possible to secure it again until\nthe whale is fairly captured and a corpse.\n\nConsider, now, how it must be in the case of four boats all engaging\none unusually strong, active, and knowing whale; when owing to these\nqualities in him, as well as to the thousand concurring accidents of\nsuch an audacious enterprise, eight or ten loose second irons may be\nsimultaneously dangling about him.  For, of course, each boat is\nsupplied with several harpoons to bend on to the line should the\nfirst one be ineffectually darted without recovery.  All these\nparticulars are faithfully narrated here, as they will not fail to\nelucidate several most important, however intricate passages, in\nscenes hereafter to be painted.\n\n\n\nCHAPTER 64\n\nStubb's Supper.\n\n\nStubb's whale had been killed some distance from the ship.  It was a\ncalm; so, forming a tandem of three boats, we commenced the slow\nbusiness of towing the trophy to the Pequod.  And now, as we eighteen\nmen with our thirty-six arms, and one hundred and eighty thumbs and\nfingers, slowly toiled hour after hour upon that inert, sluggish\ncorpse in the sea; and it seemed hardly to budge at all, except at\nlong intervals; good evidence was hereby furnished of the\nenormousness of the mass we moved.  For, upon the great canal of\nHang-Ho, or whatever they call it, in China, four or five laborers on\nthe foot-path will draw a bulky freighted junk at the rate of a mile\nan hour; but this grand argosy we towed heavily forged along, as if\nladen with pig-lead in bulk.\n\nDarkness came on; but three lights up and down in the Pequod's\nmain-rigging dimly guided our way; till drawing nearer we saw Ahab\ndropping one of several more lanterns over the bulwarks.  Vacantly\neyeing the heaving whale for a moment, he issued the usual orders for\nsecuring it for the night, and then handing his lantern to a seaman,\nwent his way into the cabin, and did not come forward again until\nmorning.\n\nThough, in overseeing the pursuit of this whale, Captain Ahab had\nevinced his customary activity, to call it so; yet now that the\ncreature was dead, some vague dissatisfaction, or impatience, or\ndespair, seemed working in him; as if the sight of that dead body\nreminded him that Moby Dick was yet to be slain; and though a\nthousand other whales were brought to his ship, all that would not\none jot advance his grand, monomaniac object.  Very soon you would\nhave thought from the sound on the Pequod's decks, that all hands\nwere preparing to cast anchor in the deep; for heavy chains are being\ndragged along the deck, and thrust rattling out of the port-holes.\nBut by those clanking links, the vast corpse itself, not the ship, is\nto be moored.  Tied by the head to the stern, and by the tail to the\nbows, the whale now lies with its black hull close to the vessel's\nand seen through the darkness of the night, which obscured the spars\nand rigging aloft, the two--ship and whale, seemed yoked together\nlike colossal bullocks, whereof one reclines while the other remains\nstanding.*\n\n\n*A little item may as well be related here.  The strongest and most\nreliable hold which the ship has upon the whale when moored\nalongside, is by the flukes or tail; and as from its greater density\nthat part is relatively heavier than any other (excepting the\nside-fins), its flexibility even in death, causes it to sink low\nbeneath the surface; so that with the hand you cannot get at it from\nthe boat, in order to put the chain round it.  But this difficulty is\ningeniously overcome: a small, strong line is prepared with a wooden\nfloat at its outer end, and a weight in its middle, while the other\nend is secured to the ship.  By adroit management the wooden float is\nmade to rise on the other side of the mass, so that now having\ngirdled the whale, the chain is readily made to follow suit; and\nbeing slipped along the body, is at last locked fast round the\nsmallest part of the tail, at the point of junction with its broad\nflukes or lobes.\n\n\nIf moody Ahab was now all quiescence, at least so far as could be\nknown on deck, Stubb, his second mate, flushed with conquest,\nbetrayed an unusual but still good-natured excitement.  Such an\nunwonted bustle was he in that the staid Starbuck, his official\nsuperior, quietly resigned to him for the time the sole management of\naffairs.  One small, helping cause of all this liveliness in Stubb,\nwas soon made strangely manifest.  Stubb was a high liver; he was\nsomewhat intemperately fond of the whale as a flavorish thing to his\npalate.\n\n\"A steak, a steak, ere I sleep!  You, Daggoo! overboard you go, and\ncut me one from his small!\"\n\nHere be it known, that though these wild fishermen do not, as a\ngeneral thing, and according to the great military maxim, make the\nenemy defray the current expenses of the war (at least before\nrealizing the proceeds of the voyage), yet now and then you find some\nof these Nantucketers who have a genuine relish for that particular\npart of the Sperm Whale designated by Stubb; comprising the tapering\nextremity of the body.\n\nAbout midnight that steak was cut and cooked; and lighted by two\nlanterns of sperm oil, Stubb stoutly stood up to his spermaceti\nsupper at the capstan-head, as if that capstan were a sideboard.  Nor\nwas Stubb the only banqueter on whale's flesh that night.  Mingling\ntheir mumblings with his own mastications, thousands on thousands of\nsharks, swarming round the dead leviathan, smackingly feasted on its\nfatness.  The few sleepers below in their bunks were often startled\nby the sharp slapping of their tails against the hull, within a few\ninches of the sleepers' hearts.  Peering over the side you could just\nsee them (as before you heard them) wallowing in the sullen, black\nwaters, and turning over on their backs as they scooped out huge\nglobular pieces of the whale of the bigness of a human head.  This\nparticular feat of the shark seems all but miraculous.  How at such\nan apparently unassailable surface, they contrive to gouge out such\nsymmetrical mouthfuls, remains a part of the universal problem of all\nthings.  The mark they thus leave on the whale, may best be likened\nto the hollow made by a carpenter in countersinking for a screw.\n\nThough amid all the smoking horror and diabolism of a sea-fight,\nsharks will be seen longingly gazing up to the ship's decks, like\nhungry dogs round a table where red meat is being carved, ready to\nbolt down every killed man that is tossed to them; and though, while\nthe valiant butchers over the deck-table are thus cannibally carving\neach other's live meat with carving-knives all gilded and tasselled,\nthe sharks, also, with their jewel-hilted mouths, are quarrelsomely\ncarving away under the table at the dead meat; and though, were you\nto turn the whole affair upside down, it would still be pretty much\nthe same thing, that is to say, a shocking sharkish business enough\nfor all parties; and though sharks also are the invariable outriders\nof all slave ships crossing the Atlantic, systematically trotting\nalongside, to be handy in case a parcel is to be carried anywhere, or\na dead slave to be decently buried; and though one or two other like\ninstances might be set down, touching the set terms, places, and\noccasions, when sharks do most socially congregate, and most\nhilariously feast; yet is there no conceivable time or occasion when\nyou will find them in such countless numbers, and in gayer or more\njovial spirits, than around a dead sperm whale, moored by night to a\nwhaleship at sea.  If you have never seen that sight, then suspend\nyour decision about the propriety of devil-worship, and the\nexpediency of conciliating the devil.\n\nBut, as yet, Stubb heeded not the mumblings of the banquet that was\ngoing on so nigh him, no more than the sharks heeded the smacking of\nhis own epicurean lips.\n\n\"Cook, cook!--where's that old Fleece?\" he cried at length, widening\nhis legs still further, as if to form a more secure base for his\nsupper; and, at the same time darting his fork into the dish, as if\nstabbing with his lance; \"cook, you cook!--sail this way, cook!\"\n\nThe old black, not in any very high glee at having been previously\nroused from his warm hammock at a most unseasonable hour, came\nshambling along from his galley, for, like many old blacks, there was\nsomething the matter with his knee-pans, which he did not keep well\nscoured like his other pans; this old Fleece, as they called him,\ncame shuffling and limping along, assisting his step with his tongs,\nwhich, after a clumsy fashion, were made of straightened iron hoops;\nthis old Ebony floundered along, and in obedience to the word of\ncommand, came to a dead stop on the opposite side of Stubb's\nsideboard; when, with both hands folded before him, and resting on\nhis two-legged cane, he bowed his arched back still further over, at\nthe same time sideways inclining his head, so as to bring his best\near into play.\n\n\"Cook,\" said Stubb, rapidly lifting a rather reddish morsel to his\nmouth, \"don't you think this steak is rather overdone?  You've been\nbeating this steak too much, cook; it's too tender.  Don't I always\nsay that to be good, a whale-steak must be tough?  There are those\nsharks now over the side, don't you see they prefer it tough and\nrare?  What a shindy they are kicking up!  Cook, go and talk to 'em;\ntell 'em they are welcome to help themselves civilly, and in\nmoderation, but they must keep quiet.  Blast me, if I can hear my own\nvoice.  Away, cook, and deliver my message.  Here, take this\nlantern,\" snatching one from his sideboard; \"now then, go and preach\nto 'em!\"\n\nSullenly taking the offered lantern, old Fleece limped across the\ndeck to the bulwarks; and then, with one hand dropping his light low\nover the sea, so as to get a good view of his congregation, with the\nother hand he solemnly flourished his tongs, and leaning far over the\nside in a mumbling voice began addressing the sharks, while Stubb,\nsoftly crawling behind, overheard all that was said.\n\n\"Fellow-critters: I'se ordered here to say dat you must stop dat dam\nnoise dare.  You hear?  Stop dat dam smackin' ob de lips!  Massa\nStubb say dat you can fill your dam bellies up to de hatchings, but\nby Gor! you must stop dat dam racket!\"\n\n\"Cook,\" here interposed Stubb, accompanying the word with a sudden\nslap on the shoulder,--\"Cook! why, damn your eyes, you mustn't swear\nthat way when you're preaching.  That's no way to convert sinners,\ncook!\"\n\n\"Who dat?  Den preach to him yourself,\" sullenly turning to go.\n\n\"No, cook; go on, go on.\"\n\n\"Well, den, Belubed fellow-critters:\"-\n\n\"Right!\" exclaimed Stubb, approvingly, \"coax 'em to it; try that,\"\nand Fleece continued.\n\n\"Do you is all sharks, and by natur wery woracious, yet I zay to you,\nfellow-critters, dat dat woraciousness--'top dat dam slappin' ob de\ntail!  How you tink to hear, spose you keep up such a dam slappin'\nand bitin' dare?\"\n\n\"Cook,\" cried Stubb, collaring him, \"I won't have that swearing.\nTalk to 'em gentlemanly.\"\n\nOnce more the sermon proceeded.\n\n\"Your woraciousness, fellow-critters, I don't blame ye so much for;\ndat is natur, and can't be helped; but to gobern dat wicked natur,\ndat is de pint.  You is sharks, sartin; but if you gobern de shark in\nyou, why den you be angel; for all angel is not'ing more dan de shark\nwell goberned.  Now, look here, bred'ren, just try wonst to be cibil,\na helping yourselbs from dat whale.  Don't be tearin' de blubber out\nyour neighbour's mout, I say.  Is not one shark dood right as toder\nto dat whale?  And, by Gor, none on you has de right to dat whale;\ndat whale belong to some one else.  I know some o' you has berry brig\nmout, brigger dan oders; but den de brig mouts sometimes has de\nsmall bellies; so dat de brigness of de mout is not to swaller wid,\nbut to bit off de blubber for de small fry ob sharks, dat can't get\ninto de scrouge to help demselves.\"\n\n\"Well done, old Fleece!\" cried Stubb, \"that's Christianity; go on.\"\n\n\"No use goin' on; de dam willains will keep a scougin' and slappin'\neach oder, Massa Stubb; dey don't hear one word; no use a-preaching\nto such dam g'uttons as you call 'em, till dare bellies is full, and\ndare bellies is bottomless; and when dey do get 'em full, dey wont\nhear you den; for den dey sink in the sea, go fast to sleep on de\ncoral, and can't hear noting at all, no more, for eber and eber.\"\n\n\"Upon my soul, I am about of the same opinion; so give the\nbenediction, Fleece, and I'll away to my supper.\"\n\nUpon this, Fleece, holding both hands over the fishy mob, raised his\nshrill voice, and cried--\n\n\"Cussed fellow-critters!  Kick up de damndest row as ever you can;\nfill your dam bellies 'till dey bust--and den die.\"\n\n\"Now, cook,\" said Stubb, resuming his supper at the capstan; \"stand\njust where you stood before, there, over against me, and pay\nparticular attention.\"\n\n\"All 'dention,\" said Fleece, again stooping over upon his tongs in\nthe desired position.\n\n\"Well,\" said Stubb, helping himself freely meanwhile; \"I shall now go\nback to the subject of this steak.  In the first place, how old are\nyou, cook?\"\n\n\"What dat do wid de 'teak,\" said the old black, testily.\n\n\"Silence!  How old are you, cook?\"\n\n\"'Bout ninety, dey say,\" he gloomily muttered.\n\n\"And you have lived in this world hard upon one hundred years, cook,\nand don't know yet how to cook a whale-steak?\" rapidly bolting\nanother mouthful at the last word, so that morsel seemed a\ncontinuation of the question.  \"Where were you born, cook?\"\n\n\"'Hind de hatchway, in ferry-boat, goin' ober de Roanoke.\"\n\n\"Born in a ferry-boat!  That's queer, too.  But I want to know what\ncountry you were born in, cook!\"\n\n\"Didn't I say de Roanoke country?\" he cried sharply.\n\n\"No, you didn't, cook; but I'll tell you what I'm coming to, cook.\nYou must go home and be born over again; you don't know how to cook a\nwhale-steak yet.\"\n\n\"Bress my soul, if I cook noder one,\" he growled, angrily, turning\nround to depart.\n\n\"Come back here, cook;--here, hand me those tongs;--now take that bit\nof steak there, and tell me if you think that steak cooked as it\nshould be?  Take it, I say\"--holding the tongs towards him--\"take it,\nand taste it.\"\n\nFaintly smacking his withered lips over it for a moment, the old\nnegro muttered, \"Best cooked 'teak I eber taste; joosy, berry joosy.\"\n\n\"Cook,\" said Stubb, squaring himself once more; \"do you belong to the\nchurch?\"\n\n\"Passed one once in Cape-Down,\" said the old man sullenly.\n\n\"And you have once in your life passed a holy church in Cape-Town,\nwhere you doubtless overheard a holy parson addressing his hearers as\nhis beloved fellow-creatures, have you, cook!  And yet you come here,\nand tell me such a dreadful lie as you did just now, eh?\" said Stubb.\n\"Where do you expect to go to, cook?\"\n\n\"Go to bed berry soon,\" he mumbled, half-turning as he spoke.\n\n\"Avast! heave to!  I mean when you die, cook.  It's an awful\nquestion.  Now what's your answer?\"\n\n\"When dis old brack man dies,\" said the negro slowly, changing his\nwhole air and demeanor, \"he hisself won't go nowhere; but some\nbressed angel will come and fetch him.\"\n\n\"Fetch him?  How?  In a coach and four, as they fetched Elijah?  And\nfetch him where?\"\n\n\"Up dere,\" said Fleece, holding his tongs straight over his head, and\nkeeping it there very solemnly.\n\n\"So, then, you expect to go up into our main-top, do you, cook, when\nyou are dead?  But don't you know the higher you climb, the colder it\ngets?  Main-top, eh?\"\n\n\"Didn't say dat t'all,\" said Fleece, again in the sulks.\n\n\"You said up there, didn't you? and now look yourself, and see where\nyour tongs are pointing.  But, perhaps you expect to get into heaven\nby crawling through the lubber's hole, cook; but, no, no, cook, you\ndon't get there, except you go the regular way, round by the rigging.\nIt's a ticklish business, but must be done, or else it's no go.  But\nnone of us are in heaven yet.  Drop your tongs, cook, and hear my\norders.  Do ye hear?  Hold your hat in one hand, and clap t'other\na'top of your heart, when I'm giving my orders, cook.  What! that\nyour heart, there?--that's your gizzard!  Aloft! aloft!--that's\nit--now you have it.  Hold it there now, and pay attention.\"\n\n\"All 'dention,\" said the old black, with both hands placed as\ndesired, vainly wriggling his grizzled head, as if to get both ears\nin front at one and the same time.\n\n\"Well then, cook, you see this whale-steak of yours was so very bad,\nthat I have put it out of sight as soon as possible; you see that,\ndon't you?  Well, for the future, when you cook another whale-steak\nfor my private table here, the capstan, I'll tell you what to do so\nas not to spoil it by overdoing.  Hold the steak in one hand, and\nshow a live coal to it with the other; that done, dish it; d'ye hear?\nAnd now to-morrow, cook, when we are cutting in the fish, be sure\nyou stand by to get the tips of his fins; have them put in pickle.\nAs for the ends of the flukes, have them soused, cook.  There, now ye\nmay go.\"\n\nBut Fleece had hardly got three paces off, when he was recalled.\n\n\"Cook, give me cutlets for supper to-morrow night in the mid-watch.\nD'ye hear? away you sail, then.--Halloa! stop! make a bow before you\ngo.--Avast heaving again!  Whale-balls for breakfast--don't forget.\"\n\n\"Wish, by gor! whale eat him, 'stead of him eat whale.  I'm bressed\nif he ain't more of shark dan Massa Shark hisself,\" muttered the old\nman, limping away; with which sage ejaculation he went to his\nhammock.\n\n\n\nCHAPTER 65\n\nThe Whale as a Dish.\n\n\nThat mortal man should feed upon the creature that feeds his lamp,\nand, like Stubb, eat him by his own light, as you may say; this seems\nso outlandish a thing that one must needs go a little into the\nhistory and philosophy of it.\n\nIt is upon record, that three centuries ago the tongue of the Right\nWhale was esteemed a great delicacy in France, and commanded large\nprices there.  Also, that in Henry VIIIth's time, a certain cook of\nthe court obtained a handsome reward for inventing an admirable sauce\nto be eaten with barbacued porpoises, which, you remember, are a\nspecies of whale.  Porpoises, indeed, are to this day considered fine\neating.  The meat is made into balls about the size of billiard\nballs, and being well seasoned and spiced might be taken for\nturtle-balls or veal balls.  The old monks of Dunfermline were very\nfond of them.  They had a great porpoise grant from the crown.\n\nThe fact is, that among his hunters at least, the whale would by all\nhands be considered a noble dish, were there not so much of him; but\nwhen you come to sit down before a meat-pie nearly one hundred feet\nlong, it takes away your appetite.  Only the most unprejudiced of men\nlike Stubb, nowadays partake of cooked whales; but the Esquimaux are\nnot so fastidious.  We all know how they live upon whales, and have\nrare old vintages of prime old train oil.  Zogranda, one of their\nmost famous doctors, recommends strips of blubber for infants, as\nbeing exceedingly juicy and nourishing.  And this reminds me that\ncertain Englishmen, who long ago were accidentally left in Greenland\nby a whaling vessel--that these men actually lived for several months\non the mouldy scraps of whales which had been left ashore after\ntrying out the blubber.  Among the Dutch whalemen these scraps are\ncalled \"fritters\"; which, indeed, they greatly resemble, being brown\nand crisp, and smelling something like old Amsterdam housewives'\ndough-nuts or oly-cooks, when fresh.  They have such an eatable look\nthat the most self-denying stranger can hardly keep his hands off.\n\nBut what further depreciates the whale as a civilized dish, is his\nexceeding richness.  He is the great prize ox of the sea, too fat to\nbe delicately good.  Look at his hump, which would be as fine eating\nas the buffalo's (which is esteemed a rare dish), were it not such a\nsolid pyramid of fat.  But the spermaceti itself, how bland and\ncreamy that is; like the transparent, half-jellied, white meat of a\ncocoanut in the third month of its growth, yet far too rich to supply\na substitute for butter.  Nevertheless, many whalemen have a method\nof absorbing it into some other substance, and then partaking of it.\nIn the long try watches of the night it is a common thing for the\nseamen to dip their ship-biscuit into the huge oil-pots and let them\nfry there awhile.  Many a good supper have I thus made.\n\nIn the case of a small Sperm Whale the brains are accounted a fine\ndish.  The casket of the skull is broken into with an axe, and the\ntwo plump, whitish lobes being withdrawn (precisely resembling two\nlarge puddings), they are then mixed with flour, and cooked into a\nmost delectable mess, in flavor somewhat resembling calves' head,\nwhich is quite a dish among some epicures; and every one knows that\nsome young bucks among the epicures, by continually dining upon\ncalves' brains, by and by get to have a little brains of their own,\nso as to be able to tell a calf's head from their own heads; which,\nindeed, requires uncommon discrimination.  And that is the reason why\na young buck with an intelligent looking calf's head before him, is\nsomehow one of the saddest sights you can see.  The head looks a sort\nof reproachfully at him, with an \"Et tu Brute!\" expression.\n\nIt is not, perhaps, entirely because the whale is so excessively\nunctuous that landsmen seem to regard the eating of him with\nabhorrence; that appears to result, in some way, from the\nconsideration before mentioned: i.e. that a man should eat a newly\nmurdered thing of the sea, and eat it too by its own light.  But no\ndoubt the first man that ever murdered an ox was regarded as a\nmurderer; perhaps he was hung; and if he had been put on his trial by\noxen, he certainly would have been; and he certainly deserved it if\nany murderer does.  Go to the meat-market of a Saturday night and see\nthe crowds of live bipeds staring up at the long rows of dead\nquadrupeds.  Does not that sight take a tooth out of the cannibal's\njaw?  Cannibals? who is not a cannibal?  I tell you it will be more\ntolerable for the Fejee that salted down a lean missionary in his\ncellar against a coming famine; it will be more tolerable for that\nprovident Fejee, I say, in the day of judgment, than for thee,\ncivilized and enlightened gourmand, who nailest geese to the ground\nand feastest on their bloated livers in thy pate-de-foie-gras.\n\nBut Stubb, he eats the whale by its own light, does he? and that is\nadding insult to injury, is it?  Look at your knife-handle, there, my\ncivilized and enlightened gourmand dining off that roast beef, what\nis that handle made of?--what but the bones of the brother of the\nvery ox you are eating?  And what do you pick your teeth with, after\ndevouring that fat goose?  With a feather of the same fowl.  And with\nwhat quill did the Secretary of the Society for the Suppression of\nCruelty to Ganders formally indite his circulars?  It is only within\nthe last month or two that that society passed a resolution to\npatronise nothing but steel pens.\n\n\n\nCHAPTER 66\n\nThe Shark Massacre.\n\n\nWhen in the Southern Fishery, a captured Sperm Whale, after long and\nweary toil, is brought alongside late at night, it is not, as a\ngeneral thing at least, customary to proceed at once to the business\nof cutting him in.  For that business is an exceedingly laborious\none; is not very soon completed; and requires all hands to set about\nit.  Therefore, the common usage is to take in all sail; lash the\nhelm a'lee; and then send every one below to his hammock till\ndaylight, with the reservation that, until that time, anchor-watches\nshall be kept; that is, two and two for an hour, each couple, the\ncrew in rotation shall mount the deck to see that all goes well.\n\nBut sometimes, especially upon the Line in the Pacific, this plan\nwill not answer at all; because such incalculable hosts of sharks\ngather round the moored carcase, that were he left so for six hours,\nsay, on a stretch, little more than the skeleton would be visible by\nmorning.  In most other parts of the ocean, however, where these fish\ndo not so largely abound, their wondrous voracity can be at times\nconsiderably diminished, by vigorously stirring them up with sharp\nwhaling-spades, a procedure notwithstanding, which, in some\ninstances, only seems to tickle them into still greater activity.\nBut it was not thus in the present case with the Pequod's sharks;\nthough, to be sure, any man unaccustomed to such sights, to have\nlooked over her side that night, would have almost thought the whole\nround sea was one huge cheese, and those sharks the maggots in it.\n\nNevertheless, upon Stubb setting the anchor-watch after his supper\nwas concluded; and when, accordingly, Queequeg and a forecastle\nseaman came on deck, no small excitement was created among the\nsharks; for immediately suspending the cutting stages over the side,\nand lowering three lanterns, so that they cast long gleams of light\nover the turbid sea, these two mariners, darting their long\nwhaling-spades, kept up an incessant murdering of the sharks,* by\nstriking the keen steel deep into their skulls, seemingly their only\nvital part.  But in the foamy confusion of their mixed and struggling\nhosts, the marksmen could not always hit their mark; and this brought\nabout new revelations of the incredible ferocity of the foe.  They\nviciously snapped, not only at each other's disembowelments, but like\nflexible bows, bent round, and bit their own; till those entrails\nseemed swallowed over and over again by the same mouth, to be\noppositely voided by the gaping wound.  Nor was this all.  It was\nunsafe to meddle with the corpses and ghosts of these creatures.  A\nsort of generic or Pantheistic vitality seemed to lurk in their very\njoints and bones, after what might be called the individual life had\ndeparted.  Killed and hoisted on deck for the sake of his skin, one\nof these sharks almost took poor Queequeg's hand off, when he tried\nto shut down the dead lid of his murderous jaw.\n\n\n*The whaling-spade used for cutting-in is made of the very best\nsteel; is about the bigness of a man's spread hand; and in general\nshape, corresponds to the garden implement after which it is named;\nonly its sides are perfectly flat, and its upper end considerably\nnarrower than the lower.  This weapon is always kept as sharp as\npossible; and when being used is occasionally honed, just like a\nrazor.  In its socket, a stiff pole, from twenty to thirty feet long,\nis inserted for a handle.\n\n\n\"Queequeg no care what god made him shark,\" said the savage,\nagonizingly lifting his hand up and down; \"wedder Fejee god or\nNantucket god; but de god wat made shark must be one dam Ingin.\"\n\n\n\nCHAPTER 67\n\nCutting In.\n\n\nIt was a Saturday night, and such a Sabbath as followed!  Ex officio\nprofessors of Sabbath breaking are all whalemen.  The ivory Pequod\nwas turned into what seemed a shamble; every sailor a butcher.  You\nwould have thought we were offering up ten thousand red oxen to the\nsea gods.\n\nIn the first place, the enormous cutting tackles, among other\nponderous things comprising a cluster of blocks generally painted\ngreen, and which no single man can possibly lift--this vast bunch of\ngrapes was swayed up to the main-top and firmly lashed to the lower\nmast-head, the strongest point anywhere above a ship's deck.  The end\nof the hawser-like rope winding through these intricacies, was then\nconducted to the windlass, and the huge lower block of the tackles\nwas swung over the whale; to this block the great blubber hook,\nweighing some one hundred pounds, was attached.  And now suspended in\nstages over the side, Starbuck and Stubb, the mates, armed with their\nlong spades, began cutting a hole in the body for the insertion of\nthe hook just above the nearest of the two side-fins.  This done, a\nbroad, semicircular line is cut round the hole, the hook is inserted,\nand the main body of the crew striking up a wild chorus, now commence\nheaving in one dense crowd at the windlass.  When instantly, the\nentire ship careens over on her side; every bolt in her starts like\nthe nail-heads of an old house in frosty weather; she trembles,\nquivers, and nods her frighted mast-heads to the sky.  More and more\nshe leans over to the whale, while every gasping heave of the\nwindlass is answered by a helping heave from the billows; till at\nlast, a swift, startling snap is heard; with a great swash the ship\nrolls upwards and backwards from the whale, and the triumphant tackle\nrises into sight dragging after it the disengaged semicircular end of\nthe first strip of blubber.  Now as the blubber envelopes the whale\nprecisely as the rind does an orange, so is it stripped off from the\nbody precisely as an orange is sometimes stripped by spiralizing it.\nFor the strain constantly kept up by the windlass continually keeps\nthe whale rolling over and over in the water, and as the blubber in\none strip uniformly peels off along the line called the \"scarf,\"\nsimultaneously cut by the spades of Starbuck and Stubb, the mates;\nand just as fast as it is thus peeled off, and indeed by that very\nact itself, it is all the time being hoisted higher and higher aloft\ntill its upper end grazes the main-top; the men at the windlass then\ncease heaving, and for a moment or two the prodigious blood-dripping\nmass sways to and fro as if let down from the sky, and every one\npresent must take good heed to dodge it when it swings, else it may\nbox his ears and pitch him headlong overboard.\n\nOne of the attending harpooneers now advances with a long, keen\nweapon called a boarding-sword, and watching his chance he\ndexterously slices out a considerable hole in the lower part of the\nswaying mass.  Into this hole, the end of the second alternating\ngreat tackle is then hooked so as to retain a hold upon the blubber,\nin order to prepare for what follows.  Whereupon, this accomplished\nswordsman, warning all hands to stand off, once more makes a\nscientific dash at the mass, and with a few sidelong, desperate,\nlunging slicings, severs it completely in twain; so that while the\nshort lower part is still fast, the long upper strip, called a\nblanket-piece, swings clear, and is all ready for lowering.  The\nheavers forward now resume their song, and while the one tackle is\npeeling and hoisting a second strip from the whale, the other is\nslowly slackened away, and down goes the first strip through the main\nhatchway right beneath, into an unfurnished parlor called the\nblubber-room.  Into this twilight apartment sundry nimble hands keep\ncoiling away the long blanket-piece as if it were a great live mass\nof plaited serpents.  And thus the work proceeds; the two tackles\nhoisting and lowering simultaneously; both whale and windlass\nheaving, the heavers singing, the blubber-room gentlemen coiling, the\nmates scarfing, the ship straining, and all hands swearing\noccasionally, by way of assuaging the general friction.\n\n\n\nCHAPTER 68\n\nThe Blanket.\n\n\nI have given no small attention to that not unvexed subject, the skin\nof the whale.  I have had controversies about it with experienced\nwhalemen afloat, and learned naturalists ashore.  My original opinion\nremains unchanged; but it is only an opinion.\n\nThe question is, what and where is the skin of the whale?  Already\nyou know what his blubber is.  That blubber is something of the\nconsistence of firm, close-grained beef, but tougher, more elastic\nand compact, and ranges from eight or ten to twelve and fifteen\ninches in thickness.\n\nNow, however preposterous it may at first seem to talk of any\ncreature's skin as being of that sort of consistence and thickness,\nyet in point of fact these are no arguments against such a\npresumption; because you cannot raise any other dense enveloping\nlayer from the whale's body but that same blubber; and the outermost\nenveloping layer of any animal, if reasonably dense, what can that be\nbut the skin?  True, from the unmarred dead body of the whale, you\nmay scrape off with your hand an infinitely thin, transparent\nsubstance, somewhat resembling the thinnest shreds of isinglass, only\nit is almost as flexible and soft as satin; that is, previous to\nbeing dried, when it not only contracts and thickens, but becomes\nrather hard and brittle.  I have several such dried bits, which I use\nfor marks in my whale-books.  It is transparent, as I said before;\nand being laid upon the printed page, I have sometimes pleased myself\nwith fancying it exerted a magnifying influence.  At any rate, it is\npleasant to read about whales through their own spectacles, as you\nmay say.  But what I am driving at here is this.  That same\ninfinitely thin, isinglass substance, which, I admit, invests the\nentire body of the whale, is not so much to be regarded as the skin\nof the creature, as the skin of the skin, so to speak; for it were\nsimply ridiculous to say, that the proper skin of the tremendous\nwhale is thinner and more tender than the skin of a new-born child.\nBut no more of this.\n\nAssuming the blubber to be the skin of the whale; then, when this\nskin, as in the case of a very large Sperm Whale, will yield the bulk\nof one hundred barrels of oil; and, when it is considered that, in\nquantity, or rather weight, that oil, in its expressed state, is only\nthree fourths, and not the entire substance of the coat; some idea\nmay hence be had of the enormousness of that animated mass, a mere\npart of whose mere integument yields such a lake of liquid as that.\nReckoning ten barrels to the ton, you have ten tons for the net\nweight of only three quarters of the stuff of the whale's skin.\n\nIn life, the visible surface of the Sperm Whale is not the least\namong the many marvels he presents.  Almost invariably it is all over\nobliquely crossed and re-crossed with numberless straight marks in\nthick array, something like those in the finest Italian line\nengravings.  But these marks do not seem to be impressed upon the\nisinglass substance above mentioned, but seem to be seen through it,\nas if they were engraved upon the body itself.  Nor is this all.  In\nsome instances, to the quick, observant eye, those linear marks, as\nin a veritable engraving, but afford the ground for far other\ndelineations.  These are hieroglyphical; that is, if you call those\nmysterious cyphers on the walls of pyramids hieroglyphics, then that\nis the proper word to use in the present connexion.  By my retentive\nmemory of the hieroglyphics upon one Sperm Whale in particular, I was\nmuch struck with a plate representing the old Indian characters\nchiselled on the famous hieroglyphic palisades on the banks of the\nUpper Mississippi.  Like those mystic rocks, too, the mystic-marked\nwhale remains undecipherable.  This allusion to the Indian rocks\nreminds me of another thing.  Besides all the other phenomena which\nthe exterior of the Sperm Whale presents, he not seldom displays the\nback, and more especially his flanks, effaced in great part of the\nregular linear appearance, by reason of numerous rude scratches,\naltogether of an irregular, random aspect.  I should say that those\nNew England rocks on the sea-coast, which Agassiz imagines to bear\nthe marks of violent scraping contact with vast floating icebergs--I\nshould say, that those rocks must not a little resemble the Sperm\nWhale in this particular.  It also seems to me that such scratches in\nthe whale are probably made by hostile contact with other whales; for\nI have most remarked them in the large, full-grown bulls of the\nspecies.\n\nA word or two more concerning this matter of the skin or blubber of\nthe whale.  It has already been said, that it is stript from him in\nlong pieces, called blanket-pieces.  Like most sea-terms, this one is\nvery happy and significant.  For the whale is indeed wrapt up in his\nblubber as in a real blanket or counterpane; or, still better, an\nIndian poncho slipt over his head, and skirting his extremity.  It is\nby reason of this cosy blanketing of his body, that the whale is\nenabled to keep himself comfortable in all weathers, in all seas,\ntimes, and tides.  What would become of a Greenland whale, say, in\nthose shuddering, icy seas of the North, if unsupplied with his cosy\nsurtout?  True, other fish are found exceedingly brisk in those\nHyperborean waters; but these, be it observed, are your cold-blooded,\nlungless fish, whose very bellies are refrigerators; creatures, that\nwarm themselves under the lee of an iceberg, as a traveller in winter\nwould bask before an inn fire; whereas, like man, the whale has lungs\nand warm blood.  Freeze his blood, and he dies.  How wonderful is it\nthen--except after explanation--that this great monster, to whom\ncorporeal warmth is as indispensable as it is to man; how wonderful\nthat he should be found at home, immersed to his lips for life in\nthose Arctic waters! where, when seamen fall overboard, they are\nsometimes found, months afterwards, perpendicularly frozen into the\nhearts of fields of ice, as a fly is found glued in amber.  But more\nsurprising is it to know, as has been proved by experiment, that the\nblood of a Polar whale is warmer than that of a Borneo negro in\nsummer.\n\nIt does seem to me, that herein we see the rare virtue of a strong\nindividual vitality, and the rare virtue of thick walls, and the rare\nvirtue of interior spaciousness.  Oh, man! admire and model thyself\nafter the whale!  Do thou, too, remain warm among ice.  Do thou, too,\nlive in this world without being of it.  Be cool at the equator; keep\nthy blood fluid at the Pole.  Like the great dome of St. Peter's, and\nlike the great whale, retain, O man! in all seasons a temperature of\nthine own.\n\nBut how easy and how hopeless to teach these fine things!  Of\nerections, how few are domed like St. Peter's! of creatures, how few\nvast as the whale!\n\n\n\nCHAPTER 69\n\nThe Funeral.\n\n\nHaul in the chains!  Let the carcase go astern!\n\nThe vast tackles have now done their duty.  The peeled white body of\nthe beheaded whale flashes like a marble sepulchre; though changed in\nhue, it has not perceptibly lost anything in bulk.  It is still\ncolossal.  Slowly it floats more and more away, the water round it\ntorn and splashed by the insatiate sharks, and the air above vexed\nwith rapacious flights of screaming fowls, whose beaks are like so\nmany insulting poniards in the whale.  The vast white headless\nphantom floats further and further from the ship, and every rod that\nit so floats, what seem square roods of sharks and cubic roods of\nfowls, augment the murderous din.  For hours and hours from the\nalmost stationary ship that hideous sight is seen.  Beneath the\nunclouded and mild azure sky, upon the fair face of the pleasant sea,\nwafted by the joyous breezes, that great mass of death floats on and\non, till lost in infinite perspectives.\n\nThere's a most doleful and most mocking funeral!  The sea-vultures\nall in pious mourning, the air-sharks all punctiliously in black or\nspeckled.  In life but few of them would have helped the whale, I\nween, if peradventure he had needed it; but upon the banquet of his\nfuneral they most piously do pounce.  Oh, horrible vultureism of\nearth! from which not the mightiest whale is free.\n\nNor is this the end.  Desecrated as the body is, a vengeful ghost\nsurvives and hovers over it to scare.  Espied by some timid\nman-of-war or blundering discovery-vessel from afar, when the\ndistance obscuring the swarming fowls, nevertheless still shows the\nwhite mass floating in the sun, and the white spray heaving high\nagainst it; straightway the whale's unharming corpse, with trembling\nfingers is set down in the log--SHOALS, ROCKS, AND BREAKERS\nHEREABOUTS: BEWARE!  And for years afterwards, perhaps, ships shun\nthe place; leaping over it as silly sheep leap over a vacuum, because\ntheir leader originally leaped there when a stick was held.  There's\nyour law of precedents; there's your utility of traditions; there's\nthe story of your obstinate survival of old beliefs never bottomed on\nthe earth, and now not even hovering in the air!  There's orthodoxy!\n\nThus, while in life the great whale's body may have been a real\nterror to his foes, in his death his ghost becomes a powerless panic\nto a world.\n\nAre you a believer in ghosts, my friend?  There are other ghosts than\nthe Cock-Lane one, and far deeper men than Doctor Johnson who believe\nin them.\n\n\n\nCHAPTER 70\n\nThe Sphynx.\n\n\nIt should not have been omitted that previous to completely stripping\nthe body of the leviathan, he was beheaded.  Now, the beheading of\nthe Sperm Whale is a scientific anatomical feat, upon which\nexperienced whale surgeons very much pride themselves: and not\nwithout reason.\n\nConsider that the whale has nothing that can properly be called a\nneck; on the contrary, where his head and body seem to join, there,\nin that very place, is the thickest part of him.  Remember, also,\nthat the surgeon must operate from above, some eight or ten feet\nintervening between him and his subject, and that subject almost\nhidden in a discoloured, rolling, and oftentimes tumultuous and\nbursting sea.  Bear in mind, too, that under these untoward\ncircumstances he has to cut many feet deep in the flesh; and in that\nsubterraneous manner, without so much as getting one single peep into\nthe ever-contracting gash thus made, he must skilfully steer clear\nof all adjacent, interdicted parts, and exactly divide the spine at a\ncritical point hard by its insertion into the skull.  Do you not\nmarvel, then, at Stubb's boast, that he demanded but ten minutes to\nbehead a sperm whale?\n\nWhen first severed, the head is dropped astern and held there by a\ncable till the body is stripped.  That done, if it belong to a small\nwhale it is hoisted on deck to be deliberately disposed of.  But,\nwith a full grown leviathan this is impossible; for the sperm whale's\nhead embraces nearly one third of his entire bulk, and completely to\nsuspend such a burden as that, even by the immense tackles of a\nwhaler, this were as vain a thing as to attempt weighing a Dutch barn\nin jewellers' scales.\n\nThe Pequod's whale being decapitated and the body stripped, the head\nwas hoisted against the ship's side--about half way out of the sea,\nso that it might yet in great part be buoyed up by its native\nelement.  And there with the strained craft steeply leaning over to it,\nby reason of the enormous downward drag from the lower mast-head, and\nevery yard-arm on that side projecting like a crane over the waves;\nthere, that blood-dripping head hung to the Pequod's waist like the\ngiant Holofernes's from the girdle of Judith.\n\nWhen this last task was accomplished it was noon, and the seamen went\nbelow to their dinner.  Silence reigned over the before tumultuous\nbut now deserted deck.  An intense copper calm, like a universal\nyellow lotus, was more and more unfolding its noiseless measureless\nleaves upon the sea.\n\nA short space elapsed, and up into this noiselessness came Ahab alone\nfrom his cabin.  Taking a few turns on the quarter-deck, he paused to\ngaze over the side, then slowly getting into the main-chains he took\nStubb's long spade--still remaining there after the whale's\nDecapitation--and striking it into the lower part of the\nhalf-suspended mass, placed its other end crutch-wise under one arm,\nand so stood leaning over with eyes attentively fixed on this head.\n\nIt was a black and hooded head; and hanging there in the midst of so\nintense a calm, it seemed the Sphynx's in the desert.  \"Speak, thou\nvast and venerable head,\" muttered Ahab, \"which, though ungarnished\nwith a beard, yet here and there lookest hoary with mosses; speak,\nmighty head, and tell us the secret thing that is in thee.  Of all\ndivers, thou hast dived the deepest.  That head upon which the upper\nsun now gleams, has moved amid this world's foundations.  Where\nunrecorded names and navies rust, and untold hopes and anchors rot;\nwhere in her murderous hold this frigate earth is ballasted with\nbones of millions of the drowned; there, in that awful water-land,\nthere was thy most familiar home.  Thou hast been where bell or diver\nnever went; hast slept by many a sailor's side, where sleepless\nmothers would give their lives to lay them down.  Thou saw'st the\nlocked lovers when leaping from their flaming ship; heart to heart\nthey sank beneath the exulting wave; true to each other, when heaven\nseemed false to them.  Thou saw'st the murdered mate when tossed by\npirates from the midnight deck; for hours he fell into the deeper\nmidnight of the insatiate maw; and his murderers still sailed on\nunharmed--while swift lightnings shivered the neighboring ship that\nwould have borne a righteous husband to outstretched, longing arms.\nO head! thou hast seen enough to split the planets and make an\ninfidel of Abraham, and not one syllable is thine!\"\n\n\"Sail ho!\" cried a triumphant voice from the main-mast-head.\n\n\"Aye?  Well, now, that's cheering,\" cried Ahab, suddenly erecting\nhimself, while whole thunder-clouds swept aside from his brow.  \"That\nlively cry upon this deadly calm might almost convert a better\nman.--Where away?\"\n\n\"Three points on the starboard bow, sir, and bringing down her breeze\nto us!\n\n\"Better and better, man.  Would now St. Paul would come along that\nway, and to my breezelessness bring his breeze!  O Nature, and O soul\nof man! how far beyond all utterance are your linked analogies! not\nthe smallest atom stirs or lives on matter, but has its cunning\nduplicate in mind.\"\n\n\n\nCHAPTER 71\n\nThe Jeroboam's Story.\n\n\nHand in hand, ship and breeze blew on; but the breeze came faster\nthan the ship, and soon the Pequod began to rock.\n\nBy and by, through the glass the stranger's boats and manned\nmast-heads proved her a whale-ship.  But as she was so far to\nwindward, and shooting by, apparently making a passage to some other\nground, the Pequod could not hope to reach her.  So the signal was\nset to see what response would be made.\n\nHere be it said, that like the vessels of military marines, the ships\nof the American Whale Fleet have each a private signal; all which\nsignals being collected in a book with the names of the respective\nvessels attached, every captain is provided with it.  Thereby, the\nwhale commanders are enabled to recognise each other upon the ocean,\neven at considerable distances and with no small facility.\n\nThe Pequod's signal was at last responded to by the stranger's\nsetting her own; which proved the ship to be the Jeroboam of\nNantucket.  Squaring her yards, she bore down, ranged abeam under the\nPequod's lee, and lowered a boat; it soon drew nigh; but, as the\nside-ladder was being rigged by Starbuck's order to accommodate the\nvisiting captain, the stranger in question waved his hand from his\nboat's stern in token of that proceeding being entirely unnecessary.\nIt turned out that the Jeroboam had a malignant epidemic on board,\nand that Mayhew, her captain, was fearful of infecting the Pequod's\ncompany.  For, though himself and boat's crew remained untainted, and\nthough his ship was half a rifle-shot off, and an incorruptible sea\nand air rolling and flowing between; yet conscientiously adhering to\nthe timid quarantine of the land, he peremptorily refused to come\ninto direct contact with the Pequod.\n\nBut this did by no means prevent all communications.  Preserving an\ninterval of some few yards between itself and the ship, the\nJeroboam's boat by the occasional use of its oars contrived to keep\nparallel to the Pequod, as she heavily forged through the sea (for by\nthis time it blew very fresh), with her main-topsail aback; though,\nindeed, at times by the sudden onset of a large rolling wave, the\nboat would be pushed some way ahead; but would be soon skilfully\nbrought to her proper bearings again.  Subject to this, and other the\nlike interruptions now and then, a conversation was sustained between\nthe two parties; but at intervals not without still another\ninterruption of a very different sort.\n\nPulling an oar in the Jeroboam's boat, was a man of a singular\nappearance, even in that wild whaling life where individual\nnotabilities make up all totalities.  He was a small, short, youngish\nman, sprinkled all over his face with freckles, and wearing redundant\nyellow hair.  A long-skirted, cabalistically-cut coat of a faded\nwalnut tinge enveloped him; the overlapping sleeves of which were\nrolled up on his wrists.  A deep, settled, fanatic delirium was in\nhis eyes.\n\nSo soon as this figure had been first descried, Stubb had\nexclaimed--\"That's he! that's he!--the long-togged scaramouch the\nTown-Ho's company told us of!\"  Stubb here alluded to a strange story\ntold of the Jeroboam, and a certain man among her crew, some time\nprevious when the Pequod spoke the Town-Ho.  According to this\naccount and what was subsequently learned, it seemed that the\nscaramouch in question had gained a wonderful ascendency over almost\neverybody in the Jeroboam.  His story was this:\n\nHe had been originally nurtured among the crazy society of Neskyeuna\nShakers, where he had been a great prophet; in their cracked, secret\nmeetings having several times descended from heaven by the way of a\ntrap-door, announcing the speedy opening of the seventh vial, which\nhe carried in his vest-pocket; but, which, instead of containing\ngunpowder, was supposed to be charged with laudanum.  A strange,\napostolic whim having seized him, he had left Neskyeuna for\nNantucket, where, with that cunning peculiar to craziness, he assumed\na steady, common-sense exterior, and offered himself as a green-hand\ncandidate for the Jeroboam's whaling voyage.  They engaged him; but\nstraightway upon the ship's getting out of sight of land, his\ninsanity broke out in a freshet.  He announced himself as the\narchangel Gabriel, and commanded the captain to jump overboard.  He\npublished his manifesto, whereby he set himself forth as the\ndeliverer of the isles of the sea and vicar-general of all Oceanica.\nThe unflinching earnestness with which he declared these things;--the\ndark, daring play of his sleepless, excited imagination, and all the\npreternatural terrors of real delirium, united to invest this Gabriel\nin the minds of the majority of the ignorant crew, with an atmosphere\nof sacredness.  Moreover, they were afraid of him.  As such a man,\nhowever, was not of much practical use in the ship, especially as he\nrefused to work except when he pleased, the incredulous captain would\nfain have been rid of him; but apprised that that individual's\nintention was to land him in the first convenient port, the archangel\nforthwith opened all his seals and vials--devoting the ship and all\nhands to unconditional perdition, in case this intention was carried\nout.  So strongly did he work upon his disciples among the crew, that\nat last in a body they went to the captain and told him if Gabriel\nwas sent from the ship, not a man of them would remain.  He was\ntherefore forced to relinquish his plan.  Nor would they permit\nGabriel to be any way maltreated, say or do what he would; so that it\ncame to pass that Gabriel had the complete freedom of the ship.  The\nconsequence of all this was, that the archangel cared little or\nnothing for the captain and mates; and since the epidemic had broken\nout, he carried a higher hand than ever; declaring that the plague,\nas he called it, was at his sole command; nor should it be stayed but\naccording to his good pleasure.  The sailors, mostly poor devils,\ncringed, and some of them fawned before him; in obedience to his\ninstructions, sometimes rendering him personal homage, as to a god.\nSuch things may seem incredible; but, however wondrous, they are\ntrue.  Nor is the history of fanatics half so striking in respect to\nthe measureless self-deception of the fanatic himself, as his\nmeasureless power of deceiving and bedevilling so many others.  But\nit is time to return to the Pequod.\n\n\"I fear not thy epidemic, man,\" said Ahab from the bulwarks, to\nCaptain Mayhew, who stood in the boat's stern; \"come on board.\"\n\nBut now Gabriel started to his feet.\n\n\"Think, think of the fevers, yellow and bilious!  Beware of the\nhorrible plague!\"\n\n\"Gabriel!  Gabriel!\" cried Captain Mayhew; \"thou must either--\"  But\nthat instant a headlong wave shot the boat far ahead, and its\nseethings drowned all speech.\n\n\"Hast thou seen the White Whale?\" demanded Ahab, when the boat\ndrifted back.\n\n\"Think, think of thy whale-boat, stoven and sunk!  Beware of the\nhorrible tail!\"\n\n\"I tell thee again, Gabriel, that--\"  But again the boat tore ahead\nas if dragged by fiends.  Nothing was said for some moments, while a\nsuccession of riotous waves rolled by, which by one of those\noccasional caprices of the seas were tumbling, not heaving it.\nMeantime, the hoisted sperm whale's head jogged about very violently,\nand Gabriel was seen eyeing it with rather more apprehensiveness than\nhis archangel nature seemed to warrant.\n\nWhen this interlude was over, Captain Mayhew began a dark story\nconcerning Moby Dick; not, however, without frequent interruptions\nfrom Gabriel, whenever his name was mentioned, and the crazy sea that\nseemed leagued with him.\n\nIt seemed that the Jeroboam had not long left home, when upon\nspeaking a whale-ship, her people were reliably apprised of the\nexistence of Moby Dick, and the havoc he had made.  Greedily sucking\nin this intelligence, Gabriel solemnly warned the captain against\nattacking the White Whale, in case the monster should be seen; in his\ngibbering insanity, pronouncing the White Whale to be no less a being\nthan the Shaker God incarnated; the Shakers receiving the Bible.  But\nwhen, some year or two afterwards, Moby Dick was fairly sighted from\nthe mast-heads, Macey, the chief mate, burned with ardour to encounter\nhim; and the captain himself being not unwilling to let him have the\nopportunity, despite all the archangel's denunciations and\nforewarnings, Macey succeeded in persuading five men to man his boat.\nWith them he pushed off; and, after much weary pulling, and many\nperilous, unsuccessful onsets, he at last succeeded in getting one\niron fast.  Meantime, Gabriel, ascending to the main-royal mast-head,\nwas tossing one arm in frantic gestures, and hurling forth prophecies\nof speedy doom to the sacrilegious assailants of his divinity.  Now,\nwhile Macey, the mate, was standing up in his boat's bow, and with\nall the reckless energy of his tribe was venting his wild\nexclamations upon the whale, and essaying to get a fair chance for\nhis poised lance, lo! a broad white shadow rose from the sea; by its\nquick, fanning motion, temporarily taking the breath out of the\nbodies of the oarsmen.  Next instant, the luckless mate, so full of\nfurious life, was smitten bodily into the air, and making a long arc\nin his descent, fell into the sea at the distance of about fifty\nyards.  Not a chip of the boat was harmed, nor a hair of any\noarsman's head; but the mate for ever sank.\n\nIt is well to parenthesize here, that of the fatal accidents in the\nSperm-Whale Fishery, this kind is perhaps almost as frequent as any.\nSometimes, nothing is injured but the man who is thus annihilated;\noftener the boat's bow is knocked off, or the thigh-board, in which\nthe headsman stands, is torn from its place and accompanies the body.\nBut strangest of all is the circumstance, that in more instances\nthan one, when the body has been recovered, not a single mark of\nviolence is discernible; the man being stark dead.\n\nThe whole calamity, with the falling form of Macey, was plainly\ndescried from the ship.  Raising a piercing shriek--\"The vial! the\nvial!\"  Gabriel called off the terror-stricken crew from the further\nhunting of the whale.  This terrible event clothed the archangel with\nadded influence; because his credulous disciples believed that he had\nspecifically fore-announced it, instead of only making a general\nprophecy, which any one might have done, and so have chanced to hit\none of many marks in the wide margin allowed.  He became a nameless\nterror to the ship.\n\nMayhew having concluded his narration, Ahab put such questions to\nhim, that the stranger captain could not forbear inquiring whether he\nintended to hunt the White Whale, if opportunity should offer.  To\nwhich Ahab answered--\"Aye.\"  Straightway, then, Gabriel once more\nstarted to his feet, glaring upon the old man, and vehemently\nexclaimed, with downward pointed finger--\"Think, think of the\nblasphemer--dead, and down there!--beware of the blasphemer's end!\"\n\nAhab stolidly turned aside; then said to Mayhew, \"Captain, I have\njust bethought me of my letter-bag; there is a letter for one of thy\nofficers, if I mistake not.  Starbuck, look over the bag.\"\n\nEvery whale-ship takes out a goodly number of letters for various\nships, whose delivery to the persons to whom they may be addressed,\ndepends upon the mere chance of encountering them in the four oceans.\nThus, most letters never reach their mark; and many are only\nreceived after attaining an age of two or three years or more.\n\nSoon Starbuck returned with a letter in his hand.  It was sorely\ntumbled, damp, and covered with a dull, spotted, green mould, in\nconsequence of being kept in a dark locker of the cabin.  Of such a\nletter, Death himself might well have been the post-boy.\n\n\"Can'st not read it?\" cried Ahab.  \"Give it me, man.  Aye, aye, it's\nbut a dim scrawl;--what's this?\"  As he was studying it out, Starbuck\ntook a long cutting-spade pole, and with his knife slightly split the\nend, to insert the letter there, and in that way, hand it to the\nboat, without its coming any closer to the ship.\n\nMeantime, Ahab holding the letter, muttered, \"Mr. Har--yes, Mr.\nHarry--(a woman's pinny hand,--the man's wife, I'll wager)--Aye--Mr.\nHarry Macey, Ship Jeroboam;--why it's Macey, and he's dead!\"\n\n\"Poor fellow! poor fellow! and from his wife,\" sighed Mayhew; \"but\nlet me have it.\"\n\n\"Nay, keep it thyself,\" cried Gabriel to Ahab; \"thou art soon going\nthat way.\"\n\n\"Curses throttle thee!\" yelled Ahab.  \"Captain Mayhew, stand by now\nto receive it\"; and taking the fatal missive from Starbuck's hands,\nhe caught it in the slit of the pole, and reached it over towards the\nboat.  But as he did so, the oarsmen expectantly desisted from\nrowing; the boat drifted a little towards the ship's stern; so that,\nas if by magic, the letter suddenly ranged along with Gabriel's eager\nhand.  He clutched it in an instant, seized the boat-knife, and\nimpaling the letter on it, sent it thus loaded back into the ship.\nIt fell at Ahab's feet.  Then Gabriel shrieked out to his comrades to\ngive way with their oars, and in that manner the mutinous boat\nrapidly shot away from the Pequod.\n\nAs, after this interlude, the seamen resumed their work upon the\njacket of the whale, many strange things were hinted in reference to\nthis wild affair.\n\n\n\nCHAPTER 72\n\nThe Monkey-Rope.\n\n\nIn the tumultuous business of cutting-in and attending to a whale,\nthere is much running backwards and forwards among the crew.  Now\nhands are wanted here, and then again hands are wanted there.  There\nis no staying in any one place; for at one and the same time\neverything has to be done everywhere.  It is much the same with him\nwho endeavors the description of the scene.  We must now retrace our\nway a little.  It was mentioned that upon first breaking ground in\nthe whale's back, the blubber-hook was inserted into the original\nhole there cut by the spades of the mates.  But how did so clumsy and\nweighty a mass as that same hook get fixed in that hole?  It was\ninserted there by my particular friend Queequeg, whose duty it was,\nas harpooneer, to descend upon the monster's back for the special\npurpose referred to.  But in very many cases, circumstances require\nthat the harpooneer shall remain on the whale till the whole tensing\nor stripping operation is concluded.  The whale, be it observed, lies\nalmost entirely submerged, excepting the immediate parts operated\nupon.  So down there, some ten feet below the level of the deck, the\npoor harpooneer flounders about, half on the whale and half in the\nwater, as the vast mass revolves like a tread-mill beneath him.  On\nthe occasion in question, Queequeg figured in the Highland costume--a\nshirt and socks--in which to my eyes, at least, he appeared to\nuncommon advantage; and no one had a better chance to observe him, as\nwill presently be seen.\n\nBeing the savage's bowsman, that is, the person who pulled the\nbow-oar in his boat (the second one from forward), it was my cheerful\nduty to attend upon him while taking that hard-scrabble scramble upon\nthe dead whale's back.  You have seen Italian organ-boys holding a\ndancing-ape by a long cord.  Just so, from the ship's steep side, did\nI hold Queequeg down there in the sea, by what is technically called\nin the fishery a monkey-rope, attached to a strong strip of canvas\nbelted round his waist.\n\nIt was a humorously perilous business for both of us.  For, before we\nproceed further, it must be said that the monkey-rope was fast at\nboth ends; fast to Queequeg's broad canvas belt, and fast to my\nnarrow leather one.  So that for better or for worse, we two, for the\ntime, were wedded; and should poor Queequeg sink to rise no more,\nthen both usage and honour demanded, that instead of cutting the cord,\nit should drag me down in his wake.  So, then, an elongated Siamese\nligature united us.  Queequeg was my own inseparable twin brother;\nnor could I any way get rid of the dangerous liabilities which the\nhempen bond entailed.\n\nSo strongly and metaphysically did I conceive of my situation then,\nthat while earnestly watching his motions, I seemed distinctly to\nperceive that my own individuality was now merged in a joint stock\ncompany of two; that my free will had received a mortal wound; and\nthat another's mistake or misfortune might plunge innocent me into\nunmerited disaster and death.  Therefore, I saw that here was a sort\nof interregnum in Providence; for its even-handed equity never could\nhave so gross an injustice.  And yet still further pondering--while I\njerked him now and then from between the whale and ship, which would\nthreaten to jam him--still further pondering, I say, I saw that this\nsituation of mine was the precise situation of every mortal that\nbreathes; only, in most cases, he, one way or other, has this Siamese\nconnexion with a plurality of other mortals.  If your banker breaks,\nyou snap; if your apothecary by mistake sends you poison in your\npills, you die.  True, you may say that, by exceeding caution, you\nmay possibly escape these and the multitudinous other evil chances of\nlife.  But handle Queequeg's monkey-rope heedfully as I would,\nsometimes he jerked it so, that I came very near sliding overboard.\nNor could I possibly forget that, do what I would, I only had the\nmanagement of one end of it.*\n\n\n*The monkey-rope is found in all whalers; but it was only in the\nPequod that the monkey and his holder were ever tied together.  This\nimprovement upon the original usage was introduced by no less a man\nthan Stubb, in order to afford the imperilled harpooneer the strongest\npossible guarantee for the faithfulness and vigilance of his\nmonkey-rope holder.\n\n\nI have hinted that I would often jerk poor Queequeg from between the\nwhale and the ship--where he would occasionally fall, from the\nincessant rolling and swaying of both.  But this was not the only\njamming jeopardy he was exposed to.  Unappalled by the massacre made\nupon them during the night, the sharks now freshly and more keenly\nallured by the before pent blood which began to flow from the\ncarcass--the rabid creatures swarmed round it like bees in a beehive.\n\nAnd right in among those sharks was Queequeg; who often pushed them\naside with his floundering feet.  A thing altogether incredible were\nit not that attracted by such prey as a dead whale, the otherwise\nmiscellaneously carnivorous shark will seldom touch a man.\n\nNevertheless, it may well be believed that since they have such a\nravenous finger in the pie, it is deemed but wise to look sharp to\nthem.  Accordingly, besides the monkey-rope, with which I now and\nthen jerked the poor fellow from too close a vicinity to the maw of\nwhat seemed a peculiarly ferocious shark--he was provided with still\nanother protection.  Suspended over the side in one of the stages,\nTashtego and Daggoo continually flourished over his head a couple of\nkeen whale-spades, wherewith they slaughtered as many sharks as they\ncould reach.  This procedure of theirs, to be sure, was very\ndisinterested and benevolent of them.  They meant Queequeg's best\nhappiness, I admit; but in their hasty zeal to befriend him, and from\nthe circumstance that both he and the sharks were at times half\nhidden by the blood-muddled water, those indiscreet spades of theirs\nwould come nearer amputating a leg than a tall.  But poor Queequeg, I\nsuppose, straining and gasping there with that great iron hook--poor\nQueequeg, I suppose, only prayed to his Yojo, and gave up his life\ninto the hands of his gods.\n\nWell, well, my dear comrade and twin-brother, thought I, as I drew in\nand then slacked off the rope to every swell of the sea--what matters\nit, after all?  Are you not the precious image of each and all of us\nmen in this whaling world?  That unsounded ocean you gasp in, is\nLife; those sharks, your foes; those spades, your friends; and what\nbetween sharks and spades you are in a sad pickle and peril, poor\nlad.\n\nBut courage! there is good cheer in store for you, Queequeg.  For\nnow, as with blue lips and blood-shot eyes the exhausted savage at\nlast climbs up the chains and stands all dripping and involuntarily\ntrembling over the side; the steward advances, and with a benevolent,\nconsolatory glance hands him--what?  Some hot Cognac?  No! hands him,\nye gods! hands him a cup of tepid ginger and water!\n\n\"Ginger?  Do I smell ginger?\" suspiciously asked Stubb, coming near.\n\"Yes, this must be ginger,\" peering into the as yet untasted cup.\nThen standing as if incredulous for a while, he calmly walked towards\nthe astonished steward slowly saying, \"Ginger? ginger? and will you\nhave the goodness to tell me, Mr. Dough-Boy, where lies the virtue of\nginger?  Ginger! is ginger the sort of fuel you use, Dough-boy, to\nkindle a fire in this shivering cannibal?  Ginger!--what the devil is\nginger?--sea-coal? firewood?--lucifer\nmatches?--tinder?--gunpowder?--what the devil is ginger, I say, that\nyou offer this cup to our poor Queequeg here.\"\n\n\"There is some sneaking Temperance Society movement about this\nbusiness,\" he suddenly added, now approaching Starbuck, who had just\ncome from forward.  \"Will you look at that kannakin, sir; smell of\nit, if you please.\"  Then watching the mate's countenance, he added,\n\"The steward, Mr. Starbuck, had the face to offer that calomel and\njalap to Queequeg, there, this instant off the whale.  Is the steward\nan apothecary, sir? and may I ask whether this is the sort of bitters\nby which he blows back the life into a half-drowned man?\"\n\n\"I trust not,\" said Starbuck, \"it is poor stuff enough.\"\n\n\"Aye, aye, steward,\" cried Stubb, \"we'll teach you to drug it\nharpooneer; none of your apothecary's medicine here; you want to\npoison us, do ye?  You have got out insurances on our lives and want\nto murder us all, and pocket the proceeds, do ye?\"\n\n\"It was not me,\" cried Dough-Boy, \"it was Aunt Charity that brought\nthe ginger on board; and bade me never give the harpooneers any\nspirits, but only this ginger-jub--so she called it.\"\n\n\"Ginger-jub! you gingerly rascal! take that! and run along with ye to\nthe lockers, and get something better.  I hope I do no wrong, Mr.\nStarbuck.  It is the captain's orders--grog for the harpooneer on a\nwhale.\"\n\n\"Enough,\" replied Starbuck, \"only don't hit him again, but--\"\n\n\"Oh, I never hurt when I hit, except when I hit a whale or something\nof that sort; and this fellow's a weazel.  What were you about\nsaying, sir?\"\n\n\"Only this: go down with him, and get what thou wantest thyself.\"\n\nWhen Stubb reappeared, he came with a dark flask in one hand, and a\nsort of tea-caddy in the other.  The first contained strong spirits,\nand was handed to Queequeg; the second was Aunt Charity's gift, and\nthat was freely given to the waves.\n\n\n\nCHAPTER 73\n\nStubb and Flask Kill a Right Whale; and Then Have a Talk Over Him.\n\n\nIt must be borne in mind that all this time we have a Sperm Whale's\nprodigious head hanging to the Pequod's side.  But we must let it\ncontinue hanging there a while till we can get a chance to attend to\nit.  For the present other matters press, and the best we can do now\nfor the head, is to pray heaven the tackles may hold.\n\nNow, during the past night and forenoon, the Pequod had gradually\ndrifted into a sea, which, by its occasional patches of yellow brit,\ngave unusual tokens of the vicinity of Right Whales, a species of the\nLeviathan that but few supposed to be at this particular time lurking\nanywhere near.  And though all hands commonly disdained the capture\nof those inferior creatures; and though the Pequod was not\ncommissioned to cruise for them at all, and though she had passed\nnumbers of them near the Crozetts without lowering a boat; yet now\nthat a Sperm Whale had been brought alongside and beheaded, to the\nsurprise of all, the announcement was made that a Right Whale should\nbe captured that day, if opportunity offered.\n\nNor was this long wanting.  Tall spouts were seen to leeward; and two\nboats, Stubb's and Flask's, were detached in pursuit.  Pulling\nfurther and further away, they at last became almost invisible to the\nmen at the mast-head.  But suddenly in the distance, they saw a great\nheap of tumultuous white water, and soon after news came from aloft\nthat one or both the boats must be fast.  An interval passed and the\nboats were in plain sight, in the act of being dragged right towards\nthe ship by the towing whale.  So close did the monster come to the\nhull, that at first it seemed as if he meant it malice; but suddenly\ngoing down in a maelstrom, within three rods of the planks, he wholly\ndisappeared from view, as if diving under the keel.  \"Cut, cut!\" was\nthe cry from the ship to the boats, which, for one instant, seemed on\nthe point of being brought with a deadly dash against the vessel's\nside.  But having plenty of line yet in the tubs, and the whale not\nsounding very rapidly, they paid out abundance of rope, and at the\nsame time pulled with all their might so as to get ahead of the ship.\nFor a few minutes the struggle was intensely critical; for while\nthey still slacked out the tightened line in one direction, and still\nplied their oars in another, the contending strain threatened to take\nthem under.  But it was only a few feet advance they sought to gain.\nAnd they stuck to it till they did gain it; when instantly, a swift\ntremor was felt running like lightning along the keel, as the\nstrained line, scraping beneath the ship, suddenly rose to view under\nher bows, snapping and quivering; and so flinging off its drippings,\nthat the drops fell like bits of broken glass on the water, while the\nwhale beyond also rose to sight, and once more the boats were free to\nfly.  But the fagged whale abated his speed, and blindly altering his\ncourse, went round the stern of the ship towing the two boats after\nhim, so that they performed a complete circuit.\n\nMeantime, they hauled more and more upon their lines, till close\nflanking him on both sides, Stubb answered Flask with lance for\nlance; and thus round and round the Pequod the battle went, while the\nmultitudes of sharks that had before swum round the Sperm Whale's\nbody, rushed to the fresh blood that was spilled, thirstily drinking\nat every new gash, as the eager Israelites did at the new bursting\nfountains that poured from the smitten rock.\n\nAt last his spout grew thick, and with a frightful roll and vomit, he\nturned upon his back a corpse.\n\nWhile the two headsmen were engaged in making fast cords to his\nflukes, and in other ways getting the mass in readiness for towing,\nsome conversation ensued between them.\n\n\"I wonder what the old man wants with this lump of foul lard,\" said\nStubb, not without some disgust at the thought of having to do with\nso ignoble a leviathan.\n\n\"Wants with it?\" said Flask, coiling some spare line in the boat's\nbow, \"did you never hear that the ship which but once has a Sperm\nWhale's head hoisted on her starboard side, and at the same time a\nRight Whale's on the larboard; did you never hear, Stubb, that that\nship can never afterwards capsize?\"\n\n\"Why not?\n\n\"I don't know, but I heard that gamboge ghost of a Fedallah saying\nso, and he seems to know all about ships' charms.  But I sometimes\nthink he'll charm the ship to no good at last.  I don't half like\nthat chap, Stubb.  Did you ever notice how that tusk of his is a sort\nof carved into a snake's head, Stubb?\"\n\n\"Sink him!  I never look at him at all; but if ever I get a chance of\na dark night, and he standing hard by the bulwarks, and no one by;\nlook down there, Flask\"--pointing into the sea with a peculiar motion\nof both hands--\"Aye, will I!  Flask, I take that Fedallah to be the\ndevil in disguise.  Do you believe that cock and bull story about his\nhaving been stowed away on board ship?  He's the devil, I say.  The\nreason why you don't see his tail, is because he tucks it up out of\nsight; he carries it coiled away in his pocket, I guess.  Blast him!\nnow that I think of it, he's always wanting oakum to stuff into the\ntoes of his boots.\"\n\n\"He sleeps in his boots, don't he?  He hasn't got any hammock; but\nI've seen him lay of nights in a coil of rigging.\"\n\n\"No doubt, and it's because of his cursed tail; he coils it down, do\nye see, in the eye of the rigging.\"\n\n\"What's the old man have so much to do with him for?\"\n\n\"Striking up a swap or a bargain, I suppose.\"\n\n\"Bargain?--about what?\"\n\n\"Why, do ye see, the old man is hard bent after that White Whale, and\nthe devil there is trying to come round him, and get him to swap away\nhis silver watch, or his soul, or something of that sort, and then\nhe'll surrender Moby Dick.\"\n\n\"Pooh!  Stubb, you are skylarking; how can Fedallah do that?\"\n\n\"I don't know, Flask, but the devil is a curious chap, and a wicked\none, I tell ye.  Why, they say as how he went a sauntering into the\nold flag-ship once, switching his tail about devilish easy and\ngentlemanlike, and inquiring if the old governor was at home.  Well,\nhe was at home, and asked the devil what he wanted.  The devil,\nswitching his hoofs, up and says, 'I want John.'  'What for?' says\nthe old governor.  'What business is that of yours,' says the devil,\ngetting mad,--'I want to use him.'  'Take him,' says the\ngovernor--and by the Lord, Flask, if the devil didn't give John the\nAsiatic cholera before he got through with him, I'll eat this whale\nin one mouthful.  But look sharp--ain't you all ready there?  Well,\nthen, pull ahead, and let's get the whale alongside.\"\n\n\"I think I remember some such story as you were telling,\" said Flask,\nwhen at last the two boats were slowly advancing with their burden\ntowards the ship, \"but I can't remember where.\"\n\n\"Three Spaniards?  Adventures of those three bloody-minded soladoes?\nDid ye read it there, Flask?  I guess ye did?\"\n\n\"No: never saw such a book; heard of it, though.  But now, tell me,\nStubb, do you suppose that that devil you was speaking of just now,\nwas the same you say is now on board the Pequod?\"\n\n\"Am I the same man that helped kill this whale?  Doesn't the devil\nlive for ever; who ever heard that the devil was dead?  Did you ever\nsee any parson a wearing mourning for the devil?  And if the devil\nhas a latch-key to get into the admiral's cabin, don't you suppose he\ncan crawl into a porthole?  Tell me that, Mr. Flask?\"\n\n\"How old do you suppose Fedallah is, Stubb?\"\n\n\"Do you see that mainmast there?\" pointing to the ship; \"well, that's\nthe figure one; now take all the hoops in the Pequod's hold, and\nstring along in a row with that mast, for oughts, do you see; well,\nthat wouldn't begin to be Fedallah's age.  Nor all the coopers in\ncreation couldn't show hoops enough to make oughts enough.\"\n\n\"But see here, Stubb, I thought you a little boasted just now, that\nyou meant to give Fedallah a sea-toss, if you got a good chance.\nNow, if he's so old as all those hoops of yours come to, and if he is\ngoing to live for ever, what good will it do to pitch him\noverboard--tell me that?\n\n\"Give him a good ducking, anyhow.\"\n\n\"But he'd crawl back.\"\n\n\"Duck him again; and keep ducking him.\"\n\n\"Suppose he should take it into his head to duck you, though--yes,\nand drown you--what then?\"\n\n\"I should like to see him try it; I'd give him such a pair of black\neyes that he wouldn't dare to show his face in the admiral's cabin\nagain for a long while, let alone down in the orlop there, where he\nlives, and hereabouts on the upper decks where he sneaks so much.\nDamn the devil, Flask; so you suppose I'm afraid of the devil?  Who's\nafraid of him, except the old governor who daresn't catch him and put\nhim in double-darbies, as he deserves, but lets him go about\nkidnapping people; aye, and signed a bond with him, that all the\npeople the devil kidnapped, he'd roast for him?  There's a governor!\"\n\n\"Do you suppose Fedallah wants to kidnap Captain Ahab?\"\n\n\"Do I suppose it?  You'll know it before long, Flask.  But I am going\nnow to keep a sharp look-out on him; and if I see anything very\nsuspicious going on, I'll just take him by the nape of his neck, and\nsay--Look here, Beelzebub, you don't do it; and if he makes any fuss,\nby the Lord I'll make a grab into his pocket for his tail, take it to\nthe capstan, and give him such a wrenching and heaving, that his tail\nwill come short off at the stump--do you see; and then, I rather\nguess when he finds himself docked in that queer fashion, he'll sneak\noff without the poor satisfaction of feeling his tail between his\nlegs.\"\n\n\"And what will you do with the tail, Stubb?\"\n\n\"Do with it?  Sell it for an ox whip when we get home;--what else?\"\n\n\"Now, do you mean what you say, and have been saying all along,\nStubb?\"\n\n\"Mean or not mean, here we are at the ship.\"\n\nThe boats were here hailed, to tow the whale on the larboard side,\nwhere fluke chains and other necessaries were already prepared for\nsecuring him.\n\n\"Didn't I tell you so?\" said Flask; \"yes, you'll soon see this right\nwhale's head hoisted up opposite that parmacetti's.\"\n\nIn good time, Flask's saying proved true.  As before, the Pequod\nsteeply leaned over towards the sperm whale's head, now, by the\ncounterpoise of both heads, she regained her even keel; though sorely\nstrained, you may well believe.  So, when on one side you hoist in\nLocke's head, you go over that way; but now, on the other side, hoist\nin Kant's and you come back again; but in very poor plight.  Thus,\nsome minds for ever keep trimming boat.  Oh, ye foolish! throw all\nthese thunder-heads overboard, and then you will float light and\nright.\n\nIn disposing of the body of a right whale, when brought alongside the\nship, the same preliminary proceedings commonly take place as in the\ncase of a sperm whale; only, in the latter instance, the head is cut\noff whole, but in the former the lips and tongue are separately\nremoved and hoisted on deck, with all the well known black bone\nattached to what is called the crown-piece.  But nothing like this,\nin the present case, had been done.  The carcases of both whales had\ndropped astern; and the head-laden ship not a little resembled a mule\ncarrying a pair of overburdening panniers.\n\nMeantime, Fedallah was calmly eyeing the right whale's head, and ever\nand anon glancing from the deep wrinkles there to the lines in his\nown hand.  And Ahab chanced so to stand, that the Parsee occupied his\nshadow; while, if the Parsee's shadow was there at all it seemed only\nto blend with, and lengthen Ahab's.  As the crew toiled on,\nLaplandish speculations were bandied among them, concerning all these\npassing things.\n\n\n\nCHAPTER 74\n\nThe Sperm Whale's Head--Contrasted View.\n\n\nHere, now, are two great whales, laying their heads together; let us\njoin them, and lay together our own.\n\nOf the grand order of folio leviathans, the Sperm Whale and the Right\nWhale are by far the most noteworthy.  They are the only whales\nregularly hunted by man.  To the Nantucketer, they present the two\nextremes of all the known varieties of the whale.  As the external\ndifference between them is mainly observable in their heads; and as a\nhead of each is this moment hanging from the Pequod's side; and as we\nmay freely go from one to the other, by merely stepping across the\ndeck:--where, I should like to know, will you obtain a better chance\nto study practical cetology than here?\n\nIn the first place, you are struck by the general contrast between\nthese heads.  Both are massive enough in all conscience; but there\nis a certain mathematical symmetry in the Sperm Whale's which the\nRight Whale's sadly lacks.  There is more character in the Sperm\nWhale's head.  As you behold it, you involuntarily yield the immense\nsuperiority to him, in point of pervading dignity.  In the present\ninstance, too, this dignity is heightened by the pepper and salt\ncolour of his head at the summit, giving token of advanced age and\nlarge experience.  In short, he is what the fishermen technically\ncall a \"grey-headed whale.\"\n\nLet us now note what is least dissimilar in these heads--namely, the\ntwo most important organs, the eye and the ear.  Far back on the side\nof the head, and low down, near the angle of either whale's jaw, if\nyou narrowly search, you will at last see a lashless eye, which you\nwould fancy to be a young colt's eye; so out of all proportion is it\nto the magnitude of the head.\n\nNow, from this peculiar sideway position of the whale's eyes, it is\nplain that he can never see an object which is exactly ahead, no more\nthan he can one exactly astern.  In a word, the position of the\nwhale's eyes corresponds to that of a man's ears; and you may fancy,\nfor yourself, how it would fare with you, did you sideways survey\nobjects through your ears.  You would find that you could only\ncommand some thirty degrees of vision in advance of the straight\nside-line of sight; and about thirty more behind it.  If your\nbitterest foe were walking straight towards you, with dagger uplifted\nin broad day, you would not be able to see him, any more than if he\nwere stealing upon you from behind.  In a word, you would have two\nbacks, so to speak; but, at the same time, also, two fronts (side\nfronts): for what is it that makes the front of a man--what, indeed,\nbut his eyes?\n\nMoreover, while in most other animals that I can now think of, the\neyes are so planted as imperceptibly to blend their visual power, so\nas to produce one picture and not two to the brain; the peculiar\nposition of the whale's eyes, effectually divided as they are by many\ncubic feet of solid head, which towers between them like a great\nmountain separating two lakes in valleys; this, of course, must\nwholly separate the impressions which each independent organ imparts.\nThe whale, therefore, must see one distinct picture on this side,\nand another distinct picture on that side; while all between must be\nprofound darkness and nothingness to him.  Man may, in effect, be\nsaid to look out on the world from a sentry-box with two joined\nsashes for his window.  But with the whale, these two sashes are\nseparately inserted, making two distinct windows, but sadly impairing\nthe view.  This peculiarity of the whale's eyes is a thing always to\nbe borne in mind in the fishery; and to be remembered by the reader\nin some subsequent scenes.\n\nA curious and most puzzling question might be started concerning this\nvisual matter as touching the Leviathan.  But I must be content with\na hint.  So long as a man's eyes are open in the light, the act of\nseeing is involuntary; that is, he cannot then help mechanically\nseeing whatever objects are before him.  Nevertheless, any one's\nexperience will teach him, that though he can take in an\nundiscriminating sweep of things at one glance, it is quite\nimpossible for him, attentively, and completely, to examine any two\nthings--however large or however small--at one and the same instant\nof time; never mind if they lie side by side and touch each other.\nBut if you now come to separate these two objects, and surround each\nby a circle of profound darkness; then, in order to see one of them,\nin such a manner as to bring your mind to bear on it, the other will\nbe utterly excluded from your contemporary consciousness.  How is it,\nthen, with the whale?  True, both his eyes, in themselves, must\nsimultaneously act; but is his brain so much more comprehensive,\ncombining, and subtle than man's, that he can at the same moment of\ntime attentively examine two distinct prospects, one on one side of\nhim, and the other in an exactly opposite direction?  If he can, then\nis it as marvellous a thing in him, as if a man were able\nsimultaneously to go through the demonstrations of two distinct\nproblems in Euclid.  Nor, strictly investigated, is there any\nincongruity in this comparison.\n\nIt may be but an idle whim, but it has always seemed to me, that the\nextraordinary vacillations of movement displayed by some whales when\nbeset by three or four boats; the timidity and liability to queer\nfrights, so common to such whales; I think that all this indirectly\nproceeds from the helpless perplexity of volition, in which their\ndivided and diametrically opposite powers of vision must involve\nthem.\n\nBut the ear of the whale is full as curious as the eye.  If you are\nan entire stranger to their race, you might hunt over these two heads\nfor hours, and never discover that organ.  The ear has no external\nleaf whatever; and into the hole itself you can hardly insert a\nquill, so wondrously minute is it.  It is lodged a little behind the\neye.  With respect to their ears, this important difference is to be\nobserved between the sperm whale and the right.  While the ear of\nthe former has an external opening, that of the latter is entirely\nand evenly covered over with a membrane, so as to be quite\nimperceptible from without.\n\nIs it not curious, that so vast a being as the whale should see the\nworld through so small an eye, and hear the thunder through an ear\nwhich is smaller than a hare's?  But if his eyes were broad as the\nlens of Herschel's great telescope; and his ears capacious as the\nporches of cathedrals; would that make him any longer of sight, or\nsharper of hearing?  Not at all.--Why then do you try to \"enlarge\"\nyour mind?  Subtilize it.\n\nLet us now with whatever levers and steam-engines we have at hand,\ncant over the sperm whale's head, that it may lie bottom up;\nthen, ascending by a ladder to the summit, have a peep down the\nmouth; and were it not that the body is now completely separated from\nit, with a lantern we might descend into the great Kentucky Mammoth\nCave of his stomach.  But let us hold on here by this tooth, and look\nabout us where we are.  What a really beautiful and chaste-looking\nmouth! from floor to ceiling, lined, or rather papered with a\nglistening white membrane, glossy as bridal satins.\n\nBut come out now, and look at this portentous lower jaw, which seems\nlike the long narrow lid of an immense snuff-box, with the hinge at\none end, instead of one side.  If you pry it up, so as to get it\noverhead, and expose its rows of teeth, it seems a terrific\nportcullis; and such, alas! it proves to many a poor wight in the\nfishery, upon whom these spikes fall with impaling force.  But far\nmore terrible is it to behold, when fathoms down in the sea, you see\nsome sulky whale, floating there suspended, with his prodigious jaw,\nsome fifteen feet long, hanging straight down at right-angles with\nhis body, for all the world like a ship's jib-boom.  This whale is\nnot dead; he is only dispirited; out of sorts, perhaps;\nhypochondriac; and so supine, that the hinges of his jaw have\nrelaxed, leaving him there in that ungainly sort of plight, a\nreproach to all his tribe, who must, no doubt, imprecate lock-jaws\nupon him.\n\nIn most cases this lower jaw--being easily unhinged by a practised\nartist--is disengaged and hoisted on deck for the purpose of\nextracting the ivory teeth, and furnishing a supply of that hard\nwhite whalebone with which the fishermen fashion all sorts of curious\narticles, including canes, umbrella-stocks, and handles to\nriding-whips.\n\nWith a long, weary hoist the jaw is dragged on board, as if it were\nan anchor; and when the proper time comes--some few days after the\nother work--Queequeg, Daggoo, and Tashtego, being all accomplished\ndentists, are set to drawing teeth.  With a keen cutting-spade,\nQueequeg lances the gums; then the jaw is lashed down to ringbolts,\nand a tackle being rigged from aloft, they drag out these teeth, as\nMichigan oxen drag stumps of old oaks out of wild wood lands.  There\nare generally forty-two teeth in all; in old whales, much worn down,\nbut undecayed; nor filled after our artificial fashion.  The jaw is\nafterwards sawn into slabs, and piled away like joists for building\nhouses.\n\n\n\nCHAPTER 75\n\nThe Right Whale's Head--Contrasted View.\n\n\nCrossing the deck, let us now have a good long look at the Right\nWhale's head.\n\nAs in general shape the noble Sperm Whale's head may be compared to a\nRoman war-chariot (especially in front, where it is so broadly\nrounded); so, at a broad view, the Right Whale's head bears a rather\ninelegant resemblance to a gigantic galliot-toed shoe.  Two hundred\nyears ago an old Dutch voyager likened its shape to that of a\nshoemaker's last.  And in this same last or shoe, that old woman of\nthe nursery tale, with the swarming brood, might very comfortably be\nlodged, she and all her progeny.\n\nBut as you come nearer to this great head it begins to assume\ndifferent aspects, according to your point of view.  If you stand on\nits summit and look at these two F-shaped spoutholes, you would take\nthe whole head for an enormous bass-viol, and these spiracles, the\napertures in its sounding-board.  Then, again, if you fix your eye\nupon this strange, crested, comb-like incrustation on the top of the\nmass--this green, barnacled thing, which the Greenlanders call the\n\"crown,\" and the Southern fishers the \"bonnet\" of the Right Whale;\nfixing your eyes solely on this, you would take the head for the\ntrunk of some huge oak, with a bird's nest in its crotch.  At any\nrate, when you watch those live crabs that nestle here on this\nbonnet, such an idea will be almost sure to occur to you; unless,\nindeed, your fancy has been fixed by the technical term \"crown\" also\nbestowed upon it; in which case you will take great interest in\nthinking how this mighty monster is actually a diademed king of the\nsea, whose green crown has been put together for him in this\nmarvellous manner.  But if this whale be a king, he is a very sulky\nlooking fellow to grace a diadem.  Look at that hanging lower lip!\nwhat a huge sulk and pout is there! a sulk and pout, by carpenter's\nmeasurement, about twenty feet long and five feet deep; a sulk and\npout that will yield you some 500 gallons of oil and more.\n\nA great pity, now, that this unfortunate whale should be hare-lipped.\nThe fissure is about a foot across.  Probably the mother during an\nimportant interval was sailing down the Peruvian coast, when\nearthquakes caused the beach to gape.  Over this lip, as over a\nslippery threshold, we now slide into the mouth.  Upon my word were I\nat Mackinaw, I should take this to be the inside of an Indian wigwam.\nGood Lord! is this the road that Jonah went?  The roof is about\ntwelve feet high, and runs to a pretty sharp angle, as if there were\na regular ridge-pole there; while these ribbed, arched, hairy sides,\npresent us with those wondrous, half vertical, scimetar-shaped slats\nof whalebone, say three hundred on a side, which depending from the\nupper part of the head or crown bone, form those Venetian blinds\nwhich have elsewhere been cursorily mentioned.  The edges of these\nbones are fringed with hairy fibres, through which the Right Whale\nstrains the water, and in whose intricacies he retains the small\nfish, when openmouthed he goes through the seas of brit in feeding\ntime.  In the central blinds of bone, as they stand in their natural\norder, there are certain curious marks, curves, hollows, and ridges,\nwhereby some whalemen calculate the creature's age, as the age of an\noak by its circular rings.  Though the certainty of this criterion is\nfar from demonstrable, yet it has the savor of analogical\nprobability.  At any rate, if we yield to it, we must grant a far\ngreater age to the Right Whale than at first glance will seem\nreasonable.\n\nIn old times, there seem to have prevailed the most curious fancies\nconcerning these blinds.  One voyager in Purchas calls them the\nwondrous \"whiskers\" inside of the whale's mouth;* another, \"hogs'\nbristles\"; a third old gentleman in Hackluyt uses the following\nelegant language: \"There are about two hundred and fifty fins growing\non each side of his upper CHOP, which arch over his tongue on each\nside of his mouth.\"\n\n\n*This reminds us that the Right Whale really has a sort of whisker,\nor rather a moustache, consisting of a few scattered white hairs on\nthe upper part of the outer end of the lower jaw.  Sometimes these\ntufts impart a rather brigandish expression to his otherwise solemn\ncountenance.\n\n\nAs every one knows, these same \"hogs' bristles,\" \"fins,\" \"whiskers,\"\n\"blinds,\" or whatever you please, furnish to the ladies their busks\nand other stiffening contrivances.  But in this particular, the\ndemand has long been on the decline.  It was in Queen Anne's time\nthat the bone was in its glory, the farthingale being then all the\nfashion.  And as those ancient dames moved about gaily, though in the\njaws of the whale, as you may say; even so, in a shower, with the\nlike thoughtlessness, do we nowadays fly under the same jaws for\nprotection; the umbrella being a tent spread over the same bone.\n\nBut now forget all about blinds and whiskers for a moment, and,\nstanding in the Right Whale's mouth, look around you afresh.  Seeing\nall these colonnades of bone so methodically ranged about, would you\nnot think you were inside of the great Haarlem organ, and gazing\nupon its thousand pipes?  For a carpet to the organ we have a rug of\nthe softest Turkey--the tongue, which is glued, as it were, to the\nfloor of the mouth.  It is very fat and tender, and apt to tear in\npieces in hoisting it on deck.  This particular tongue now before us;\nat a passing glance I should say it was a six-barreler; that is, it\nwill yield you about that amount of oil.\n\nEre this, you must have plainly seen the truth of what I started\nwith--that the Sperm Whale and the Right Whale have almost entirely\ndifferent heads.  To sum up, then: in the Right Whale's there is no\ngreat well of sperm; no ivory teeth at all; no long, slender mandible\nof a lower jaw, like the Sperm Whale's.  Nor in the Sperm Whale are\nthere any of those blinds of bone; no huge lower lip; and scarcely\nanything of a tongue.  Again, the Right Whale has two external\nspout-holes, the Sperm Whale only one.\n\nLook your last, now, on these venerable hooded heads, while they yet\nlie together; for one will soon sink, unrecorded, in the sea; the\nother will not be very long in following.\n\nCan you catch the expression of the Sperm Whale's there?  It is the\nsame he died with, only some of the longer wrinkles in the forehead\nseem now faded away.  I think his broad brow to be full of a\nprairie-like placidity, born of a speculative indifference as to\ndeath.  But mark the other head's expression.  See that amazing lower\nlip, pressed by accident against the vessel's side, so as firmly to\nembrace the jaw.  Does not this whole head seem to speak of an\nenormous practical resolution in facing death?  This Right Whale I\ntake to have been a Stoic; the Sperm Whale, a Platonian, who might\nhave taken up Spinoza in his latter years.\n\n\n\nCHAPTER 76\n\nThe Battering-Ram.\n\n\nEre quitting, for the nonce, the Sperm Whale's head, I would have\nyou, as a sensible physiologist, simply--particularly remark its\nfront aspect, in all its compacted collectedness.  I would have you\ninvestigate it now with the sole view of forming to yourself some\nunexaggerated, intelligent estimate of whatever battering-ram power\nmay be lodged there.  Here is a vital point; for you must either\nsatisfactorily settle this matter with yourself, or for ever remain\nan infidel as to one of the most appalling, but not the less true\nevents, perhaps anywhere to be found in all recorded history.\n\nYou observe that in the ordinary swimming position of the Sperm\nWhale, the front of his head presents an almost wholly vertical plane\nto the water; you observe that the lower part of that front slopes\nconsiderably backwards, so as to furnish more of a retreat for the\nlong socket which receives the boom-like lower jaw; you observe that\nthe mouth is entirely under the head, much in the same way, indeed,\nas though your own mouth were entirely under your chin.  Moreover you\nobserve that the whale has no external nose; and that what nose he\nhas--his spout hole--is on the top of his head; you observe that his\neyes and ears are at the sides of his head, nearly one third of his\nentire length from the front.  Wherefore, you must now have perceived\nthat the front of the Sperm Whale's head is a dead, blind wall,\nwithout a single organ or tender prominence of any sort whatsoever.\nFurthermore, you are now to consider that only in the extreme, lower,\nbackward sloping part of the front of the head, is there the\nslightest vestige of bone; and not till you get near twenty feet from\nthe forehead do you come to the full cranial development.  So that\nthis whole enormous boneless mass is as one wad.  Finally, though, as\nwill soon be revealed, its contents partly comprise the most delicate\noil; yet, you are now to be apprised of the nature of the substance\nwhich so impregnably invests all that apparent effeminacy.  In some\nprevious place I have described to you how the blubber wraps the body\nof the whale, as the rind wraps an orange.  Just so with the head;\nbut with this difference: about the head this envelope, though not so\nthick, is of a boneless toughness, inestimable by any man who has not\nhandled it.  The severest pointed harpoon, the sharpest lance darted\nby the strongest human arm, impotently rebounds from it.  It is as\nthough the forehead of the Sperm Whale were paved with horses' hoofs.\nI do not think that any sensation lurks in it.\n\nBethink yourself also of another thing.  When two large, loaded\nIndiamen chance to crowd and crush towards each other in the\ndocks, what do the sailors do?  They do not suspend between them, at\nthe point of coming contact, any merely hard substance, like iron or\nwood.  No, they hold there a large, round wad of tow and cork,\nenveloped in the thickest and toughest of ox-hide.  That bravely and\nuninjured takes the jam which would have snapped all their oaken\nhandspikes and iron crow-bars.  By itself this sufficiently\nillustrates the obvious fact I drive at.  But supplementary to this,\nit has hypothetically occurred to me, that as ordinary fish possess\nwhat is called a swimming bladder in them, capable, at will, of\ndistension or contraction; and as the Sperm Whale, as far as I know,\nhas no such provision in him; considering, too, the otherwise\ninexplicable manner in which he now depresses his head altogether\nbeneath the surface, and anon swims with it high elevated out of the\nwater; considering the unobstructed elasticity of its envelope;\nconsidering the unique interior of his head; it has hypothetically\noccurred to me, I say, that those mystical lung-celled honeycombs\nthere may possibly have some hitherto unknown and unsuspected\nconnexion with the outer air, so as to be susceptible to atmospheric\ndistension and contraction.  If this be so, fancy the\nirresistibleness of that might, to which the most impalpable and\ndestructive of all elements contributes.\n\nNow, mark.  Unerringly impelling this dead, impregnable, uninjurable\nwall, and this most buoyant thing within; there swims behind it all a\nmass of tremendous life, only to be adequately estimated as piled\nwood is--by the cord; and all obedient to one volition, as the\nsmallest insect.  So that when I shall hereafter detail to you all\nthe specialities and concentrations of potency everywhere lurking in\nthis expansive monster; when I shall show you some of his more\ninconsiderable braining feats; I trust you will have renounced all\nignorant incredulity, and be ready to abide by this; that though the\nSperm Whale stove a passage through the Isthmus of Darien, and mixed\nthe Atlantic with the Pacific, you would not elevate one hair of your\neye-brow.  For unless you own the whale, you are but a provincial and\nsentimentalist in Truth.  But clear Truth is a thing for salamander\ngiants only to encounter; how small the chances for the provincials\nthen?  What befell the weakling youth lifting the dread goddess's\nveil at Lais?\n\n\n\nCHAPTER 77\n\nThe Great Heidelburgh Tun.\n\n\nNow comes the Baling of the Case.  But to comprehend it aright, you\nmust know something of the curious internal structure of the thing\noperated upon.\n\nRegarding the Sperm Whale's head as a solid oblong, you may, on an\ninclined plane, sideways divide it into two quoins,* whereof the\nlower is the bony structure, forming the cranium and jaws, and the\nupper an unctuous mass wholly free from bones; its broad forward end\nforming the expanded vertical apparent forehead of the whale.  At the\nmiddle of the forehead horizontally subdivide this upper quoin, and\nthen you have two almost equal parts, which before were naturally\ndivided by an internal wall of a thick tendinous substance.\n\n\n*Quoin is not a Euclidean term.  It belongs to the pure nautical\nmathematics.  I know not that it has been defined before.  A quoin is\na solid which differs from a wedge in having its sharp end formed by\nthe steep inclination of one side, instead of the mutual tapering of\nboth sides.\n\n\nThe lower subdivided part, called the junk, is one immense honeycomb\nof oil, formed by the crossing and recrossing, into ten thousand\ninfiltrated cells, of tough elastic white fibres throughout its whole\nextent.  The upper part, known as the Case, may be regarded as the\ngreat Heidelburgh Tun of the Sperm Whale.  And as that famous great\ntierce is mystically carved in front, so the whale's vast plaited\nforehead forms innumerable strange devices for the emblematical\nadornment of his wondrous tun.  Moreover, as that of Heidelburgh was\nalways replenished with the most excellent of the wines of the\nRhenish valleys, so the tun of the whale contains by far the most\nprecious of all his oily vintages; namely, the highly-prized\nspermaceti, in its absolutely pure, limpid, and odoriferous state.\nNor is this precious substance found unalloyed in any other part of\nthe creature.  Though in life it remains perfectly fluid, yet, upon\nexposure to the air, after death, it soon begins to concrete; sending\nforth beautiful crystalline shoots, as when the first thin delicate\nice is just forming in water.  A large whale's case generally yields\nabout five hundred gallons of sperm, though from unavoidable\ncircumstances, considerable of it is spilled, leaks, and dribbles\naway, or is otherwise irrevocably lost in the ticklish business of\nsecuring what you can.\n\nI know not with what fine and costly material the Heidelburgh Tun was\ncoated within, but in superlative richness that coating could not\npossibly have compared with the silken pearl-coloured membrane, like\nthe lining of a fine pelisse, forming the inner surface of the Sperm\nWhale's case.\n\nIt will have been seen that the Heidelburgh Tun of the Sperm Whale\nembraces the entire length of the entire top of the head; and\nsince--as has been elsewhere set forth--the head embraces one third\nof the whole length of the creature, then setting that length down at\neighty feet for a good sized whale, you have more than twenty-six\nfeet for the depth of the tun, when it is lengthwise hoisted up and\ndown against a ship's side.\n\nAs in decapitating the whale, the operator's instrument is brought\nclose to the spot where an entrance is subsequently forced into the\nspermaceti magazine; he has, therefore, to be uncommonly heedful,\nlest a careless, untimely stroke should invade the sanctuary and\nwastingly let out its invaluable contents.  It is this decapitated\nend of the head, also, which is at last elevated out of the water,\nand retained in that position by the enormous cutting tackles, whose\nhempen combinations, on one side, make quite a wilderness of ropes in\nthat quarter.\n\nThus much being said, attend now, I pray you, to that marvellous\nand--in this particular instance--almost fatal operation whereby the\nSperm Whale's great Heidelburgh Tun is tapped.\n\n\n\nCHAPTER 78\n\nCistern and Buckets.\n\n\nNimble as a cat, Tashtego mounts aloft; and without altering his\nerect posture, runs straight out upon the overhanging mainyard-arm,\nto the part where it exactly projects over the hoisted Tun.  He has\ncarried with him a light tackle called a whip, consisting of only two\nparts, travelling through a single-sheaved block.  Securing this\nblock, so that it hangs down from the yard-arm, he swings one end of\nthe rope, till it is caught and firmly held by a hand on deck.\nThen, hand-over-hand, down the other part, the Indian drops through\nthe air, till dexterously he lands on the summit of the head.\nThere--still high elevated above the rest of the company, to whom he\nvivaciously cries--he seems some Turkish Muezzin calling the good\npeople to prayers from the top of a tower.  A short-handled sharp\nspade being sent up to him, he diligently searches for the proper\nplace to begin breaking into the Tun.  In this business he proceeds\nvery heedfully, like a treasure-hunter in some old house, sounding\nthe walls to find where the gold is masoned in.  By the time this\ncautious search is over, a stout iron-bound bucket, precisely like a\nwell-bucket, has been attached to one end of the whip; while the\nother end, being stretched across the deck, is there held by two or\nthree alert hands.  These last now hoist the bucket within grasp of\nthe Indian, to whom another person has reached up a very long pole.\nInserting this pole into the bucket, Tashtego downward guides the\nbucket into the Tun, till it entirely disappears; then giving the\nword to the seamen at the whip, up comes the bucket again, all\nbubbling like a dairy-maid's pail of new milk.  Carefully lowered\nfrom its height, the full-freighted vessel is caught by an appointed\nhand, and quickly emptied into a large tub.  Then remounting aloft,\nit again goes through the same round until the deep cistern will\nyield no more.  Towards the end, Tashtego has to ram his long pole\nharder and harder, and deeper and deeper into the Tun, until some\ntwenty feet of the pole have gone down.\n\nNow, the people of the Pequod had been baling some time in this way;\nseveral tubs had been filled with the fragrant sperm; when all at\nonce a queer accident happened.  Whether it was that Tashtego, that\nwild Indian, was so heedless and reckless as to let go for a moment\nhis one-handed hold on the great cabled tackles suspending the head;\nor whether the place where he stood was so treacherous and oozy; or\nwhether the Evil One himself would have it to fall out so, without\nstating his particular reasons; how it was exactly, there is no\ntelling now; but, on a sudden, as the eightieth or ninetieth bucket\ncame suckingly up--my God! poor Tashtego--like the twin reciprocating\nbucket in a veritable well, dropped head-foremost down into this\ngreat Tun of Heidelburgh, and with a horrible oily gurgling, went\nclean out of sight!\n\n\"Man overboard!\" cried Daggoo, who amid the general consternation\nfirst came to his senses.  \"Swing the bucket this way!\" and putting\none foot into it, so as the better to secure his slippery hand-hold\non the whip itself, the hoisters ran him high up to the top of the\nhead, almost before Tashtego could have reached its interior bottom.\nMeantime, there was a terrible tumult.  Looking over the side, they\nsaw the before lifeless head throbbing and heaving just below the\nsurface of the sea, as if that moment seized with some momentous\nidea; whereas it was only the poor Indian unconsciously revealing by\nthose struggles the perilous depth to which he had sunk.\n\nAt this instant, while Daggoo, on the summit of the head, was\nclearing the whip--which had somehow got foul of the great cutting\ntackles--a sharp cracking noise was heard; and to the unspeakable\nhorror of all, one of the two enormous hooks suspending the head tore\nout, and with a vast vibration the enormous mass sideways swung, till\nthe drunk ship reeled and shook as if smitten by an iceberg.  The one\nremaining hook, upon which the entire strain now depended, seemed\nevery instant to be on the point of giving way; an event still more\nlikely from the violent motions of the head.\n\n\"Come down, come down!\" yelled the seamen to Daggoo, but with one\nhand holding on to the heavy tackles, so that if the head should\ndrop, he would still remain suspended; the negro having cleared the\nfoul line, rammed down the bucket into the now collapsed well,\nmeaning that the buried harpooneer should grasp it, and so be hoisted\nout.\n\n\"In heaven's name, man,\" cried Stubb, \"are you ramming home a\ncartridge there?--Avast!  How will that help him; jamming that\niron-bound bucket on top of his head?  Avast, will ye!\"\n\n\"Stand clear of the tackle!\" cried a voice like the bursting of a\nrocket.\n\nAlmost in the same instant, with a thunder-boom, the enormous mass\ndropped into the sea, like Niagara's Table-Rock into the whirlpool;\nthe suddenly relieved hull rolled away from it, to far down her\nglittering copper; and all caught their breath, as half swinging--now\nover the sailors' heads, and now over the water--Daggoo, through a\nthick mist of spray, was dimly beheld clinging to the pendulous\ntackles, while poor, buried-alive Tashtego was sinking utterly down\nto the bottom of the sea!  But hardly had the blinding vapour cleared\naway, when a naked figure with a boarding-sword in his hand, was for\none swift moment seen hovering over the bulwarks.  The next, a loud\nsplash announced that my brave Queequeg had dived to the rescue.  One\npacked rush was made to the side, and every eye counted every ripple,\nas moment followed moment, and no sign of either the sinker or the\ndiver could be seen.  Some hands now jumped into a boat alongside,\nand pushed a little off from the ship.\n\n\"Ha! ha!\" cried Daggoo, all at once, from his now quiet, swinging\nperch overhead; and looking further off from the side, we saw an arm\nthrust upright from the blue waves; a sight strange to see, as an arm\nthrust forth from the grass over a grave.\n\n\"Both! both!--it is both!\"--cried Daggoo again with a joyful shout;\nand soon after, Queequeg was seen boldly striking out with one hand,\nand with the other clutching the long hair of the Indian.  Drawn into\nthe waiting boat, they were quickly brought to the deck; but Tashtego\nwas long in coming to, and Queequeg did not look very brisk.\n\nNow, how had this noble rescue been accomplished?  Why, diving after\nthe slowly descending head, Queequeg with his keen sword had made\nside lunges near its bottom, so as to scuttle a large hole there;\nthen dropping his sword, had thrust his long arm far inwards and\nupwards, and so hauled out poor Tash by the head.  He averred, that\nupon first thrusting in for him, a leg was presented; but well\nknowing that that was not as it ought to be, and might occasion great\ntrouble;--he had thrust back the leg, and by a dexterous heave and\ntoss, had wrought a somerset upon the Indian; so that with the next\ntrial, he came forth in the good old way--head foremost.  As for the\ngreat head itself, that was doing as well as could be expected.\n\nAnd thus, through the courage and great skill in obstetrics of\nQueequeg, the deliverance, or rather, delivery of Tashtego, was\nsuccessfully accomplished, in the teeth, too, of the most untoward\nand apparently hopeless impediments; which is a lesson by no means to\nbe forgotten.  Midwifery should be taught in the same course with\nfencing and boxing, riding and rowing.\n\nI know that this queer adventure of the Gay-Header's will be sure to\nseem incredible to some landsmen, though they themselves may have\neither seen or heard of some one's falling into a cistern ashore; an\naccident which not seldom happens, and with much less reason too than\nthe Indian's, considering the exceeding slipperiness of the curb of\nthe Sperm Whale's well.\n\nBut, peradventure, it may be sagaciously urged, how is this?  We\nthought the tissued, infiltrated head of the Sperm Whale, was the\nlightest and most corky part about him; and yet thou makest it sink\nin an element of a far greater specific gravity than itself.  We have\nthee there.  Not at all, but I have ye; for at the time poor Tash\nfell in, the case had been nearly emptied of its lighter contents,\nleaving little but the dense tendinous wall of the well--a double\nwelded, hammered substance, as I have before said, much heavier than\nthe sea water, and a lump of which sinks in it like lead almost.  But\nthe tendency to rapid sinking in this substance was in the present\ninstance materially counteracted by the other parts of the head\nremaining undetached from it, so that it sank very slowly and\ndeliberately indeed, affording Queequeg a fair chance for performing\nhis agile obstetrics on the run, as you may say.  Yes, it was a\nrunning delivery, so it was.\n\nNow, had Tashtego perished in that head, it had been a very precious\nperishing; smothered in the very whitest and daintiest of fragrant\nspermaceti; coffined, hearsed, and tombed in the secret inner chamber\nand sanctum sanctorum of the whale.  Only one sweeter end can readily\nbe recalled--the delicious death of an Ohio honey-hunter, who seeking\nhoney in the crotch of a hollow tree, found such exceeding store of\nit, that leaning too far over, it sucked him in, so that he died\nembalmed.  How many, think ye, have likewise fallen into Plato's\nhoney head, and sweetly perished there?\n\n\n\nCHAPTER 79\n\nThe Prairie.\n\n\nTo scan the lines of his face, or feel the bumps on the head of this\nLeviathan; this is a thing which no Physiognomist or Phrenologist has\nas yet undertaken.  Such an enterprise would seem almost as hopeful\nas for Lavater to have scrutinized the wrinkles on the Rock of\nGibraltar, or for Gall to have mounted a ladder and manipulated the\nDome of the Pantheon.  Still, in that famous work of his, Lavater\nnot only treats of the various faces of men, but also attentively\nstudies the faces of horses, birds, serpents, and fish; and dwells in\ndetail upon the modifications of expression discernible therein.  Nor\nhave Gall and his disciple Spurzheim failed to throw out some hints\ntouching the phrenological characteristics of other beings than man.\nTherefore, though I am but ill qualified for a pioneer, in the\napplication of these two semi-sciences to the whale, I will do my\nendeavor.  I try all things; I achieve what I can.\n\nPhysiognomically regarded, the Sperm Whale is an anomalous creature.\nHe has no proper nose.  And since the nose is the central and most\nconspicuous of the features; and since it perhaps most modifies and\nfinally controls their combined expression; hence it would seem that\nits entire absence, as an external appendage, must very largely\naffect the countenance of the whale.  For as in landscape gardening,\na spire, cupola, monument, or tower of some sort, is deemed almost\nindispensable to the completion of the scene; so no face can be\nphysiognomically in keeping without the elevated open-work belfry of\nthe nose.  Dash the nose from Phidias's marble Jove, and what a sorry\nremainder!  Nevertheless, Leviathan is of so mighty a magnitude, all\nhis proportions are so stately, that the same deficiency which in the\nsculptured Jove were hideous, in him is no blemish at all.  Nay, it\nis an added grandeur.  A nose to the whale would have been\nimpertinent.  As on your physiognomical voyage you sail round his\nvast head in your jolly-boat, your noble conceptions of him are never\ninsulted by the reflection that he has a nose to be pulled.  A\npestilent conceit, which so often will insist upon obtruding even\nwhen beholding the mightiest royal beadle on his throne.\n\nIn some particulars, perhaps the most imposing physiognomical view\nto be had of the Sperm Whale, is that of the full front of his head.\nThis aspect is sublime.\n\nIn thought, a fine human brow is like the East when troubled with\nthe morning.  In the repose of the pasture, the curled brow of the\nbull has a touch of the grand in it.  Pushing heavy cannon up\nmountain defiles, the elephant's brow is majestic.  Human or animal,\nthe mystical brow is as that great golden seal affixed by the German\nEmperors to their decrees.  It signifies--\"God: done this day by my\nhand.\"  But in most creatures, nay in man himself, very often the\nbrow is but a mere strip of alpine land lying along the snow line.\nFew are the foreheads which like Shakespeare's or Melancthon's rise\nso high, and descend so low, that the eyes themselves seem clear,\neternal, tideless mountain lakes; and all above them in the forehead's\nwrinkles, you seem to track the antlered thoughts descending there to\ndrink, as the Highland hunters track the snow prints of the deer.\nBut in the great Sperm Whale, this high and mighty god-like dignity\ninherent in the brow is so immensely amplified, that gazing on it, in\nthat full front view, you feel the Deity and the dread powers more\nforcibly than in beholding any other object in living nature.  For\nyou see no one point precisely; not one distinct feature is revealed;\nno nose, eyes, ears, or mouth; no face; he has none, proper; nothing\nbut that one broad firmament of a forehead, pleated with riddles;\ndumbly lowering with the doom of boats, and ships, and men.  Nor, in\nprofile, does this wondrous brow diminish; though that way viewed its\ngrandeur does not domineer upon you so.  In profile, you plainly\nperceive that horizontal, semi-crescentic depression in the\nforehead's middle, which, in man, is Lavater's mark of genius.\n\nBut how?  Genius in the Sperm Whale?  Has the Sperm Whale ever\nwritten a book, spoken a speech?  No, his great genius is declared in\nhis doing nothing particular to prove it.  It is moreover declared in\nhis pyramidical silence.  And this reminds me that had the great\nSperm Whale been known to the young Orient World, he would have been\ndeified by their child-magian thoughts.  They deified the crocodile\nof the Nile, because the crocodile is tongueless; and the Sperm Whale\nhas no tongue, or at least it is so exceedingly small, as to be\nincapable of protrusion.  If hereafter any highly cultured, poetical\nnation shall lure back to their birth-right, the merry May-day gods\nof old; and livingly enthrone them again in the now egotistical sky;\nin the now unhaunted hill; then be sure, exalted to Jove's high seat,\nthe great Sperm Whale shall lord it.\n\nChampollion deciphered the wrinkled granite hieroglyphics.  But there\nis no Champollion to decipher the Egypt of every man's and every\nbeing's face.  Physiognomy, like every other human science, is but a\npassing fable.  If then, Sir William Jones, who read in thirty\nlanguages, could not read the simplest peasant's face in its\nprofounder and more subtle meanings, how may unlettered Ishmael hope\nto read the awful Chaldee of the Sperm Whale's brow?  I but put that\nbrow before you.  Read it if you can.\n\n\n\nCHAPTER 80\n\nThe Nut.\n\n\nIf the Sperm Whale be physiognomically a Sphinx, to the phrenologist\nhis brain seems that geometrical circle which it is impossible to\nsquare.\n\nIn the full-grown creature the skull will measure at least twenty\nfeet in length.  Unhinge the lower jaw, and the side view of this\nskull is as the side of a moderately inclined plane resting\nthroughout on a level base.  But in life--as we have elsewhere\nseen--this inclined plane is angularly filled up, and almost squared\nby the enormous superincumbent mass of the junk and sperm.  At the\nhigh end the skull forms a crater to bed that part of the mass; while\nunder the long floor of this crater--in another cavity seldom\nexceeding ten inches in length and as many in depth--reposes the\nmere handful of this monster's brain.  The brain is at least twenty\nfeet from his apparent forehead in life; it is hidden away behind its\nvast outworks, like the innermost citadel within the amplified\nfortifications of Quebec.  So like a choice casket is it secreted in\nhim, that I have known some whalemen who peremptorily deny that the\nSperm Whale has any other brain than that palpable semblance of one\nformed by the cubic-yards of his sperm magazine.  Lying in strange\nfolds, courses, and convolutions, to their apprehensions, it seems\nmore in keeping with the idea of his general might to regard that\nmystic part of him as the seat of his intelligence.\n\nIt is plain, then, that phrenologically the head of this Leviathan,\nin the creature's living intact state, is an entire delusion.  As for\nhis true brain, you can then see no indications of it, nor feel any.\nThe whale, like all things that are mighty, wears a false brow to the\ncommon world.\n\nIf you unload his skull of its spermy heaps and then take a rear view\nof its rear end, which is the high end, you will be struck by its\nresemblance to the human skull, beheld in the same situation, and\nfrom the same point of view.  Indeed, place this reversed skull\n(scaled down to the human magnitude) among a plate of men's skulls,\nand you would involuntarily confound it with them; and remarking the\ndepressions on one part of its summit, in phrenological phrase you\nwould say--This man had no self-esteem, and no veneration.  And by\nthose negations, considered along with the affirmative fact of his\nprodigious bulk and power, you can best form to yourself the truest,\nthough not the most exhilarating conception of what the most exalted\npotency is.\n\nBut if from the comparative dimensions of the whale's proper brain,\nyou deem it incapable of being adequately charted, then I have\nanother idea for you.  If you attentively regard almost any\nquadruped's spine, you will be struck with the resemblance of its\nvertebrae to a strung necklace of dwarfed skulls, all bearing\nrudimental resemblance to the skull proper.  It is a German conceit,\nthat the vertebrae are absolutely undeveloped skulls.  But the\ncurious external resemblance, I take it the Germans were not the\nfirst men to perceive.  A foreign friend once pointed it out to me,\nin the skeleton of a foe he had slain, and with the vertebrae of\nwhich he was inlaying, in a sort of basso-relievo, the beaked prow\nof his canoe.  Now, I consider that the phrenologists have omitted an\nimportant thing in not pushing their investigations from the\ncerebellum through the spinal canal.  For I believe that much of a\nman's character will be found betokened in his backbone.  I would\nrather feel your spine than your skull, whoever you are.  A thin\njoist of a spine never yet upheld a full and noble soul.  I rejoice\nin my spine, as in the firm audacious staff of that flag which I\nfling half out to the world.\n\nApply this spinal branch of phrenology to the Sperm Whale.  His\ncranial cavity is continuous with the first neck-vertebra; and in\nthat vertebra the bottom of the spinal canal will measure ten inches\nacross, being eight in height, and of a triangular figure with the\nbase downwards.  As it passes through the remaining vertebrae the\ncanal tapers in size, but for a considerable distance remains of\nlarge capacity.  Now, of course, this canal is filled with much the\nsame strangely fibrous substance--the spinal cord--as the brain; and\ndirectly communicates with the brain.  And what is still more, for\nmany feet after emerging from the brain's cavity, the spinal cord\nremains of an undecreasing girth, almost equal to that of the brain.\nUnder all these circumstances, would it be unreasonable to survey and\nmap out the whale's spine phrenologically?  For, viewed in this\nlight, the wonderful comparative smallness of his brain proper is\nmore than compensated by the wonderful comparative magnitude of his\nspinal cord.\n\nBut leaving this hint to operate as it may with the phrenologists, I\nwould merely assume the spinal theory for a moment, in reference to\nthe Sperm Whale's hump.  This august hump, if I mistake not, rises\nover one of the larger vertebrae, and is, therefore, in some sort,\nthe outer convex mould of it.  From its relative situation then, I\nshould call this high hump the organ of firmness or indomitableness\nin the Sperm Whale.  And that the great monster is indomitable, you\nwill yet have reason to know.\n\n\n\nCHAPTER 81\n\nThe Pequod Meets The Virgin.\n\n\nThe predestinated day arrived, and we duly met the ship Jungfrau,\nDerick De Deer, master, of Bremen.\n\nAt one time the greatest whaling people in the world, the Dutch and\nGermans are now among the least; but here and there at very wide\nintervals of latitude and longitude, you still occasionally meet with\ntheir flag in the Pacific.\n\nFor some reason, the Jungfrau seemed quite eager to pay her respects.\nWhile yet some distance from the Pequod, she rounded to, and\ndropping a boat, her captain was impelled towards us, impatiently\nstanding in the bows instead of the stern.\n\n\"What has he in his hand there?\" cried Starbuck, pointing to\nsomething wavingly held by the German.  \"Impossible!--a lamp-feeder!\"\n\n\"Not that,\" said Stubb, \"no, no, it's a coffee-pot, Mr. Starbuck;\nhe's coming off to make us our coffee, is the Yarman; don't you see\nthat big tin can there alongside of him?--that's his boiling water.\nOh! he's all right, is the Yarman.\"\n\n\"Go along with you,\" cried Flask, \"it's a lamp-feeder and an oil-can.\nHe's out of oil, and has come a-begging.\"\n\nHowever curious it may seem for an oil-ship to be borrowing oil on\nthe whale-ground, and however much it may invertedly contradict the\nold proverb about carrying coals to Newcastle, yet sometimes such a\nthing really happens; and in the present case Captain Derick De Deer\ndid indubitably conduct a lamp-feeder as Flask did declare.\n\nAs he mounted the deck, Ahab abruptly accosted him, without at all\nheeding what he had in his hand; but in his broken lingo, the German\nsoon evinced his complete ignorance of the White Whale; immediately\nturning the conversation to his lamp-feeder and oil can, with some\nremarks touching his having to turn into his hammock at night in\nprofound darkness--his last drop of Bremen oil being gone, and not a\nsingle flying-fish yet captured to supply the deficiency; concluding\nby hinting that his ship was indeed what in the Fishery is\ntechnically called a CLEAN one (that is, an empty one), well\ndeserving the name of Jungfrau or the Virgin.\n\nHis necessities supplied, Derick departed; but he had not gained his\nship's side, when whales were almost simultaneously raised from the\nmast-heads of both vessels; and so eager for the chase was Derick,\nthat without pausing to put his oil-can and lamp-feeder aboard, he\nslewed round his boat and made after the leviathan lamp-feeders.\n\nNow, the game having risen to leeward, he and the other three German\nboats that soon followed him, had considerably the start of the\nPequod's keels.  There were eight whales, an average pod.  Aware of\ntheir danger, they were going all abreast with great speed straight\nbefore the wind, rubbing their flanks as closely as so many spans of\nhorses in harness.  They left a great, wide wake, as though\ncontinually unrolling a great wide parchment upon the sea.\n\nFull in this rapid wake, and many fathoms in the rear, swam a huge,\nhumped old bull, which by his comparatively slow progress, as well as\nby the unusual yellowish incrustations overgrowing him, seemed\nafflicted with the jaundice, or some other infirmity.  Whether this\nwhale belonged to the pod in advance, seemed questionable; for it is\nnot customary for such venerable leviathans to be at all social.\nNevertheless, he stuck to their wake, though indeed their back water\nmust have retarded him, because the white-bone or swell at his broad\nmuzzle was a dashed one, like the swell formed when two hostile\ncurrents meet.  His spout was short, slow, and laborious; coming\nforth with a choking sort of gush, and spending itself in torn\nshreds, followed by strange subterranean commotions in him, which\nseemed to have egress at his other buried extremity, causing the\nwaters behind him to upbubble.\n\n\"Who's got some paregoric?\" said Stubb, \"he has the stomach-ache, I'm\nafraid.  Lord, think of having half an acre of stomach-ache!  Adverse\nwinds are holding mad Christmas in him, boys.  It's the first foul\nwind I ever knew to blow from astern; but look, did ever whale yaw\nso before? it must be, he's lost his tiller.\"\n\nAs an overladen Indiaman bearing down the Hindostan coast with a deck\nload of frightened horses, careens, buries, rolls, and wallows on her\nway; so did this old whale heave his aged bulk, and now and then\npartly turning over on his cumbrous rib-ends, expose the cause of his\ndevious wake in the unnatural stump of his starboard fin.  Whether he\nhad lost that fin in battle, or had been born without it, it were\nhard to say.\n\n\"Only wait a bit, old chap, and I'll give ye a sling for that wounded\narm,\" cried cruel Flask, pointing to the whale-line near him.\n\n\"Mind he don't sling thee with it,\" cried Starbuck.  \"Give way, or\nthe German will have him.\"\n\nWith one intent all the combined rival boats were pointed for this\none fish, because not only was he the largest, and therefore the most\nvaluable whale, but he was nearest to them, and the other whales were\ngoing with such great velocity, moreover, as almost to defy pursuit\nfor the time.  At this juncture the Pequod's keels had shot by the\nthree German boats last lowered; but from the great start he had had,\nDerick's boat still led the chase, though every moment neared by his\nforeign rivals.  The only thing they feared, was, that from being\nalready so nigh to his mark, he would be enabled to dart his iron\nbefore they could completely overtake and pass him.  As for Derick,\nhe seemed quite confident that this would be the case, and\noccasionally with a deriding gesture shook his lamp-feeder at the\nother boats.\n\n\"The ungracious and ungrateful dog!\" cried Starbuck; \"he mocks and\ndares me with the very poor-box I filled for him not five minutes\nago!\"--then in his old intense whisper--\"Give way, greyhounds!  Dog\nto it!\"\n\n\"I tell ye what it is, men\"--cried Stubb to his crew--\"it's against\nmy religion to get mad; but I'd like to eat that villainous\nYarman--Pull--won't ye?  Are ye going to let that rascal beat ye?  Do\nye love brandy?  A hogshead of brandy, then, to the best man.  Come,\nwhy don't some of ye burst a blood-vessel?  Who's that been dropping\nan anchor overboard--we don't budge an inch--we're becalmed.  Halloo,\nhere's grass growing in the boat's bottom--and by the Lord, the mast\nthere's budding.  This won't do, boys.  Look at that Yarman!  The\nshort and long of it is, men, will ye spit fire or not?\"\n\n\"Oh! see the suds he makes!\" cried Flask, dancing up and down--\"What\na hump--Oh, DO pile on the beef--lays like a log!  Oh! my lads, DO\nspring--slap-jacks and quahogs for supper, you know, my lads--baked\nclams and muffins--oh, DO, DO, spring,--he's a hundred barreller--don't\nlose him now--don't oh, DON'T!--see that Yarman--Oh,\nwon't ye pull for your duff, my lads--such a sog! such a sogger!\nDon't ye love sperm?  There goes three thousand dollars, men!--a\nbank!--a whole bank!  The bank of England!--Oh, DO, DO, DO!--What's\nthat Yarman about now?\"\n\nAt this moment Derick was in the act of pitching his lamp-feeder at\nthe advancing boats, and also his oil-can; perhaps with the double\nview of retarding his rivals' way, and at the same time economically\naccelerating his own by the momentary impetus of the backward toss.\n\n\"The unmannerly Dutch dogger!\" cried Stubb.  \"Pull now, men, like\nfifty thousand line-of-battle-ship loads of red-haired devils.  What\nd'ye say, Tashtego; are you the man to snap your spine in\ntwo-and-twenty pieces for the honour of old Gayhead?  What d'ye say?\"\n\n\"I say, pull like god-dam,\"--cried the Indian.\n\nFiercely, but evenly incited by the taunts of the German, the\nPequod's three boats now began ranging almost abreast; and, so\ndisposed, momentarily neared him.  In that fine, loose, chivalrous\nattitude of the headsman when drawing near to his prey, the three\nmates stood up proudly, occasionally backing the after oarsman with\nan exhilarating cry of, \"There she slides, now!  Hurrah for the\nwhite-ash breeze!  Down with the Yarman!  Sail over him!\"\n\nBut so decided an original start had Derick had, that spite of all\ntheir gallantry, he would have proved the victor in this race, had\nnot a righteous judgment descended upon him in a crab which caught\nthe blade of his midship oarsman.  While this clumsy lubber was\nstriving to free his white-ash, and while, in consequence, Derick's\nboat was nigh to capsizing, and he thundering away at his men in a\nmighty rage;--that was a good time for Starbuck, Stubb, and Flask.\nWith a shout, they took a mortal start forwards, and slantingly\nranged up on the German's quarter.  An instant more, and all four\nboats were diagonically in the whale's immediate wake, while\nstretching from them, on both sides, was the foaming swell that he\nmade.\n\nIt was a terrific, most pitiable, and maddening sight.  The whale was\nnow going head out, and sending his spout before him in a continual\ntormented jet; while his one poor fin beat his side in an agony of\nfright.  Now to this hand, now to that, he yawed in his faltering\nflight, and still at every billow that he broke, he spasmodically\nsank in the sea, or sideways rolled towards the sky his one beating\nfin.  So have I seen a bird with clipped wing making affrighted\nbroken circles in the air, vainly striving to escape the piratical\nhawks.  But the bird has a voice, and with plaintive cries will make\nknown her fear; but the fear of this vast dumb brute of the sea, was\nchained up and enchanted in him; he had no voice, save that choking\nrespiration through his spiracle, and this made the sight of him\nunspeakably pitiable; while still, in his amazing bulk, portcullis\njaw, and omnipotent tail, there was enough to appal the stoutest man\nwho so pitied.\n\nSeeing now that but a very few moments more would give the Pequod's\nboats the advantage, and rather than be thus foiled of his game,\nDerick chose to hazard what to him must have seemed a most unusually\nlong dart, ere the last chance would for ever escape.\n\nBut no sooner did his harpooneer stand up for the stroke, than all\nthree tigers--Queequeg, Tashtego, Daggoo--instinctively sprang to\ntheir feet, and standing in a diagonal row, simultaneously pointed\ntheir barbs; and darted over the head of the German harpooneer, their\nthree Nantucket irons entered the whale.  Blinding vapours of foam and\nwhite-fire!  The three boats, in the first fury of the whale's\nheadlong rush, bumped the German's aside with such force, that both\nDerick and his baffled harpooneer were spilled out, and sailed over\nby the three flying keels.\n\n\"Don't be afraid, my butter-boxes,\" cried Stubb, casting a passing\nglance upon them as he shot by; \"ye'll be picked up presently--all\nright--I saw some sharks astern--St. Bernard's dogs, you\nknow--relieve distressed travellers.  Hurrah! this is the way to sail\nnow.  Every keel a sunbeam!  Hurrah!--Here we go like three tin\nkettles at the tail of a mad cougar!  This puts me in mind of\nfastening to an elephant in a tilbury on a plain--makes the\nwheel-spokes fly, boys, when you fasten to him that way; and there's\ndanger of being pitched out too, when you strike a hill.  Hurrah!\nthis is the way a fellow feels when he's going to Davy Jones--all a\nrush down an endless inclined plane!  Hurrah! this whale carries the\neverlasting mail!\"\n\nBut the monster's run was a brief one.  Giving a sudden gasp, he\ntumultuously sounded.  With a grating rush, the three lines flew\nround the loggerheads with such a force as to gouge deep grooves in\nthem; while so fearful were the harpooneers that this rapid sounding\nwould soon exhaust the lines, that using all their dexterous might,\nthey caught repeated smoking turns with the rope to hold on; till at\nlast--owing to the perpendicular strain from the lead-lined chocks of\nthe boats, whence the three ropes went straight down into the\nblue--the gunwales of the bows were almost even with the water, while\nthe three sterns tilted high in the air.  And the whale soon ceasing\nto sound, for some time they remained in that attitude, fearful of\nexpending more line, though the position was a little ticklish.  But\nthough boats have been taken down and lost in this way, yet it is\nthis \"holding on,\" as it is called; this hooking up by the sharp\nbarbs of his live flesh from the back; this it is that often torments\nthe Leviathan into soon rising again to meet the sharp lance of his\nfoes.  Yet not to speak of the peril of the thing, it is to be\ndoubted whether this course is always the best; for it is but\nreasonable to presume, that the longer the stricken whale stays under\nwater, the more he is exhausted.  Because, owing to the enormous\nsurface of him--in a full grown sperm whale something less than 2000\nsquare feet--the pressure of the water is immense.  We all know what\nan astonishing atmospheric weight we ourselves stand up under; even\nhere, above-ground, in the air; how vast, then, the burden of a\nwhale, bearing on his back a column of two hundred fathoms of ocean!\nIt must at least equal the weight of fifty atmospheres.  One whaleman\nhas estimated it at the weight of twenty line-of-battle ships, with\nall their guns, and stores, and men on board.\n\nAs the three boats lay there on that gently rolling sea, gazing down\ninto its eternal blue noon; and as not a single groan or cry of any\nsort, nay, not so much as a ripple or a bubble came up from its\ndepths; what landsman would have thought, that beneath all that\nsilence and placidity, the utmost monster of the seas was writhing\nand wrenching in agony!  Not eight inches of perpendicular rope were\nvisible at the bows.  Seems it credible that by three such thin\nthreads the great Leviathan was suspended like the big weight to an\neight day clock.  Suspended? and to what?  To three bits of board.\nIs this the creature of whom it was once so triumphantly said--\"Canst\nthou fill his skin with barbed irons? or his head with fish-spears?\nThe sword of him that layeth at him cannot hold, the spear, the dart,\nnor the habergeon: he esteemeth iron as straw; the arrow cannot make\nhim flee; darts are counted as stubble; he laugheth at the shaking of\na spear!\"  This the creature? this he?  Oh! that unfulfilments should\nfollow the prophets.  For with the strength of a thousand thighs in\nhis tail, Leviathan had run his head under the mountains of the sea,\nto hide him from the Pequod's fish-spears!\n\nIn that sloping afternoon sunlight, the shadows that the three boats\nsent down beneath the surface, must have been long enough and broad\nenough to shade half Xerxes' army.  Who can tell how appalling to the\nwounded whale must have been such huge phantoms flitting over his\nhead!\n\n\"Stand by, men; he stirs,\" cried Starbuck, as the three lines\nsuddenly vibrated in the water, distinctly conducting upwards to\nthem, as by magnetic wires, the life and death throbs of the whale,\nso that every oarsman felt them in his seat.  The next moment,\nrelieved in great part from the downward strain at the bows, the\nboats gave a sudden bounce upwards, as a small icefield will, when a\ndense herd of white bears are scared from it into the sea.\n\n\"Haul in!  Haul in!\" cried Starbuck again; \"he's rising.\"\n\nThe lines, of which, hardly an instant before, not one hand's breadth\ncould have been gained, were now in long quick coils flung back all\ndripping into the boats, and soon the whale broke water within two\nship's lengths of the hunters.\n\nHis motions plainly denoted his extreme exhaustion.  In most land\nanimals there are certain valves or flood-gates in many of their\nveins, whereby when wounded, the blood is in some degree at least\ninstantly shut off in certain directions.  Not so with the whale; one\nof whose peculiarities it is to have an entire non-valvular structure\nof the blood-vessels, so that when pierced even by so small a point\nas a harpoon, a deadly drain is at once begun upon his whole\narterial system; and when this is heightened by the extraordinary\npressure of water at a great distance below the surface, his life may\nbe said to pour from him in incessant streams.  Yet so vast is the\nquantity of blood in him, and so distant and numerous its interior\nfountains, that he will keep thus bleeding and bleeding for a\nconsiderable period; even as in a drought a river will flow, whose\nsource is in the well-springs of far-off and undiscernible hills.\nEven now, when the boats pulled upon this whale, and perilously drew\nover his swaying flukes, and the lances were darted into him, they\nwere followed by steady jets from the new made wound, which kept\ncontinually playing, while the natural spout-hole in his head was\nonly at intervals, however rapid, sending its affrighted moisture\ninto the air.  From this last vent no blood yet came, because no\nvital part of him had thus far been struck.  His life, as they\nsignificantly call it, was untouched.\n\nAs the boats now more closely surrounded him, the whole upper part of\nhis form, with much of it that is ordinarily submerged, was plainly\nrevealed.  His eyes, or rather the places where his eyes had been,\nwere beheld.  As strange misgrown masses gather in the knot-holes of\nthe noblest oaks when prostrate, so from the points which the whale's\neyes had once occupied, now protruded blind bulbs, horribly pitiable\nto see.  But pity there was none.  For all his old age, and his one\narm, and his blind eyes, he must die the death and be murdered, in\norder to light the gay bridals and other merry-makings of men, and\nalso to illuminate the solemn churches that preach unconditional\ninoffensiveness by all to all.  Still rolling in his blood, at last\nhe partially disclosed a strangely discoloured bunch or protuberance,\nthe size of a bushel, low down on the flank.\n\n\"A nice spot,\" cried Flask; \"just let me prick him there once.\"\n\n\"Avast!\" cried Starbuck, \"there's no need of that!\"\n\nBut humane Starbuck was too late.  At the instant of the dart an\nulcerous jet shot from this cruel wound, and goaded by it into more\nthan sufferable anguish, the whale now spouting thick blood, with\nswift fury blindly darted at the craft, bespattering them and their\nglorying crews all over with showers of gore, capsizing Flask's boat\nand marring the bows.  It was his death stroke.  For, by this time,\nso spent was he by loss of blood, that he helplessly rolled away from\nthe wreck he had made; lay panting on his side, impotently flapped\nwith his stumped fin, then over and over slowly revolved like a\nwaning world; turned up the white secrets of his belly; lay like a\nlog, and died.  It was most piteous, that last expiring spout.  As\nwhen by unseen hands the water is gradually drawn off from some\nmighty fountain, and with half-stifled melancholy gurglings the\nspray-column lowers and lowers to the ground--so the last long dying\nspout of the whale.\n\nSoon, while the crews were awaiting the arrival of the ship, the body\nshowed symptoms of sinking with all its treasures unrifled.\nImmediately, by Starbuck's orders, lines were secured to it at\ndifferent points, so that ere long every boat was a buoy; the sunken\nwhale being suspended a few inches beneath them by the cords.  By\nvery heedful management, when the ship drew nigh, the whale was\ntransferred to her side, and was strongly secured there by the\nstiffest fluke-chains, for it was plain that unless artificially\nupheld, the body would at once sink to the bottom.\n\nIt so chanced that almost upon first cutting into him with the\nspade, the entire length of a corroded harpoon was found imbedded in\nhis flesh, on the lower part of the bunch before described.  But as\nthe stumps of harpoons are frequently found in the dead bodies of\ncaptured whales, with the flesh perfectly healed around them, and no\nprominence of any kind to denote their place; therefore, there must\nneeds have been some other unknown reason in the present case fully\nto account for the ulceration alluded to.  But still more curious was\nthe fact of a lance-head of stone being found in him, not far from\nthe buried iron, the flesh perfectly firm about it.  Who had darted\nthat stone lance?  And when?  It might have been darted by some Nor'\nWest Indian long before America was discovered.\n\nWhat other marvels might have been rummaged out of this monstrous\ncabinet there is no telling.  But a sudden stop was put to further\ndiscoveries, by the ship's being unprecedentedly dragged over\nsideways to the sea, owing to the body's immensely increasing\ntendency to sink.  However, Starbuck, who had the ordering of\naffairs, hung on to it to the last; hung on to it so resolutely,\nindeed, that when at length the ship would have been capsized, if\nstill persisting in locking arms with the body; then, when the\ncommand was given to break clear from it, such was the immovable\nstrain upon the timber-heads to which the fluke-chains and cables\nwere fastened, that it was impossible to cast them off.  Meantime\neverything in the Pequod was aslant.  To cross to the other side of\nthe deck was like walking up the steep gabled roof of a house.  The\nship groaned and gasped.  Many of the ivory inlayings of her bulwarks\nand cabins were started from their places, by the unnatural\ndislocation.  In vain handspikes and crows were brought to bear upon\nthe immovable fluke-chains, to pry them adrift from the timberheads;\nand so low had the whale now settled that the submerged ends could\nnot be at all approached, while every moment whole tons of\nponderosity seemed added to the sinking bulk, and the ship seemed on\nthe point of going over.\n\n\"Hold on, hold on, won't ye?\" cried Stubb to the body, \"don't be in\nsuch a devil of a hurry to sink!  By thunder, men, we must do\nsomething or go for it.  No use prying there; avast, I say with your\nhandspikes, and run one of ye for a prayer book and a pen-knife, and\ncut the big chains.\"\n\n\"Knife?  Aye, aye,\" cried Queequeg, and seizing the carpenter's heavy\nhatchet, he leaned out of a porthole, and steel to iron, began\nslashing at the largest fluke-chains.  But a few strokes, full of\nsparks, were given, when the exceeding strain effected the rest.\nWith a terrific snap, every fastening went adrift; the ship righted,\nthe carcase sank.\n\nNow, this occasional inevitable sinking of the recently killed Sperm\nWhale is a very curious thing; nor has any fisherman yet adequately\naccounted for it.  Usually the dead Sperm Whale floats with great\nbuoyancy, with its side or belly considerably elevated above the\nsurface.  If the only whales that thus sank were old, meagre, and\nbroken-hearted creatures, their pads of lard diminished and all their\nbones heavy and rheumatic; then you might with some reason assert\nthat this sinking is caused by an uncommon specific gravity in the\nfish so sinking, consequent upon this absence of buoyant matter in\nhim.  But it is not so.  For young whales, in the highest health, and\nswelling with noble aspirations, prematurely cut off in the warm\nflush and May of life, with all their panting lard about them; even\nthese brawny, buoyant heroes do sometimes sink.\n\nBe it said, however, that the Sperm Whale is far less liable to this\naccident than any other species.  Where one of that sort go down,\ntwenty Right Whales do.  This difference in the species is no doubt\nimputable in no small degree to the greater quantity of bone in the\nRight Whale; his Venetian blinds alone sometimes weighing more than a\nton; from this incumbrance the Sperm Whale is wholly free.  But there\nare instances where, after the lapse of many hours or several days,\nthe sunken whale again rises, more buoyant than in life.  But the\nreason of this is obvious.  Gases are generated in him; he swells to\na prodigious magnitude; becomes a sort of animal balloon.  A\nline-of-battle ship could hardly keep him under then.  In the Shore\nWhaling, on soundings, among the Bays of New Zealand, when a Right\nWhale gives token of sinking, they fasten buoys to him, with plenty\nof rope; so that when the body has gone down, they know where to look\nfor it when it shall have ascended again.\n\nIt was not long after the sinking of the body that a cry was heard\nfrom the Pequod's mast-heads, announcing that the Jungfrau was again\nlowering her boats; though the only spout in sight was that of a\nFin-Back, belonging to the species of uncapturable whales, because of\nits incredible power of swimming.  Nevertheless, the Fin-Back's spout\nis so similar to the Sperm Whale's, that by unskilful fishermen it is\noften mistaken for it.  And consequently Derick and all his host were\nnow in valiant chase of this unnearable brute.  The Virgin crowding\nall sail, made after her four young keels, and thus they all\ndisappeared far to leeward, still in bold, hopeful chase.\n\nOh! many are the Fin-Backs, and many are the Dericks, my friend.\n\n\n\nCHAPTER 82\n\nThe Honour and Glory of Whaling.\n\n\nThere are some enterprises in which a careful disorderliness is the\ntrue method.\n\nThe more I dive into this matter of whaling, and push my researches\nup to the very spring-head of it so much the more am I impressed with\nits great honourableness and antiquity; and especially when I find so\nmany great demi-gods and heroes, prophets of all sorts, who one way\nor other have shed distinction upon it, I am transported with the\nreflection that I myself belong, though but subordinately, to so\nemblazoned a fraternity.\n\nThe gallant Perseus, a son of Jupiter, was the first whaleman; and to\nthe eternal honour of our calling be it said, that the first whale\nattacked by our brotherhood was not killed with any sordid intent.\nThose were the knightly days of our profession, when we only bore\narms to succor the distressed, and not to fill men's lamp-feeders.\nEvery one knows the fine story of Perseus and Andromeda; how the\nlovely Andromeda, the daughter of a king, was tied to a rock on the\nsea-coast, and as Leviathan was in the very act of carrying her off,\nPerseus, the prince of whalemen, intrepidly advancing, harpooned the\nmonster, and delivered and married the maid.  It was an admirable\nartistic exploit, rarely achieved by the best harpooneers of the\npresent day; inasmuch as this Leviathan was slain at the very first\ndart.  And let no man doubt this Arkite story; for in the ancient\nJoppa, now Jaffa, on the Syrian coast, in one of the Pagan temples,\nthere stood for many ages the vast skeleton of a whale, which the\ncity's legends and all the inhabitants asserted to be the identical\nbones of the monster that Perseus slew.  When the Romans took Joppa,\nthe same skeleton was carried to Italy in triumph.  What seems most\nsingular and suggestively important in this story, is this: it was\nfrom Joppa that Jonah set sail.\n\nAkin to the adventure of Perseus and Andromeda--indeed, by some\nsupposed to be indirectly derived from it--is that famous story of\nSt. George and the Dragon; which dragon I maintain to have been a\nwhale; for in many old chronicles whales and dragons are strangely\njumbled together, and often stand for each other.  \"Thou art as a\nlion of the waters, and as a dragon of the sea,\" saith Ezekiel;\nhereby, plainly meaning a whale; in truth, some versions of the Bible\nuse that word itself.  Besides, it would much subtract from the glory\nof the exploit had St. George but encountered a crawling reptile of\nthe land, instead of doing battle with the great monster of the deep.\nAny man may kill a snake, but only a Perseus, a St. George, a\nCoffin, have the heart in them to march boldly up to a whale.\n\nLet not the modern paintings of this scene mislead us; for though the\ncreature encountered by that valiant whaleman of old is vaguely\nrepresented of a griffin-like shape, and though the battle is\ndepicted on land and the saint on horseback, yet considering the\ngreat ignorance of those times, when the true form of the whale was\nunknown to artists; and considering that as in Perseus' case, St.\nGeorge's whale might have crawled up out of the sea on the beach; and\nconsidering that the animal ridden by St. George might have been only\na large seal, or sea-horse; bearing all this in mind, it will not\nappear altogether incompatible with the sacred legend and the\nancientest draughts of the scene, to hold this so-called dragon no\nother than the great Leviathan himself.  In fact, placed before the\nstrict and piercing truth, this whole story will fare like that fish,\nflesh, and fowl idol of the Philistines, Dagon by name; who being\nplanted before the ark of Israel, his horse's head and both the palms\nof his hands fell off from him, and only the stump or fishy part of\nhim remained.  Thus, then, one of our own noble stamp, even a\nwhaleman, is the tutelary guardian of England; and by good rights, we\nharpooneers of Nantucket should be enrolled in the most noble order\nof St. George.  And therefore, let not the knights of that honourable\ncompany (none of whom, I venture to say, have ever had to do with a\nwhale like their great patron), let them never eye a Nantucketer with\ndisdain, since even in our woollen frocks and tarred trowsers we are\nmuch better entitled to St. George's decoration than they.\n\nWhether to admit Hercules among us or not, concerning this I long\nremained dubious: for though according to the Greek mythologies, that\nantique Crockett and Kit Carson--that brawny doer of rejoicing good\ndeeds, was swallowed down and thrown up by a whale; still, whether\nthat strictly makes a whaleman of him, that might be mooted.  It\nnowhere appears that he ever actually harpooned his fish, unless,\nindeed, from the inside.  Nevertheless, he may be deemed a sort of\ninvoluntary whaleman; at any rate the whale caught him, if he did not\nthe whale.  I claim him for one of our clan.\n\nBut, by the best contradictory authorities, this Grecian story of\nHercules and the whale is considered to be derived from the still\nmore ancient Hebrew story of Jonah and the whale; and vice versa;\ncertainly they are very similar.  If I claim the demigod then, why\nnot the prophet?\n\nNor do heroes, saints, demigods, and prophets alone comprise the\nwhole roll of our order.  Our grand master is still to be named; for\nlike royal kings of old times, we find the head waters of our\nfraternity in nothing short of the great gods themselves.  That\nwondrous oriental story is now to be rehearsed from the Shaster,\nwhich gives us the dread Vishnoo, one of the three persons in the\ngodhead of the Hindoos; gives us this divine Vishnoo himself for our\nLord;--Vishnoo, who, by the first of his ten earthly incarnations,\nhas for ever set apart and sanctified the whale.  When Brahma, or the\nGod of Gods, saith the Shaster, resolved to recreate the world after\none of its periodical dissolutions, he gave birth to Vishnoo, to\npreside over the work; but the Vedas, or mystical books, whose\nperusal would seem to have been indispensable to Vishnoo before\nbeginning the creation, and which therefore must have contained\nsomething in the shape of practical hints to young architects, these\nVedas were lying at the bottom of the waters; so Vishnoo became\nincarnate in a whale, and sounding down in him to the uttermost\ndepths, rescued the sacred volumes.  Was not this Vishnoo a whaleman,\nthen? even as a man who rides a horse is called a horseman?\n\nPerseus, St. George, Hercules, Jonah, and Vishnoo! there's a\nmember-roll for you!  What club but the whaleman's can head off like\nthat?\n\n\n\nCHAPTER 83\n\nJonah Historically Regarded.\n\n\nReference was made to the historical story of Jonah and the whale in\nthe preceding chapter.  Now some Nantucketers rather distrust this\nhistorical story of Jonah and the whale.  But then there were some\nsceptical Greeks and Romans, who, standing out from the orthodox\npagans of their times, equally doubted the story of Hercules and the\nwhale, and Arion and the dolphin; and yet their doubting those\ntraditions did not make those traditions one whit the less facts, for\nall that.\n\nOne old Sag-Harbor whaleman's chief reason for questioning the Hebrew\nstory was this:--He had one of those quaint old-fashioned Bibles,\nembellished with curious, unscientific plates; one of which\nrepresented Jonah's whale with two spouts in his head--a peculiarity\nonly true with respect to a species of the Leviathan (the Right\nWhale, and the varieties of that order), concerning which the\nfishermen have this saying, \"A penny roll would choke him\"; his\nswallow is so very small.  But, to this, Bishop Jebb's anticipative\nanswer is ready.  It is not necessary, hints the Bishop, that we\nconsider Jonah as tombed in the whale's belly, but as temporarily\nlodged in some part of his mouth.  And this seems reasonable enough\nin the good Bishop.  For truly, the Right Whale's mouth would\naccommodate a couple of whist-tables, and comfortably seat all the\nplayers.  Possibly, too, Jonah might have ensconced himself in a\nhollow tooth; but, on second thoughts, the Right Whale is toothless.\n\nAnother reason which Sag-Harbor (he went by that name) urged for his\nwant of faith in this matter of the prophet, was something obscurely\nin reference to his incarcerated body and the whale's gastric juices.\nBut this objection likewise falls to the ground, because a German\nexegetist supposes that Jonah must have taken refuge in the floating\nbody of a DEAD whale--even as the French soldiers in the Russian\ncampaign turned their dead horses into tents, and crawled into them.\nBesides, it has been divined by other continental commentators, that\nwhen Jonah was thrown overboard from the Joppa ship, he straightway\neffected his escape to another vessel near by, some vessel with a\nwhale for a figure-head; and, I would add, possibly called \"The\nWhale,\" as some craft are nowadays christened the \"Shark,\" the\n\"Gull,\" the \"Eagle.\"  Nor have there been wanting learned exegetists\nwho have opined that the whale mentioned in the book of Jonah merely\nmeant a life-preserver--an inflated bag of wind--which the endangered\nprophet swam to, and so was saved from a watery doom.  Poor\nSag-Harbor, therefore, seems worsted all round.  But he had still\nanother reason for his want of faith.  It was this, if I remember\nright: Jonah was swallowed by the whale in the Mediterranean Sea, and\nafter three days he was vomited up somewhere within three days'\njourney of Nineveh, a city on the Tigris, very much more than three\ndays' journey across from the nearest point of the Mediterranean\ncoast.  How is that?\n\nBut was there no other way for the whale to land the prophet within\nthat short distance of Nineveh?  Yes.  He might have carried him\nround by the way of the Cape of Good Hope.  But not to speak of the\npassage through the whole length of the Mediterranean, and another\npassage up the Persian Gulf and Red Sea, such a supposition would\ninvolve the complete circumnavigation of all Africa in three days,\nnot to speak of the Tigris waters, near the site of Nineveh, being\ntoo shallow for any whale to swim in.  Besides, this idea of Jonah's\nweathering the Cape of Good Hope at so early a day would wrest the\nhonour of the discovery of that great headland from Bartholomew Diaz,\nits reputed discoverer, and so make modern history a liar.\n\nBut all these foolish arguments of old Sag-Harbor only evinced his\nfoolish pride of reason--a thing still more reprehensible in him,\nseeing that he had but little learning except what he had picked up\nfrom the sun and the sea.  I say it only shows his foolish, impious\npride, and abominable, devilish rebellion against the reverend\nclergy.  For by a Portuguese Catholic priest, this very idea of\nJonah's going to Nineveh via the Cape of Good Hope was advanced as a\nsignal magnification of the general miracle.  And so it was.\nBesides, to this day, the highly enlightened Turks devoutly believe\nin the historical story of Jonah.  And some three centuries ago, an\nEnglish traveller in old Harris's Voyages, speaks of a Turkish Mosque\nbuilt in honour of Jonah, in which Mosque was a miraculous lamp that\nburnt without any oil.\n\n\n\nCHAPTER 84\n\nPitchpoling.\n\n\nTo make them run easily and swiftly, the axles of carriages are\nanointed; and for much the same purpose, some whalers perform an\nanalogous operation upon their boat; they grease the bottom.  Nor is\nit to be doubted that as such a procedure can do no harm, it may\npossibly be of no contemptible advantage; considering that oil and\nwater are hostile; that oil is a sliding thing, and that the object\nin view is to make the boat slide bravely.  Queequeg believed\nstrongly in anointing his boat, and one morning not long after the\nGerman ship Jungfrau disappeared, took more than customary pains in\nthat occupation; crawling under its bottom, where it hung over the\nside, and rubbing in the unctuousness as though diligently seeking to\ninsure a crop of hair from the craft's bald keel.  He seemed to be\nworking in obedience to some particular presentiment.  Nor did it\nremain unwarranted by the event.\n\nTowards noon whales were raised; but so soon as the ship sailed down\nto them, they turned and fled with swift precipitancy; a disordered\nflight, as of Cleopatra's barges from Actium.\n\nNevertheless, the boats pursued, and Stubb's was foremost.  By great\nexertion, Tashtego at last succeeded in planting one iron; but the\nstricken whale, without at all sounding, still continued his\nhorizontal flight, with added fleetness.  Such unintermitted\nstrainings upon the planted iron must sooner or later inevitably\nextract it.  It became imperative to lance the flying whale, or be\ncontent to lose him.  But to haul the boat up to his flank was\nimpossible, he swam so fast and furious.  What then remained?\n\nOf all the wondrous devices and dexterities, the sleights of hand and\ncountless subtleties, to which the veteran whaleman is so often\nforced, none exceed that fine manoeuvre with the lance called\npitchpoling.  Small sword, or broad sword, in all its exercises\nboasts nothing like it.  It is only indispensable with an inveterate\nrunning whale; its grand fact and feature is the wonderful distance\nto which the long lance is accurately darted from a violently\nrocking, jerking boat, under extreme headway.  Steel and wood\nincluded, the entire spear is some ten or twelve feet in length; the\nstaff is much slighter than that of the harpoon, and also of a\nlighter material--pine.  It is furnished with a small rope called a\nwarp, of considerable length, by which it can be hauled back to the\nhand after darting.\n\nBut before going further, it is important to mention here, that\nthough the harpoon may be pitchpoled in the same way with the lance,\nyet it is seldom done; and when done, is still less frequently\nsuccessful, on account of the greater weight and inferior length of\nthe harpoon as compared with the lance, which in effect become\nserious drawbacks.  As a general thing, therefore, you must first\nget fast to a whale, before any pitchpoling comes into play.\n\nLook now at Stubb; a man who from his humorous, deliberate coolness\nand equanimity in the direst emergencies, was specially qualified to\nexcel in pitchpoling.  Look at him; he stands upright in the tossed\nbow of the flying boat; wrapt in fleecy foam, the towing whale is\nforty feet ahead.  Handling the long lance lightly, glancing twice or\nthrice along its length to see if it be exactly straight, Stubb\nwhistlingly gathers up the coil of the warp in one hand, so as to\nsecure its free end in his grasp, leaving the rest unobstructed.\nThen holding the lance full before his waistband's middle, he levels\nit at the whale; when, covering him with it, he steadily depresses\nthe butt-end in his hand, thereby elevating the point till the weapon\nstands fairly balanced upon his palm, fifteen feet in the air.  He\nminds you somewhat of a juggler, balancing a long staff on his chin.\nNext moment with a rapid, nameless impulse, in a superb lofty arch the\nbright steel spans the foaming distance, and quivers in the life spot\nof the whale.  Instead of sparkling water, he now spouts red blood.\n\n\"That drove the spigot out of him!\" cried Stubb.  \"'Tis July's\nimmortal Fourth; all fountains must run wine today!  Would now, it\nwere old Orleans whiskey, or old Ohio, or unspeakable old\nMonongahela!  Then, Tashtego, lad, I'd have ye hold a canakin to the\njet, and we'd drink round it!  Yea, verily, hearts alive, we'd brew\nchoice punch in the spread of his spout-hole there, and from that\nlive punch-bowl quaff the living stuff.\"\n\nAgain and again to such gamesome talk, the dexterous dart is\nrepeated, the spear returning to its master like a greyhound held in\nskilful leash.  The agonized whale goes into his flurry; the tow-line\nis slackened, and the pitchpoler dropping astern, folds his hands,\nand mutely watches the monster die.\n\n\n\nCHAPTER 85\n\nThe Fountain.\n\n\nThat for six thousand years--and no one knows how many millions of\nages before--the great whales should have been spouting all over the\nsea, and sprinkling and mistifying the gardens of the deep, as with\nso many sprinkling or mistifying pots; and that for some centuries\nback, thousands of hunters should have been close by the fountain of\nthe whale, watching these sprinklings and spoutings--that all this\nshould be, and yet, that down to this blessed minute (fifteen and a\nquarter minutes past one o'clock P.M. of this sixteenth day of\nDecember, A.D. 1851), it should still remain a problem, whether these\nspoutings are, after all, really water, or nothing but vapour--this is\nsurely a noteworthy thing.\n\nLet us, then, look at this matter, along with some interesting items\ncontingent.  Every one knows that by the peculiar cunning of their\ngills, the finny tribes in general breathe the air which at all times\nis combined with the element in which they swim; hence, a herring or\na cod might live a century, and never once raise its head above the\nsurface.  But owing to his marked internal structure which gives him\nregular lungs, like a human being's, the whale can only live by\ninhaling the disengaged air in the open atmosphere.  Wherefore the\nnecessity for his periodical visits to the upper world.  But he\ncannot in any degree breathe through his mouth, for, in his ordinary\nattitude, the Sperm Whale's mouth is buried at least eight feet\nbeneath the surface; and what is still more, his windpipe has no\nconnexion with his mouth.  No, he breathes through his spiracle\nalone; and this is on the top of his head.\n\nIf I say, that in any creature breathing is only a function\nindispensable to vitality, inasmuch as it withdraws from the air a\ncertain element, which being subsequently brought into contact with\nthe blood imparts to the blood its vivifying principle, I do not\nthink I shall err; though I may possibly use some superfluous\nscientific words.  Assume it, and it follows that if all the blood in\na man could be aerated with one breath, he might then seal up his\nnostrils and not fetch another for a considerable time.  That is to\nsay, he would then live without breathing.  Anomalous as it may seem,\nthis is precisely the case with the whale, who systematically lives,\nby intervals, his full hour and more (when at the bottom) without\ndrawing a single breath, or so much as in any way inhaling a particle\nof air; for, remember, he has no gills.  How is this?  Between his\nribs and on each side of his spine he is supplied with a remarkable\ninvolved Cretan labyrinth of vermicelli-like vessels, which vessels,\nwhen he quits the surface, are completely distended with oxygenated\nblood.  So that for an hour or more, a thousand fathoms in the sea,\nhe carries a surplus stock of vitality in him, just as the camel\ncrossing the waterless desert carries a surplus supply of drink for\nfuture use in its four supplementary stomachs.  The anatomical fact\nof this labyrinth is indisputable; and that the supposition founded\nupon it is reasonable and true, seems the more cogent to me, when I\nconsider the otherwise inexplicable obstinacy of that leviathan in\nHAVING HIS SPOUTINGS OUT, as the fishermen phrase it.  This is what I\nmean.  If unmolested, upon rising to the surface, the Sperm Whale\nwill continue there for a period of time exactly uniform with all his\nother unmolested risings.  Say he stays eleven minutes, and jets\nseventy times, that is, respires seventy breaths; then whenever he\nrises again, he will be sure to have his seventy breaths over again,\nto a minute.  Now, if after he fetches a few breaths you alarm him,\nso that he sounds, he will be always dodging up again to make good\nhis regular allowance of air.  And not till those seventy breaths are\ntold, will he finally go down to stay out his full term below.\nRemark, however, that in different individuals these rates are\ndifferent; but in any one they are alike.  Now, why should the whale\nthus insist upon having his spoutings out, unless it be to replenish\nhis reservoir of air, ere descending for good?  How obvious is it,\ntoo, that this necessity for the whale's rising exposes him to all\nthe fatal hazards of the chase.  For not by hook or by net could\nthis vast leviathan be caught, when sailing a thousand fathoms\nbeneath the sunlight.  Not so much thy skill, then, O hunter, as the\ngreat necessities that strike the victory to thee!\n\nIn man, breathing is incessantly going on--one breath only serving\nfor two or three pulsations; so that whatever other business he has\nto attend to, waking or sleeping, breathe he must, or die he will.\nBut the Sperm Whale only breathes about one seventh or Sunday of his\ntime.\n\nIt has been said that the whale only breathes through his spout-hole;\nif it could truthfully be added that his spouts are mixed with water,\nthen I opine we should be furnished with the reason why his sense of\nsmell seems obliterated in him; for the only thing about him that at\nall answers to his nose is that identical spout-hole; and being so\nclogged with two elements, it could not be expected to have the power\nof smelling.  But owing to the mystery of the spout--whether it be\nwater or whether it be vapour--no absolute certainty can as yet be\narrived at on this head.  Sure it is, nevertheless, that the Sperm\nWhale has no proper olfactories.  But what does he want of them?  No\nroses, no violets, no Cologne-water in the sea.\n\nFurthermore, as his windpipe solely opens into the tube of his\nspouting canal, and as that long canal--like the grand Erie Canal--is\nfurnished with a sort of locks (that open and shut) for the downward\nretention of air or the upward exclusion of water, therefore the\nwhale has no voice; unless you insult him by saying, that when he so\nstrangely rumbles, he talks through his nose.  But then again, what\nhas the whale to say?  Seldom have I known any profound being that\nhad anything to say to this world, unless forced to stammer out\nsomething by way of getting a living.  Oh! happy that the world is\nsuch an excellent listener!\n\nNow, the spouting canal of the Sperm Whale, chiefly intended as it is\nfor the conveyance of air, and for several feet laid along,\nhorizontally, just beneath the upper surface of his head, and a\nlittle to one side; this curious canal is very much like a gas-pipe\nlaid down in a city on one side of a street.  But the question\nreturns whether this gas-pipe is also a water-pipe; in other words,\nwhether the spout of the Sperm Whale is the mere vapour of the exhaled\nbreath, or whether that exhaled breath is mixed with water taken in\nat the mouth, and discharged through the spiracle.  It is certain\nthat the mouth indirectly communicates with the spouting canal; but\nit cannot be proved that this is for the purpose of discharging water\nthrough the spiracle.  Because the greatest necessity for so doing\nwould seem to be, when in feeding he accidentally takes in water.\nBut the Sperm Whale's food is far beneath the surface, and there he\ncannot spout even if he would.  Besides, if you regard him very\nclosely, and time him with your watch, you will find that when\nunmolested, there is an undeviating rhyme between the periods of his\njets and the ordinary periods of respiration.\n\nBut why pester one with all this reasoning on the subject?  Speak\nout!  You have seen him spout; then declare what the spout is; can\nyou not tell water from air?  My dear sir, in this world it is not so\neasy to settle these plain things.  I have ever found your plain\nthings the knottiest of all.  And as for this whale spout, you might\nalmost stand in it, and yet be undecided as to what it is precisely.\n\nThe central body of it is hidden in the snowy sparkling mist\nenveloping it; and how can you certainly tell whether any water falls\nfrom it, when, always, when you are close enough to a whale to get a\nclose view of his spout, he is in a prodigious commotion, the water\ncascading all around him.  And if at such times you should think that\nyou really perceived drops of moisture in the spout, how do you know\nthat they are not merely condensed from its vapour; or how do you know\nthat they are not those identical drops superficially lodged in the\nspout-hole fissure, which is countersunk into the summit of the\nwhale's head?  For even when tranquilly swimming through the mid-day\nsea in a calm, with his elevated hump sun-dried as a dromedary's in\nthe desert; even then, the whale always carries a small basin of\nwater on his head, as under a blazing sun you will sometimes see a\ncavity in a rock filled up with rain.\n\nNor is it at all prudent for the hunter to be over curious touching\nthe precise nature of the whale spout.  It will not do for him to be\npeering into it, and putting his face in it.  You cannot go with your\npitcher to this fountain and fill it, and bring it away.  For even\nwhen coming into slight contact with the outer, vapoury shreds of the\njet, which will often happen, your skin will feverishly smart, from\nthe acridness of the thing so touching it.  And I know one, who\ncoming into still closer contact with the spout, whether with some\nscientific object in view, or otherwise, I cannot say, the skin\npeeled off from his cheek and arm.  Wherefore, among whalemen, the\nspout is deemed poisonous; they try to evade it.  Another thing; I\nhave heard it said, and I do not much doubt it, that if the jet is\nfairly spouted into your eyes, it will blind you.  The wisest thing\nthe investigator can do then, it seems to me, is to let this deadly\nspout alone.\n\nStill, we can hypothesize, even if we cannot prove and establish.  My\nhypothesis is this: that the spout is nothing but mist.  And besides\nother reasons, to this conclusion I am impelled, by considerations\ntouching the great inherent dignity and sublimity of the Sperm Whale;\nI account him no common, shallow being, inasmuch as it is an\nundisputed fact that he is never found on soundings, or near shores;\nall other whales sometimes are.  He is both ponderous and profound.\nAnd I am convinced that from the heads of all ponderous profound\nbeings, such as Plato, Pyrrho, the Devil, Jupiter, Dante, and so on,\nthere always goes up a certain semi-visible steam, while in the act\nof thinking deep thoughts.  While composing a little treatise on\nEternity, I had the curiosity to place a mirror before me; and ere\nlong saw reflected there, a curious involved worming and undulation\nin the atmosphere over my head.  The invariable moisture of my hair,\nwhile plunged in deep thought, after six cups of hot tea in my thin\nshingled attic, of an August noon; this seems an additional argument\nfor the above supposition.\n\nAnd how nobly it raises our conceit of the mighty, misty monster, to\nbehold him solemnly sailing through a calm tropical sea; his vast,\nmild head overhung by a canopy of vapour, engendered by his\nincommunicable contemplations, and that vapour--as you will sometimes\nsee it--glorified by a rainbow, as if Heaven itself had put its seal\nupon his thoughts.  For, d'ye see, rainbows do not visit the clear\nair; they only irradiate vapour.  And so, through all the thick mists\nof the dim doubts in my mind, divine intuitions now and then shoot,\nenkindling my fog with a heavenly ray.  And for this I thank God; for\nall have doubts; many deny; but doubts or denials, few along with\nthem, have intuitions.  Doubts of all things earthly, and intuitions\nof some things heavenly; this combination makes neither believer nor\ninfidel, but makes a man who regards them both with equal eye.\n\n\n\nCHAPTER 86\n\nThe Tail.\n\n\nOther poets have warbled the praises of the soft eye of the antelope,\nand the lovely plumage of the bird that never alights; less\ncelestial, I celebrate a tail.\n\nReckoning the largest sized Sperm Whale's tail to begin at that point\nof the trunk where it tapers to about the girth of a man, it\ncomprises upon its upper surface alone, an area of at least fifty\nsquare feet.  The compact round body of its root expands into two\nbroad, firm, flat palms or flukes, gradually shoaling away to less\nthan an inch in thickness.  At the crotch or junction, these flukes\nslightly overlap, then sideways recede from each other like wings,\nleaving a wide vacancy between.  In no living thing are the lines of\nbeauty more exquisitely defined than in the crescentic borders of\nthese flukes.  At its utmost expansion in the full grown whale, the\ntail will considerably exceed twenty feet across.\n\nThe entire member seems a dense webbed bed of welded sinews; but cut\ninto it, and you find that three distinct strata compose it:--upper,\nmiddle, and lower.  The fibres in the upper and lower layers, are\nlong and horizontal; those of the middle one, very short, and running\ncrosswise between the outside layers.  This triune structure, as much\nas anything else, imparts power to the tail.  To the student of old\nRoman walls, the middle layer will furnish a curious parallel to the\nthin course of tiles always alternating with the stone in those\nwonderful relics of the antique, and which undoubtedly contribute so\nmuch to the great strength of the masonry.\n\nBut as if this vast local power in the tendinous tail were not\nenough, the whole bulk of the leviathan is knit over with a warp and\nwoof of muscular fibres and filaments, which passing on either side\nthe loins and running down into the flukes, insensibly blend with\nthem, and largely contribute to their might; so that in the tail the\nconfluent measureless force of the whole whale seems concentrated to\na point.  Could annihilation occur to matter, this were the thing to\ndo it.\n\nNor does this--its amazing strength, at all tend to cripple the\ngraceful flexion of its motions; where infantileness of ease\nundulates through a Titanism of power.  On the contrary, those\nmotions derive their most appalling beauty from it.  Real strength\nnever impairs beauty or harmony, but it often bestows it; and in\neverything imposingly beautiful, strength has much to do with the\nmagic.  Take away the tied tendons that all over seem bursting from\nthe marble in the carved Hercules, and its charm would be gone.  As\ndevout Eckerman lifted the linen sheet from the naked corpse of\nGoethe, he was overwhelmed with the massive chest of the man, that\nseemed as a Roman triumphal arch.  When Angelo paints even God the\nFather in human form, mark what robustness is there.  And whatever\nthey may reveal of the divine love in the Son, the soft, curled,\nhermaphroditical Italian pictures, in which his idea has been most\nsuccessfully embodied; these pictures, so destitute as they are of\nall brawniness, hint nothing of any power, but the mere negative,\nfeminine one of submission and endurance, which on all hands it is\nconceded, form the peculiar practical virtues of his teachings.\n\nSuch is the subtle elasticity of the organ I treat of, that whether\nwielded in sport, or in earnest, or in anger, whatever be the mood it\nbe in, its flexions are invariably marked by exceeding grace.\nTherein no fairy's arm can transcend it.\n\nFive great motions are peculiar to it.  First, when used as a fin for\nprogression; Second, when used as a mace in battle; Third, in\nsweeping; Fourth, in lobtailing; Fifth, in peaking flukes.\n\nFirst: Being horizontal in its position, the Leviathan's tail acts in\na different manner from the tails of all other sea creatures.  It\nnever wriggles.  In man or fish, wriggling is a sign of inferiority.\nTo the whale, his tail is the sole means of propulsion.  Scroll-wise\ncoiled forwards beneath the body, and then rapidly sprung backwards,\nit is this which gives that singular darting, leaping motion to the\nmonster when furiously swimming.  His side-fins only serve to steer\nby.\n\nSecond: It is a little significant, that while one sperm whale only\nfights another sperm whale with his head and jaw, nevertheless, in\nhis conflicts with man, he chiefly and contemptuously uses his tail.\nIn striking at a boat, he swiftly curves away his flukes from it, and\nthe blow is only inflicted by the recoil.  If it be made in the\nunobstructed air, especially if it descend to its mark, the stroke is\nthen simply irresistible.  No ribs of man or boat can withstand it.\nYour only salvation lies in eluding it; but if it comes sideways\nthrough the opposing water, then partly owing to the light buoyancy\nof the whale boat, and the elasticity of its materials, a cracked\nrib or a dashed plank or two, a sort of stitch in the side, is\ngenerally the most serious result.  These submerged side blows are so\noften received in the fishery, that they are accounted mere child's\nplay.  Some one strips off a frock, and the hole is stopped.\n\nThird: I cannot demonstrate it, but it seems to me, that in the whale\nthe sense of touch is concentrated in the tail; for in this respect\nthere is a delicacy in it only equalled by the daintiness of the\nelephant's trunk.  This delicacy is chiefly evinced in the action of\nsweeping, when in maidenly gentleness the whale with a certain soft\nslowness moves his immense flukes from side to side upon the surface of\nthe sea; and if he feel but a sailor's whisker, woe to that sailor,\nwhiskers and all.  What tenderness there is in that preliminary\ntouch!  Had this tail any prehensile power, I should straightway\nbethink me of Darmonodes' elephant that so frequented the\nflower-market, and with low salutations presented nosegays to\ndamsels, and then caressed their zones.  On more accounts than one, a\npity it is that the whale does not possess this prehensile virtue in\nhis tail; for I have heard of yet another elephant, that when wounded\nin the fight, curved round his trunk and extracted the dart.\n\nFourth: Stealing unawares upon the whale in the fancied security of\nthe middle of solitary seas, you find him unbent from the vast\ncorpulence of his dignity, and kitten-like, he plays on the ocean as\nif it were a hearth.  But still you see his power in his play.  The\nbroad palms of his tail are flirted high into the air; then smiting\nthe surface, the thunderous concussion resounds for miles.  You would\nalmost think a great gun had been discharged; and if you noticed the\nlight wreath of vapour from the spiracle at his other extremity, you\nwould think that that was the smoke from the touch-hole.\n\nFifth: As in the ordinary floating posture of the leviathan the\nflukes lie considerably below the level of his back, they are then\ncompletely out of sight beneath the surface; but when he is about to\nplunge into the deeps, his entire flukes with at least thirty feet of\nhis body are tossed erect in the air, and so remain vibrating a\nmoment, till they downwards shoot out of view.  Excepting the sublime\nBREACH--somewhere else to be described--this peaking of the whale's\nflukes is perhaps the grandest sight to be seen in all animated\nnature.  Out of the bottomless profundities the gigantic tail seems\nspasmodically snatching at the highest heaven.  So in dreams, have I\nseen majestic Satan thrusting forth his tormented colossal claw from\nthe flame Baltic of Hell.  But in gazing at such scenes, it is all in\nall what mood you are in; if in the Dantean, the devils will occur to\nyou; if in that of Isaiah, the archangels.  Standing at the mast-head\nof my ship during a sunrise that crimsoned sky and sea, I once saw a\nlarge herd of whales in the east, all heading towards the sun, and\nfor a moment vibrating in concert with peaked flukes.  As it seemed\nto me at the time, such a grand embodiment of adoration of the gods\nwas never beheld, even in Persia, the home of the fire worshippers.\nAs Ptolemy Philopater testified of the African elephant, I then\ntestified of the whale, pronouncing him the most devout of all\nbeings.  For according to King Juba, the military elephants of\nantiquity often hailed the morning with their trunks uplifted in the\nprofoundest silence.\n\nThe chance comparison in this chapter, between the whale and the\nelephant, so far as some aspects of the tail of the one and the trunk\nof the other are concerned, should not tend to place those two\nopposite organs on an equality, much less the creatures to which they\nrespectively belong.  For as the mightiest elephant is but a terrier\nto Leviathan, so, compared with Leviathan's tail, his trunk is but\nthe stalk of a lily.  The most direful blow from the elephant's trunk\nwere as the playful tap of a fan, compared with the measureless crush\nand crash of the sperm whale's ponderous flukes, which in repeated\ninstances have one after the other hurled entire boats with all their\noars and crews into the air, very much as an Indian juggler tosses\nhis balls.*\n\n\n*Though all comparison in the way of general bulk between the whale\nand the elephant is preposterous, inasmuch as in that particular the\nelephant stands in much the same respect to the whale that a dog does\nto the elephant; nevertheless, there are not wanting some points of\ncurious similitude; among these is the spout.  It is well known that\nthe elephant will often draw up water or dust in his trunk, and then\nelevating it, jet it forth in a stream.\n\n\nThe more I consider this mighty tail, the more do I deplore my\ninability to express it.  At times there are gestures in it, which,\nthough they would well grace the hand of man, remain wholly\ninexplicable.  In an extensive herd, so remarkable, occasionally, are\nthese mystic gestures, that I have heard hunters who have declared\nthem akin to Free-Mason signs and symbols; that the whale, indeed, by\nthese methods intelligently conversed with the world.  Nor are there\nwanting other motions of the whale in his general body, full of\nstrangeness, and unaccountable to his most experienced assailant.\nDissect him how I may, then, I but go skin deep; I know him not,\nand never will.  But if I know not even the tail of this whale, how\nunderstand his head? much more, how comprehend his face, when face he\nhas none?  Thou shalt see my back parts, my tail, he seems to say,\nbut my face shall not be seen.  But I cannot completely make out his\nback parts; and hint what he will about his face, I say again he has\nno face.\n\n\n\nCHAPTER 87\n\nThe Grand Armada.\n\n\nThe long and narrow peninsula of Malacca, extending south-eastward\nfrom the territories of Birmah, forms the most southerly point of all\nAsia.  In a continuous line from that peninsula stretch the long\nislands of Sumatra, Java, Bally, and Timor; which, with many others,\nform a vast mole, or rampart, lengthwise connecting Asia with\nAustralia, and dividing the long unbroken Indian ocean from the\nthickly studded oriental archipelagoes.  This rampart is pierced by\nseveral sally-ports for the convenience of ships and whales;\nconspicuous among which are the straits of Sunda and Malacca.  By the\nstraits of Sunda, chiefly, vessels bound to China from the west,\nemerge into the China seas.\n\nThose narrow straits of Sunda divide Sumatra from Java; and standing\nmidway in that vast rampart of islands, buttressed by that bold green\npromontory, known to seamen as Java Head; they not a little\ncorrespond to the central gateway opening into some vast walled\nempire: and considering the inexhaustible wealth of spices, and\nsilks, and jewels, and gold, and ivory, with which the thousand\nislands of that oriental sea are enriched, it seems a significant\nprovision of nature, that such treasures, by the very formation of\nthe land, should at least bear the appearance, however ineffectual,\nof being guarded from the all-grasping western world.  The shores of\nthe Straits of Sunda are unsupplied with those domineering fortresses\nwhich guard the entrances to the Mediterranean, the Baltic, and the\nPropontis.  Unlike the Danes, these Orientals do not demand the\nobsequious homage of lowered top-sails from the endless procession of\nships before the wind, which for centuries past, by night and by day,\nhave passed between the islands of Sumatra and Java, freighted with\nthe costliest cargoes of the east.  But while they freely waive a\nceremonial like this, they do by no means renounce their claim to\nmore solid tribute.\n\nTime out of mind the piratical proas of the Malays, lurking among the\nlow shaded coves and islets of Sumatra, have sallied out upon the\nvessels sailing through the straits, fiercely demanding tribute at\nthe point of their spears.  Though by the repeated bloody\nchastisements they have received at the hands of European cruisers,\nthe audacity of these corsairs has of late been somewhat repressed;\nyet, even at the present day, we occasionally hear of English and\nAmerican vessels, which, in those waters, have been remorselessly\nboarded and pillaged.\n\nWith a fair, fresh wind, the Pequod was now drawing nigh to these\nstraits; Ahab purposing to pass through them into the Javan sea, and\nthence, cruising northwards, over waters known to be frequented here\nand there by the Sperm Whale, sweep inshore by the Philippine\nIslands, and gain the far coast of Japan, in time for the great\nwhaling season there.  By these means, the circumnavigating Pequod\nwould sweep almost all the known Sperm Whale cruising grounds of the\nworld, previous to descending upon the Line in the Pacific; where\nAhab, though everywhere else foiled in his pursuit, firmly counted\nupon giving battle to Moby Dick, in the sea he was most known to\nfrequent; and at a season when he might most reasonably be presumed\nto be haunting it.\n\nBut how now? in this zoned quest, does Ahab touch no land? does his\ncrew drink air?  Surely, he will stop for water.  Nay.  For a long\ntime, now, the circus-running sun has raced within his fiery ring,\nand needs no sustenance but what's in himself.  So Ahab.  Mark this,\ntoo, in the whaler.  While other hulls are loaded down with alien\nstuff, to be transferred to foreign wharves; the world-wandering\nwhale-ship carries no cargo but herself and crew, their weapons and\ntheir wants.  She has a whole lake's contents bottled in her ample\nhold.  She is ballasted with utilities; not altogether with unusable\npig-lead and kentledge.  She carries years' water in her.  Clear old\nprime Nantucket water; which, when three years afloat, the\nNantucketer, in the Pacific, prefers to drink before the brackish\nfluid, but yesterday rafted off in casks, from the Peruvian or Indian\nstreams.  Hence it is, that, while other ships may have gone to China\nfrom New York, and back again, touching at a score of ports, the\nwhale-ship, in all that interval, may not have sighted one grain of\nsoil; her crew having seen no man but floating seamen like\nthemselves.  So that did you carry them the news that another flood\nhad come; they would only answer--\"Well, boys, here's the ark!\"\n\nNow, as many Sperm Whales had been captured off the western coast of\nJava, in the near vicinity of the Straits of Sunda; indeed, as most\nof the ground, roundabout, was generally recognised by the fishermen\nas an excellent spot for cruising; therefore, as the Pequod gained\nmore and more upon Java Head, the look-outs were repeatedly hailed,\nand admonished to keep wide awake.  But though the green palmy cliffs\nof the land soon loomed on the starboard bow, and with delighted\nnostrils the fresh cinnamon was snuffed in the air, yet not a single\njet was descried.  Almost renouncing all thought of falling in with\nany game hereabouts, the ship had well nigh entered the straits, when\nthe customary cheering cry was heard from aloft, and ere long a\nspectacle of singular magnificence saluted us.\n\nBut here be it premised, that owing to the unwearied activity with\nwhich of late they have been hunted over all four oceans, the Sperm\nWhales, instead of almost invariably sailing in small detached\ncompanies, as in former times, are now frequently met with in\nextensive herds, sometimes embracing so great a multitude, that it\nwould almost seem as if numerous nations of them had sworn solemn\nleague and covenant for mutual assistance and protection.  To this\naggregation of the Sperm Whale into such immense caravans, may be\nimputed the circumstance that even in the best cruising grounds, you\nmay now sometimes sail for weeks and months together, without being\ngreeted by a single spout; and then be suddenly saluted by what\nsometimes seems thousands on thousands.\n\nBroad on both bows, at the distance of some two or three miles, and\nforming a great semicircle, embracing one half of the level horizon,\na continuous chain of whale-jets were up-playing and sparkling in the\nnoon-day air.  Unlike the straight perpendicular twin-jets of the\nRight Whale, which, dividing at top, fall over in two branches, like\nthe cleft drooping boughs of a willow, the single forward-slanting\nspout of the Sperm Whale presents a thick curled bush of white mist,\ncontinually rising and falling away to leeward.\n\nSeen from the Pequod's deck, then, as she would rise on a high hill\nof the sea, this host of vapoury spouts, individually curling up into\nthe air, and beheld through a blending atmosphere of bluish haze,\nshowed like the thousand cheerful chimneys of some dense metropolis,\ndescried of a balmy autumnal morning, by some horseman on a height.\n\nAs marching armies approaching an unfriendly defile in the mountains,\naccelerate their march, all eagerness to place that perilous passage\nin their rear, and once more expand in comparative security upon the\nplain; even so did this vast fleet of whales now seem hurrying\nforward through the straits; gradually contracting the wings of their\nsemicircle, and swimming on, in one solid, but still crescentic\ncentre.\n\nCrowding all sail the Pequod pressed after them; the harpooneers\nhandling their weapons, and loudly cheering from the heads of their\nyet suspended boats.  If the wind only held, little doubt had they,\nthat chased through these Straits of Sunda, the vast host would only\ndeploy into the Oriental seas to witness the capture of not a few of\ntheir number.  And who could tell whether, in that congregated\ncaravan, Moby Dick himself might not temporarily be swimming, like\nthe worshipped white-elephant in the coronation procession of the\nSiamese!  So with stun-sail piled on stun-sail, we sailed along,\ndriving these leviathans before us; when, of a sudden, the voice of\nTashtego was heard, loudly directing attention to something in our\nwake.\n\nCorresponding to the crescent in our van, we beheld another in our\nrear.  It seemed formed of detached white vapours, rising and falling\nsomething like the spouts of the whales; only they did not so\ncompletely come and go; for they constantly hovered, without finally\ndisappearing.  Levelling his glass at this sight, Ahab quickly\nrevolved in his pivot-hole, crying, \"Aloft there, and rig whips and\nbuckets to wet the sails;--Malays, sir, and after us!\"\n\nAs if too long lurking behind the headlands, till the Pequod should\nfairly have entered the straits, these rascally Asiatics were now in\nhot pursuit, to make up for their over-cautious delay.  But when the\nswift Pequod, with a fresh leading wind, was herself in hot chase;\nhow very kind of these tawny philanthropists to assist in speeding\nher on to her own chosen pursuit,--mere riding-whips and rowels to\nher, that they were.  As with glass under arm, Ahab to-and-fro paced\nthe deck; in his forward turn beholding the monsters he chased, and\nin the after one the bloodthirsty pirates chasing him; some such\nfancy as the above seemed his.  And when he glanced upon the green\nwalls of the watery defile in which the ship was then sailing, and\nbethought him that through that gate lay the route to his vengeance,\nand beheld, how that through that same gate he was now both chasing\nand being chased to his deadly end; and not only that, but a herd of\nremorseless wild pirates and inhuman atheistical devils were\ninfernally cheering him on with their curses;--when all these\nconceits had passed through his brain, Ahab's brow was left gaunt and\nribbed, like the black sand beach after some stormy tide has been\ngnawing it, without being able to drag the firm thing from its place.\n\nBut thoughts like these troubled very few of the reckless crew; and\nwhen, after steadily dropping and dropping the pirates astern, the\nPequod at last shot by the vivid green Cockatoo Point on the Sumatra\nside, emerging at last upon the broad waters beyond; then, the\nharpooneers seemed more to grieve that the swift whales had been\ngaining upon the ship, than to rejoice that the ship had so\nvictoriously gained upon the Malays.  But still driving on in the\nwake of the whales, at length they seemed abating their speed;\ngradually the ship neared them; and the wind now dying away, word was\npassed to spring to the boats.  But no sooner did the herd, by some\npresumed wonderful instinct of the Sperm Whale, become notified of\nthe three keels that were after them,--though as yet a mile in their\nrear,--than they rallied again, and forming in close ranks and\nbattalions, so that their spouts all looked like flashing lines of\nstacked bayonets, moved on with redoubled velocity.\n\nStripped to our shirts and drawers, we sprang to the white-ash, and\nafter several hours' pulling were almost disposed to renounce the\nchase, when a general pausing commotion among the whales gave\nanimating token that they were now at last under the influence of\nthat strange perplexity of inert irresolution, which, when the\nfishermen perceive it in the whale, they say he is gallied.  The\ncompact martial columns in which they had been hitherto rapidly and\nsteadily swimming, were now broken up in one measureless rout; and\nlike King Porus' elephants in the Indian battle with Alexander, they\nseemed going mad with consternation.  In all directions expanding in\nvast irregular circles, and aimlessly swimming hither and thither, by\ntheir short thick spoutings, they plainly betrayed their distraction\nof panic.  This was still more strangely evinced by those of their\nnumber, who, completely paralysed as it were, helplessly floated like\nwater-logged dismantled ships on the sea.  Had these Leviathans been\nbut a flock of simple sheep, pursued over the pasture by three fierce\nwolves, they could not possibly have evinced such excessive dismay.\nBut this occasional timidity is characteristic of almost all herding\ncreatures.  Though banding together in tens of thousands, the\nlion-maned buffaloes of the West have fled before a solitary\nhorseman.  Witness, too, all human beings, how when herded together\nin the sheepfold of a theatre's pit, they will, at the slightest\nalarm of fire, rush helter-skelter for the outlets, crowding,\ntrampling, jamming, and remorselessly dashing each other to death.\nBest, therefore, withhold any amazement at the strangely gallied\nwhales before us, for there is no folly of the beasts of the earth\nwhich is not infinitely outdone by the madness of men.\n\nThough many of the whales, as has been said, were in violent motion,\nyet it is to be observed that as a whole the herd neither advanced\nnor retreated, but collectively remained in one place.  As is\ncustomary in those cases, the boats at once separated, each making\nfor some one lone whale on the outskirts of the shoal.  In about\nthree minutes' time, Queequeg's harpoon was flung; the stricken fish\ndarted blinding spray in our faces, and then running away with us like\nlight, steered straight for the heart of the herd.  Though such a\nmovement on the part of the whale struck under such circumstances, is\nin no wise unprecedented; and indeed is almost always more or less\nanticipated; yet does it present one of the more perilous\nvicissitudes of the fishery.  For as the swift monster drags you\ndeeper and deeper into the frantic shoal, you bid adieu to\ncircumspect life and only exist in a delirious throb.\n\nAs, blind and deaf, the whale plunged forward, as if by sheer power\nof speed to rid himself of the iron leech that had fastened to him;\nas we thus tore a white gash in the sea, on all sides menaced as we\nflew, by the crazed creatures to and fro rushing about us; our beset\nboat was like a ship mobbed by ice-isles in a tempest, and striving\nto steer through their complicated channels and straits, knowing not at\nwhat moment it may be locked in and crushed.\n\nBut not a bit daunted, Queequeg steered us manfully; now sheering off\nfrom this monster directly across our route in advance; now edging\naway from that, whose colossal flukes were suspended overhead, while\nall the time, Starbuck stood up in the bows, lance in hand, pricking\nout of our way whatever whales he could reach by short darts, for\nthere was no time to make long ones.  Nor were the oarsmen quite\nidle, though their wonted duty was now altogether dispensed with.\nThey chiefly attended to the shouting part of the business.  \"Out of\nthe way, Commodore!\" cried one, to a great dromedary that of a sudden\nrose bodily to the surface, and for an instant threatened to swamp\nus.  \"Hard down with your tail, there!\" cried a second to another,\nwhich, close to our gunwale, seemed calmly cooling himself with his\nown fan-like extremity.\n\nAll whaleboats carry certain curious contrivances, originally\ninvented by the Nantucket Indians, called druggs.  Two thick squares\nof wood of equal size are stoutly clenched together, so that they\ncross each other's grain at right angles; a line of considerable\nlength is then attached to the middle of this block, and the other\nend of the line being looped, it can in a moment be fastened to a\nharpoon.  It is chiefly among gallied whales that this drugg is used.\nFor then, more whales are close round you than you can possibly\nchase at one time.  But sperm whales are not every day encountered;\nwhile you may, then, you must kill all you can.  And if you cannot\nkill them all at once, you must wing them, so that they can be\nafterwards killed at your leisure.  Hence it is, that at times like\nthese the drugg, comes into requisition.  Our boat was furnished with\nthree of them.  The first and second were successfully darted, and we\nsaw the whales staggeringly running off, fettered by the enormous\nsidelong resistance of the towing drugg.  They were cramped like\nmalefactors with the chain and ball.  But upon flinging the third, in\nthe act of tossing overboard the clumsy wooden block, it caught under\none of the seats of the boat, and in an instant tore it out and\ncarried it away, dropping the oarsman in the boat's bottom as the\nseat slid from under him.  On both sides the sea came in at the\nwounded planks, but we stuffed two or three drawers and shirts in,\nand so stopped the leaks for the time.\n\nIt had been next to impossible to dart these drugged-harpoons, were\nit not that as we advanced into the herd, our whale's way greatly\ndiminished; moreover, that as we went still further and further from\nthe circumference of commotion, the direful disorders seemed waning.\nSo that when at last the jerking harpoon drew out, and the towing\nwhale sideways vanished; then, with the tapering force of his parting\nmomentum, we glided between two whales into the innermost heart of\nthe shoal, as if from some mountain torrent we had slid into a serene\nvalley lake.  Here the storms in the roaring glens between the\noutermost whales, were heard but not felt.  In this central expanse\nthe sea presented that smooth satin-like surface, called a sleek,\nproduced by the subtle moisture thrown off by the whale in his more\nquiet moods.  Yes, we were now in that enchanted calm which they say\nlurks at the heart of every commotion.  And still in the distracted\ndistance we beheld the tumults of the outer concentric circles, and\nsaw successive pods of whales, eight or ten in each, swiftly going\nround and round, like multiplied spans of horses in a ring; and so\nclosely shoulder to shoulder, that a Titanic circus-rider might\neasily have over-arched the middle ones, and so have gone round on\ntheir backs.  Owing to the density of the crowd of reposing whales,\nmore immediately surrounding the embayed axis of the herd, no\npossible chance of escape was at present afforded us.  We must watch\nfor a breach in the living wall that hemmed us in; the wall that had\nonly admitted us in order to shut us up.  Keeping at the centre of\nthe lake, we were occasionally visited by small tame cows and calves;\nthe women and children of this routed host.\n\nNow, inclusive of the occasional wide intervals between the revolving\nouter circles, and inclusive of the spaces between the various pods\nin any one of those circles, the entire area at this juncture,\nembraced by the whole multitude, must have contained at least two or\nthree square miles.  At any rate--though indeed such a test at such a\ntime might be deceptive--spoutings might be discovered from our low\nboat that seemed playing up almost from the rim of the horizon.  I\nmention this circumstance, because, as if the cows and calves had\nbeen purposely locked up in this innermost fold; and as if the wide\nextent of the herd had hitherto prevented them from learning the\nprecise cause of its stopping; or, possibly, being so young,\nunsophisticated, and every way innocent and inexperienced; however it\nmay have been, these smaller whales--now and then visiting our\nbecalmed boat from the margin of the lake--evinced a wondrous\nfearlessness and confidence, or else a still becharmed panic which it\nwas impossible not to marvel at.  Like household dogs they came\nsnuffling round us, right up to our gunwales, and touching them; till\nit almost seemed that some spell had suddenly domesticated them.\nQueequeg patted their foreheads; Starbuck scratched their backs with\nhis lance; but fearful of the consequences, for the time refrained\nfrom darting it.\n\nBut far beneath this wondrous world upon the surface, another and\nstill stranger world met our eyes as we gazed over the side.  For,\nsuspended in those watery vaults, floated the forms of the nursing\nmothers of the whales, and those that by their enormous girth seemed\nshortly to become mothers.  The lake, as I have hinted, was to a\nconsiderable depth exceedingly transparent; and as human infants\nwhile suckling will calmly and fixedly gaze away from the breast, as\nif leading two different lives at the time; and while yet drawing\nmortal nourishment, be still spiritually feasting upon some unearthly\nreminiscence;--even so did the young of these whales seem looking up\ntowards us, but not at us, as if we were but a bit of Gulfweed in\ntheir new-born sight.  Floating on their sides, the mothers also\nseemed quietly eyeing us.  One of these little infants, that from\ncertain queer tokens seemed hardly a day old, might have measured\nsome fourteen feet in length, and some six feet in girth.  He was a\nlittle frisky; though as yet his body seemed scarce yet recovered\nfrom that irksome position it had so lately occupied in the maternal\nreticule; where, tail to head, and all ready for the final spring,\nthe unborn whale lies bent like a Tartar's bow.  The delicate\nside-fins, and the palms of his flukes, still freshly retained the\nplaited crumpled appearance of a baby's ears newly arrived from\nforeign parts.\n\n\"Line! line!\" cried Queequeg, looking over the gunwale; \"him fast!\nhim fast!--Who line him!  Who struck?--Two whale; one big, one\nlittle!\"\n\n\"What ails ye, man?\" cried Starbuck.\n\n\"Look-e here,\" said Queequeg, pointing down.\n\nAs when the stricken whale, that from the tub has reeled out hundreds\nof fathoms of rope; as, after deep sounding, he floats up again, and\nshows the slackened curling line buoyantly rising and spiralling\ntowards the air; so now, Starbuck saw long coils of the umbilical\ncord of Madame Leviathan, by which the young cub seemed still\ntethered to its dam.  Not seldom in the rapid vicissitudes of the\nchase, this natural line, with the maternal end loose, becomes\nentangled with the hempen one, so that the cub is thereby trapped.\nSome of the subtlest secrets of the seas seemed divulged to us in\nthis enchanted pond.  We saw young Leviathan amours in the deep.*\n\n\n*The sperm whale, as with all other species of the Leviathan, but\nunlike most other fish, breeds indifferently at all seasons; after a\ngestation which may probably be set down at nine months, producing\nbut one at a time; though in some few known instances giving birth to\nan Esau and Jacob:--a contingency provided for in suckling by two\nteats, curiously situated, one on each side of the anus; but the\nbreasts themselves extend upwards from that.  When by chance these\nprecious parts in a nursing whale are cut by the hunter's lance, the\nmother's pouring milk and blood rivallingly discolour the sea for\nrods.  The milk is very sweet and rich; it has been tasted by man; it\nmight do well with strawberries.  When overflowing with mutual\nesteem, the whales salute MORE HOMINUM.\n\n\nAnd thus, though surrounded by circle upon circle of consternations\nand affrights, did these inscrutable creatures at the centre freely\nand fearlessly indulge in all peaceful concernments; yea, serenely\nrevelled in dalliance and delight.  But even so, amid the tornadoed\nAtlantic of my being, do I myself still for ever centrally disport in\nmute calm; and while ponderous planets of unwaning woe revolve round\nme, deep down and deep inland there I still bathe me in eternal\nmildness of joy.\n\nMeanwhile, as we thus lay entranced, the occasional sudden frantic\nspectacles in the distance evinced the activity of the other boats,\nstill engaged in drugging the whales on the frontier of the host; or\npossibly carrying on the war within the first circle, where abundance\nof room and some convenient retreats were afforded them.  But the\nsight of the enraged drugged whales now and then blindly darting to\nand fro across the circles, was nothing to what at last met our eyes.\nIt is sometimes the custom when fast to a whale more than commonly\npowerful and alert, to seek to hamstring him, as it were, by\nsundering or maiming his gigantic tail-tendon.  It is done by darting\na short-handled cutting-spade, to which is attached a rope for\nhauling it back again.  A whale wounded (as we afterwards learned) in\nthis part, but not effectually, as it seemed, had broken away from\nthe boat, carrying along with him half of the harpoon line; and in\nthe extraordinary agony of the wound, he was now dashing among the\nrevolving circles like the lone mounted desperado Arnold, at the\nbattle of Saratoga, carrying dismay wherever he went.\n\nBut agonizing as was the wound of this whale, and an appalling\nspectacle enough, any way; yet the peculiar horror with which he\nseemed to inspire the rest of the herd, was owing to a cause which at\nfirst the intervening distance obscured from us.  But at length we\nperceived that by one of the unimaginable accidents of the fishery,\nthis whale had become entangled in the harpoon-line that he towed; he\nhad also run away with the cutting-spade in him; and while the free\nend of the rope attached to that weapon, had permanently caught in\nthe coils of the harpoon-line round his tail, the cutting-spade\nitself had worked loose from his flesh.  So that tormented to\nmadness, he was now churning through the water, violently flailing\nwith his flexible tail, and tossing the keen spade about him,\nwounding and murdering his own comrades.\n\nThis terrific object seemed to recall the whole herd from their\nstationary fright.  First, the whales forming the margin of our lake\nbegan to crowd a little, and tumble against each other, as if lifted\nby half spent billows from afar; then the lake itself began faintly\nto heave and swell; the submarine bridal-chambers and nurseries\nvanished; in more and more contracting orbits the whales in the more\ncentral circles began to swim in thickening clusters.  Yes, the long\ncalm was departing.  A low advancing hum was soon heard; and then\nlike to the tumultuous masses of block-ice when the great river\nHudson breaks up in Spring, the entire host of whales came tumbling\nupon their inner centre, as if to pile themselves up in one common\nmountain.  Instantly Starbuck and Queequeg changed places; Starbuck\ntaking the stern.\n\n\"Oars!  Oars!\" he intensely whispered, seizing the helm--\"gripe your\noars, and clutch your souls, now!  My God, men, stand by!  Shove him\noff, you Queequeg--the whale there!--prick him!--hit him!  Stand\nup--stand up, and stay so!  Spring, men--pull, men; never mind their\nbacks--scrape them!--scrape away!\"\n\nThe boat was now all but jammed between two vast black bulks, leaving\na narrow Dardanelles between their long lengths.  But by desperate\nendeavor we at last shot into a temporary opening; then giving way\nrapidly, and at the same time earnestly watching for another outlet.\nAfter many similar hair-breadth escapes, we at last swiftly glided\ninto what had just been one of the outer circles, but now crossed by\nrandom whales, all violently making for one centre.  This lucky\nsalvation was cheaply purchased by the loss of Queequeg's hat, who,\nwhile standing in the bows to prick the fugitive whales, had his hat\ntaken clean from his head by the air-eddy made by the sudden tossing\nof a pair of broad flukes close by.\n\nRiotous and disordered as the universal commotion now was, it soon\nresolved itself into what seemed a systematic movement; for having\nclumped together at last in one dense body, they then renewed their\nonward flight with augmented fleetness.  Further pursuit was useless;\nbut the boats still lingered in their wake to pick up what drugged\nwhales might be dropped astern, and likewise to secure one which\nFlask had killed and waifed.  The waif is a pennoned pole, two or\nthree of which are carried by every boat; and which, when additional\ngame is at hand, are inserted upright into the floating body of a\ndead whale, both to mark its place on the sea, and also as token of\nprior possession, should the boats of any other ship draw near.\n\nThe result of this lowering was somewhat illustrative of that\nsagacious saying in the Fishery,--the more whales the less fish.  Of\nall the drugged whales only one was captured.  The rest contrived to\nescape for the time, but only to be taken, as will hereafter be seen,\nby some other craft than the Pequod.\n\n\n\nCHAPTER 88\n\nSchools and Schoolmasters.\n\n\nThe previous chapter gave account of an immense body or herd of Sperm\nWhales, and there was also then given the probable cause inducing\nthose vast aggregations.\n\nNow, though such great bodies are at times encountered, yet, as must\nhave been seen, even at the present day, small detached bands are\noccasionally observed, embracing from twenty to fifty individuals\neach.  Such bands are known as schools.  They generally are of two\nsorts; those composed almost entirely of females, and those mustering\nnone but young vigorous males, or bulls, as they are familiarly\ndesignated.\n\nIn cavalier attendance upon the school of females, you invariably see\na male of full grown magnitude, but not old; who, upon any alarm,\nevinces his gallantry by falling in the rear and covering the flight\nof his ladies.  In truth, this gentleman is a luxurious Ottoman,\nswimming about over the watery world, surroundingly accompanied by\nall the solaces and endearments of the harem.  The contrast between\nthis Ottoman and his concubines is striking; because, while he is\nalways of the largest leviathanic proportions, the ladies, even at\nfull growth, are not more than one-third of the bulk of an\naverage-sized male.  They are comparatively delicate, indeed; I dare\nsay, not to exceed half a dozen yards round the waist.  Nevertheless,\nit cannot be denied, that upon the whole they are hereditarily\nentitled to EMBONPOINT.\n\nIt is very curious to watch this harem and its lord in their indolent\nramblings.  Like fashionables, they are for ever on the move in\nleisurely search of variety.  You meet them on the Line in time for\nthe full flower of the Equatorial feeding season, having just\nreturned, perhaps, from spending the summer in the Northern seas, and\nso cheating summer of all unpleasant weariness and warmth.  By the\ntime they have lounged up and down the promenade of the Equator\nawhile, they start for the Oriental waters in anticipation of the\ncool season there, and so evade the other excessive temperature of\nthe year.\n\nWhen serenely advancing on one of these journeys, if any strange\nsuspicious sights are seen, my lord whale keeps a wary eye on his\ninteresting family.  Should any unwarrantably pert young Leviathan\ncoming that way, presume to draw confidentially close to one of the\nladies, with what prodigious fury the Bashaw assails him, and chases\nhim away!  High times, indeed, if unprincipled young rakes like him\nare to be permitted to invade the sanctity of domestic bliss; though\ndo what the Bashaw will, he cannot keep the most notorious Lothario\nout of his bed; for, alas! all fish bed in common.  As ashore, the\nladies often cause the most terrible duels among their rival\nadmirers; just so with the whales, who sometimes come to deadly\nbattle, and all for love.  They fence with their long lower jaws,\nsometimes locking them together, and so striving for the supremacy\nlike elks that warringly interweave their antlers.  Not a few are\ncaptured having the deep scars of these encounters,--furrowed heads,\nbroken teeth, scolloped fins; and in some instances, wrenched and\ndislocated mouths.\n\nBut supposing the invader of domestic bliss to betake himself away at\nthe first rush of the harem's lord, then is it very diverting to\nwatch that lord.  Gently he insinuates his vast bulk among them again\nand revels there awhile, still in tantalizing vicinity to young\nLothario, like pious Solomon devoutly worshipping among his thousand\nconcubines.  Granting other whales to be in sight, the fishermen\nwill seldom give chase to one of these Grand Turks; for these Grand\nTurks are too lavish of their strength, and hence their unctuousness\nis small.  As for the sons and the daughters they beget, why, those sons\nand daughters must take care of themselves; at least, with only the\nmaternal help.  For like certain other omnivorous roving lovers that\nmight be named, my Lord Whale has no taste for the nursery, however\nmuch for the bower; and so, being a great traveller, he leaves his\nanonymous babies all over the world; every baby an exotic.  In good\ntime, nevertheless, as the ardour of youth declines; as years and\ndumps increase; as reflection lends her solemn pauses; in short, as a\ngeneral lassitude overtakes the sated Turk; then a love of ease and\nvirtue supplants the love for maidens; our Ottoman enters upon the\nimpotent, repentant, admonitory stage of life, forswears, disbands\nthe harem, and grown to an exemplary, sulky old soul, goes about all\nalone among the meridians and parallels saying his prayers, and\nwarning each young Leviathan from his amorous errors.\n\nNow, as the harem of whales is called by the fishermen a school, so\nis the lord and master of that school technically known as the\nschoolmaster.  It is therefore not in strict character, however\nadmirably satirical, that after going to school himself, he should\nthen go abroad inculcating not what he learned there, but the folly\nof it.  His title, schoolmaster, would very naturally seem derived\nfrom the name bestowed upon the harem itself, but some have surmised\nthat the man who first thus entitled this sort of Ottoman whale, must\nhave read the memoirs of Vidocq, and informed himself what sort of a\ncountry-schoolmaster that famous Frenchman was in his younger days,\nand what was the nature of those occult lessons he inculcated into\nsome of his pupils.\n\nThe same secludedness and isolation to which the schoolmaster whale\nbetakes himself in his advancing years, is true of all aged Sperm\nWhales.  Almost universally, a lone whale--as a solitary Leviathan is\ncalled--proves an ancient one.  Like venerable moss-bearded Daniel\nBoone, he will have no one near him but Nature herself; and her he\ntakes to wife in the wilderness of waters, and the best of wives she\nis, though she keeps so many moody secrets.\n\nThe schools composing none but young and vigorous males, previously\nmentioned, offer a strong contrast to the harem schools.  For while\nthose female whales are characteristically timid, the young males, or\nforty-barrel-bulls, as they call them, are by far the most pugnacious\nof all Leviathans, and proverbially the most dangerous to encounter;\nexcepting those wondrous grey-headed, grizzled whales, sometimes met,\nand these will fight you like grim fiends exasperated by a penal\ngout.\n\nThe Forty-barrel-bull schools are larger than the harem schools.\nLike a mob of young collegians, they are full of fight, fun, and\nwickedness, tumbling round the world at such a reckless, rollicking\nrate, that no prudent underwriter would insure them any more than he\nwould a riotous lad at Yale or Harvard.  They soon relinquish this\nturbulence though, and when about three-fourths grown, break up, and\nseparately go about in quest of settlements, that is, harems.\n\nAnother point of difference between the male and female schools is\nstill more characteristic of the sexes.  Say you strike a\nForty-barrel-bull--poor devil! all his comrades quit him.  But strike\na member of the harem school, and her companions swim around her with\nevery token of concern, sometimes lingering so near her and so long,\nas themselves to fall a prey.\n\n\n\nCHAPTER 89\n\nFast-Fish and Loose-Fish.\n\n\nThe allusion to the waif and waif-poles in the last chapter but one,\nnecessitates some account of the laws and regulations of the whale\nfishery, of which the waif may be deemed the grand symbol and badge.\n\nIt frequently happens that when several ships are cruising in\ncompany, a whale may be struck by one vessel, then escape, and be\nfinally killed and captured by another vessel; and herein are\nindirectly comprised many minor contingencies, all partaking of this\none grand feature.  For example,--after a weary and perilous chase\nand capture of a whale, the body may get loose from the ship by\nreason of a violent storm; and drifting far away to leeward, be\nretaken by a second whaler, who, in a calm, snugly tows it alongside,\nwithout risk of life or line.  Thus the most vexatious and violent\ndisputes would often arise between the fishermen, were there not some\nwritten or unwritten, universal, undisputed law applicable to all\ncases.\n\nPerhaps the only formal whaling code authorized by legislative\nenactment, was that of Holland.  It was decreed by the States-General\nin A.D. 1695.  But though no other nation has ever had any written\nwhaling law, yet the American fishermen have been their own\nlegislators and lawyers in this matter.  They have provided a system\nwhich for terse comprehensiveness surpasses Justinian's Pandects and\nthe By-laws of the Chinese Society for the Suppression of Meddling\nwith other People's Business.  Yes; these laws might be engraven on a\nQueen Anne's forthing, or the barb of a harpoon, and worn round the\nneck, so small are they.\n\nI.  A Fast-Fish belongs to the party fast to it.\n\nII.  A Loose-Fish is fair game for anybody who can soonest catch it.\n\nBut what plays the mischief with this masterly code is the admirable\nbrevity of it, which necessitates a vast volume of commentaries to\nexpound it.\n\nFirst: What is a Fast-Fish?  Alive or dead a fish is technically\nfast, when it is connected with an occupied ship or boat, by any\nmedium at all controllable by the occupant or occupants,--a mast, an\noar, a nine-inch cable, a telegraph wire, or a strand of cobweb, it\nis all the same.  Likewise a fish is technically fast when it bears a\nwaif, or any other recognised symbol of possession; so long as the\nparty waifing it plainly evince their ability at any time to take it\nalongside, as well as their intention so to do.\n\nThese are scientific commentaries; but the commentaries of the\nwhalemen themselves sometimes consist in hard words and harder\nknocks--the Coke-upon-Littleton of the fist.  True, among the more\nupright and honourable whalemen allowances are always made for\npeculiar cases, where it would be an outrageous moral injustice for\none party to claim possession of a whale previously chased or killed\nby another party.  But others are by no means so scrupulous.\n\nSome fifty years ago there was a curious case of whale-trover\nlitigated in England, wherein the plaintiffs set forth that after a\nhard chase of a whale in the Northern seas; and when indeed they (the\nplaintiffs) had succeeded in harpooning the fish; they were at last,\nthrough peril of their lives, obliged to forsake not only their\nlines, but their boat itself.  Ultimately the defendants (the crew of\nanother ship) came up with the whale, struck, killed, seized, and\nfinally appropriated it before the very eyes of the plaintiffs.  And\nwhen those defendants were remonstrated with, their captain snapped\nhis fingers in the plaintiffs' teeth, and assured them that by way of\ndoxology to the deed he had done, he would now retain their line,\nharpoons, and boat, which had remained attached to the whale at the\ntime of the seizure.  Wherefore the plaintiffs now sued for the\nrecovery of the value of their whale, line, harpoons, and boat.\n\nMr. Erskine was counsel for the defendants; Lord Ellenborough was the\njudge.  In the course of the defence, the witty Erskine went on to\nillustrate his position, by alluding to a recent crim. con. case,\nwherein a gentleman, after in vain trying to bridle his wife's\nviciousness, had at last abandoned her upon the seas of life; but in\nthe course of years, repenting of that step, he instituted an action\nto recover possession of her.  Erskine was on the other side; and he\nthen supported it by saying, that though the gentleman had originally\nharpooned the lady, and had once had her fast, and only by reason of\nthe great stress of her plunging viciousness, had at last abandoned\nher; yet abandon her he did, so that she became a loose-fish; and\ntherefore when a subsequent gentleman re-harpooned her, the lady then\nbecame that subsequent gentleman's property, along with whatever\nharpoon might have been found sticking in her.\n\nNow in the present case Erskine contended that the examples of the\nwhale and the lady were reciprocally illustrative of each other.\n\nThese pleadings, and the counter pleadings, being duly heard, the\nvery learned Judge in set terms decided, to wit,--That as for the\nboat, he awarded it to the plaintiffs, because they had merely\nabandoned it to save their lives; but that with regard to the\ncontroverted whale, harpoons, and line, they belonged to the\ndefendants; the whale, because it was a Loose-Fish at the time of the\nfinal capture; and the harpoons and line because when the fish made\noff with them, it (the fish) acquired a property in those articles;\nand hence anybody who afterwards took the fish had a right to them.\nNow the defendants afterwards took the fish; ergo, the aforesaid\narticles were theirs.\n\nA common man looking at this decision of the very learned Judge,\nmight possibly object to it.  But ploughed up to the primary rock of\nthe matter, the two great principles laid down in the twin whaling\nlaws previously quoted, and applied and elucidated by Lord\nEllenborough in the above cited case; these two laws touching\nFast-Fish and Loose-Fish, I say, will, on reflection, be found the\nfundamentals of all human jurisprudence; for notwithstanding its\ncomplicated tracery of sculpture, the Temple of the Law, like the\nTemple of the Philistines, has but two props to stand on.\n\nIs it not a saying in every one's mouth, Possession is half of the\nlaw: that is, regardless of how the thing came into possession?  But\noften possession is the whole of the law.  What are the sinews and\nsouls of Russian serfs and Republican slaves but Fast-Fish, whereof\npossession is the whole of the law?  What to the rapacious landlord\nis the widow's last mite but a Fast-Fish?  What is yonder undetected\nvillain's marble mansion with a door-plate for a waif; what is that\nbut a Fast-Fish?  What is the ruinous discount which Mordecai, the\nbroker, gets from poor Woebegone, the bankrupt, on a loan to\nkeep Woebegone's family from starvation; what is that ruinous\ndiscount but a Fast-Fish?  What is the Archbishop of Savesoul's\nincome of L100,000 seized from the scant bread and cheese of\nhundreds of thousands of broken-backed laborers (all sure of heaven\nwithout any of Savesoul's help) what is that globular L100,000 but a\nFast-Fish?  What are the Duke of Dunder's hereditary towns and\nhamlets but Fast-Fish?  What to that redoubted harpooneer, John Bull,\nis poor Ireland, but a Fast-Fish?  What to that apostolic lancer,\nBrother Jonathan, is Texas but a Fast-Fish?  And concerning all\nthese, is not Possession the whole of the law?\n\nBut if the doctrine of Fast-Fish be pretty generally applicable, the\nkindred doctrine of Loose-Fish is still more widely so.  That is\ninternationally and universally applicable.\n\nWhat was America in 1492 but a Loose-Fish, in which Columbus struck\nthe Spanish standard by way of waifing it for his royal master and\nmistress?  What was Poland to the Czar?  What Greece to the Turk?\nWhat India to England?  What at last will Mexico be to the United\nStates?  All Loose-Fish.\n\nWhat are the Rights of Man and the Liberties of the World but\nLoose-Fish?  What all men's minds and opinions but Loose-Fish?  What\nis the principle of religious belief in them but a Loose-Fish?  What\nto the ostentatious smuggling verbalists are the thoughts of thinkers\nbut Loose-Fish?  What is the great globe itself but a Loose-Fish?\nAnd what are you, reader, but a Loose-Fish and a Fast-Fish, too?\n\n\n\nCHAPTER 90\n\nHeads or Tails.\n\n\n\"De balena vero sufficit, si rex habeat caput, et regina caudam.\"\nBRACTON, L. 3, C. 3.\n\n\nLatin from the books of the Laws of England, which taken along with\nthe context, means, that of all whales captured by anybody on the\ncoast of that land, the King, as Honourary Grand Harpooneer, must have\nthe head, and the Queen be respectfully presented with the tail.  A\ndivision which, in the whale, is much like halving an apple; there is\nno intermediate remainder.  Now as this law, under a modified form,\nis to this day in force in England; and as it offers in various\nrespects a strange anomaly touching the general law of Fast and\nLoose-Fish, it is here treated of in a separate chapter, on the same\ncourteous principle that prompts the English railways to be at the\nexpense of a separate car, specially reserved for the accommodation\nof royalty.  In the first place, in curious proof of the fact that\nthe above-mentioned law is still in force, I proceed to lay before\nyou a circumstance that happened within the last two years.\n\nIt seems that some honest mariners of Dover, or Sandwich, or some one\nof the Cinque Ports, had after a hard chase succeeded in killing and\nbeaching a fine whale which they had originally descried afar off\nfrom the shore.  Now the Cinque Ports are partially or somehow under\nthe jurisdiction of a sort of policeman or beadle, called a Lord\nWarden.  Holding the office directly from the crown, I believe, all\nthe royal emoluments incident to the Cinque Port territories become\nby assignment his.  By some writers this office is called a sinecure.\nBut not so.  Because the Lord Warden is busily employed at times in\nfobbing his perquisites; which are his chiefly by virtue of that same\nfobbing of them.\n\nNow when these poor sun-burnt mariners, bare-footed, and with their\ntrowsers rolled high up on their eely legs, had wearily hauled their\nfat fish high and dry, promising themselves a good L150 from the\nprecious oil and bone; and in fantasy sipping rare tea with their\nwives, and good ale with their cronies, upon the strength of their\nrespective shares; up steps a very learned and most Christian and\ncharitable gentleman, with a copy of Blackstone under his arm; and\nlaying it upon the whale's head, he says--\"Hands off! this fish, my\nmasters, is a Fast-Fish.  I seize it as the Lord Warden's.\"  Upon\nthis the poor mariners in their respectful consternation--so truly\nEnglish--knowing not what to say, fall to vigorously scratching their\nheads all round; meanwhile ruefully glancing from the whale to the\nstranger.  But that did in nowise mend the matter, or at all soften\nthe hard heart of the learned gentleman with the copy of Blackstone.\nAt length one of them, after long scratching about for his ideas,\nmade bold to speak,\n\n\"Please, sir, who is the Lord Warden?\"\n\n\"The Duke.\"\n\n\"But the duke had nothing to do with taking this fish?\"\n\n\"It is his.\"\n\n\"We have been at great trouble, and peril, and some expense, and is\nall that to go to the Duke's benefit; we getting nothing at all for\nour pains but our blisters?\"\n\n\"It is his.\"\n\n\"Is the Duke so very poor as to be forced to this desperate mode of\ngetting a livelihood?\"\n\n\"It is his.\"\n\n\"I thought to relieve my old bed-ridden mother by part of my share of\nthis whale.\"\n\n\"It is his.\"\n\n\"Won't the Duke be content with a quarter or a half?\"\n\n\"It is his.\"\n\nIn a word, the whale was seized and sold, and his Grace the Duke of\nWellington received the money.  Thinking that viewed in some\nparticular lights, the case might by a bare possibility in some small\ndegree be deemed, under the circumstances, a rather hard one, an\nhonest clergyman of the town respectfully addressed a note to his\nGrace, begging him to take the case of those unfortunate mariners\ninto full consideration.  To which my Lord Duke in substance replied\n(both letters were published) that he had already done so, and\nreceived the money, and would be obliged to the reverend gentleman if\nfor the future he (the reverend gentleman) would decline meddling\nwith other people's business.  Is this the still militant old man,\nstanding at the corners of the three kingdoms, on all hands coercing\nalms of beggars?\n\nIt will readily be seen that in this case the alleged right of the\nDuke to the whale was a delegated one from the Sovereign.  We must\nneeds inquire then on what principle the Sovereign is originally\ninvested with that right.  The law itself has already been set forth.\nBut Plowdon gives us the reason for it.  Says Plowdon, the whale so\ncaught belongs to the King and Queen, \"because of its superior\nexcellence.\"  And by the soundest commentators this has ever been\nheld a cogent argument in such matters.\n\nBut why should the King have the head, and the Queen the tail?  A\nreason for that, ye lawyers!\n\nIn his treatise on \"Queen-Gold,\" or Queen-pinmoney, an old King's\nBench author, one William Prynne, thus discourseth: \"Ye tail is ye\nQueen's, that ye Queen's wardrobe may be supplied with ye whalebone.\"\nNow this was written at a time when the black limber bone of the\nGreenland or Right whale was largely used in ladies' bodices.  But\nthis same bone is not in the tail; it is in the head, which is a sad\nmistake for a sagacious lawyer like Prynne.  But is the Queen a\nmermaid, to be presented with a tail?  An allegorical meaning may\nlurk here.\n\nThere are two royal fish so styled by the English law writers--the\nwhale and the sturgeon; both royal property under certain\nlimitations, and nominally supplying the tenth branch of the crown's\nordinary revenue.  I know not that any other author has hinted of the\nmatter; but by inference it seems to me that the sturgeon must be\ndivided in the same way as the whale, the King receiving the highly\ndense and elastic head peculiar to that fish, which, symbolically\nregarded, may possibly be humorously grounded upon some presumed\ncongeniality.  And thus there seems a reason in all things, even in\nlaw.\n\n\n\nCHAPTER 91\n\nThe Pequod Meets The Rose-Bud.\n\n\n\"In vain it was to rake for Ambergriese in the paunch of this\nLeviathan, insufferable fetor denying not inquiry.\"\nSIR T. BROWNE, V.E.\n\n\nIt was a week or two after the last whaling scene recounted, and when\nwe were slowly sailing over a sleepy, vapoury, mid-day sea, that the\nmany noses on the Pequod's deck proved more vigilant discoverers than\nthe three pairs of eyes aloft.  A peculiar and not very pleasant\nsmell was smelt in the sea.\n\n\"I will bet something now,\" said Stubb, \"that somewhere hereabouts\nare some of those drugged whales we tickled the other day.  I thought\nthey would keel up before long.\"\n\nPresently, the vapours in advance slid aside; and there in the\ndistance lay a ship, whose furled sails betokened that some sort of\nwhale must be alongside.  As we glided nearer, the stranger showed\nFrench colours from his peak; and by the eddying cloud of vulture\nsea-fowl that circled, and hovered, and swooped around him, it was\nplain that the whale alongside must be what the fishermen call a\nblasted whale, that is, a whale that has died unmolested on the sea,\nand so floated an unappropriated corpse.  It may well be conceived,\nwhat an unsavory odor such a mass must exhale; worse than an Assyrian\ncity in the plague, when the living are incompetent to bury the\ndeparted.  So intolerable indeed is it regarded by some, that no\ncupidity could persuade them to moor alongside of it.  Yet are there\nthose who will still do it; notwithstanding the fact that the oil\nobtained from such subjects is of a very inferior quality, and by no\nmeans of the nature of attar-of-rose.\n\nComing still nearer with the expiring breeze, we saw that the\nFrenchman had a second whale alongside; and this second whale seemed\neven more of a nosegay than the first.  In truth, it turned out to be\none of those problematical whales that seem to dry up and die with a\nsort of prodigious dyspepsia, or indigestion; leaving their defunct\nbodies almost entirely bankrupt of anything like oil.  Nevertheless,\nin the proper place we shall see that no knowing fisherman will ever\nturn up his nose at such a whale as this, however much he may shun\nblasted whales in general.\n\nThe Pequod had now swept so nigh to the stranger, that Stubb vowed he\nrecognised his cutting spade-pole entangled in the lines that were\nknotted round the tail of one of these whales.\n\n\"There's a pretty fellow, now,\" he banteringly laughed, standing in\nthe ship's bows, \"there's a jackal for ye!  I well know that these\nCrappoes of Frenchmen are but poor devils in the fishery; sometimes\nlowering their boats for breakers, mistaking them for Sperm Whale\nspouts; yes, and sometimes sailing from their port with their hold\nfull of boxes of tallow candles, and cases of snuffers, foreseeing\nthat all the oil they will get won't be enough to dip the Captain's\nwick into; aye, we all know these things; but look ye, here's a\nCrappo that is content with our leavings, the drugged whale there, I\nmean; aye, and is content too with scraping the dry bones of that\nother precious fish he has there.  Poor devil!  I say, pass round a\nhat, some one, and let's make him a present of a little oil for dear\ncharity's sake.  For what oil he'll get from that drugged whale\nthere, wouldn't be fit to burn in a jail; no, not in a condemned\ncell.  And as for the other whale, why, I'll agree to get more oil by\nchopping up and trying out these three masts of ours, than he'll get\nfrom that bundle of bones; though, now that I think of it, it may\ncontain something worth a good deal more than oil; yes, ambergris.  I\nwonder now if our old man has thought of that.  It's worth trying.\nYes, I'm for it;\" and so saying he started for the quarter-deck.\n\nBy this time the faint air had become a complete calm; so that\nwhether or no, the Pequod was now fairly entrapped in the smell, with\nno hope of escaping except by its breezing up again.  Issuing from\nthe cabin, Stubb now called his boat's crew, and pulled off for the\nstranger.  Drawing across her bow, he perceived that in accordance\nwith the fanciful French taste, the upper part of her stem-piece was\ncarved in the likeness of a huge drooping stalk, was painted green,\nand for thorns had copper spikes projecting from it here and there;\nthe whole terminating in a symmetrical folded bulb of a bright red\ncolour.  Upon her head boards, in large gilt letters, he read \"Bouton\nde Rose,\"--Rose-button, or Rose-bud; and this was the romantic name\nof this aromatic ship.\n\nThough Stubb did not understand the BOUTON part of the inscription,\nyet the word ROSE, and the bulbous figure-head put together,\nsufficiently explained the whole to him.\n\n\"A wooden rose-bud, eh?\" he cried with his hand to his nose, \"that\nwill do very well; but how like all creation it smells!\"\n\nNow in order to hold direct communication with the people on deck, he\nhad to pull round the bows to the starboard side, and thus come close\nto the blasted whale; and so talk over it.\n\nArrived then at this spot, with one hand still to his nose, he\nbawled--\"Bouton-de-Rose, ahoy! are there any of you Bouton-de-Roses\nthat speak English?\"\n\n\"Yes,\" rejoined a Guernsey-man from the bulwarks, who turned out to\nbe the chief-mate.\n\n\"Well, then, my Bouton-de-Rose-bud, have you seen the White Whale?\"\n\n\"WHAT whale?\"\n\n\"The WHITE Whale--a Sperm Whale--Moby Dick, have ye seen him?\n\n\"Never heard of such a whale.  Cachalot Blanche!  White Whale--no.\"\n\n\"Very good, then; good bye now, and I'll call again in a minute.\"\n\nThen rapidly pulling back towards the Pequod, and seeing Ahab leaning\nover the quarter-deck rail awaiting his report, he moulded his two\nhands into a trumpet and shouted--\"No, Sir!  No!\"  Upon which Ahab\nretired, and Stubb returned to the Frenchman.\n\nHe now perceived that the Guernsey-man, who had just got into the\nchains, and was using a cutting-spade, had slung his nose in a sort\nof bag.\n\n\"What's the matter with your nose, there?\" said Stubb.  \"Broke it?\"\n\n\"I wish it was broken, or that I didn't have any nose at all!\"\nanswered the Guernsey-man, who did not seem to relish the job he was\nat very much.  \"But what are you holding YOURS for?\"\n\n\"Oh, nothing!  It's a wax nose; I have to hold it on.  Fine day,\nain't it?  Air rather gardenny, I should say; throw us a bunch of\nposies, will ye, Bouton-de-Rose?\"\n\n\"What in the devil's name do you want here?\" roared the Guernseyman,\nflying into a sudden passion.\n\n\"Oh! keep cool--cool? yes, that's the word! why don't you pack those\nwhales in ice while you're working at 'em?  But joking aside, though;\ndo you know, Rose-bud, that it's all nonsense trying to get any oil\nout of such whales?  As for that dried up one, there, he hasn't a\ngill in his whole carcase.\"\n\n\"I know that well enough; but, d'ye see, the Captain here won't\nbelieve it; this is his first voyage; he was a Cologne manufacturer\nbefore.  But come aboard, and mayhap he'll believe you, if he won't\nme; and so I'll get out of this dirty scrape.\"\n\n\"Anything to oblige ye, my sweet and pleasant fellow,\" rejoined\nStubb, and with that he soon mounted to the deck.  There a queer\nscene presented itself.  The sailors, in tasselled caps of red\nworsted, were getting the heavy tackles in readiness for the whales.\nBut they worked rather slow and talked very fast, and seemed in\nanything but a good humor.  All their noses upwardly projected from\ntheir faces like so many jib-booms.  Now and then pairs of them would\ndrop their work, and run up to the mast-head to get some fresh air.\nSome thinking they would catch the plague, dipped oakum in coal-tar,\nand at intervals held it to their nostrils.  Others having broken the\nstems of their pipes almost short off at the bowl, were vigorously\npuffing tobacco-smoke, so that it constantly filled their\nolfactories.\n\nStubb was struck by a shower of outcries and anathemas proceeding\nfrom the Captain's round-house abaft; and looking in that direction\nsaw a fiery face thrust from behind the door, which was held ajar\nfrom within.  This was the tormented surgeon, who, after in vain\nremonstrating against the proceedings of the day, had betaken himself\nto the Captain's round-house (CABINET he called it) to avoid the\npest; but still, could not help yelling out his entreaties and\nindignations at times.\n\nMarking all this, Stubb argued well for his scheme, and turning to\nthe Guernsey-man had a little chat with him, during which the\nstranger mate expressed his detestation of his Captain as a conceited\nignoramus, who had brought them all into so unsavory and unprofitable\na pickle.  Sounding him carefully, Stubb further perceived that the\nGuernsey-man had not the slightest suspicion concerning the\nambergris.  He therefore held his peace on that head, but otherwise\nwas quite frank and confidential with him, so that the two quickly\nconcocted a little plan for both circumventing and satirizing the\nCaptain, without his at all dreaming of distrusting their sincerity.\nAccording to this little plan of theirs, the Guernsey-man, under\ncover of an interpreter's office, was to tell the Captain what he\npleased, but as coming from Stubb; and as for Stubb, he was to utter\nany nonsense that should come uppermost in him during the interview.\n\nBy this time their destined victim appeared from his cabin.  He was a\nsmall and dark, but rather delicate looking man for a sea-captain,\nwith large whiskers and moustache, however; and wore a red cotton\nvelvet vest with watch-seals at his side.  To this gentleman, Stubb\nwas now politely introduced by the Guernsey-man, who at once\nostentatiously put on the aspect of interpreting between them.\n\n\"What shall I say to him first?\" said he.\n\n\"Why,\" said Stubb, eyeing the velvet vest and the watch and seals,\n\"you may as well begin by telling him that he looks a sort of babyish\nto me, though I don't pretend to be a judge.\"\n\n\"He says, Monsieur,\" said the Guernsey-man, in French, turning to his\ncaptain, \"that only yesterday his ship spoke a vessel, whose captain\nand chief-mate, with six sailors, had all died of a fever caught from\na blasted whale they had brought alongside.\"\n\nUpon this the captain started, and eagerly desired to know more.\n\n\"What now?\" said the Guernsey-man to Stubb.\n\n\"Why, since he takes it so easy, tell him that now I have eyed him\ncarefully, I'm quite certain that he's no more fit to command a\nwhale-ship than a St. Jago monkey.  In fact, tell him from me he's a\nbaboon.\"\n\n\"He vows and declares, Monsieur, that the other whale, the dried one,\nis far more deadly than the blasted one; in fine, Monsieur, he\nconjures us, as we value our lives, to cut loose from these fish.\"\n\nInstantly the captain ran forward, and in a loud voice commanded his\ncrew to desist from hoisting the cutting-tackles, and at once cast\nloose the cables and chains confining the whales to the ship.\n\n\"What now?\" said the Guernsey-man, when the Captain had returned to\nthem.\n\n\"Why, let me see; yes, you may as well tell him now that--that--in\nfact, tell him I've diddled him, and (aside to himself) perhaps\nsomebody else.\"\n\n\"He says, Monsieur, that he's very happy to have been of any service\nto us.\"\n\nHearing this, the captain vowed that they were the grateful parties\n(meaning himself and mate) and concluded by inviting Stubb down\ninto his cabin to drink a bottle of Bordeaux.\n\n\"He wants you to take a glass of wine with him,\" said the\ninterpreter.\n\n\"Thank him heartily; but tell him it's against my principles to drink\nwith the man I've diddled.  In fact, tell him I must go.\"\n\n\"He says, Monsieur, that his principles won't admit of his drinking;\nbut that if Monsieur wants to live another day to drink, then\nMonsieur had best drop all four boats, and pull the ship away from\nthese whales, for it's so calm they won't drift.\"\n\nBy this time Stubb was over the side, and getting into his boat,\nhailed the Guernsey-man to this effect,--that having a long tow-line\nin his boat, he would do what he could to help them, by pulling out\nthe lighter whale of the two from the ship's side.  While the\nFrenchman's boats, then, were engaged in towing the ship one way,\nStubb benevolently towed away at his whale the other way,\nostentatiously slacking out a most unusually long tow-line.\n\nPresently a breeze sprang up; Stubb feigned to cast off from the\nwhale; hoisting his boats, the Frenchman soon increased his distance,\nwhile the Pequod slid in between him and Stubb's whale.  Whereupon\nStubb quickly pulled to the floating body, and hailing the Pequod to\ngive notice of his intentions, at once proceeded to reap the fruit of\nhis unrighteous cunning.  Seizing his sharp boat-spade, he commenced\nan excavation in the body, a little behind the side fin.  You would\nalmost have thought he was digging a cellar there in the sea; and\nwhen at length his spade struck against the gaunt ribs, it was like\nturning up old Roman tiles and pottery buried in fat English loam.\nHis boat's crew were all in high excitement, eagerly helping their\nchief, and looking as anxious as gold-hunters.\n\nAnd all the time numberless fowls were diving, and ducking, and\nscreaming, and yelling, and fighting around them.  Stubb was\nbeginning to look disappointed, especially as the horrible nosegay\nincreased, when suddenly from out the very heart of this plague,\nthere stole a faint stream of perfume, which flowed through the tide\nof bad smells without being absorbed by it, as one river will flow\ninto and then along with another, without at all blending with it for\na time.\n\n\"I have it, I have it,\" cried Stubb, with delight, striking something\nin the subterranean regions, \"a purse! a purse!\"\n\nDropping his spade, he thrust both hands in, and drew out handfuls of\nsomething that looked like ripe Windsor soap, or rich mottled old\ncheese; very unctuous and savory withal.  You might easily dent it\nwith your thumb; it is of a hue between yellow and ash colour.  And\nthis, good friends, is ambergris, worth a gold guinea an ounce to any\ndruggist.  Some six handfuls were obtained; but more was unavoidably\nlost in the sea, and still more, perhaps, might have been secured\nwere it not for impatient Ahab's loud command to Stubb to desist, and\ncome on board, else the ship would bid them good bye.\n\n\n\nCHAPTER 92\n\nAmbergris.\n\n\nNow this ambergris is a very curious substance, and so important as\nan article of commerce, that in 1791 a certain Nantucket-born Captain\nCoffin was examined at the bar of the English House of Commons on\nthat subject.  For at that time, and indeed until a comparatively\nlate day, the precise origin of ambergris remained, like amber\nitself, a problem to the learned.  Though the word ambergris is but\nthe French compound for grey amber, yet the two substances are quite\ndistinct.  For amber, though at times found on the sea-coast, is also\ndug up in some far inland soils, whereas ambergris is never found\nexcept upon the sea.  Besides, amber is a hard, transparent, brittle,\nodorless substance, used for mouth-pieces to pipes, for beads and\nornaments; but ambergris is soft, waxy, and so highly fragrant and\nspicy, that it is largely used in perfumery, in pastiles, precious\ncandles, hair-powders, and pomatum.  The Turks use it in cooking, and\nalso carry it to Mecca, for the same purpose that frankincense is\ncarried to St. Peter's in Rome.  Some wine merchants drop a few\ngrains into claret, to flavor it.\n\nWho would think, then, that such fine ladies and gentlemen should\nregale themselves with an essence found in the inglorious bowels of a\nsick whale!  Yet so it is.  By some, ambergris is supposed to be the\ncause, and by others the effect, of the dyspepsia in the whale.  How\nto cure such a dyspepsia it were hard to say, unless by administering\nthree or four boat loads of Brandreth's pills, and then running out\nof harm's way, as laborers do in blasting rocks.\n\nI have forgotten to say that there were found in this ambergris,\ncertain hard, round, bony plates, which at first Stubb thought might\nbe sailors' trowsers buttons; but it afterwards turned out that they\nwere nothing more than pieces of small squid bones embalmed in that\nmanner.\n\nNow that the incorruption of this most fragrant ambergris should be\nfound in the heart of such decay; is this nothing?  Bethink thee of\nthat saying of St. Paul in Corinthians, about corruption and\nincorruption; how that we are sown in dishonour, but raised in glory.\nAnd likewise call to mind that saying of Paracelsus about what it is\nthat maketh the best musk.  Also forget not the strange fact that of\nall things of ill-savor, Cologne-water, in its rudimental\nmanufacturing stages, is the worst.\n\nI should like to conclude the chapter with the above appeal, but\ncannot, owing to my anxiety to repel a charge often made against\nwhalemen, and which, in the estimation of some already biased minds,\nmight be considered as indirectly substantiated by what has been said\nof the Frenchman's two whales.  Elsewhere in this volume the\nslanderous aspersion has been disproved, that the vocation of whaling\nis throughout a slatternly, untidy business.  But there is another\nthing to rebut.  They hint that all whales always smell bad.  Now how\ndid this odious stigma originate?\n\nI opine, that it is plainly traceable to the first arrival of the\nGreenland whaling ships in London, more than two centuries ago.\nBecause those whalemen did not then, and do not now, try out their\noil at sea as the Southern ships have always done; but cutting up the\nfresh blubber in small bits, thrust it through the bung holes of\nlarge casks, and carry it home in that manner; the shortness of the\nseason in those Icy Seas, and the sudden and violent storms to which\nthey are exposed, forbidding any other course.  The consequence is,\nthat upon breaking into the hold, and unloading one of these whale\ncemeteries, in the Greenland dock, a savor is given forth somewhat\nsimilar to that arising from excavating an old city grave-yard, for\nthe foundations of a Lying-in-Hospital.\n\nI partly surmise also, that this wicked charge against whalers may be\nlikewise imputed to the existence on the coast of Greenland, in\nformer times, of a Dutch village called Schmerenburgh or Smeerenberg,\nwhich latter name is the one used by the learned Fogo Von Slack, in\nhis great work on Smells, a text-book on that subject.  As its name\nimports (smeer, fat; berg, to put up), this village was founded in\norder to afford a place for the blubber of the Dutch whale fleet to\nbe tried out, without being taken home to Holland for that purpose.\nIt was a collection of furnaces, fat-kettles, and oil sheds; and when\nthe works were in full operation certainly gave forth no very\npleasant savor.  But all this is quite different with a South Sea\nSperm Whaler; which in a voyage of four years perhaps, after\ncompletely filling her hold with oil, does not, perhaps, consume\nfifty days in the business of boiling out; and in the state that it\nis casked, the oil is nearly scentless.  The truth is, that living or\ndead, if but decently treated, whales as a species are by no means\ncreatures of ill odor; nor can whalemen be recognised, as the people\nof the middle ages affected to detect a Jew in the company, by the\nnose.  Nor indeed can the whale possibly be otherwise than fragrant,\nwhen, as a general thing, he enjoys such high health; taking\nabundance of exercise; always out of doors; though, it is true,\nseldom in the open air.  I say, that the motion of a Sperm Whale's\nflukes above water dispenses a perfume, as when a musk-scented lady\nrustles her dress in a warm parlor.  What then shall I liken the\nSperm Whale to for fragrance, considering his magnitude?  Must it not\nbe to that famous elephant, with jewelled tusks, and redolent with\nmyrrh, which was led out of an Indian town to do honour to Alexander\nthe Great?\n\n\n\nCHAPTER 93\n\nThe Castaway.\n\n\nIt was but some few days after encountering the Frenchman, that a\nmost significant event befell the most insignificant of the Pequod's\ncrew; an event most lamentable; and which ended in providing the\nsometimes madly merry and predestinated craft with a living and ever\naccompanying prophecy of whatever shattered sequel might prove her\nown.\n\nNow, in the whale ship, it is not every one that goes in the boats.\nSome few hands are reserved called ship-keepers, whose province it is\nto work the vessel while the boats are pursuing the whale.  As a\ngeneral thing, these ship-keepers are as hardy fellows as the men\ncomprising the boats' crews.  But if there happen to be an unduly\nslender, clumsy, or timorous wight in the ship, that wight is certain\nto be made a ship-keeper.  It was so in the Pequod with the little\nnegro Pippin by nick-name, Pip by abbreviation.  Poor Pip! ye have\nheard of him before; ye must remember his tambourine on that dramatic\nmidnight, so gloomy-jolly.\n\nIn outer aspect, Pip and Dough-Boy made a match, like a black pony\nand a white one, of equal developments, though of dissimilar colour,\ndriven in one eccentric span.  But while hapless Dough-Boy was by\nnature dull and torpid in his intellects, Pip, though over\ntender-hearted, was at bottom very bright, with that pleasant,\ngenial, jolly brightness peculiar to his tribe; a tribe, which ever\nenjoy all holidays and festivities with finer, freer relish than any\nother race.  For blacks, the year's calendar should show naught but\nthree hundred and sixty-five Fourth of Julys and New Year's Days.\nNor smile so, while I write that this little black was brilliant, for\neven blackness has its brilliancy; behold yon lustrous ebony,\npanelled in king's cabinets.  But Pip loved life, and all life's\npeaceable securities; so that the panic-striking business in which he\nhad somehow unaccountably become entrapped, had most sadly blurred\nhis brightness; though, as ere long will be seen, what was thus\ntemporarily subdued in him, in the end was destined to be luridly\nillumined by strange wild fires, that fictitiously showed him off to\nten times the natural lustre with which in his native Tolland County\nin Connecticut, he had once enlivened many a fiddler's frolic on the\ngreen; and at melodious even-tide, with his gay ha-ha! had turned the\nround horizon into one star-belled tambourine.  So, though in the\nclear air of day, suspended against a blue-veined neck, the\npure-watered diamond drop will healthful glow; yet, when the cunning\njeweller would show you the diamond in its most impressive lustre, he\nlays it against a gloomy ground, and then lights it up, not by the\nsun, but by some unnatural gases.  Then come out those fiery\neffulgences, infernally superb; then the evil-blazing diamond, once\nthe divinest symbol of the crystal skies, looks like some crown-jewel\nstolen from the King of Hell.  But let us to the story.\n\nIt came to pass, that in the ambergris affair Stubb's after-oarsman\nchanced so to sprain his hand, as for a time to become quite maimed;\nand, temporarily, Pip was put into his place.\n\nThe first time Stubb lowered with him, Pip evinced much nervousness;\nbut happily, for that time, escaped close contact with the whale; and\ntherefore came off not altogether discreditably; though Stubb\nobserving him, took care, afterwards, to exhort him to cherish his\ncourageousness to the utmost, for he might often find it needful.\n\nNow upon the second lowering, the boat paddled upon the whale; and as\nthe fish received the darted iron, it gave its customary rap, which\nhappened, in this instance, to be right under poor Pip's seat.  The\ninvoluntary consternation of the moment caused him to leap, paddle in\nhand, out of the boat; and in such a way, that part of the slack\nwhale line coming against his chest, he breasted it overboard with\nhim, so as to become entangled in it, when at last plumping into the\nwater.  That instant the stricken whale started on a fierce run, the\nline swiftly straightened; and presto! poor Pip came all foaming up\nto the chocks of the boat, remorselessly dragged there by the line,\nwhich had taken several turns around his chest and neck.\n\nTashtego stood in the bows.  He was full of the fire of the hunt.  He\nhated Pip for a poltroon.  Snatching the boat-knife from its sheath,\nhe suspended its sharp edge over the line, and turning towards Stubb,\nexclaimed interrogatively, \"Cut?\"  Meantime Pip's blue, choked face\nplainly looked, Do, for God's sake!  All passed in a flash.  In less\nthan half a minute, this entire thing happened.\n\n\"Damn him, cut!\" roared Stubb; and so the whale was lost and Pip was\nsaved.\n\nSo soon as he recovered himself, the poor little negro was assailed\nby yells and execrations from the crew.  Tranquilly permitting these\nirregular cursings to evaporate, Stubb then in a plain,\nbusiness-like, but still half humorous manner, cursed Pip officially;\nand that done, unofficially gave him much wholesome advice.  The\nsubstance was, Never jump from a boat, Pip, except--but all the rest\nwas indefinite, as the soundest advice ever is.  Now, in general,\nSTICK TO THE BOAT, is your true motto in whaling; but cases will\nsometimes happen when LEAP FROM THE BOAT, is still better.  Moreover,\nas if perceiving at last that if he should give undiluted\nconscientious advice to Pip, he would be leaving him too wide a\nmargin to jump in for the future; Stubb suddenly dropped all advice,\nand concluded with a peremptory command, \"Stick to the boat, Pip, or\nby the Lord, I won't pick you up if you jump; mind that.  We can't\nafford to lose whales by the likes of you; a whale would sell for\nthirty times what you would, Pip, in Alabama.  Bear that in mind, and\ndon't jump any more.\"  Hereby perhaps Stubb indirectly hinted, that\nthough man loved his fellow, yet man is a money-making animal, which\npropensity too often interferes with his benevolence.\n\nBut we are all in the hands of the Gods; and Pip jumped again.  It\nwas under very similar circumstances to the first performance; but\nthis time he did not breast out the line; and hence, when the whale\nstarted to run, Pip was left behind on the sea, like a hurried\ntraveller's trunk.  Alas!  Stubb was but too true to his word.  It\nwas a beautiful, bounteous, blue day; the spangled sea calm and\ncool, and flatly stretching away, all round, to the horizon, like\ngold-beater's skin hammered out to the extremest.  Bobbing up and\ndown in that sea, Pip's ebon head showed like a head of cloves.  No\nboat-knife was lifted when he fell so rapidly astern.  Stubb's\ninexorable back was turned upon him; and the whale was winged.  In\nthree minutes, a whole mile of shoreless ocean was between Pip and\nStubb.  Out from the centre of the sea, poor Pip turned his crisp,\ncurling, black head to the sun, another lonely castaway, though the\nloftiest and the brightest.\n\nNow, in calm weather, to swim in the open ocean is as easy to the\npractised swimmer as to ride in a spring-carriage ashore.  But the\nawful lonesomeness is intolerable.  The intense concentration of self\nin the middle of such a heartless immensity, my God! who can tell it?\nMark, how when sailors in a dead calm bathe in the open sea--mark\nhow closely they hug their ship and only coast along her sides.\n\nBut had Stubb really abandoned the poor little negro to his fate?\nNo; he did not mean to, at least.  Because there were two boats in\nhis wake, and he supposed, no doubt, that they would of course come\nup to Pip very quickly, and pick him up; though, indeed, such\nconsiderations towards oarsmen jeopardized through their own\ntimidity, is not always manifested by the hunters in all similar\ninstances; and such instances not unfrequently occur; almost\ninvariably in the fishery, a coward, so called, is marked with the\nsame ruthless detestation peculiar to military navies and armies.\n\nBut it so happened, that those boats, without seeing Pip, suddenly\nspying whales close to them on one side, turned, and gave chase; and\nStubb's boat was now so far away, and he and all his crew so intent\nupon his fish, that Pip's ringed horizon began to expand around him\nmiserably.  By the merest chance the ship itself at last rescued him;\nbut from that hour the little negro went about the deck an idiot;\nsuch, at least, they said he was.  The sea had jeeringly kept his\nfinite body up, but drowned the infinite of his soul.  Not drowned\nentirely, though.  Rather carried down alive to wondrous depths,\nwhere strange shapes of the unwarped primal world glided to and fro\nbefore his passive eyes; and the miser-merman, Wisdom, revealed his\nhoarded heaps; and among the joyous, heartless, ever-juvenile\neternities, Pip saw the multitudinous, God-omnipresent, coral\ninsects, that out of the firmament of waters heaved the colossal\norbs.  He saw God's foot upon the treadle of the loom, and spoke it;\nand therefore his shipmates called him mad.  So man's insanity is\nheaven's sense; and wandering from all mortal reason, man comes at\nlast to that celestial thought, which, to reason, is absurd and\nfrantic; and weal or woe, feels then uncompromised, indifferent as\nhis God.\n\nFor the rest, blame not Stubb too hardly.  The thing is common in\nthat fishery; and in the sequel of the narrative, it will then be\nseen what like abandonment befell myself.\n\n\n\nCHAPTER 94\n\nA Squeeze of the Hand.\n\n\nThat whale of Stubb's, so dearly purchased, was duly brought to the\nPequod's side, where all those cutting and hoisting operations\npreviously detailed, were regularly gone through, even to the baling\nof the Heidelburgh Tun, or Case.\n\nWhile some were occupied with this latter duty, others were employed\nin dragging away the larger tubs, so soon as filled with the sperm;\nand when the proper time arrived, this same sperm was carefully\nmanipulated ere going to the try-works, of which anon.\n\nIt had cooled and crystallized to such a degree, that when, with\nseveral others, I sat down before a large Constantine's bath of it, I\nfound it strangely concreted into lumps, here and there rolling about\nin the liquid part.  It was our business to squeeze these lumps back\ninto fluid.  A sweet and unctuous duty!  No wonder that in old times\nthis sperm was such a favourite cosmetic.  Such a clearer! such a\nsweetener! such a softener! such a delicious molifier!  After\nhaving my hands in it for only a few minutes, my fingers felt like\neels, and began, as it were, to serpentine and spiralise.\n\nAs I sat there at my ease, cross-legged on the deck; after the bitter\nexertion at the windlass; under a blue tranquil sky; the ship under\nindolent sail, and gliding so serenely along; as I bathed my hands\namong those soft, gentle globules of infiltrated tissues, woven\nalmost within the hour; as they richly broke to my fingers, and\ndischarged all their opulence, like fully ripe grapes their wine; as\nI snuffed up that uncontaminated aroma,--literally and truly, like\nthe smell of spring violets; I declare to you, that for the time I\nlived as in a musky meadow; I forgot all about our horrible oath; in\nthat inexpressible sperm, I washed my hands and my heart of it; I\nalmost began to credit the old Paracelsan superstition that sperm is\nof rare virtue in allaying the heat of anger; while bathing in that\nbath, I felt divinely free from all ill-will, or petulance, or\nmalice, of any sort whatsoever.\n\nSqueeze! squeeze! squeeze! all the morning long; I squeezed that\nsperm till I myself almost melted into it; I squeezed that sperm till\na strange sort of insanity came over me; and I found myself\nunwittingly squeezing my co-laborers' hands in it, mistaking their\nhands for the gentle globules.  Such an abounding, affectionate,\nfriendly, loving feeling did this avocation beget; that at last I was\ncontinually squeezing their hands, and looking up into their eyes\nsentimentally; as much as to say,--Oh! my dear fellow beings, why\nshould we longer cherish any social acerbities, or know the slightest\nill-humor or envy!  Come; let us squeeze hands all round; nay, let us\nall squeeze ourselves into each other; let us squeeze ourselves\nuniversally into the very milk and sperm of kindness.\n\nWould that I could keep squeezing that sperm for ever!  For now,\nsince by many prolonged, repeated experiences, I have perceived that\nin all cases man must eventually lower, or at least shift, his\nconceit of attainable felicity; not placing it anywhere in the\nintellect or the fancy; but in the wife, the heart, the bed, the\ntable, the saddle, the fireside, the country; now that I have\nperceived all this, I am ready to squeeze case eternally.  In\nthoughts of the visions of the night, I saw long rows of angels in\nparadise, each with his hands in a jar of spermaceti.\n\nNow, while discoursing of sperm, it behooves to speak of other things\nakin to it, in the business of preparing the sperm whale for the\ntry-works.\n\nFirst comes white-horse, so called, which is obtained from the\ntapering part of the fish, and also from the thicker portions of his\nflukes.  It is tough with congealed tendons--a wad of muscle--but\nstill contains some oil.  After being severed from the whale, the\nwhite-horse is first cut into portable oblongs ere going to the\nmincer.  They look much like blocks of Berkshire marble.\n\nPlum-pudding is the term bestowed upon certain fragmentary parts of\nthe whale's flesh, here and there adhering to the blanket of blubber,\nand often participating to a considerable degree in its unctuousness.\nIt is a most refreshing, convivial, beautiful object to behold.  As\nits name imports, it is of an exceedingly rich, mottled tint, with a\nbestreaked snowy and golden ground, dotted with spots of the deepest\ncrimson and purple.  It is plums of rubies, in pictures of citron.\nSpite of reason, it is hard to keep yourself from eating it.  I\nconfess, that once I stole behind the foremast to try it.  It tasted\nsomething as I should conceive a royal cutlet from the thigh of Louis\nle Gros might have tasted, supposing him to have been killed the\nfirst day after the venison season, and that particular venison\nseason contemporary with an unusually fine vintage of the vineyards\nof Champagne.\n\nThere is another substance, and a very singular one, which turns up\nin the course of this business, but which I feel it to be very\npuzzling adequately to describe.  It is called slobgollion; an\nappellation original with the whalemen, and even so is the nature of\nthe substance.  It is an ineffably oozy, stringy affair, most\nfrequently found in the tubs of sperm, after a prolonged squeezing,\nand subsequent decanting.  I hold it to be the wondrously thin,\nruptured membranes of the case, coalescing.\n\nGurry, so called, is a term properly belonging to right whalemen, but\nsometimes incidentally used by the sperm fishermen.  It designates\nthe dark, glutinous substance which is scraped off the back of the\nGreenland or right whale, and much of which covers the decks of those\ninferior souls who hunt that ignoble Leviathan.\n\nNippers.  Strictly this word is not indigenous to the whale's\nvocabulary.  But as applied by whalemen, it becomes so.  A whaleman's\nnipper is a short firm strip of tendinous stuff cut from the tapering\npart of Leviathan's tail: it averages an inch in thickness, and for\nthe rest, is about the size of the iron part of a hoe.  Edgewise\nmoved along the oily deck, it operates like a leathern squilgee; and\nby nameless blandishments, as of magic, allures along with it all\nimpurities.\n\nBut to learn all about these recondite matters, your best way is at\nonce to descend into the blubber-room, and have a long talk with its\ninmates.  This place has previously been mentioned as the receptacle\nfor the blanket-pieces, when stript and hoisted from the whale.  When\nthe proper time arrives for cutting up its contents, this apartment\nis a scene of terror to all tyros, especially by night.  On one side,\nlit by a dull lantern, a space has been left clear for the workmen.\nThey generally go in pairs,--a pike-and-gaffman and a spade-man.\nThe whaling-pike is similar to a frigate's boarding-weapon of the\nsame name.  The gaff is something like a boat-hook.  With his gaff,\nthe gaffman hooks on to a sheet of blubber, and strives to hold it\nfrom slipping, as the ship pitches and lurches about.  Meanwhile, the\nspade-man stands on the sheet itself, perpendicularly chopping it\ninto the portable horse-pieces.  This spade is sharp as hone can make\nit; the spademan's feet are shoeless; the thing he stands on will\nsometimes irresistibly slide away from him, like a sledge.  If he\ncuts off one of his own toes, or one of his assistants', would you be\nvery much astonished?  Toes are scarce among veteran blubber-room\nmen.\n\n\n\nCHAPTER 95\n\nThe Cassock.\n\n\nHad you stepped on board the Pequod at a certain juncture of this\npost-mortemizing of the whale; and had you strolled forward nigh the\nwindlass, pretty sure am I that you would have scanned with no small\ncuriosity a very strange, enigmatical object, which you would have\nseen there, lying along lengthwise in the lee scuppers.  Not the\nwondrous cistern in the whale's huge head; not the prodigy of his\nunhinged lower jaw; not the miracle of his symmetrical tail; none of\nthese would so surprise you, as half a glimpse of that unaccountable\ncone,--longer than a Kentuckian is tall, nigh a foot in diameter at\nthe base, and jet-black as Yojo, the ebony idol of Queequeg.  And an\nidol, indeed, it is; or, rather, in old times, its likeness was.\nSuch an idol as that found in the secret groves of Queen Maachah in\nJudea; and for worshipping which, King Asa, her son, did depose her,\nand destroyed the idol, and burnt it for an abomination at the brook\nKedron, as darkly set forth in the 15th chapter of the First Book of\nKings.\n\nLook at the sailor, called the mincer, who now comes along, and\nassisted by two allies, heavily backs the grandissimus, as the\nmariners call it, and with bowed shoulders, staggers off with it as\nif he were a grenadier carrying a dead comrade from the field.\nExtending it upon the forecastle deck, he now proceeds cylindrically\nto remove its dark pelt, as an African hunter the pelt of a boa.\nThis done he turns the pelt inside out, like a pantaloon leg; gives\nit a good stretching, so as almost to double its diameter; and at\nlast hangs it, well spread, in the rigging, to dry.  Ere long, it is\ntaken down; when removing some three feet of it, towards the pointed\nextremity, and then cutting two slits for arm-holes at the other end,\nhe lengthwise slips himself bodily into it.  The mincer now stands\nbefore you invested in the full canonicals of his calling.\nImmemorial to all his order, this investiture alone will adequately\nprotect him, while employed in the peculiar functions of his office.\n\nThat office consists in mincing the horse-pieces of blubber for the\npots; an operation which is conducted at a curious wooden horse,\nplanted endwise against the bulwarks, and with a capacious tub\nbeneath it, into which the minced pieces drop, fast as the sheets\nfrom a rapt orator's desk.  Arrayed in decent black; occupying a\nconspicuous pulpit; intent on bible leaves; what a candidate for an\narchbishopric, what a lad for a Pope were this mincer!*\n\n\n*Bible leaves!  Bible leaves!  This is the invariable cry from the\nmates to the mincer.  It enjoins him to be careful, and cut his work\ninto as thin slices as possible, inasmuch as by so doing the business\nof boiling out the oil is much accelerated, and its quantity\nconsiderably increased, besides perhaps improving it in quality.\n\n\n\nCHAPTER 96\n\nThe Try-Works.\n\n\nBesides her hoisted boats, an American whaler is outwardly\ndistinguished by her try-works.  She presents the curious anomaly of\nthe most solid masonry joining with oak and hemp in constituting the\ncompleted ship.  It is as if from the open field a brick-kiln were\ntransported to her planks.\n\nThe try-works are planted between the foremast and mainmast, the\nmost roomy part of the deck.  The timbers beneath are of a peculiar\nstrength, fitted to sustain the weight of an almost solid mass of\nbrick and mortar, some ten feet by eight square, and five in height.\nThe foundation does not penetrate the deck, but the masonry is firmly\nsecured to the surface by ponderous knees of iron bracing it on all\nsides, and screwing it down to the timbers.  On the flanks it is\ncased with wood, and at top completely covered by a large, sloping,\nbattened hatchway.  Removing this hatch we expose the great try-pots,\ntwo in number, and each of several barrels' capacity.  When not in\nuse, they are kept remarkably clean.  Sometimes they are polished\nwith soapstone and sand, till they shine within like silver\npunch-bowls.  During the night-watches some cynical old sailors will\ncrawl into them and coil themselves away there for a nap.  While\nemployed in polishing them--one man in each pot, side by side--many\nconfidential communications are carried on, over the iron lips.  It\nis a place also for profound mathematical meditation.  It was in the\nleft hand try-pot of the Pequod, with the soapstone diligently\ncircling round me, that I was first indirectly struck by the\nremarkable fact, that in geometry all bodies gliding along the\ncycloid, my soapstone for example, will descend from any point in\nprecisely the same time.\n\nRemoving the fire-board from the front of the try-works, the bare\nmasonry of that side is exposed, penetrated by the two iron mouths of\nthe furnaces, directly underneath the pots.  These mouths are fitted\nwith heavy doors of iron.  The intense heat of the fire is prevented\nfrom communicating itself to the deck, by means of a shallow\nreservoir extending under the entire inclosed surface of the works.\nBy a tunnel inserted at the rear, this reservoir is kept replenished\nwith water as fast as it evaporates.  There are no external chimneys;\nthey open direct from the rear wall.  And here let us go back for a\nmoment.\n\nIt was about nine o'clock at night that the Pequod's try-works were\nfirst started on this present voyage.  It belonged to Stubb to\noversee the business.\n\n\"All ready there?  Off hatch, then, and start her.  You cook, fire\nthe works.\"  This was an easy thing, for the carpenter had been\nthrusting his shavings into the furnace throughout the passage.  Here\nbe it said that in a whaling voyage the first fire in the try-works has\nto be fed for a time with wood.  After that no wood is used, except\nas a means of quick ignition to the staple fuel.  In a word, after\nbeing tried out, the crisp, shrivelled blubber, now called scraps or\nfritters, still contains considerable of its unctuous properties.\nThese fritters feed the flames.  Like a plethoric burning martyr, or\na self-consuming misanthrope, once ignited, the whale supplies his\nown fuel and burns by his own body.  Would that he consumed his own\nsmoke! for his smoke is horrible to inhale, and inhale it you must,\nand not only that, but you must live in it for the time.  It has an\nunspeakable, wild, Hindoo odor about it, such as may lurk in the\nvicinity of funereal pyres.  It smells like the left wing of the day\nof judgment; it is an argument for the pit.\n\nBy midnight the works were in full operation.  We were clear from the\ncarcase; sail had been made; the wind was freshening; the wild ocean\ndarkness was intense.  But that darkness was licked up by the fierce\nflames, which at intervals forked forth from the sooty flues, and\nilluminated every lofty rope in the rigging, as with the famed Greek\nfire.  The burning ship drove on, as if remorselessly commissioned to\nsome vengeful deed.  So the pitch and sulphur-freighted brigs of the\nbold Hydriote, Canaris, issuing from their midnight harbors, with\nbroad sheets of flame for sails, bore down upon the Turkish frigates,\nand folded them in conflagrations.\n\nThe hatch, removed from the top of the works, now afforded a wide\nhearth in front of them.  Standing on this were the Tartarean shapes\nof the pagan harpooneers, always the whale-ship's stokers.  With huge\npronged poles they pitched hissing masses of blubber into the\nscalding pots, or stirred up the fires beneath, till the snaky flames\ndarted, curling, out of the doors to catch them by the feet.  The\nsmoke rolled away in sullen heaps.  To every pitch of the ship there\nwas a pitch of the boiling oil, which seemed all eagerness to leap\ninto their faces.  Opposite the mouth of the works, on the further\nside of the wide wooden hearth, was the windlass.  This served for a\nsea-sofa.  Here lounged the watch, when not otherwise employed,\nlooking into the red heat of the fire, till their eyes felt scorched\nin their heads.  Their tawny features, now all begrimed with smoke\nand sweat, their matted beards, and the contrasting barbaric\nbrilliancy of their teeth, all these were strangely revealed in the\ncapricious emblazonings of the works.  As they narrated to each other\ntheir unholy adventures, their tales of terror told in words of\nmirth; as their uncivilized laughter forked upwards out of them, like\nthe flames from the furnace; as to and fro, in their front, the\nharpooneers wildly gesticulated with their huge pronged forks and\ndippers; as the wind howled on, and the sea leaped, and the ship\ngroaned and dived, and yet steadfastly shot her red hell further and\nfurther into the blackness of the sea and the night, and scornfully\nchamped the white bone in her mouth, and viciously spat round her on\nall sides; then the rushing Pequod, freighted with savages, and laden\nwith fire, and burning a corpse, and plunging into that blackness of\ndarkness, seemed the material counterpart of her monomaniac\ncommander's soul.\n\nSo seemed it to me, as I stood at her helm, and for long hours\nsilently guided the way of this fire-ship on the sea.  Wrapped, for\nthat interval, in darkness myself, I but the better saw the redness,\nthe madness, the ghastliness of others.  The continual sight of the\nfiend shapes before me, capering half in smoke and half in fire,\nthese at last begat kindred visions in my soul, so soon as I began to\nyield to that unaccountable drowsiness which ever would come over me\nat a midnight helm.\n\nBut that night, in particular, a strange (and ever since\ninexplicable) thing occurred to me.  Starting from a brief standing\nsleep, I was horribly conscious of something fatally wrong.  The\njaw-bone tiller smote my side, which leaned against it; in my ears\nwas the low hum of sails, just beginning to shake in the wind; I\nthought my eyes were open; I was half conscious of putting my fingers\nto the lids and mechanically stretching them still further apart.\nBut, spite of all this, I could see no compass before me to steer by;\nthough it seemed but a minute since I had been watching the card, by\nthe steady binnacle lamp illuminating it.  Nothing seemed before me\nbut a jet gloom, now and then made ghastly by flashes of redness.\nUppermost was the impression, that whatever swift, rushing thing I\nstood on was not so much bound to any haven ahead as rushing from all\nhavens astern.  A stark, bewildered feeling, as of death, came over\nme.  Convulsively my hands grasped the tiller, but with the crazy\nconceit that the tiller was, somehow, in some enchanted way,\ninverted.  My God! what is the matter with me? thought I.  Lo! in my\nbrief sleep I had turned myself about, and was fronting the ship's\nstern, with my back to her prow and the compass.  In an instant I\nfaced back, just in time to prevent the vessel from flying up into\nthe wind, and very probably capsizing her.  How glad and how grateful\nthe relief from this unnatural hallucination of the night, and the\nfatal contingency of being brought by the lee!\n\nLook not too long in the face of the fire, O man!  Never dream with\nthy hand on the helm!  Turn not thy back to the compass; accept the\nfirst hint of the hitching tiller; believe not the artificial fire,\nwhen its redness makes all things look ghastly.  To-morrow, in the\nnatural sun, the skies will be bright; those who glared like devils\nin the forking flames, the morn will show in far other, at least\ngentler, relief; the glorious, golden, glad sun, the only true\nlamp--all others but liars!\n\nNevertheless the sun hides not Virginia's Dismal Swamp, nor Rome's\naccursed Campagna, nor wide Sahara, nor all the millions of miles of\ndeserts and of griefs beneath the moon.  The sun hides not the ocean,\nwhich is the dark side of this earth, and which is two thirds of this\nearth.  So, therefore, that mortal man who hath more of joy than\nsorrow in him, that mortal man cannot be true--not true, or\nundeveloped.  With books the same.  The truest of all men was the Man\nof Sorrows, and the truest of all books is Solomon's, and\nEcclesiastes is the fine hammered steel of woe.  \"All is vanity.\"\nALL.  This wilful world hath not got hold of unchristian Solomon's\nwisdom yet.  But he who dodges hospitals and jails, and walks fast\ncrossing graveyards, and would rather talk of operas than hell;\ncalls Cowper, Young, Pascal, Rousseau, poor devils all of sick men;\nand throughout a care-free lifetime swears by Rabelais as passing\nwise, and therefore jolly;--not that man is fitted to sit down on\ntomb-stones, and break the green damp mould with unfathomably\nwondrous Solomon.\n\nBut even Solomon, he says, \"the man that wandereth out of the way of\nunderstanding shall remain\" (I.E., even while living) \"in the\ncongregation of the dead.\"  Give not thyself up, then, to fire, lest\nit invert thee, deaden thee; as for the time it did me.  There is a\nwisdom that is woe; but there is a woe that is madness.  And there is\na Catskill eagle in some souls that can alike dive down into the\nblackest gorges, and soar out of them again and become invisible in\nthe sunny spaces.  And even if he for ever flies within the gorge,\nthat gorge is in the mountains; so that even in his lowest swoop the\nmountain eagle is still higher than other birds upon the plain, even\nthough they soar.\n\n\n\nCHAPTER 97\n\nThe Lamp.\n\n\nHad you descended from the Pequod's try-works to the Pequod's\nforecastle, where the off duty watch were sleeping, for one single\nmoment you would have almost thought you were standing in some\nilluminated shrine of canonized kings and counsellors.  There they\nlay in their triangular oaken vaults, each mariner a chiselled\nmuteness; a score of lamps flashing upon his hooded eyes.\n\nIn merchantmen, oil for the sailor is more scarce than the milk of\nqueens.  To dress in the dark, and eat in the dark, and stumble in\ndarkness to his pallet, this is his usual lot.  But the whaleman, as\nhe seeks the food of light, so he lives in light.  He makes his berth\nan Aladdin's lamp, and lays him down in it; so that in the pitchiest\nnight the ship's black hull still houses an illumination.\n\nSee with what entire freedom the whaleman takes his handful of\nlamps--often but old bottles and vials, though--to the copper cooler\nat the try-works, and replenishes them there, as mugs of ale at a\nvat.  He burns, too, the purest of oil, in its unmanufactured, and,\ntherefore, unvitiated state; a fluid unknown to solar, lunar, or\nastral contrivances ashore.  It is sweet as early grass butter in\nApril.  He goes and hunts for his oil, so as to be sure of its\nfreshness and genuineness, even as the traveller on the prairie hunts\nup his own supper of game.\n\n\n\nCHAPTER 98\n\nStowing Down and Clearing Up.\n\n\nAlready has it been related how the great leviathan is afar off\ndescried from the mast-head; how he is chased over the watery moors,\nand slaughtered in the valleys of the deep; how he is then towed\nalongside and beheaded; and how (on the principle which entitled the\nheadsman of old to the garments in which the beheaded was killed) his\ngreat padded surtout becomes the property of his executioner; how, in\ndue time, he is condemned to the pots, and, like Shadrach, Meshach,\nand Abednego, his spermaceti, oil, and bone pass unscathed through\nthe fire;--but now it remains to conclude the last chapter of this\npart of the description by rehearsing--singing, if I may--the\nromantic proceeding of decanting off his oil into the casks and\nstriking them down into the hold, where once again leviathan returns\nto his native profundities, sliding along beneath the surface as\nbefore; but, alas! never more to rise and blow.\n\nWhile still warm, the oil, like hot punch, is received into the\nsix-barrel casks; and while, perhaps, the ship is pitching and\nrolling this way and that in the midnight sea, the enormous casks are\nslewed round and headed over, end for end, and sometimes perilously\nscoot across the slippery deck, like so many land slides, till at\nlast man-handled and stayed in their course; and all round the hoops,\nrap, rap, go as many hammers as can play upon them, for now, EX\nOFFICIO, every sailor is a cooper.\n\nAt length, when the last pint is casked, and all is cool, then the\ngreat hatchways are unsealed, the bowels of the ship are thrown open,\nand down go the casks to their final rest in the sea.  This done, the\nhatches are replaced, and hermetically closed, like a closet walled\nup.\n\nIn the sperm fishery, this is perhaps one of the most remarkable\nincidents in all the business of whaling.  One day the planks stream\nwith freshets of blood and oil; on the sacred quarter-deck enormous\nmasses of the whale's head are profanely piled; great rusty casks lie\nabout, as in a brewery yard; the smoke from the try-works has\nbesooted all the bulwarks; the mariners go about suffused with\nunctuousness; the entire ship seems great leviathan himself; while on\nall hands the din is deafening.\n\nBut a day or two after, you look about you, and prick your ears in\nthis self-same ship; and were it not for the tell-tale boats and\ntry-works, you would all but swear you trod some silent merchant\nvessel, with a most scrupulously neat commander.  The unmanufactured\nsperm oil possesses a singularly cleansing virtue.  This is the\nreason why the decks never look so white as just after what they call\nan affair of oil.  Besides, from the ashes of the burned scraps of\nthe whale, a potent lye is readily made; and whenever any\nadhesiveness from the back of the whale remains clinging to the side,\nthat lye quickly exterminates it.  Hands go diligently along the\nbulwarks, and with buckets of water and rags restore them to their\nfull tidiness.  The soot is brushed from the lower rigging.  All the\nnumerous implements which have been in use are likewise faithfully\ncleansed and put away.  The great hatch is scrubbed and placed upon\nthe try-works, completely hiding the pots; every cask is out of\nsight; all tackles are coiled in unseen nooks; and when by the\ncombined and simultaneous industry of almost the entire ship's\ncompany, the whole of this conscientious duty is at last concluded,\nthen the crew themselves proceed to their own ablutions; shift\nthemselves from top to toe; and finally issue to the immaculate deck,\nfresh and all aglow, as bridegrooms new-leaped from out the daintiest\nHolland.\n\nNow, with elated step, they pace the planks in twos and threes, and\nhumorously discourse of parlors, sofas, carpets, and fine cambrics;\npropose to mat the deck; think of having hanging to the top; object\nnot to taking tea by moonlight on the piazza of the forecastle.  To\nhint to such musked mariners of oil, and bone, and blubber, were\nlittle short of audacity.  They know not the thing you distantly\nallude to.  Away, and bring us napkins!\n\nBut mark: aloft there, at the three mast heads, stand three men\nintent on spying out more whales, which, if caught, infallibly will\nagain soil the old oaken furniture, and drop at least one small\ngrease-spot somewhere.  Yes; and many is the time, when, after the\nseverest uninterrupted labors, which know no night; continuing\nstraight through for ninety-six hours; when from the boat, where they\nhave swelled their wrists with all day rowing on the Line,--they only\nstep to the deck to carry vast chains, and heave the heavy windlass,\nand cut and slash, yea, and in their very sweatings to be smoked and\nburned anew by the combined fires of the equatorial sun and the\nequatorial try-works; when, on the heel of all this, they have\nfinally bestirred themselves to cleanse the ship, and make a spotless\ndairy room of it; many is the time the poor fellows, just buttoning\nthe necks of their clean frocks, are startled by the cry of \"There\nshe blows!\" and away they fly to fight another whale, and go through\nthe whole weary thing again.  Oh! my friends, but this is\nman-killing!  Yet this is life.  For hardly have we mortals by long\ntoilings extracted from this world's vast bulk its small but\nvaluable sperm; and then, with weary patience, cleansed ourselves\nfrom its defilements, and learned to live here in clean tabernacles\nof the soul; hardly is this done, when--THERE SHE BLOWS!--the ghost\nis spouted up, and away we sail to fight some other world, and go\nthrough young life's old routine again.\n\nOh! the metempsychosis!  Oh!  Pythagoras, that in bright Greece, two\nthousand years ago, did die, so good, so wise, so mild; I sailed with\nthee along the Peruvian coast last voyage--and, foolish as I am,\ntaught thee, a green simple boy, how to splice a rope!\n\n\n\nCHAPTER 99\n\nThe Doubloon.\n\n\nEre now it has been related how Ahab was wont to pace his\nquarter-deck, taking regular turns at either limit, the binnacle and\nmainmast; but in the multiplicity of other things requiring narration\nit has not been added how that sometimes in these walks, when most\nplunged in his mood, he was wont to pause in turn at each spot, and\nstand there strangely eyeing the particular object before him.  When\nhe halted before the binnacle, with his glance fastened on the\npointed needle in the compass, that glance shot like a javelin with\nthe pointed intensity of his purpose; and when resuming his walk he\nagain paused before the mainmast, then, as the same riveted glance\nfastened upon the riveted gold coin there, he still wore the same\naspect of nailed firmness, only dashed with a certain wild longing,\nif not hopefulness.\n\nBut one morning, turning to pass the doubloon, he seemed to be newly\nattracted by the strange figures and inscriptions stamped on it, as\nthough now for the first time beginning to interpret for himself in\nsome monomaniac way whatever significance might lurk in them.  And\nsome certain significance lurks in all things, else all things are\nlittle worth, and the round world itself but an empty cipher, except\nto sell by the cartload, as they do hills about Boston, to fill up\nsome morass in the Milky Way.\n\nNow this doubloon was of purest, virgin gold, raked somewhere out of\nthe heart of gorgeous hills, whence, east and west, over golden\nsands, the head-waters of many a Pactolus flows.  And though now\nnailed amidst all the rustiness of iron bolts and the verdigris of\ncopper spikes, yet, untouchable and immaculate to any foulness, it\nstill preserved its Quito glow.  Nor, though placed amongst a\nruthless crew and every hour passed by ruthless hands, and through\nthe livelong nights shrouded with thick darkness which might cover\nany pilfering approach, nevertheless every sunrise found the doubloon\nwhere the sunset left it last.  For it was set apart and sanctified\nto one awe-striking end; and however wanton in their sailor ways, one\nand all, the mariners revered it as the white whale's talisman.\nSometimes they talked it over in the weary watch by night, wondering\nwhose it was to be at last, and whether he would ever live to spend\nit.\n\nNow those noble golden coins of South America are as medals of the\nsun and tropic token-pieces.  Here palms, alpacas, and volcanoes;\nsun's disks and stars; ecliptics, horns-of-plenty, and rich banners\nwaving, are in luxuriant profusion stamped; so that the precious gold\nseems almost to derive an added preciousness and enhancing glories,\nby passing through those fancy mints, so Spanishly poetic.\n\nIt so chanced that the doubloon of the Pequod was a most wealthy\nexample of these things.  On its round border it bore the letters,\nREPUBLICA DEL ECUADOR: QUITO.  So this bright coin came from a\ncountry planted in the middle of the world, and beneath the great\nequator, and named after it; and it had been cast midway up the\nAndes, in the unwaning clime that knows no autumn.  Zoned by those\nletters you saw the likeness of three Andes' summits; from one a\nflame; a tower on another; on the third a crowing cock; while arching\nover all was a segment of the partitioned zodiac, the signs all\nmarked with their usual cabalistics, and the keystone sun entering\nthe equinoctial point at Libra.\n\nBefore this equatorial coin, Ahab, not unobserved by others, was now\npausing.\n\n\"There's something ever egotistical in mountain-tops and towers, and\nall other grand and lofty things; look here,--three peaks as proud as\nLucifer.  The firm tower, that is Ahab; the volcano, that is Ahab;\nthe courageous, the undaunted, and victorious fowl, that, too, is\nAhab; all are Ahab; and this round gold is but the image of the\nrounder globe, which, like a magician's glass, to each and every man\nin turn but mirrors back his own mysterious self.  Great pains, small\ngains for those who ask the world to solve them; it cannot solve\nitself.  Methinks now this coined sun wears a ruddy face; but see!\naye, he enters the sign of storms, the equinox! and but six months\nbefore he wheeled out of a former equinox at Aries!  From storm to\nstorm!  So be it, then.  Born in throes, 't is fit that man should\nlive in pains and die in pangs!  So be it, then!  Here's stout stuff\nfor woe to work on.  So be it, then.\"\n\n\"No fairy fingers can have pressed the gold, but devil's claws must have\nleft their mouldings there since yesterday,\" murmured Starbuck to\nhimself, leaning against the bulwarks.  \"The old man seems to read\nBelshazzar's awful writing.  I have never marked the coin\ninspectingly.  He goes below; let me read.  A dark valley between\nthree mighty, heaven-abiding peaks, that almost seem the Trinity, in\nsome faint earthly symbol.  So in this vale of Death, God girds us\nround; and over all our gloom, the sun of Righteousness still shines\na beacon and a hope.  If we bend down our eyes, the dark vale shows\nher mouldy soil; but if we lift them, the bright sun meets our glance\nhalf way, to cheer.  Yet, oh, the great sun is no fixture; and if, at\nmidnight, we would fain snatch some sweet solace from him, we gaze\nfor him in vain!  This coin speaks wisely, mildly, truly, but still\nsadly to me.  I will quit it, lest Truth shake me falsely.\"\n\n\"There now's the old Mogul,\" soliloquized Stubb by the try-works,\n\"he's been twigging it; and there goes Starbuck from the same, and\nboth with faces which I should say might be somewhere within nine\nfathoms long.  And all from looking at a piece of gold, which did I\nhave it now on Negro Hill or in Corlaer's Hook, I'd not look at it\nvery long ere spending it.  Humph! in my poor, insignificant opinion,\nI regard this as queer.  I have seen doubloons before now in my\nvoyagings; your doubloons of old Spain, your doubloons of Peru, your\ndoubloons of Chili, your doubloons of Bolivia, your doubloons of\nPopayan; with plenty of gold moidores and pistoles, and joes, and\nhalf joes, and quarter joes.  What then should there be in this\ndoubloon of the Equator that is so killing wonderful?  By Golconda!\nlet me read it once.  Halloa! here's signs and wonders truly!  That,\nnow, is what old Bowditch in his Epitome calls the zodiac, and what\nmy almanac below calls ditto.  I'll get the almanac and as I have\nheard devils can be raised with Daboll's arithmetic, I'll try my hand\nat raising a meaning out of these queer curvicues here with the\nMassachusetts calendar.  Here's the book.  Let's see now.  Signs and\nwonders; and the sun, he's always among 'em.  Hem, hem, hem; here\nthey are--here they go--all alive:--Aries, or the Ram; Taurus, or the\nBull and Jimimi! here's Gemini himself, or the Twins.  Well; the sun\nhe wheels among 'em.  Aye, here on the coin he's just crossing the\nthreshold between two of twelve sitting-rooms all in a ring.  Book!\nyou lie there; the fact is, you books must know your places.  You'll\ndo to give us the bare words and facts, but we come in to supply the\nthoughts.  That's my small experience, so far as the Massachusetts\ncalendar, and Bowditch's navigator, and Daboll's arithmetic go.\nSigns and wonders, eh?  Pity if there is nothing wonderful in signs,\nand significant in wonders!  There's a clue somewhere; wait a bit;\nhist--hark!  By Jove, I have it!  Look you, Doubloon, your zodiac\nhere is the life of man in one round chapter; and now I'll read it\noff, straight out of the book.  Come, Almanack!  To begin: there's\nAries, or the Ram--lecherous dog, he begets us; then, Taurus, or the\nBull--he bumps us the first thing; then Gemini, or the Twins--that\nis, Virtue and Vice; we try to reach Virtue, when lo! comes Cancer\nthe Crab, and drags us back; and here, going from Virtue, Leo, a\nroaring Lion, lies in the path--he gives a few fierce bites and surly\ndabs with his paw; we escape, and hail Virgo, the Virgin! that's our\nfirst love; we marry and think to be happy for aye, when pop comes\nLibra, or the Scales--happiness weighed and found wanting; and while\nwe are very sad about that, Lord! how we suddenly jump, as Scorpio,\nor the Scorpion, stings us in the rear; we are curing the wound, when\nwhang come the arrows all round; Sagittarius, or the Archer, is\namusing himself.  As we pluck out the shafts, stand aside! here's\nthe battering-ram, Capricornus, or the Goat; full tilt, he comes\nrushing, and headlong we are tossed; when Aquarius, or the\nWater-bearer, pours out his whole deluge and drowns us; and to wind\nup with Pisces, or the Fishes, we sleep.  There's a sermon now, writ\nin high heaven, and the sun goes through it every year, and yet comes\nout of it all alive and hearty.  Jollily he, aloft there, wheels\nthrough toil and trouble; and so, alow here, does jolly Stubb.  Oh,\njolly's the word for aye!  Adieu, Doubloon!  But stop; here comes\nlittle King-Post; dodge round the try-works, now, and let's hear what\nhe'll have to say.  There; he's before it; he'll out with something\npresently.  So, so; he's beginning.\"\n\n\"I see nothing here, but a round thing made of gold, and whoever\nraises a certain whale, this round thing belongs to him.  So, what's\nall this staring been about?  It is worth sixteen dollars, that's\ntrue; and at two cents the cigar, that's nine hundred and sixty\ncigars.  I won't smoke dirty pipes like Stubb, but I like cigars, and\nhere's nine hundred and sixty of them; so here goes Flask aloft to\nspy 'em out.\"\n\n\"Shall I call that wise or foolish, now; if it be really wise it has\na foolish look to it; yet, if it be really foolish, then has it a\nsort of wiseish look to it.  But, avast; here comes our old\nManxman--the old hearse-driver, he must have been, that is, before he\ntook to the sea.  He luffs up before the doubloon; halloa, and goes\nround on the other side of the mast; why, there's a horse-shoe nailed\non that side; and now he's back again; what does that mean?  Hark!\nhe's muttering--voice like an old worn-out coffee-mill.  Prick ears,\nand listen!\"\n\n\"If the White Whale be raised, it must be in a month and a day, when\nthe sun stands in some one of these signs.  I've studied signs, and\nknow their marks; they were taught me two score years ago, by the old\nwitch in Copenhagen.  Now, in what sign will the sun then be?  The\nhorse-shoe sign; for there it is, right opposite the gold.  And\nwhat's the horse-shoe sign?  The lion is the horse-shoe sign--the\nroaring and devouring lion.  Ship, old ship! my old head shakes to\nthink of thee.\"\n\n\"There's another rendering now; but still one text.  All sorts of men\nin one kind of world, you see.  Dodge again! here comes Queequeg--all\ntattooing--looks like the signs of the Zodiac himself.  What says the\nCannibal?  As I live he's comparing notes; looking at his thigh bone;\nthinks the sun is in the thigh, or in the calf, or in the bowels, I\nsuppose, as the old women talk Surgeon's Astronomy in the back\ncountry.  And by Jove, he's found something there in the vicinity of\nhis thigh--I guess it's Sagittarius, or the Archer.  No: he don't\nknow what to make of the doubloon; he takes it for an old button off\nsome king's trowsers.  But, aside again! here comes that ghost-devil,\nFedallah; tail coiled out of sight as usual, oakum in the toes of his\npumps as usual.  What does he say, with that look of his?  Ah, only\nmakes a sign to the sign and bows himself; there is a sun on the\ncoin--fire worshipper, depend upon it.  Ho! more and more.  This way\ncomes Pip--poor boy! would he had died, or I; he's half horrible to\nme.  He too has been watching all of these interpreters--myself\nincluded--and look now, he comes to read, with that unearthly idiot\nface.  Stand away again and hear him.  Hark!\"\n\n\"I look, you look, he looks; we look, ye look, they look.\"\n\n\"Upon my soul, he's been studying Murray's Grammar!  Improving his\nmind, poor fellow!  But what's that he says now--hist!\"\n\n\"I look, you look, he looks; we look, ye look, they look.\"\n\n\"Why, he's getting it by heart--hist! again.\"\n\n\"I look, you look, he looks; we look, ye look, they look.\"\n\n\"Well, that's funny.\"\n\n\"And I, you, and he; and we, ye, and they, are all bats; and I'm a\ncrow, especially when I stand a'top of this pine tree here.  Caw!\ncaw! caw! caw! caw! caw!  Ain't I a crow?  And where's the\nscare-crow?  There he stands; two bones stuck into a pair of old\ntrowsers, and two more poked into the sleeves of an old jacket.\"\n\n\"Wonder if he means me?--complimentary!--poor lad!--I could go hang\nmyself.  Any way, for the present, I'll quit Pip's vicinity.  I can\nstand the rest, for they have plain wits; but he's too crazy-witty\nfor my sanity.  So, so, I leave him muttering.\"\n\n\"Here's the ship's navel, this doubloon here, and they are all on\nfire to unscrew it.  But, unscrew your navel, and what's the\nconsequence?  Then again, if it stays here, that is ugly, too, for\nwhen aught's nailed to the mast it's a sign that things grow\ndesperate.  Ha, ha! old Ahab! the White Whale; he'll nail ye!  This\nis a pine tree.  My father, in old Tolland county, cut down a pine\ntree once, and found a silver ring grown over in it; some old\ndarkey's wedding ring.  How did it get there?  And so they'll say in\nthe resurrection, when they come to fish up this old mast, and find a\ndoubloon lodged in it, with bedded oysters for the shaggy bark.  Oh,\nthe gold! the precious, precious, gold! the green miser'll hoard ye\nsoon!  Hish! hish!  God goes 'mong the worlds blackberrying.  Cook!\nho, cook! and cook us!  Jenny! hey, hey, hey, hey, hey, Jenny, Jenny!\nand get your hoe-cake done!\"\n\n\n\nCHAPTER 100\n\nLeg and Arm.\n\nThe Pequod, of Nantucket, Meets the Samuel Enderby, of London.\n\n\n\"Ship, ahoy!  Hast seen the White Whale?\"\n\nSo cried Ahab, once more hailing a ship showing English colours,\nbearing down under the stern.  Trumpet to mouth, the old man was\nstanding in his hoisted quarter-boat, his ivory leg plainly revealed\nto the stranger captain, who was carelessly reclining in his own\nboat's bow.  He was a darkly-tanned, burly, good-natured,\nfine-looking man, of sixty or thereabouts, dressed in a spacious\nroundabout, that hung round him in festoons of blue pilot-cloth; and\none empty arm of this jacket streamed behind him like the broidered\narm of a hussar's surcoat.\n\n\"Hast seen the White Whale!\"\n\n\"See you this?\" and withdrawing it from the folds that had hidden\nit, he held up a white arm of sperm whale bone, terminating in a\nwooden head like a mallet.\n\n\"Man my boat!\" cried Ahab, impetuously, and tossing about the oars\nnear him--\"Stand by to lower!\"\n\nIn less than a minute, without quitting his little craft, he and his\ncrew were dropped to the water, and were soon alongside of the\nstranger.  But here a curious difficulty presented itself.  In the\nexcitement of the moment, Ahab had forgotten that since the loss of\nhis leg he had never once stepped on board of any vessel at sea but\nhis own, and then it was always by an ingenious and very handy\nmechanical contrivance peculiar to the Pequod, and a thing not to be\nrigged and shipped in any other vessel at a moment's warning.  Now,\nit is no very easy matter for anybody--except those who are almost\nhourly used to it, like whalemen--to clamber up a ship's side from a\nboat on the open sea; for the great swells now lift the boat high up\ntowards the bulwarks, and then instantaneously drop it half way down\nto the kelson.  So, deprived of one leg, and the strange ship of\ncourse being altogether unsupplied with the kindly invention, Ahab\nnow found himself abjectly reduced to a clumsy landsman again;\nhopelessly eyeing the uncertain changeful height he could hardly hope\nto attain.\n\nIt has before been hinted, perhaps, that every little untoward\ncircumstance that befell him, and which indirectly sprang from his\nluckless mishap, almost invariably irritated or exasperated Ahab.\nAnd in the present instance, all this was heightened by the sight of\nthe two officers of the strange ship, leaning over the side, by the\nperpendicular ladder of nailed cleets there, and swinging towards him\na pair of tastefully-ornamented man-ropes; for at first they did not\nseem to bethink them that a one-legged man must be too much of a\ncripple to use their sea bannisters.  But this awkwardness only\nlasted a minute, because the strange captain, observing at a glance\nhow affairs stood, cried out, \"I see, I see!--avast heaving there!\nJump, boys, and swing over the cutting-tackle.\"\n\nAs good luck would have it, they had had a whale alongside a day or\ntwo previous, and the great tackles were still aloft, and the massive\ncurved blubber-hook, now clean and dry, was still attached to the\nend.  This was quickly lowered to Ahab, who at once comprehending it\nall, slid his solitary thigh into the curve of the hook (it was like\nsitting in the fluke of an anchor, or the crotch of an apple tree),\nand then giving the word, held himself fast, and at the same time\nalso helped to hoist his own weight, by pulling hand-over-hand upon\none of the running parts of the tackle.  Soon he was carefully swung\ninside the high bulwarks, and gently landed upon the capstan head.\nWith his ivory arm frankly thrust forth in welcome, the other captain\nadvanced, and Ahab, putting out his ivory leg, and crossing the ivory\narm (like two sword-fish blades) cried out in his walrus way, \"Aye,\naye, hearty! let us shake bones together!--an arm and a leg!--an arm\nthat never can shrink, d'ye see; and a leg that never can run.  Where\ndid'st thou see the White Whale?--how long ago?\"\n\n\"The White Whale,\" said the Englishman, pointing his ivory arm\ntowards the East, and taking a rueful sight along it, as if it had\nbeen a telescope; \"there I saw him, on the Line, last season.\"\n\n\"And he took that arm off, did he?\" asked Ahab, now sliding down from\nthe capstan, and resting on the Englishman's shoulder, as he did so.\n\n\"Aye, he was the cause of it, at least; and that leg, too?\"\n\n\"Spin me the yarn,\" said Ahab; \"how was it?\"\n\n\"It was the first time in my life that I ever cruised on the Line,\"\nbegan the Englishman.  \"I was ignorant of the White Whale at that\ntime.  Well, one day we lowered for a pod of four or five whales, and\nmy boat fastened to one of them; a regular circus horse he was, too,\nthat went milling and milling round so, that my boat's crew could\nonly trim dish, by sitting all their sterns on the outer gunwale.\nPresently up breaches from the bottom of the sea a bouncing great\nwhale, with a milky-white head and hump, all crows' feet and\nwrinkles.\"\n\n\"It was he, it was he!\" cried Ahab, suddenly letting out his\nsuspended breath.\n\n\"And harpoons sticking in near his starboard fin.\"\n\n\"Aye, aye--they were mine--MY irons,\" cried Ahab, exultingly--\"but\non!\"\n\n\"Give me a chance, then,\" said the Englishman, good-humoredly.\n\"Well, this old great-grandfather, with the white head and hump, runs\nall afoam into the pod, and goes to snapping furiously at my\nfast-line!\n\n\"Aye, I see!--wanted to part it; free the fast-fish--an old trick--I\nknow him.\"\n\n\"How it was exactly,\" continued the one-armed commander, \"I do not\nknow; but in biting the line, it got foul of his teeth, caught there\nsomehow; but we didn't know it then; so that when we afterwards\npulled on the line, bounce we came plump on to his hump! instead of\nthe other whale's; that went off to windward, all fluking.  Seeing\nhow matters stood, and what a noble great whale it was--the noblest\nand biggest I ever saw, sir, in my life--I resolved to capture him,\nspite of the boiling rage he seemed to be in.  And thinking the\nhap-hazard line would get loose, or the tooth it was tangled to\nmight draw (for I have a devil of a boat's crew for a pull on a\nwhale-line); seeing all this, I say, I jumped into my first mate's\nboat--Mr. Mounttop's here (by the way, Captain--Mounttop;\nMounttop--the captain);--as I was saying, I jumped into Mounttop's\nboat, which, d'ye see, was gunwale and gunwale with mine, then; and\nsnatching the first harpoon, let this old great-grandfather have it.\nBut, Lord, look you, sir--hearts and souls alive, man--the next\ninstant, in a jiff, I was blind as a bat--both eyes out--all befogged\nand bedeadened with black foam--the whale's tail looming straight up\nout of it, perpendicular in the air, like a marble steeple.  No use\nsterning all, then; but as I was groping at midday, with a blinding\nsun, all crown-jewels; as I was groping, I say, after the second\niron, to toss it overboard--down comes the tail like a Lima tower,\ncutting my boat in two, leaving each half in splinters; and, flukes\nfirst, the white hump backed through the wreck, as though it was all\nchips.  We all struck out.  To escape his terrible flailings, I\nseized hold of my harpoon-pole sticking in him, and for a moment\nclung to that like a sucking fish.  But a combing sea dashed me off,\nand at the same instant, the fish, taking one good dart forwards,\nwent down like a flash; and the barb of that cursed second iron\ntowing along near me caught me here\" (clapping his hand just below\nhis shoulder); \"yes, caught me just here, I say, and bore me down to\nHell's flames, I was thinking; when, when, all of a sudden, thank the\ngood God, the barb ript its way along the flesh--clear along the\nwhole length of my arm--came out nigh my wrist, and up I\nfloated;--and that gentleman there will tell you the rest (by the\nway, captain--Dr. Bunger, ship's surgeon: Bunger, my lad,--the\ncaptain).  Now, Bunger boy, spin your part of the yarn.\"\n\nThe professional gentleman thus familiarly pointed out, had been all\nthe time standing near them, with nothing specific visible, to denote\nhis gentlemanly rank on board.  His face was an exceedingly round but\nsober one; he was dressed in a faded blue woollen frock or shirt, and\npatched trowsers; and had thus far been dividing his attention\nbetween a marlingspike he held in one hand, and a pill-box held in\nthe other, occasionally casting a critical glance at the ivory limbs\nof the two crippled captains.  But, at his superior's introduction of\nhim to Ahab, he politely bowed, and straightway went on to do his\ncaptain's bidding.\n\n\"It was a shocking bad wound,\" began the whale-surgeon; \"and, taking\nmy advice, Captain Boomer here, stood our old Sammy--\"\n\n\"Samuel Enderby is the name of my ship,\" interrupted the one-armed\ncaptain, addressing Ahab; \"go on, boy.\"\n\n\"Stood our old Sammy off to the northward, to get out of the blazing\nhot weather there on the Line.  But it was no use--I did all I could;\nsat up with him nights; was very severe with him in the matter of\ndiet--\"\n\n\"Oh, very severe!\" chimed in the patient himself; then suddenly\naltering his voice, \"Drinking hot rum toddies with me every night,\ntill he couldn't see to put on the bandages; and sending me to bed,\nhalf seas over, about three o'clock in the morning.  Oh, ye stars! he\nsat up with me indeed, and was very severe in my diet.  Oh! a great\nwatcher, and very dietetically severe, is Dr. Bunger. (Bunger, you\ndog, laugh out! why don't ye?  You know you're a precious jolly\nrascal.) But, heave ahead, boy, I'd rather be killed by you than kept\nalive by any other man.\"\n\n\"My captain, you must have ere this perceived, respected sir\"--said\nthe imperturbable godly-looking Bunger, slightly bowing to Ahab--\"is\napt to be facetious at times; he spins us many clever things of that\nsort.  But I may as well say--en passant, as the French remark--that\nI myself--that is to say, Jack Bunger, late of the reverend\nclergy--am a strict total abstinence man; I never drink--\"\n\n\"Water!\" cried the captain; \"he never drinks it; it's a sort of fits\nto him; fresh water throws him into the hydrophobia; but go on--go on\nwith the arm story.\"\n\n\"Yes, I may as well,\" said the surgeon, coolly.  \"I was about\nobserving, sir, before Captain Boomer's facetious interruption, that\nspite of my best and severest endeavors, the wound kept getting worse\nand worse; the truth was, sir, it was as ugly gaping wound as surgeon\never saw; more than two feet and several inches long.  I measured it\nwith the lead line.  In short, it grew black; I knew what was\nthreatened, and off it came.  But I had no hand in shipping that\nivory arm there; that thing is against all rule\"--pointing at it with\nthe marlingspike--\"that is the captain's work, not mine; he ordered\nthe carpenter to make it; he had that club-hammer there put to the\nend, to knock some one's brains out with, I suppose, as he tried mine\nonce.  He flies into diabolical passions sometimes.  Do ye see this\ndent, sir\"--removing his hat, and brushing aside his hair, and\nexposing a bowl-like cavity in his skull, but which bore not the\nslightest scarry trace, or any token of ever having been a\nwound--\"Well, the captain there will tell you how that came here;\nhe knows.\"\n\n\"No, I don't,\" said the captain, \"but his mother did; he was born\nwith it.  Oh, you solemn rogue, you--you Bunger! was there ever such\nanother Bunger in the watery world?  Bunger, when you die, you ought\nto die in pickle, you dog; you should be preserved to future ages,\nyou rascal.\"\n\n\"What became of the White Whale?\" now cried Ahab, who thus far had\nbeen impatiently listening to this by-play between the two\nEnglishmen.\n\n\"Oh!\" cried the one-armed captain, \"oh, yes!  Well; after he sounded,\nwe didn't see him again for some time; in fact, as I before hinted, I\ndidn't then know what whale it was that had served me such a trick,\ntill some time afterwards, when coming back to the Line, we heard\nabout Moby Dick--as some call him--and then I knew it was he.\"\n\n\"Did'st thou cross his wake again?\"\n\n\"Twice.\"\n\n\"But could not fasten?\"\n\n\"Didn't want to try to: ain't one limb enough?  What should I do\nwithout this other arm?  And I'm thinking Moby Dick doesn't bite so\nmuch as he swallows.\"\n\n\"Well, then,\" interrupted Bunger, \"give him your left arm for bait to\nget the right.  Do you know, gentlemen\"--very gravely and\nmathematically bowing to each Captain in succession--\"Do you know,\ngentlemen, that the digestive organs of the whale are so inscrutably\nconstructed by Divine Providence, that it is quite impossible for him\nto completely digest even a man's arm?  And he knows it too.  So that\nwhat you take for the White Whale's malice is only his awkwardness.\nFor he never means to swallow a single limb; he only thinks to\nterrify by feints.  But sometimes he is like the old juggling fellow,\nformerly a patient of mine in Ceylon, that making believe swallow\njack-knives, once upon a time let one drop into him in good earnest,\nand there it stayed for a twelvemonth or more; when I gave him an\nemetic, and he heaved it up in small tacks, d'ye see.  No possible\nway for him to digest that jack-knife, and fully incorporate it into\nhis general bodily system.  Yes, Captain Boomer, if you are quick\nenough about it, and have a mind to pawn one arm for the sake of the\nprivilege of giving decent burial to the other, why in that case\nthe arm is yours; only let the whale have another chance at you\nshortly, that's all.\"\n\n\"No, thank ye, Bunger,\" said the English Captain, \"he's welcome to\nthe arm he has, since I can't help it, and didn't know him then; but\nnot to another one.  No more White Whales for me; I've lowered for\nhim once, and that has satisfied me.  There would be great glory in\nkilling him, I know that; and there is a ship-load of precious sperm\nin him, but, hark ye, he's best let alone; don't you think so,\nCaptain?\"--glancing at the ivory leg.\n\n\"He is.  But he will still be hunted, for all that.  What is best let\nalone, that accursed thing is not always what least allures.  He's\nall a magnet!  How long since thou saw'st him last?  Which way\nheading?\"\n\n\"Bless my soul, and curse the foul fiend's,\" cried Bunger, stoopingly\nwalking round Ahab, and like a dog, strangely snuffing; \"this man's\nblood--bring the thermometer!--it's at the boiling point!--his pulse\nmakes these planks beat!--sir!\"--taking a lancet from his pocket, and\ndrawing near to Ahab's arm.\n\n\"Avast!\" roared Ahab, dashing him against the bulwarks--\"Man the\nboat!  Which way heading?\"\n\n\"Good God!\" cried the English Captain, to whom the question was put.\n\"What's the matter?  He was heading east, I think.--Is your Captain\ncrazy?\" whispering Fedallah.\n\nBut Fedallah, putting a finger on his lip, slid over the bulwarks to\ntake the boat's steering oar, and Ahab, swinging the cutting-tackle\ntowards him, commanded the ship's sailors to stand by to lower.\n\nIn a moment he was standing in the boat's stern, and the Manilla men\nwere springing to their oars.  In vain the English Captain hailed\nhim.  With back to the stranger ship, and face set like a flint to\nhis own, Ahab stood upright till alongside of the Pequod.\n\n\n\nCHAPTER 101\n\nThe Decanter.\n\n\nEre the English ship fades from sight, be it set down here, that she\nhailed from London, and was named after the late Samuel Enderby,\nmerchant of that city, the original of the famous whaling house of\nEnderby & Sons; a house which in my poor whaleman's opinion, comes\nnot far behind the united royal houses of the Tudors and Bourbons, in\npoint of real historical interest.  How long, prior to the year of\nour Lord 1775, this great whaling house was in existence, my numerous\nfish-documents do not make plain; but in that year (1775) it fitted\nout the first English ships that ever regularly hunted the Sperm\nWhale; though for some score of years previous (ever since 1726) our\nvaliant Coffins and Maceys of Nantucket and the Vineyard had in large\nfleets pursued that Leviathan, but only in the North and South\nAtlantic: not elsewhere.  Be it distinctly recorded here, that the\nNantucketers were the first among mankind to harpoon with civilized\nsteel the great Sperm Whale; and that for half a century they were\nthe only people of the whole globe who so harpooned him.\n\nIn 1778, a fine ship, the Amelia, fitted out for the express purpose,\nand at the sole charge of the vigorous Enderbys, boldly rounded Cape\nHorn, and was the first among the nations to lower a whale-boat of\nany sort in the great South Sea.  The voyage was a skilful and lucky\none; and returning to her berth with her hold full of the precious\nsperm, the Amelia's example was soon followed by other ships, English\nand American, and thus the vast Sperm Whale grounds of the Pacific\nwere thrown open.  But not content with this good deed, the\nindefatigable house again bestirred itself: Samuel and all his\nSons--how many, their mother only knows--and under their immediate\nauspices, and partly, I think, at their expense, the British\ngovernment was induced to send the sloop-of-war Rattler on a whaling\nvoyage of discovery into the South Sea.  Commanded by a naval\nPost-Captain, the Rattler made a rattling voyage of it, and did some\nservice; how much does not appear.  But this is not all.  In 1819,\nthe same house fitted out a discovery whale ship of their own, to go\non a tasting cruise to the remote waters of Japan.  That ship--well\ncalled the \"Syren\"--made a noble experimental cruise; and it was thus\nthat the great Japanese Whaling Ground first became generally known.\nThe Syren in this famous voyage was commanded by a Captain Coffin, a\nNantucketer.\n\nAll honour to the Enderbies, therefore, whose house, I think, exists\nto the present day; though doubtless the original Samuel must long\nago have slipped his cable for the great South Sea of the other\nworld.\n\nThe ship named after him was worthy of the honour, being a very fast\nsailer and a noble craft every way.  I boarded her once at midnight\nsomewhere off the Patagonian coast, and drank good flip down in the\nforecastle.  It was a fine gam we had, and they were all\ntrumps--every soul on board.  A short life to them, and a jolly\ndeath.  And that fine gam I had--long, very long after old Ahab\ntouched her planks with his ivory heel--it minds me of the noble,\nsolid, Saxon hospitality of that ship; and may my parson forget me,\nand the devil remember me, if I ever lose sight of it.  Flip?  Did I\nsay we had flip?  Yes, and we flipped it at the rate of ten gallons\nthe hour; and when the squall came (for it's squally off there by\nPatagonia), and all hands--visitors and all--were called to reef\ntopsails, we were so top-heavy that we had to swing each other aloft\nin bowlines; and we ignorantly furled the skirts of our jackets into\nthe sails, so that we hung there, reefed fast in the howling gale, a\nwarning example to all drunken tars.  However, the masts did not go\noverboard; and by and by we scrambled down, so sober, that we had to\npass the flip again, though the savage salt spray bursting down the\nforecastle scuttle, rather too much diluted and pickled it to my\ntaste.\n\nThe beef was fine--tough, but with body in it.  They said it was\nbull-beef; others, that it was dromedary beef; but I do not know, for\ncertain, how that was.  They had dumplings too; small, but\nsubstantial, symmetrically globular, and indestructible dumplings.  I\nfancied that you could feel them, and roll them about in you after\nthey were swallowed.  If you stooped over too far forward, you risked\ntheir pitching out of you like billiard-balls.  The bread--but that\ncouldn't be helped; besides, it was an anti-scorbutic; in short, the\nbread contained the only fresh fare they had.  But the forecastle was\nnot very light, and it was very easy to step over into a dark corner\nwhen you ate it.  But all in all, taking her from truck to helm,\nconsidering the dimensions of the cook's boilers, including his own\nlive parchment boilers; fore and aft, I say, the Samuel Enderby was a\njolly ship; of good fare and plenty; fine flip and strong; crack\nfellows all, and capital from boot heels to hat-band.\n\nBut why was it, think ye, that the Samuel Enderby, and some other\nEnglish whalers I know of--not all though--were such famous,\nhospitable ships; that passed round the beef, and the bread, and the\ncan, and the joke; and were not soon weary of eating, and drinking,\nand laughing?  I will tell you.  The abounding good cheer of these\nEnglish whalers is matter for historical research.  Nor have I been\nat all sparing of historical whale research, when it has seemed\nneeded.\n\nThe English were preceded in the whale fishery by the Hollanders,\nZealanders, and Danes; from whom they derived many terms still extant\nin the fishery; and what is yet more, their fat old fashions,\ntouching plenty to eat and drink.  For, as a general thing, the\nEnglish merchant-ship scrimps her crew; but not so the English\nwhaler.  Hence, in the English, this thing of whaling good cheer is\nnot normal and natural, but incidental and particular; and,\ntherefore, must have some special origin, which is here pointed out,\nand will be still further elucidated.\n\nDuring my researches in the Leviathanic histories, I stumbled upon an\nancient Dutch volume, which, by the musty whaling smell of it, I knew\nmust be about whalers.  The title was, \"Dan Coopman,\" wherefore I\nconcluded that this must be the invaluable memoirs of some Amsterdam\ncooper in the fishery, as every whale ship must carry its cooper.  I\nwas reinforced in this opinion by seeing that it was the production\nof one \"Fitz Swackhammer.\"  But my friend Dr. Snodhead, a very\nlearned man, professor of Low Dutch and High German in the college of\nSanta Claus and St. Pott's, to whom I handed the work for\ntranslation, giving him a box of sperm candles for his trouble--this\nsame Dr. Snodhead, so soon as he spied the book, assured me that \"Dan\nCoopman\" did not mean \"The Cooper,\" but \"The Merchant.\"  In short,\nthis ancient and learned Low Dutch book treated of the commerce of\nHolland; and, among other subjects, contained a very interesting\naccount of its whale fishery.  And in this chapter it was, headed,\n\"Smeer,\" or \"Fat,\" that I found a long detailed list of the outfits\nfor the larders and cellars of 180 sail of Dutch whalemen; from which\nlist, as translated by Dr. Snodhead, I transcribe the following:\n\n400,000 lbs. of beef.\n60,000 lbs. Friesland pork.\n150,000 lbs. of stock fish.\n550,000 lbs. of biscuit.\n72,000 lbs. of soft bread.\n2,800 firkins of butter.\n20,000 lbs. Texel & Leyden cheese.\n144,000 lbs. cheese (probably an inferior article).\n550 ankers of Geneva.\n10,800 barrels of beer.\n\nMost statistical tables are parchingly dry in the reading; not so in\nthe present case, however, where the reader is flooded with whole\npipes, barrels, quarts, and gills of good gin and good cheer.\n\nAt the time, I devoted three days to the studious digesting of all\nthis beer, beef, and bread, during which many profound thoughts were\nincidentally suggested to me, capable of a transcendental and\nPlatonic application; and, furthermore, I compiled supplementary\ntables of my own, touching the probable quantity of stock-fish, etc.,\nconsumed by every Low Dutch harpooneer in that ancient Greenland and\nSpitzbergen whale fishery.  In the first place, the amount of butter,\nand Texel and Leyden cheese consumed, seems amazing.  I impute it,\nthough, to their naturally unctuous natures, being rendered still\nmore unctuous by the nature of their vocation, and especially by\ntheir pursuing their game in those frigid Polar Seas, on the very\ncoasts of that Esquimaux country where the convivial natives pledge\neach other in bumpers of train oil.\n\nThe quantity of beer, too, is very large, 10,800 barrels.  Now,\nas those polar fisheries could only be prosecuted in the short summer\nof that climate, so that the whole cruise of one of these Dutch\nwhalemen, including the short voyage to and from the Spitzbergen sea,\ndid not much exceed three months, say, and reckoning 30 men to each\nof their fleet of 180 sail, we have 5,400 Low Dutch seamen in all;\ntherefore, I say, we have precisely two barrels of beer per man, for\na twelve weeks' allowance, exclusive of his fair proportion of that\n550 ankers of gin.  Now, whether these gin and beer harpooneers, so\nfuddled as one might fancy them to have been, were the right sort of\nmen to stand up in a boat's head, and take good aim at flying whales;\nthis would seem somewhat improbable.  Yet they did aim at them, and\nhit them too.  But this was very far North, be it remembered, where\nbeer agrees well with the constitution; upon the Equator, in our\nsouthern fishery, beer would be apt to make the harpooneer sleepy at\nthe mast-head and boozy in his boat; and grievous loss might ensue to\nNantucket and New Bedford.\n\nBut no more; enough has been said to show that the old Dutch whalers\nof two or three centuries ago were high livers; and that the English\nwhalers have not neglected so excellent an example.  For, say they,\nwhen cruising in an empty ship, if you can get nothing better out of\nthe world, get a good dinner out of it, at least.  And this empties\nthe decanter.\n\n\n\nCHAPTER 102\n\nA Bower in the Arsacides.\n\n\nHitherto, in descriptively treating of the Sperm Whale, I have\nchiefly dwelt upon the marvels of his outer aspect; or separately and\nin detail upon some few interior structural features.  But to a large\nand thorough sweeping comprehension of him, it behooves me now to\nunbutton him still further, and untagging the points of his hose,\nunbuckling his garters, and casting loose the hooks and the eyes of\nthe joints of his innermost bones, set him before you in his\nultimatum; that is to say, in his unconditional skeleton.\n\nBut how now, Ishmael?  How is it, that you, a mere oarsman in the\nfishery, pretend to know aught about the subterranean parts of the\nwhale?  Did erudite Stubb, mounted upon your capstan, deliver\nlectures on the anatomy of the Cetacea; and by help of the windlass,\nhold up a specimen rib for exhibition?  Explain thyself, Ishmael.\nCan you land a full-grown whale on your deck for examination, as a\ncook dishes a roast-pig?  Surely not.  A veritable witness have you\nhitherto been, Ishmael; but have a care how you seize the privilege\nof Jonah alone; the privilege of discoursing upon the joists and\nbeams; the rafters, ridge-pole, sleepers, and under-pinnings, making\nup the frame-work of leviathan; and belike of the tallow-vats,\ndairy-rooms, butteries, and cheeseries in his bowels.\n\nI confess, that since Jonah, few whalemen have penetrated very far\nbeneath the skin of the adult whale; nevertheless, I have been\nblessed with an opportunity to dissect him in miniature.  In a ship I\nbelonged to, a small cub Sperm Whale was once bodily hoisted to the\ndeck for his poke or bag, to make sheaths for the barbs of the\nharpoons, and for the heads of the lances.  Think you I let that\nchance go, without using my boat-hatchet and jack-knife, and breaking\nthe seal and reading all the contents of that young cub?\n\nAnd as for my exact knowledge of the bones of the leviathan in their\ngigantic, full grown development, for that rare knowledge I am\nindebted to my late royal friend Tranquo, king of Tranque, one of\nthe Arsacides.  For being at Tranque, years ago, when attached to the\ntrading-ship Dey of Algiers, I was invited to spend part of the\nArsacidean holidays with the lord of Tranque, at his retired palm\nvilla at Pupella; a sea-side glen not very far distant from what our\nsailors called Bamboo-Town, his capital.\n\nAmong many other fine qualities, my royal friend Tranquo, being\ngifted with a devout love for all matters of barbaric vertu, had\nbrought together in Pupella whatever rare things the more ingenious\nof his people could invent; chiefly carved woods of wonderful\ndevices, chiselled shells, inlaid spears, costly paddles, aromatic\ncanoes; and all these distributed among whatever natural wonders, the\nwonder-freighted, tribute-rendering waves had cast upon his shores.\n\nChief among these latter was a great Sperm Whale, which, after an\nunusually long raging gale, had been found dead and stranded, with\nhis head against a cocoa-nut tree, whose plumage-like, tufted\ndroopings seemed his verdant jet.  When the vast body had at last\nbeen stripped of its fathom-deep enfoldings, and the bones become\ndust dry in the sun, then the skeleton was carefully transported up\nthe Pupella glen, where a grand temple of lordly palms now sheltered\nit.\n\nThe ribs were hung with trophies; the vertebrae were carved with\nArsacidean annals, in strange hieroglyphics; in the skull, the\npriests kept up an unextinguished aromatic flame, so that the mystic\nhead again sent forth its vapoury spout; while, suspended from a\nbough, the terrific lower jaw vibrated over all the devotees, like\nthe hair-hung sword that so affrighted Damocles.\n\nIt was a wondrous sight.  The wood was green as mosses of the Icy\nGlen; the trees stood high and haughty, feeling their living sap; the\nindustrious earth beneath was as a weaver's loom, with a gorgeous\ncarpet on it, whereof the ground-vine tendrils formed the warp and\nwoof, and the living flowers the figures.  All the trees, with all\ntheir laden branches; all the shrubs, and ferns, and grasses; the\nmessage-carrying air; all these unceasingly were active.  Through the\nlacings of the leaves, the great sun seemed a flying shuttle weaving\nthe unwearied verdure.  Oh, busy weaver! unseen weaver!--pause!--one\nword!--whither flows the fabric? what palace may it deck? wherefore\nall these ceaseless toilings?  Speak, weaver!--stay thy hand!--but\none single word with thee!  Nay--the shuttle flies--the figures float\nfrom forth the loom; the freshet-rushing carpet for ever slides\naway.  The weaver-god, he weaves; and by that weaving is he deafened,\nthat he hears no mortal voice; and by that humming, we, too, who look\non the loom are deafened; and only when we escape it shall we hear\nthe thousand voices that speak through it.  For even so it is in all\nmaterial factories.  The spoken words that are inaudible among the\nflying spindles; those same words are plainly heard without the\nwalls, bursting from the opened casements.  Thereby have villainies\nbeen detected.  Ah, mortal! then, be heedful; for so, in all this din\nof the great world's loom, thy subtlest thinkings may be overheard\nafar.\n\nNow, amid the green, life-restless loom of that Arsacidean wood, the\ngreat, white, worshipped skeleton lay lounging--a gigantic idler!\nYet, as the ever-woven verdant warp and woof intermixed and hummed\naround him, the mighty idler seemed the cunning weaver; himself all\nwoven over with the vines; every month assuming greener, fresher\nverdure; but himself a skeleton.  Life folded Death; Death trellised\nLife; the grim god wived with youthful Life, and begat him\ncurly-headed glories.\n\nNow, when with royal Tranquo I visited this wondrous whale, and saw\nthe skull an altar, and the artificial smoke ascending from where the\nreal jet had issued, I marvelled that the king should regard a chapel\nas an object of vertu.  He laughed.  But more I marvelled that the\npriests should swear that smoky jet of his was genuine.  To and fro I\npaced before this skeleton--brushed the vines aside--broke through\nthe ribs--and with a ball of Arsacidean twine, wandered, eddied long\namid its many winding, shaded colonnades and arbours.  But soon my\nline was out; and following it back, I emerged from the opening where I\nentered.  I saw no living thing within; naught was there but bones.\n\nCutting me a green measuring-rod, I once more dived within the\nskeleton.  From their arrow-slit in the skull, the priests perceived\nme taking the altitude of the final rib, \"How now!\" they shouted;\n\"Dar'st thou measure this our god!  That's for us.\"  \"Aye,\npriests--well, how long do ye make him, then?\"  But hereupon a fierce\ncontest rose among them, concerning feet and inches; they cracked\neach other's sconces with their yard-sticks--the great skull\nechoed--and seizing that lucky chance, I quickly concluded my own\nadmeasurements.\n\nThese admeasurements I now propose to set before you.  But first, be\nit recorded, that, in this matter, I am not free to utter any fancied\nmeasurement I please.  Because there are skeleton authorities you\ncan refer to, to test my accuracy.  There is a Leviathanic Museum,\nthey tell me, in Hull, England, one of the whaling ports of that\ncountry, where they have some fine specimens of fin-backs and other\nwhales.  Likewise, I have heard that in the museum of Manchester, in\nNew Hampshire, they have what the proprietors call \"the only perfect\nspecimen of a Greenland or River Whale in the United States.\"\nMoreover, at a place in Yorkshire, England, Burton Constable by name,\na certain Sir Clifford Constable has in his possession the skeleton\nof a Sperm Whale, but of moderate size, by no means of the full-grown\nmagnitude of my friend King Tranquo's.\n\nIn both cases, the stranded whales to which these two skeletons\nbelonged, were originally claimed by their proprietors upon similar\ngrounds.  King Tranquo seizing his because he wanted it; and Sir\nClifford, because he was lord of the seignories of those parts.  Sir\nClifford's whale has been articulated throughout; so that, like a\ngreat chest of drawers, you can open and shut him, in all his bony\ncavities--spread out his ribs like a gigantic fan--and swing all day\nupon his lower jaw.  Locks are to be put upon some of his trap-doors\nand shutters; and a footman will show round future visitors with a\nbunch of keys at his side.  Sir Clifford thinks of charging twopence\nfor a peep at the whispering gallery in the spinal column; threepence\nto hear the echo in the hollow of his cerebellum; and sixpence for\nthe unrivalled view from his forehead.\n\nThe skeleton dimensions I shall now proceed to set down are copied\nverbatim from my right arm, where I had them tattooed; as in my wild\nwanderings at that period, there was no other secure way of\npreserving such valuable statistics.  But as I was crowded for space,\nand wished the other parts of my body to remain a blank page for a\npoem I was then composing--at least, what untattooed parts might\nremain--I did not trouble myself with the odd inches; nor, indeed,\nshould inches at all enter into a congenial admeasurement of the\nwhale.\n\n\n\nCHAPTER 103\n\nMeasurement of The Whale's Skeleton.\n\n\nIn the first place, I wish to lay before you a particular, plain\nstatement, touching the living bulk of this leviathan, whose skeleton\nwe are briefly to exhibit.  Such a statement may prove useful here.\n\nAccording to a careful calculation I have made, and which I partly\nbase upon Captain Scoresby's estimate, of seventy tons for the\nlargest sized Greenland whale of sixty feet in length; according to\nmy careful calculation, I say, a Sperm Whale of the largest\nmagnitude, between eighty-five and ninety feet in length, and\nsomething less than forty feet in its fullest circumference, such a\nwhale will weigh at least ninety tons; so that, reckoning thirteen\nmen to a ton, he would considerably outweigh the combined population\nof a whole village of one thousand one hundred inhabitants.\n\nThink you not then that brains, like yoked cattle, should be put to\nthis leviathan, to make him at all budge to any landsman's\nimagination?\n\nHaving already in various ways put before you his skull, spout-hole,\njaw, teeth, tail, forehead, fins, and divers other parts, I shall now\nsimply point out what is most interesting in the general bulk of his\nunobstructed bones.  But as the colossal skull embraces so very large\na proportion of the entire extent of the skeleton; as it is by far\nthe most complicated part; and as nothing is to be repeated\nconcerning it in this chapter, you must not fail to carry it in your\nmind, or under your arm, as we proceed, otherwise you will not gain a\ncomplete notion of the general structure we are about to view.\n\nIn length, the Sperm Whale's skeleton at Tranque measured seventy-two\nFeet; so that when fully invested and extended in life, he must have\nbeen ninety feet long; for in the whale, the skeleton loses about one\nfifth in length compared with the living body.  Of this seventy-two\nfeet, his skull and jaw comprised some twenty feet, leaving some\nfifty feet of plain back-bone.  Attached to this back-bone, for\nsomething less than a third of its length, was the mighty circular\nbasket of ribs which once enclosed his vitals.\n\nTo me this vast ivory-ribbed chest, with the long, unrelieved spine,\nextending far away from it in a straight line, not a little resembled\nthe hull of a great ship new-laid upon the stocks, when only some\ntwenty of her naked bow-ribs are inserted, and the keel is otherwise,\nfor the time, but a long, disconnected timber.\n\nThe ribs were ten on a side.  The first, to begin from the neck, was\nnearly six feet long; the second, third, and fourth were each\nsuccessively longer, till you came to the climax of the fifth, or one\nof the middle ribs, which measured eight feet and some inches.  From\nthat part, the remaining ribs diminished, till the tenth and last\nonly spanned five feet and some inches.  In general thickness, they\nall bore a seemly correspondence to their length.  The middle ribs\nwere the most arched.  In some of the Arsacides they are used for\nbeams whereon to lay footpath bridges over small streams.\n\nIn considering these ribs, I could not but be struck anew with the\ncircumstance, so variously repeated in this book, that the skeleton\nof the whale is by no means the mould of his invested form.  The\nlargest of the Tranque ribs, one of the middle ones, occupied that\npart of the fish which, in life, is greatest in depth.  Now, the\ngreatest depth of the invested body of this particular whale must\nhave been at least sixteen feet; whereas, the corresponding rib\nmeasured but little more than eight feet.  So that this rib only\nconveyed half of the true notion of the living magnitude of that\npart.  Besides, for some way, where I now saw but a naked spine, all\nthat had been once wrapped round with tons of added bulk in flesh,\nmuscle, blood, and bowels.  Still more, for the ample fins, I here\nsaw but a few disordered joints; and in place of the weighty and\nmajestic, but boneless flukes, an utter blank!\n\nHow vain and foolish, then, thought I, for timid untravelled man to\ntry to comprehend aright this wondrous whale, by merely poring over\nhis dead attenuated skeleton, stretched in this peaceful wood.  No.\nOnly in the heart of quickest perils; only when within the eddyings\nof his angry flukes; only on the profound unbounded sea, can the\nfully invested whale be truly and livingly found out.\n\nBut the spine.  For that, the best way we can consider it is, with a\ncrane, to pile its bones high up on end.  No speedy enterprise.  But\nnow it's done, it looks much like Pompey's Pillar.\n\nThere are forty and odd vertebrae in all, which in the skeleton are\nnot locked together.  They mostly lie like the great knobbed blocks\non a Gothic spire, forming solid courses of heavy masonry.  The\nlargest, a middle one, is in width something less than three feet,\nand in depth more than four.  The smallest, where the spine tapers\naway into the tail, is only two inches in width, and looks something\nlike a white billiard-ball.  I was told that there were still smaller\nones, but they had been lost by some little cannibal urchins, the\npriest's children, who had stolen them to play marbles with.  Thus we\nsee how that the spine of even the hugest of living things tapers off\nat last into simple child's play.\n\n\n\nCHAPTER 104\n\nThe Fossil Whale.\n\n\nFrom his mighty bulk the whale affords a most congenial theme whereon\nto enlarge, amplify, and generally expatiate.  Would you, you could\nnot compress him.  By good rights he should only be treated of in\nimperial folio.  Not to tell over again his furlongs from spiracle to\ntail, and the yards he measures about the waist; only think of the\ngigantic involutions of his intestines, where they lie in him like\ngreat cables and hawsers coiled away in the subterranean orlop-deck\nof a line-of-battle-ship.\n\nSince I have undertaken to manhandle this Leviathan, it behooves me\nto approve myself omnisciently exhaustive in the enterprise; not\noverlooking the minutest seminal germs of his blood, and spinning him\nout to the uttermost coil of his bowels.  Having already described\nhim in most of his present habitatory and anatomical peculiarities,\nit now remains to magnify him in an archaeological, fossiliferous,\nand antediluvian point of view.  Applied to any other creature than\nthe Leviathan--to an ant or a flea--such portly terms might justly be\ndeemed unwarrantably grandiloquent.  But when Leviathan is the text,\nthe case is altered.  Fain am I to stagger to this emprise under\nthe weightiest words of the dictionary.  And here be it said, that\nwhenever it has been convenient to consult one in the course of these\ndissertations, I have invariably used a huge quarto edition of\nJohnson, expressly purchased for that purpose; because that famous\nlexicographer's uncommon personal bulk more fitted him to compile a\nlexicon to be used by a whale author like me.\n\nOne often hears of writers that rise and swell with their subject,\nthough it may seem but an ordinary one.  How, then, with me, writing\nof this Leviathan?  Unconsciously my chirography expands into placard\ncapitals.  Give me a condor's quill!  Give me Vesuvius' crater for an\ninkstand!  Friends, hold my arms!  For in the mere act of penning my\nthoughts of this Leviathan, they weary me, and make me faint with\ntheir outreaching comprehensiveness of sweep, as if to include the\nwhole circle of the sciences, and all the generations of whales, and\nmen, and mastodons, past, present, and to come, with all the\nrevolving panoramas of empire on earth, and throughout the whole\nuniverse, not excluding its suburbs.  Such, and so magnifying, is the\nvirtue of a large and liberal theme!  We expand to its bulk.  To\nproduce a mighty book, you must choose a mighty theme.  No great and\nenduring volume can ever be written on the flea, though many there be\nwho have tried it.\n\nEre entering upon the subject of Fossil Whales, I present my\ncredentials as a geologist, by stating that in my miscellaneous time\nI have been a stone-mason, and also a great digger of ditches,\ncanals and wells, wine-vaults, cellars, and cisterns of all sorts.\nLikewise, by way of preliminary, I desire to remind the reader, that\nwhile in the earlier geological strata there are found the fossils of\nmonsters now almost completely extinct; the subsequent relics\ndiscovered in what are called the Tertiary formations seem the\nconnecting, or at any rate intercepted links, between the\nantichronical creatures, and those whose remote posterity are said to\nhave entered the Ark; all the Fossil Whales hitherto discovered\nbelong to the Tertiary period, which is the last preceding the\nsuperficial formations.  And though none of them precisely answer to\nany known species of the present time, they are yet sufficiently akin\nto them in general respects, to justify their taking rank as\nCetacean fossils.\n\nDetached broken fossils of pre-adamite whales, fragments of their\nbones and skeletons, have within thirty years past, at various\nintervals, been found at the base of the Alps, in Lombardy, in\nFrance, in England, in Scotland, and in the States of Louisiana,\nMississippi, and Alabama.  Among the more curious of such remains is\npart of a skull, which in the year 1779 was disinterred in the Rue\nDauphine in Paris, a short street opening almost directly upon the\npalace of the Tuileries; and bones disinterred in excavating the\ngreat docks of Antwerp, in Napoleon's time.  Cuvier pronounced these\nfragments to have belonged to some utterly unknown Leviathanic\nspecies.\n\nBut by far the most wonderful of all Cetacean relics was the almost\ncomplete vast skeleton of an extinct monster, found in the year 1842,\non the plantation of Judge Creagh, in Alabama.  The awe-stricken\ncredulous slaves in the vicinity took it for the bones of one of the\nfallen angels.  The Alabama doctors declared it a huge reptile, and\nbestowed upon it the name of Basilosaurus.  But some specimen bones\nof it being taken across the sea to Owen, the English Anatomist, it\nturned out that this alleged reptile was a whale, though of a\ndeparted species.  A significant illustration of the fact, again and\nagain repeated in this book, that the skeleton of the whale furnishes\nbut little clue to the shape of his fully invested body.  So Owen\nrechristened the monster Zeuglodon; and in his paper read before the\nLondon Geological Society, pronounced it, in substance, one of the\nmost extraordinary creatures which the mutations of the globe have\nblotted out of existence.\n\nWhen I stand among these mighty Leviathan skeletons, skulls, tusks,\njaws, ribs, and vertebrae, all characterized by partial resemblances\nto the existing breeds of sea-monsters; but at the same time bearing\non the other hand similar affinities to the annihilated antichronical\nLeviathans, their incalculable seniors; I am, by a flood, borne back\nto that wondrous period, ere time itself can be said to have begun;\nfor time began with man.  Here Saturn's grey chaos rolls over me, and\nI obtain dim, shuddering glimpses into those Polar eternities; when\nwedged bastions of ice pressed hard upon what are now the Tropics;\nand in all the 25,000 miles of this world's circumference, not an\ninhabitable hand's breadth of land was visible.  Then the whole world\nwas the whale's; and, king of creation, he left his wake along the\npresent lines of the Andes and the Himmalehs.  Who can show a\npedigree like Leviathan?  Ahab's harpoon had shed older blood than\nthe Pharaoh's.  Methuselah seems a school-boy.  I look round to shake\nhands with Shem.  I am horror-struck at this antemosaic, unsourced\nexistence of the unspeakable terrors of the whale, which, having been\nbefore all time, must needs exist after all humane ages are over.\n\nBut not alone has this Leviathan left his pre-adamite traces in the\nstereotype plates of nature, and in limestone and marl bequeathed his\nancient bust; but upon Egyptian tablets, whose antiquity seems to\nclaim for them an almost fossiliferous character, we find the\nunmistakable print of his fin.  In an apartment of the great temple\nof Denderah, some fifty years ago, there was discovered upon the\ngranite ceiling a sculptured and painted planisphere, abounding in\ncentaurs, griffins, and dolphins, similar to the grotesque figures\non the celestial globe of the moderns.  Gliding among them, old\nLeviathan swam as of yore; was there swimming in that planisphere,\ncenturies before Solomon was cradled.\n\nNor must there be omitted another strange attestation of the\nantiquity of the whale, in his own osseous post-diluvian reality, as\nset down by the venerable John Leo, the old Barbary traveller.\n\n\"Not far from the Sea-side, they have a Temple, the Rafters and Beams\nof which are made of Whale-Bones; for Whales of a monstrous size are\noftentimes cast up dead upon that shore.  The Common People imagine,\nthat by a secret Power bestowed by God upon the temple, no Whale can\npass it without immediate death.  But the truth of the Matter is,\nthat on either side of the Temple, there are Rocks that shoot two\nMiles into the Sea, and wound the Whales when they light upon 'em.\nThey keep a Whale's Rib of an incredible length for a Miracle, which\nlying upon the Ground with its convex part uppermost, makes an Arch,\nthe Head of which cannot be reached by a Man upon a Camel's Back.\nThis Rib (says John Leo) is said to have layn there a hundred Years\nbefore I saw it.  Their Historians affirm, that a Prophet who\nprophesy'd of Mahomet, came from this Temple, and some do not stand\nto assert, that the Prophet Jonas was cast forth by the Whale at the\nBase of the Temple.\"\n\nIn this Afric Temple of the Whale I leave you, reader, and if you be\na Nantucketer, and a whaleman, you will silently worship there.\n\n\n\nCHAPTER 105\n\nDoes the Whale's Magnitude Diminish?--Will He Perish?\n\n\nInasmuch, then, as this Leviathan comes floundering down upon us from\nthe head-waters of the Eternities, it may be fitly inquired, whether,\nin the long course of his generations, he has not degenerated from\nthe original bulk of his sires.\n\nBut upon investigation we find, that not only are the whales of the\npresent day superior in magnitude to those whose fossil remains are\nfound in the Tertiary system (embracing a distinct geological period\nprior to man), but of the whales found in that Tertiary system, those\nbelonging to its latter formations exceed in size those of its\nearlier ones.\n\nOf all the pre-adamite whales yet exhumed, by far the largest is the\nAlabama one mentioned in the last chapter, and that was less than\nseventy feet in length in the skeleton.  Whereas, we have already\nseen, that the tape-measure gives seventy-two feet for the skeleton\nof a large sized modern whale.  And I have heard, on whalemen's\nauthority, that Sperm Whales have been captured near a hundred feet\nlong at the time of capture.\n\nBut may it not be, that while the whales of the present hour are an\nadvance in magnitude upon those of all previous geological periods;\nmay it not be, that since Adam's time they have degenerated?\n\nAssuredly, we must conclude so, if we are to credit the accounts of\nsuch gentlemen as Pliny, and the ancient naturalists generally.  For\nPliny tells us of Whales that embraced acres of living bulk, and\nAldrovandus of others which measured eight hundred feet in\nlength--Rope Walks and Thames Tunnels of Whales!  And even in the\ndays of Banks and Solander, Cooke's naturalists, we find a Danish\nmember of the Academy of Sciences setting down certain Iceland Whales\n(reydan-siskur, or Wrinkled Bellies) at one hundred and twenty yards;\nthat is, three hundred and sixty feet.  And Lacepede, the French\nnaturalist, in his elaborate history of whales, in the very beginning\nof his work (page 3), sets down the Right Whale at one hundred\nmetres, three hundred and twenty-eight feet.  And this work was\npublished so late as A.D. 1825.\n\nBut will any whaleman believe these stories?  No.  The whale of\nto-day is as big as his ancestors in Pliny's time.  And if ever I go\nwhere Pliny is, I, a whaleman (more than he was), will make bold to\ntell him so.  Because I cannot understand how it is, that while the\nEgyptian mummies that were buried thousands of years before even\nPliny was born, do not measure so much in their coffins as a modern\nKentuckian in his socks; and while the cattle and other animals\nsculptured on the oldest Egyptian and Nineveh tablets, by the\nrelative proportions in which they are drawn, just as plainly prove\nthat the high-bred, stall-fed, prize cattle of Smithfield, not only\nequal, but far exceed in magnitude the fattest of Pharaoh's fat kine;\nin the face of all this, I will not admit that of all animals the\nwhale alone should have degenerated.\n\nBut still another inquiry remains; one often agitated by the more\nrecondite Nantucketers.  Whether owing to the almost omniscient\nlook-outs at the mast-heads of the whaleships, now penetrating even\nthrough Behring's straits, and into the remotest secret drawers and\nlockers of the world; and the thousand harpoons and lances darted\nalong all continental coasts; the moot point is, whether Leviathan\ncan long endure so wide a chase, and so remorseless a havoc; whether\nhe must not at last be exterminated from the waters, and the last\nwhale, like the last man, smoke his last pipe, and then himself\nevaporate in the final puff.\n\nComparing the humped herds of whales with the humped herds of\nbuffalo, which, not forty years ago, overspread by tens of thousands\nthe prairies of Illinois and Missouri, and shook their iron manes and\nscowled with their thunder-clotted brows upon the sites of populous\nriver-capitals, where now the polite broker sells you land at a\ndollar an inch; in such a comparison an irresistible argument would\nseem furnished, to show that the hunted whale cannot now escape\nspeedy extinction.\n\nBut you must look at this matter in every light.  Though so short a\nperiod ago--not a good lifetime--the census of the buffalo in\nIllinois exceeded the census of men now in London, and though at the\npresent day not one horn or hoof of them remains in all that region;\nand though the cause of this wondrous extermination was the spear of\nman; yet the far different nature of the whale-hunt peremptorily\nforbids so inglorious an end to the Leviathan.  Forty men in one ship\nhunting the Sperm Whales for forty-eight months think they have done\nextremely well, and thank God, if at last they carry home the oil of\nforty fish.  Whereas, in the days of the old Canadian and Indian\nhunters and trappers of the West, when the far west (in whose sunset\nsuns still rise) was a wilderness and a virgin, the same number of\nmoccasined men, for the same number of months, mounted on horse\ninstead of sailing in ships, would have slain not forty, but forty\nthousand and more buffaloes; a fact that, if need were, could be\nstatistically stated.\n\nNor, considered aright, does it seem any argument in favour of the\ngradual extinction of the Sperm Whale, for example, that in former\nyears (the latter part of the last century, say) these Leviathans, in\nsmall pods, were encountered much oftener than at present, and, in\nconsequence, the voyages were not so prolonged, and were also much\nmore remunerative.  Because, as has been elsewhere noticed, those\nwhales, influenced by some views to safety, now swim the seas in\nimmense caravans, so that to a large degree the scattered solitaries,\nyokes, and pods, and schools of other days are now aggregated into\nvast but widely separated, unfrequent armies.  That is all.  And\nequally fallacious seems the conceit, that because the so-called\nwhale-bone whales no longer haunt many grounds in former years\nabounding with them, hence that species also is declining.  For they\nare only being driven from promontory to cape; and if one coast is no\nlonger enlivened with their jets, then, be sure, some other and\nremoter strand has been very recently startled by the unfamiliar\nspectacle.\n\nFurthermore: concerning these last mentioned Leviathans, they have\ntwo firm fortresses, which, in all human probability, will for ever\nremain impregnable.  And as upon the invasion of their valleys, the\nfrosty Swiss have retreated to their mountains; so, hunted from the\nsavannas and glades of the middle seas, the whale-bone whales can at\nlast resort to their Polar citadels, and diving under the ultimate\nglassy barriers and walls there, come up among icy fields and floes;\nand in a charmed circle of everlasting December, bid defiance to all\npursuit from man.\n\nBut as perhaps fifty of these whale-bone whales are harpooned for one\ncachalot, some philosophers of the forecastle have concluded that\nthis positive havoc has already very seriously diminished their\nbattalions.  But though for some time past a number of these whales,\nnot less than 13,000, have been annually slain on the nor'-west\ncoast by the Americans alone; yet there are considerations which\nrender even this circumstance of little or no account as an opposing\nargument in this matter.\n\nNatural as it is to be somewhat incredulous concerning the\npopulousness of the more enormous creatures of the globe, yet what\nshall we say to Harto, the historian of Goa, when he tells us that at\none hunting the King of Siam took 4,000 elephants; that in those\nregions elephants are numerous as droves of cattle in the temperate\nclimes.  And there seems no reason to doubt that if these elephants,\nwhich have now been hunted for thousands of years, by Semiramis, by\nPorus, by Hannibal, and by all the successive monarchs of the\nEast--if they still survive there in great numbers, much more may the\ngreat whale outlast all hunting, since he has a pasture to expatiate\nin, which is precisely twice as large as all Asia, both Americas,\nEurope and Africa, New Holland, and all the Isles of the sea\ncombined.\n\nMoreover: we are to consider, that from the presumed great longevity\nof whales, their probably attaining the age of a century and more,\ntherefore at any one period of time, several distinct adult\ngenerations must be contemporary.  And what that is, we may soon\ngain some idea of, by imagining all the grave-yards, cemeteries, and\nfamily vaults of creation yielding up the live bodies of all the men,\nwomen, and children who were alive seventy-five years ago; and adding\nthis countless host to the present human population of the globe.\n\nWherefore, for all these things, we account the whale immortal in his\nspecies, however perishable in his individuality.  He swam the seas\nbefore the continents broke water; he once swam over the site of the\nTuileries, and Windsor Castle, and the Kremlin.  In Noah's flood he\ndespised Noah's Ark; and if ever the world is to be again flooded,\nlike the Netherlands, to kill off its rats, then the eternal whale\nwill still survive, and rearing upon the topmost crest of the\nequatorial flood, spout his frothed defiance to the skies.\n\n\n\nCHAPTER 106\n\nAhab's Leg.\n\n\nThe precipitating manner in which Captain Ahab had quitted the Samuel\nEnderby of London, had not been unattended with some small violence\nto his own person.  He had lighted with such energy upon a thwart of\nhis boat that his ivory leg had received a half-splintering shock.\nAnd when after gaining his own deck, and his own pivot-hole there, he\nso vehemently wheeled round with an urgent command to the steersman\n(it was, as ever, something about his not steering inflexibly\nenough); then, the already shaken ivory received such an additional\ntwist and wrench, that though it still remained entire, and to all\nappearances lusty, yet Ahab did not deem it entirely trustworthy.\n\nAnd, indeed, it seemed small matter for wonder, that for all his\npervading, mad recklessness, Ahab did at times give careful heed to\nthe condition of that dead bone upon which he partly stood.  For it\nhad not been very long prior to the Pequod's sailing from Nantucket,\nthat he had been found one night lying prone upon the ground, and\ninsensible; by some unknown, and seemingly inexplicable, unimaginable\ncasualty, his ivory limb having been so violently displaced, that it\nhad stake-wise smitten, and all but pierced his groin; nor was it\nwithout extreme difficulty that the agonizing wound was entirely\ncured.\n\nNor, at the time, had it failed to enter his monomaniac mind, that\nall the anguish of that then present suffering was but the direct\nissue of a former woe; and he too plainly seemed to see, that as the\nmost poisonous reptile of the marsh perpetuates his kind as\ninevitably as the sweetest songster of the grove; so, equally with\nevery felicity, all miserable events do naturally beget their like.\nYea, more than equally, thought Ahab; since both the ancestry and\nposterity of Grief go further than the ancestry and posterity of Joy.\nFor, not to hint of this: that it is an inference from certain\ncanonic teachings, that while some natural enjoyments here shall have\nno children born to them for the other world, but, on the contrary,\nshall be followed by the joy-childlessness of all hell's despair;\nwhereas, some guilty mortal miseries shall still fertilely beget to\nthemselves an eternally progressive progeny of griefs beyond the\ngrave; not at all to hint of this, there still seems an inequality in\nthe deeper analysis of the thing.  For, thought Ahab, while even the\nhighest earthly felicities ever have a certain unsignifying pettiness\nlurking in them, but, at bottom, all heartwoes, a mystic\nsignificance, and, in some men, an archangelic grandeur; so do their\ndiligent tracings-out not belie the obvious deduction.  To trail the\ngenealogies of these high mortal miseries, carries us at last among\nthe sourceless primogenitures of the gods; so that, in the face of\nall the glad, hay-making suns, and soft cymballing, round\nharvest-moons, we must needs give in to this: that the gods\nthemselves are not for ever glad.  The ineffaceable, sad birth-mark\nin the brow of man, is but the stamp of sorrow in the signers.\n\nUnwittingly here a secret has been divulged, which perhaps might more\nproperly, in set way, have been disclosed before.  With many other\nparticulars concerning Ahab, always had it remained a mystery to\nsome, why it was, that for a certain period, both before and after\nthe sailing of the Pequod, he had hidden himself away with such\nGrand-Lama-like exclusiveness; and, for that one interval, sought\nspeechless refuge, as it were, among the marble senate of the dead.\nCaptain Peleg's bruited reason for this thing appeared by no means\nadequate; though, indeed, as touching all Ahab's deeper part, every\nrevelation partook more of significant darkness than of explanatory\nlight.  But, in the end, it all came out; this one matter did, at\nleast.  That direful mishap was at the bottom of his temporary\nrecluseness.  And not only this, but to that ever-contracting,\ndropping circle ashore, who, for any reason, possessed the privilege\nof a less banned approach to him; to that timid circle the above\nhinted casualty--remaining, as it did, moodily unaccounted for by\nAhab--invested itself with terrors, not entirely underived from the\nland of spirits and of wails.  So that, through their zeal for him,\nthey had all conspired, so far as in them lay, to muffle up the\nknowledge of this thing from others; and hence it was, that not till\na considerable interval had elapsed, did it transpire upon the\nPequod's decks.\n\nBut be all this as it may; let the unseen, ambiguous synod in the\nair, or the vindictive princes and potentates of fire, have to do or\nnot with earthly Ahab, yet, in this present matter of his leg, he\ntook plain practical procedures;--he called the carpenter.\n\nAnd when that functionary appeared before him, he bade him without\ndelay set about making a new leg, and directed the mates to see him\nsupplied with all the studs and joists of jaw-ivory (Sperm Whale)\nwhich had thus far been accumulated on the voyage, in order that a\ncareful selection of the stoutest, clearest-grained stuff might be\nsecured.  This done, the carpenter received orders to have the leg\ncompleted that night; and to provide all the fittings for it,\nindependent of those pertaining to the distrusted one in use.\nMoreover, the ship's forge was ordered to be hoisted out of its\ntemporary idleness in the hold; and, to accelerate the affair, the\nblacksmith was commanded to proceed at once to the forging of\nwhatever iron contrivances might be needed.\n\n\n\nCHAPTER 107\n\nThe Carpenter.\n\n\nSeat thyself sultanically among the moons of Saturn, and take high\nabstracted man alone; and he seems a wonder, a grandeur, and a woe.\nBut from the same point, take mankind in mass, and for the most part,\nthey seem a mob of unnecessary duplicates, both contemporary and\nhereditary.  But most humble though he was, and far from furnishing\nan example of the high, humane abstraction; the Pequod's carpenter\nwas no duplicate; hence, he now comes in person on this stage.\n\nLike all sea-going ship carpenters, and more especially those\nbelonging to whaling vessels, he was, to a certain off-handed,\npractical extent, alike experienced in numerous trades and callings\ncollateral to his own; the carpenter's pursuit being the ancient and\noutbranching trunk of all those numerous handicrafts which more or\nless have to do with wood as an auxiliary material.  But, besides the\napplication to him of the generic remark above, this carpenter of the\nPequod was singularly efficient in those thousand nameless mechanical\nemergencies continually recurring in a large ship, upon a three or\nfour years' voyage, in uncivilized and far-distant seas.  For not to\nspeak of his readiness in ordinary duties:--repairing stove boats,\nsprung spars, reforming the shape of clumsy-bladed oars, inserting\nbull's eyes in the deck, or new tree-nails in the side planks, and\nother miscellaneous matters more directly pertaining to his special\nbusiness; he was moreover unhesitatingly expert in all manner of\nconflicting aptitudes, both useful and capricious.\n\nThe one grand stage where he enacted all his various parts so\nmanifold, was his vice-bench; a long rude ponderous table furnished\nwith several vices, of different sizes, and both of iron and of wood.\nAt all times except when whales were alongside, this bench was\nsecurely lashed athwartships against the rear of the Try-works.\n\nA belaying pin is found too large to be easily inserted into its\nhole: the carpenter claps it into one of his ever-ready vices, and\nstraightway files it smaller.  A lost land-bird of strange plumage\nstrays on board, and is made a captive: out of clean shaved rods of\nright-whale bone, and cross-beams of sperm whale ivory, the carpenter\nmakes a pagoda-looking cage for it.  An oarsman sprains his wrist:\nthe carpenter concocts a soothing lotion.  Stubb longed for\nvermillion stars to be painted upon the blade of his every oar;\nscrewing each oar in his big vice of wood, the carpenter\nsymmetrically supplies the constellation.  A sailor takes a fancy to\nwear shark-bone ear-rings: the carpenter drills his ears.  Another\nhas the toothache: the carpenter out pincers, and clapping one hand\nupon his bench bids him be seated there; but the poor fellow\nunmanageably winces under the unconcluded operation; whirling round\nthe handle of his wooden vice, the carpenter signs him to clap his\njaw in that, if he would have him draw the tooth.\n\nThus, this carpenter was prepared at all points, and alike\nindifferent and without respect in all.  Teeth he accounted bits of\nivory; heads he deemed but top-blocks; men themselves he lightly held\nfor capstans.  But while now upon so wide a field thus variously\naccomplished and with such liveliness of expertness in him, too; all\nthis would seem to argue some uncommon vivacity of intelligence.  But\nnot precisely so.  For nothing was this man more remarkable, than for\na certain impersonal stolidity as it were; impersonal, I say; for it\nso shaded off into the surrounding infinite of things, that it seemed\none with the general stolidity discernible in the whole visible\nworld; which while pauselessly active in uncounted modes, still\neternally holds its peace, and ignores you, though you dig\nfoundations for cathedrals.  Yet was this half-horrible stolidity in\nhim, involving, too, as it appeared, an all-ramifying\nheartlessness;--yet was it oddly dashed at times, with an old,\ncrutch-like, antediluvian, wheezing humorousness, not unstreaked now\nand then with a certain grizzled wittiness; such as might have served\nto pass the time during the midnight watch on the bearded forecastle\nof Noah's ark.  Was it that this old carpenter had been a life-long\nwanderer, whose much rolling, to and fro, not only had gathered no\nmoss; but what is more, had rubbed off whatever small outward\nclingings might have originally pertained to him?  He was a stript\nabstract; an unfractioned integral; uncompromised as a new-born babe;\nliving without premeditated reference to this world or the next.  You\nmight almost say, that this strange uncompromisedness in him involved\na sort of unintelligence; for in his numerous trades, he did not seem\nto work so much by reason or by instinct, or simply because he had\nbeen tutored to it, or by any intermixture of all these, even or\nuneven; but merely by a kind of deaf and dumb, spontaneous literal\nprocess.  He was a pure manipulator; his brain, if he had ever had\none, must have early oozed along into the muscles of his fingers.  He\nwas like one of those unreasoning but still highly useful, MULTUM IN\nPARVO, Sheffield contrivances, assuming the exterior--though a little\nswelled--of a common pocket knife; but containing, not only blades of\nvarious sizes, but also screw-drivers, cork-screws, tweezers, awls,\npens, rulers, nail-filers, countersinkers.  So, if his superiors\nwanted to use the carpenter for a screw-driver, all they had to do\nwas to open that part of him, and the screw was fast: or if for\ntweezers, take him up by the legs, and there they were.\n\nYet, as previously hinted, this omnitooled, open-and-shut carpenter,\nwas, after all, no mere machine of an automaton.  If he did not have\na common soul in him, he had a subtle something that somehow\nanomalously did its duty.  What that was, whether essence of\nquicksilver, or a few drops of hartshorn, there is no telling.  But\nthere it was; and there it had abided for now some sixty years or\nmore.  And this it was, this same unaccountable, cunning\nlife-principle in him; this it was, that kept him a great part of the\ntime soliloquizing; but only like an unreasoning wheel, which also\nhummingly soliloquizes; or rather, his body was a sentry-box and this\nsoliloquizer on guard there, and talking all the time to keep himself\nawake.\n\n\n\nCHAPTER 108\n\nAhab and the Carpenter.\n\nThe Deck--First Night Watch.\n\n\n(CARPENTER STANDING BEFORE HIS VICE-BENCH, AND BY THE LIGHT OF TWO\nLANTERNS BUSILY FILING THE IVORY JOIST FOR THE LEG, WHICH JOIST IS\nFIRMLY FIXED IN THE VICE.  SLABS OF IVORY, LEATHER STRAPS, PADS,\nSCREWS, AND VARIOUS TOOLS OF ALL SORTS LYING ABOUT THE BENCH.\nFORWARD, THE RED FLAME OF THE FORGE IS SEEN, WHERE THE BLACKSMITH IS\nAT WORK.)\n\n\nDrat the file, and drat the bone!  That is hard which should be soft,\nand that is soft which should be hard.  So we go, who file old jaws\nand shinbones.  Let's try another.  Aye, now, this works better\n(SNEEZES).  Halloa, this bone dust is (SNEEZES)--why it's\n(SNEEZES)--yes it's (SNEEZES)--bless my soul, it won't let me speak!\nThis is what an old fellow gets now for working in dead lumber.  Saw\na live tree, and you don't get this dust; amputate a live bone, and\nyou don't get it (SNEEZES).  Come, come, you old Smut, there, bear a\nhand, and let's have that ferule and buckle-screw; I'll be ready\nfor them presently.  Lucky now (SNEEZES) there's no knee-joint to\nmake; that might puzzle a little; but a mere shinbone--why it's\neasy as making hop-poles; only I should like to put a good finish on.\nTime, time; if I but only had the time, I could turn him out as neat\na leg now as ever (SNEEZES) scraped to a lady in a parlor.  Those\nbuckskin legs and calves of legs I've seen in shop windows wouldn't\ncompare at all.  They soak water, they do; and of course get\nrheumatic, and have to be doctored (SNEEZES) with washes and lotions,\njust like live legs.  There; before I saw it off, now, I must call his\nold Mogulship, and see whether the length will be all right; too\nshort, if anything, I guess.  Ha! that's the heel; we are in luck;\nhere he comes, or it's somebody else, that's certain.\n\nAHAB (ADVANCING)\n\n(DURING THE ENSUING SCENE, THE CARPENTER CONTINUES SNEEZING AT TIMES)\n\n\nWell, manmaker!\n\nJust in time, sir.  If the captain pleases, I will now mark the\nlength.  Let me measure, sir.\n\nMeasured for a leg! good.  Well, it's not the first time.  About it!\nThere; keep thy finger on it.  This is a cogent vice thou hast here,\ncarpenter; let me feel its grip once.  So, so; it does pinch some.\n\nOh, sir, it will break bones--beware, beware!\n\nNo fear; I like a good grip; I like to feel something in this\nslippery world that can hold, man.  What's Prometheus about\nthere?--the blacksmith, I mean--what's he about?\n\nHe must be forging the buckle-screw, sir, now.\n\nRight.  It's a partnership; he supplies the muscle part.  He makes a\nfierce red flame there!\n\nAye, sir; he must have the white heat for this kind of fine work.\n\nUm-m.  So he must.  I do deem it now a most meaning thing, that that\nold Greek, Prometheus, who made men, they say, should have been a\nblacksmith, and animated them with fire; for what's made in fire must\nproperly belong to fire; and so hell's probable.  How the soot flies!\nThis must be the remainder the Greek made the Africans of.\nCarpenter, when he's through with that buckle, tell him to forge a\npair of steel shoulder-blades; there's a pedlar aboard with a\ncrushing pack.\n\nSir?\n\nHold; while Prometheus is about it, I'll order a complete man after a\ndesirable pattern.  Imprimis, fifty feet high in his socks; then,\nchest modelled after the Thames Tunnel; then, legs with roots to 'em,\nto stay in one place; then, arms three feet through the wrist; no\nheart at all, brass forehead, and about a quarter of an acre of fine\nbrains; and let me see--shall I order eyes to see outwards?  No, but\nput a sky-light on top of his head to illuminate inwards.  There,\ntake the order, and away.\n\nNow, what's he speaking about, and who's he speaking to, I should\nlike to know?  Shall I keep standing here? (ASIDE).\n\n'Tis but indifferent architecture to make a blind dome; here's one.\nNo, no, no; I must have a lantern.\n\nHo, ho!  That's it, hey?  Here are two, sir; one will serve my turn.\n\nWhat art thou thrusting that thief-catcher into my face for, man?\nThrusted light is worse than presented pistols.\n\nI thought, sir, that you spoke to carpenter.\n\n\nCarpenter? why that's--but no;--a very tidy, and, I may say, an\nextremely gentlemanlike sort of business thou art in here,\ncarpenter;--or would'st thou rather work in clay?\n\nSir?--Clay? clay, sir?  That's mud; we leave clay to ditchers, sir.\n\nThe fellow's impious!  What art thou sneezing about?\n\nBone is rather dusty, sir.\n\nTake the hint, then; and when thou art dead, never bury thyself under\nliving people's noses.\n\nSir?--oh! ah!--I guess so;--yes--dear!\n\nLook ye, carpenter, I dare say thou callest thyself a right good\nworkmanlike workman, eh?  Well, then, will it speak thoroughly well\nfor thy work, if, when I come to mount this leg thou makest, I shall\nnevertheless feel another leg in the same identical place with it;\nthat is, carpenter, my old lost leg; the flesh and blood one, I mean.\nCanst thou not drive that old Adam away?\n\nTruly, sir, I begin to understand somewhat now.  Yes, I have heard\nsomething curious on that score, sir; how that a dismasted man never\nentirely loses the feeling of his old spar, but it will be still\npricking him at times.  May I humbly ask if it be really so, sir?\n\nIt is, man.  Look, put thy live leg here in the place where mine once\nwas; so, now, here is only one distinct leg to the eye, yet two to\nthe soul.  Where thou feelest tingling life; there, exactly there,\nthere to a hair, do I.  Is't a riddle?\n\nI should humbly call it a poser, sir.\n\nHist, then.  How dost thou know that some entire, living, thinking\nthing may not be invisibly and uninterpenetratingly standing\nprecisely where thou now standest; aye, and standing there in thy\nspite?  In thy most solitary hours, then, dost thou not fear\neavesdroppers?  Hold, don't speak!  And if I still feel the smart of\nmy crushed leg, though it be now so long dissolved; then, why mayst\nnot thou, carpenter, feel the fiery pains of hell for ever, and\nwithout a body?  Hah!\n\nGood Lord!  Truly, sir, if it comes to that, I must calculate over\nagain; I think I didn't carry a small figure, sir.\n\nLook ye, pudding-heads should never grant premises.--How long before\nthe leg is done?\n\nPerhaps an hour, sir.\n\nBungle away at it then, and bring it to me (TURNS TO GO).  Oh, Life!\nHere I am, proud as Greek god, and yet standing debtor to this\nblockhead for a bone to stand on!  Cursed be that mortal\ninter-indebtedness which will not do away with ledgers.  I would be\nfree as air; and I'm down in the whole world's books.  I am so rich,\nI could have given bid for bid with the wealthiest Praetorians at the\nauction of the Roman empire (which was the world's); and yet I owe\nfor the flesh in the tongue I brag with.  By heavens!  I'll get a\ncrucible, and into it, and dissolve myself down to one small,\ncompendious vertebra.  So.\n\nCARPENTER (RESUMING HIS WORK).\n\n\nWell, well, well!  Stubb knows him best of all, and Stubb always says\nhe's queer; says nothing but that one sufficient little word queer;\nhe's queer, says Stubb; he's queer--queer, queer; and keeps dinning\nit into Mr. Starbuck all the time--queer--sir--queer, queer, very\nqueer.  And here's his leg!  Yes, now that I think of it, here's his\nbedfellow! has a stick of whale's jaw-bone for a wife!  And this is\nhis leg; he'll stand on this.  What was that now about one leg\nstanding in three places, and all three places standing in one\nhell--how was that?  Oh!  I don't wonder he looked so scornful at me!\nI'm a sort of strange-thoughted sometimes, they say; but that's only\nhaphazard-like.  Then, a short, little old body like me, should never\nundertake to wade out into deep waters with tall, heron-built\ncaptains; the water chucks you under the chin pretty quick, and\nthere's a great cry for life-boats.  And here's the heron's leg! long\nand slim, sure enough!  Now, for most folks one pair of legs lasts a\nlifetime, and that must be because they use them mercifully, as a\ntender-hearted old lady uses her roly-poly old coach-horses.  But\nAhab; oh he's a hard driver.  Look, driven one leg to death, and\nspavined the other for life, and now wears out bone legs by the cord.\nHalloa, there, you Smut! bear a hand there with those screws, and\nlet's finish it before the resurrection fellow comes a-calling with\nhis horn for all legs, true or false, as brewery-men go round\ncollecting old beer barrels, to fill 'em up again.  What a leg this\nis!  It looks like a real live leg, filed down to nothing but the\ncore; he'll be standing on this to-morrow; he'll be taking altitudes\non it.  Halloa!  I almost forgot the little oval slate, smoothed\nivory, where he figures up the latitude.  So, so; chisel, file, and\nsand-paper, now!\n\n\n\nCHAPTER 109\n\nAhab and Starbuck in the Cabin.\n\n\nAccording to usage they were pumping the ship next morning; and lo!\nno inconsiderable oil came up with the water; the casks below must\nhave sprung a bad leak.  Much concern was shown; and Starbuck went\ndown into the cabin to report this unfavourable affair.*\n\n\n*In Sperm-whalemen with any considerable quantity of oil on board, it\nis a regular semiweekly duty to conduct a hose into the hold, and\ndrench the casks with sea-water; which afterwards, at varying\nintervals, is removed by the ship's pumps.  Hereby the casks are\nsought to be kept damply tight; while by the changed character of the\nwithdrawn water, the mariners readily detect any serious leakage in\nthe precious cargo.\n\n\nNow, from the South and West the Pequod was drawing nigh to Formosa\nand the Bashee Isles, between which lies one of the tropical outlets\nfrom the China waters into the Pacific.  And so Starbuck found Ahab\nwith a general chart of the oriental archipelagoes spread before him;\nand another separate one representing the long eastern coasts of the\nJapanese islands--Niphon, Matsmai, and Sikoke.  With his snow-white\nnew ivory leg braced against the screwed leg of his table, and with a\nlong pruning-hook of a jack-knife in his hand, the wondrous old man,\nwith his back to the gangway door, was wrinkling his brow, and\ntracing his old courses again.\n\n\"Who's there?\" hearing the footstep at the door, but not turning\nround to it.  \"On deck!  Begone!\"\n\n\"Captain Ahab mistakes; it is I.  The oil in the hold is leaking,\nsir.  We must up Burtons and break out.\"\n\n\"Up Burtons and break out?  Now that we are nearing Japan; heave-to\nhere for a week to tinker a parcel of old hoops?\"\n\n\"Either do that, sir, or waste in one day more oil than we may make\ngood in a year.  What we come twenty thousand miles to get is worth\nsaving, sir.\"\n\n\"So it is, so it is; if we get it.\"\n\n\"I was speaking of the oil in the hold, sir.\"\n\n\"And I was not speaking or thinking of that at all.  Begone!  Let it\nleak!  I'm all aleak myself.  Aye! leaks in leaks! not only full of\nleaky casks, but those leaky casks are in a leaky ship; and that's a\nfar worse plight than the Pequod's, man.  Yet I don't stop to plug my\nleak; for who can find it in the deep-loaded hull; or how hope to\nplug it, even if found, in this life's howling gale?  Starbuck!\nI'll not have the Burtons hoisted.\"\n\n\"What will the owners say, sir?\"\n\n\"Let the owners stand on Nantucket beach and outyell the Typhoons.\nWhat cares Ahab?  Owners, owners?  Thou art always prating to me,\nStarbuck, about those miserly owners, as if the owners were my\nconscience.  But look ye, the only real owner of anything is its\ncommander; and hark ye, my conscience is in this ship's keel.--On\ndeck!\"\n\n\"Captain Ahab,\" said the reddening mate, moving further into the\ncabin, with a daring so strangely respectful and cautious that it\nalmost seemed not only every way seeking to avoid the slightest\noutward manifestation of itself, but within also seemed more than\nhalf distrustful of itself; \"A better man than I might well pass over\nin thee what he would quickly enough resent in a younger man; aye,\nand in a happier, Captain Ahab.\"\n\n\"Devils!  Dost thou then so much as dare to critically think of\nme?--On deck!\"\n\n\"Nay, sir, not yet; I do entreat.  And I do dare, sir--to be\nforbearing!  Shall we not understand each other better than hitherto,\nCaptain Ahab?\"\n\nAhab seized a loaded musket from the rack (forming part of most\nSouth-Sea-men's cabin furniture), and pointing it towards Starbuck,\nexclaimed: \"There is one God that is Lord over the earth, and one\nCaptain that is lord over the Pequod.--On deck!\"\n\nFor an instant in the flashing eyes of the mate, and his fiery\ncheeks, you would have almost thought that he had really received the\nblaze of the levelled tube.  But, mastering his emotion, he half\ncalmly rose, and as he quitted the cabin, paused for an instant and\nsaid: \"Thou hast outraged, not insulted me, sir; but for that I ask\nthee not to beware of Starbuck; thou wouldst but laugh; but let Ahab\nbeware of Ahab; beware of thyself, old man.\"\n\n\"He waxes brave, but nevertheless obeys; most careful bravery that!\"\nmurmured Ahab, as Starbuck disappeared.  \"What's that he said--Ahab\nbeware of Ahab--there's something there!\"  Then unconsciously using\nthe musket for a staff, with an iron brow he paced to and fro in the\nlittle cabin; but presently the thick plaits of his forehead relaxed,\nand returning the gun to the rack, he went to the deck.\n\n\"Thou art but too good a fellow, Starbuck,\" he said lowly to the\nmate; then raising his voice to the crew: \"Furl the t'gallant-sails,\nand close-reef the top-sails, fore and aft; back the main-yard; up\nBurton, and break out in the main-hold.\"\n\nIt were perhaps vain to surmise exactly why it was, that as\nrespecting Starbuck, Ahab thus acted.  It may have been a flash of\nhonesty in him; or mere prudential policy which, under the\ncircumstance, imperiously forbade the slightest symptom of open\ndisaffection, however transient, in the important chief officer of\nhis ship.  However it was, his orders were executed; and the Burtons\nwere hoisted.\n\n\n\nCHAPTER 110\n\nQueequeg in His Coffin.\n\n\nUpon searching, it was found that the casks last struck into the hold\nwere perfectly sound, and that the leak must be further off.  So, it\nbeing calm weather, they broke out deeper and deeper, disturbing the\nslumbers of the huge ground-tier butts; and from that black midnight\nsending those gigantic moles into the daylight above.  So deep did\nthey go; and so ancient, and corroded, and weedy the aspect of the\nlowermost puncheons, that you almost looked next for some mouldy\ncorner-stone cask containing coins of Captain Noah, with copies of\nthe posted placards, vainly warning the infatuated old world from the\nflood.  Tierce after tierce, too, of water, and bread, and beef, and\nshooks of staves, and iron bundles of hoops, were hoisted out, till\nat last the piled decks were hard to get about; and the hollow hull\nechoed under foot, as if you were treading over empty catacombs, and\nreeled and rolled in the sea like an air-freighted demijohn.\nTop-heavy was the ship as a dinnerless student with all Aristotle in\nhis head.  Well was it that the Typhoons did not visit them then.\n\nNow, at this time it was that my poor pagan companion, and fast\nbosom-friend, Queequeg, was seized with a fever, which brought him\nnigh to his endless end.\n\nBe it said, that in this vocation of whaling, sinecures are unknown;\ndignity and danger go hand in hand; till you get to be Captain, the\nhigher you rise the harder you toil.  So with poor Queequeg, who, as\nharpooneer, must not only face all the rage of the living whale,\nbut--as we have elsewhere seen--mount his dead back in a rolling sea;\nand finally descend into the gloom of the hold, and bitterly sweating\nall day in that subterraneous confinement, resolutely manhandle the\nclumsiest casks and see to their stowage.  To be short, among\nwhalemen, the harpooneers are the holders, so called.\n\nPoor Queequeg! when the ship was about half disembowelled, you should\nhave stooped over the hatchway, and peered down upon him there;\nwhere, stripped to his woollen drawers, the tattooed savage was\ncrawling about amid that dampness and slime, like a green spotted\nlizard at the bottom of a well.  And a well, or an ice-house, it\nsomehow proved to him, poor pagan; where, strange to say, for all the\nheat of his sweatings, he caught a terrible chill which lapsed into a\nfever; and at last, after some days' suffering, laid him in his\nhammock, close to the very sill of the door of death.  How he wasted\nand wasted away in those few long-lingering days, till there seemed\nbut little left of him but his frame and tattooing.  But as all else\nin him thinned, and his cheek-bones grew sharper, his eyes,\nnevertheless, seemed growing fuller and fuller; they became of a\nstrange softness of lustre; and mildly but deeply looked out at you\nthere from his sickness, a wondrous testimony to that immortal health\nin him which could not die, or be weakened.  And like circles on the\nwater, which, as they grow fainter, expand; so his eyes seemed\nrounding and rounding, like the rings of Eternity.  An awe that\ncannot be named would steal over you as you sat by the side of this\nwaning savage, and saw as strange things in his face, as any beheld\nwho were bystanders when Zoroaster died.  For whatever is truly\nwondrous and fearful in man, never yet was put into words or books.\nAnd the drawing near of Death, which alike levels all, alike\nimpresses all with a last revelation, which only an author from the\ndead could adequately tell.  So that--let us say it again--no dying\nChaldee or Greek had higher and holier thoughts than those, whose\nmysterious shades you saw creeping over the face of poor Queequeg, as\nhe quietly lay in his swaying hammock, and the rolling sea seemed\ngently rocking him to his final rest, and the ocean's invisible\nflood-tide lifted him higher and higher towards his destined heaven.\n\nNot a man of the crew but gave him up; and, as for Queequeg himself,\nwhat he thought of his case was forcibly shown by a curious favour he\nasked.  He called one to him in the grey morning watch, when the day\nwas just breaking, and taking his hand, said that while in Nantucket\nhe had chanced to see certain little canoes of dark wood, like the\nrich war-wood of his native isle; and upon inquiry, he had learned\nthat all whalemen who died in Nantucket, were laid in those same dark\ncanoes, and that the fancy of being so laid had much pleased him; for\nit was not unlike the custom of his own race, who, after embalming a\ndead warrior, stretched him out in his canoe, and so left him to be\nfloated away to the starry archipelagoes; for not only do they\nbelieve that the stars are isles, but that far beyond all visible\nhorizons, their own mild, uncontinented seas, interflow with the blue\nheavens; and so form the white breakers of the milky way.  He added,\nthat he shuddered at the thought of being buried in his hammock,\naccording to the usual sea-custom, tossed like something vile to the\ndeath-devouring sharks.  No: he desired a canoe like those of\nNantucket, all the more congenial to him, being a whaleman, that like\na whale-boat these coffin-canoes were without a keel; though that\ninvolved but uncertain steering, and much lee-way adown the dim ages.\n\nNow, when this strange circumstance was made known aft, the carpenter\nwas at once commanded to do Queequeg's bidding, whatever it might\ninclude.  There was some heathenish, coffin-coloured old lumber\naboard, which, upon a long previous voyage, had been cut from the\naboriginal groves of the Lackaday islands, and from these dark planks\nthe coffin was recommended to be made.  No sooner was the carpenter\napprised of the order, than taking his rule, he forthwith with all\nthe indifferent promptitude of his character, proceeded into the\nforecastle and took Queequeg's measure with great accuracy, regularly\nchalking Queequeg's person as he shifted the rule.\n\n\"Ah! poor fellow! he'll have to die now,\" ejaculated the Long Island\nsailor.\n\nGoing to his vice-bench, the carpenter for convenience sake and\ngeneral reference, now transferringly measured on it the exact length\nthe coffin was to be, and then made the transfer permanent by cutting\ntwo notches at its extremities.  This done, he marshalled the planks\nand his tools, and to work.\n\nWhen the last nail was driven, and the lid duly planed and fitted, he\nlightly shouldered the coffin and went forward with it, inquiring\nwhether they were ready for it yet in that direction.\n\nOverhearing the indignant but half-humorous cries with which the\npeople on deck began to drive the coffin away, Queequeg, to every\none's consternation, commanded that the thing should be instantly\nbrought to him, nor was there any denying him; seeing that, of all\nmortals, some dying men are the most tyrannical; and certainly, since\nthey will shortly trouble us so little for evermore, the poor fellows\nought to be indulged.\n\nLeaning over in his hammock, Queequeg long regarded the coffin with\nan attentive eye.  He then called for his harpoon, had the wooden\nstock drawn from it, and then had the iron part placed in the coffin\nalong with one of the paddles of his boat.  All by his own request,\nalso, biscuits were then ranged round the sides within: a flask of\nfresh water was placed at the head, and a small bag of woody earth\nscraped up in the hold at the foot; and a piece of sail-cloth being\nrolled up for a pillow, Queequeg now entreated to be lifted into his\nfinal bed, that he might make trial of its comforts, if any it had.\nHe lay without moving a few minutes, then told one to go to his bag\nand bring out his little god, Yojo.  Then crossing his arms on his\nbreast with Yojo between, he called for the coffin lid (hatch he\ncalled it) to be placed over him.  The head part turned over with a\nleather hinge, and there lay Queequeg in his coffin with little but\nhis composed countenance in view.  \"Rarmai\" (it will do; it is easy),\nhe murmured at last, and signed to be replaced in his hammock.\n\nBut ere this was done, Pip, who had been slily hovering near by all\nthis while, drew nigh to him where he lay, and with soft sobbings,\ntook him by the hand; in the other, holding his tambourine.\n\n\"Poor rover! will ye never have done with all this weary roving?\nwhere go ye now?  But if the currents carry ye to those sweet\nAntilles where the beaches are only beat with water-lilies, will ye\ndo one little errand for me?  Seek out one Pip, who's now been\nmissing long: I think he's in those far Antilles.  If ye find him,\nthen comfort him; for he must be very sad; for look! he's left his\ntambourine behind;--I found it.  Rig-a-dig, dig, dig!  Now, Queequeg,\ndie; and I'll beat ye your dying march.\"\n\n\"I have heard,\" murmured Starbuck, gazing down the scuttle, \"that in\nviolent fevers, men, all ignorance, have talked in ancient tongues;\nand that when the mystery is probed, it turns out always that in\ntheir wholly forgotten childhood those ancient tongues had been\nreally spoken in their hearing by some lofty scholars.  So, to my\nfond faith, poor Pip, in this strange sweetness of his lunacy, brings\nheavenly vouchers of all our heavenly homes.  Where learned he that,\nbut there?--Hark! he speaks again: but more wildly now.\"\n\n\"Form two and two!  Let's make a General of him!  Ho, where's his\nharpoon?  Lay it across here.--Rig-a-dig, dig, dig! huzza!  Oh for a\ngame cock now to sit upon his head and crow!  Queequeg dies\ngame!--mind ye that; Queequeg dies game!--take ye good heed of that;\nQueequeg dies game!  I say; game, game, game! but base little Pip, he\ndied a coward; died all a'shiver;--out upon Pip!  Hark ye; if ye find\nPip, tell all the Antilles he's a runaway; a coward, a coward, a\ncoward!  Tell them he jumped from a whale-boat!  I'd never beat my\ntambourine over base Pip, and hail him General, if he were once more\ndying here.  No, no! shame upon all cowards--shame upon them!  Let 'em\ngo drown like Pip, that jumped from a whale-boat.  Shame! shame!\"\n\nDuring all this, Queequeg lay with closed eyes, as if in a dream.\nPip was led away, and the sick man was replaced in his hammock.\n\nBut now that he had apparently made every preparation for death; now\nthat his coffin was proved a good fit, Queequeg suddenly rallied;\nsoon there seemed no need of the carpenter's box: and thereupon,\nwhen some expressed their delighted surprise, he, in substance, said,\nthat the cause of his sudden convalescence was this;--at a critical\nmoment, he had just recalled a little duty ashore, which he was\nleaving undone; and therefore had changed his mind about dying: he\ncould not die yet, he averred.  They asked him, then, whether to live\nor die was a matter of his own sovereign will and pleasure.  He\nanswered, certainly.  In a word, it was Queequeg's conceit, that if a\nman made up his mind to live, mere sickness could not kill him:\nnothing but a whale, or a gale, or some violent, ungovernable,\nunintelligent destroyer of that sort.\n\nNow, there is this noteworthy difference between savage and\ncivilized; that while a sick, civilized man may be six months\nconvalescing, generally speaking, a sick savage is almost half-well\nagain in a day.  So, in good time my Queequeg gained strength; and at\nlength after sitting on the windlass for a few indolent days (but\neating with a vigorous appetite) he suddenly leaped to his feet,\nthrew out his arms and legs, gave himself a good stretching, yawned\na little bit, and then springing into the head of his hoisted boat,\nand poising a harpoon, pronounced himself fit for a fight.\n\nWith a wild whimsiness, he now used his coffin for a sea-chest; and\nemptying into it his canvas bag of clothes, set them in order there.\nMany spare hours he spent, in carving the lid with all manner of\ngrotesque figures and drawings; and it seemed that hereby he was\nstriving, in his rude way, to copy parts of the twisted tattooing on\nhis body.  And this tattooing had been the work of a departed\nprophet and seer of his island, who, by those hieroglyphic marks, had\nwritten out on his body a complete theory of the heavens and the\nearth, and a mystical treatise on the art of attaining truth; so that\nQueequeg in his own proper person was a riddle to unfold; a wondrous\nwork in one volume; but whose mysteries not even himself could read,\nthough his own live heart beat against them; and these mysteries were\ntherefore destined in the end to moulder away with the living\nparchment whereon they were inscribed, and so be unsolved to the\nlast.  And this thought it must have been which suggested to Ahab\nthat wild exclamation of his, when one morning turning away from\nsurveying poor Queequeg--\"Oh, devilish tantalization of the gods!\"\n\n\n\nCHAPTER 111\n\nThe Pacific.\n\n\nWhen gliding by the Bashee isles we emerged at last upon the great\nSouth Sea; were it not for other things, I could have greeted my dear\nPacific with uncounted thanks, for now the long supplication of my\nyouth was answered; that serene ocean rolled eastwards from me a\nthousand leagues of blue.\n\nThere is, one knows not what sweet mystery about this sea, whose\ngently awful stirrings seem to speak of some hidden soul beneath;\nlike those fabled undulations of the Ephesian sod over the buried\nEvangelist St. John.  And meet it is, that over these sea-pastures,\nwide-rolling watery prairies and Potters' Fields of all four\ncontinents, the waves should rise and fall, and ebb and flow\nunceasingly; for here, millions of mixed shades and shadows, drowned\ndreams, somnambulisms, reveries; all that we call lives and souls,\nlie dreaming, dreaming, still; tossing like slumberers in their beds;\nthe ever-rolling waves but made so by their restlessness.\n\nTo any meditative Magian rover, this serene Pacific, once beheld,\nmust ever after be the sea of his adoption.  It rolls the midmost\nwaters of the world, the Indian ocean and Atlantic being but its\narms.  The same waves wash the moles of the new-built Californian\ntowns, but yesterday planted by the recentest race of men, and lave\nthe faded but still gorgeous skirts of Asiatic lands, older than\nAbraham; while all between float milky-ways of coral isles, and\nlow-lying, endless, unknown Archipelagoes, and impenetrable Japans.\nThus this mysterious, divine Pacific zones the world's whole bulk\nabout; makes all coasts one bay to it; seems the tide-beating heart\nof earth.  Lifted by those eternal swells, you needs must own the\nseductive god, bowing your head to Pan.\n\nBut few thoughts of Pan stirred Ahab's brain, as standing like an\niron statue at his accustomed place beside the mizen rigging, with\none nostril he unthinkingly snuffed the sugary musk from the Bashee\nisles (in whose sweet woods mild lovers must be walking), and with\nthe other consciously inhaled the salt breath of the new found sea;\nthat sea in which the hated White Whale must even then be swimming.\nLaunched at length upon these almost final waters, and gliding\ntowards the Japanese cruising-ground, the old man's purpose\nintensified itself.  His firm lips met like the lips of a vice; the\nDelta of his forehead's veins swelled like overladen brooks; in his\nvery sleep, his ringing cry ran through the vaulted hull, \"Stern all!\nthe White Whale spouts thick blood!\"\n\n\n\nCHAPTER 112\n\nThe Blacksmith.\n\n\nAvailing himself of the mild, summer-cool weather that now reigned\nin these latitudes, and in preparation for the peculiarly active\npursuits shortly to be anticipated, Perth, the begrimed, blistered\nold blacksmith, had not removed his portable forge to the hold again,\nafter concluding his contributory work for Ahab's leg, but still\nretained it on deck, fast lashed to ringbolts by the foremast; being\nnow almost incessantly invoked by the headsmen, and harpooneers, and\nbowsmen to do some little job for them; altering, or repairing, or\nnew shaping their various weapons and boat furniture.  Often he would\nbe surrounded by an eager circle, all waiting to be served; holding\nboat-spades, pike-heads, harpoons, and lances, and jealously watching\nhis every sooty movement, as he toiled.  Nevertheless, this old man's\nwas a patient hammer wielded by a patient arm.  No murmur, no\nimpatience, no petulance did come from him.  Silent, slow, and\nsolemn; bowing over still further his chronically broken back, he\ntoiled away, as if toil were life itself, and the heavy beating of\nhis hammer the heavy beating of his heart.  And so it was.--Most\nmiserable!\n\nA peculiar walk in this old man, a certain slight but painful\nappearing yawing in his gait, had at an early period of the voyage\nexcited the curiosity of the mariners.  And to the importunity of\ntheir persisted questionings he had finally given in; and so it came\nto pass that every one now knew the shameful story of his wretched\nfate.\n\nBelated, and not innocently, one bitter winter's midnight, on the\nroad running between two country towns, the blacksmith half-stupidly\nfelt the deadly numbness stealing over him, and sought refuge in a\nleaning, dilapidated barn.  The issue was, the loss of the\nextremities of both feet.  Out of this revelation, part by part, at\nlast came out the four acts of the gladness, and the one long, and as\nyet uncatastrophied fifth act of the grief of his life's drama.\n\nHe was an old man, who, at the age of nearly sixty, had postponedly\nencountered that thing in sorrow's technicals called ruin.  He had\nbeen an artisan of famed excellence, and with plenty to do; owned a\nhouse and garden; embraced a youthful, daughter-like, loving wife,\nand three blithe, ruddy children; every Sunday went to a\ncheerful-looking church, planted in a grove.  But one night, under\ncover of darkness, and further concealed in a most cunning\ndisguisement, a desperate burglar slid into his happy home, and\nrobbed them all of everything.  And darker yet to tell, the\nblacksmith himself did ignorantly conduct this burglar into his\nfamily's heart.  It was the Bottle Conjuror!  Upon the opening of\nthat fatal cork, forth flew the fiend, and shrivelled up his home.\nNow, for prudent, most wise, and economic reasons, the blacksmith's\nshop was in the basement of his dwelling, but with a separate\nentrance to it; so that always had the young and loving healthy wife\nlistened with no unhappy nervousness, but with vigorous pleasure, to\nthe stout ringing of her young-armed old husband's hammer; whose\nreverberations, muffled by passing through the floors and walls, came\nup to her, not unsweetly, in her nursery; and so, to stout Labor's\niron lullaby, the blacksmith's infants were rocked to slumber.\n\nOh, woe on woe!  Oh, Death, why canst thou not sometimes be timely?\nHadst thou taken this old blacksmith to thyself ere his full ruin\ncame upon him, then had the young widow had a delicious grief, and\nher orphans a truly venerable, legendary sire to dream of in their\nafter years; and all of them a care-killing competency.  But Death\nplucked down some virtuous elder brother, on whose whistling daily\ntoil solely hung the responsibilities of some other family, and left\nthe worse than useless old man standing, till the hideous rot of life\nshould make him easier to harvest.\n\nWhy tell the whole?  The blows of the basement hammer every day grew\nmore and more between; and each blow every day grew fainter than the\nlast; the wife sat frozen at the window, with tearless eyes,\nglitteringly gazing into the weeping faces of her children; the\nbellows fell; the forge choked up with cinders; the house was sold;\nthe mother dived down into the long church-yard grass; her children\ntwice followed her thither; and the houseless, familyless old man\nstaggered off a vagabond in crape; his every woe unreverenced; his\ngrey head a scorn to flaxen curls!\n\nDeath seems the only desirable sequel for a career like this; but\nDeath is only a launching into the region of the strange Untried; it\nis but the first salutation to the possibilities of the immense\nRemote, the Wild, the Watery, the Unshored; therefore, to the\ndeath-longing eyes of such men, who still have left in them some\ninterior compunctions against suicide, does the all-contributed and\nall-receptive ocean alluringly spread forth his whole plain of\nunimaginable, taking terrors, and wonderful, new-life adventures; and\nfrom the hearts of infinite Pacifics, the thousand mermaids sing to\nthem--\"Come hither, broken-hearted; here is another life without the\nguilt of intermediate death; here are wonders supernatural, without\ndying for them.  Come hither! bury thyself in a life which, to your\nnow equally abhorred and abhorring, landed world, is more oblivious\nthan death.  Come hither! put up THY gravestone, too, within the\nchurchyard, and come hither, till we marry thee!\"\n\nHearkening to these voices, East and West, by early sunrise, and by\nfall of eve, the blacksmith's soul responded, Aye, I come!  And so\nPerth went a-whaling.\n\n\n\nCHAPTER 113\n\nThe Forge.\n\n\nWith matted beard, and swathed in a bristling shark-skin apron, about\nmid-day, Perth was standing between his forge and anvil, the latter\nplaced upon an iron-wood log, with one hand holding a pike-head in\nthe coals, and with the other at his forge's lungs, when Captain Ahab\ncame along, carrying in his hand a small rusty-looking leathern bag.\nWhile yet a little distance from the forge, moody Ahab paused; till\nat last, Perth, withdrawing his iron from the fire, began hammering\nit upon the anvil--the red mass sending off the sparks in thick\nhovering flights, some of which flew close to Ahab.\n\n\"Are these thy Mother Carey's chickens, Perth? they are always flying\nin thy wake; birds of good omen, too, but not to all;--look here,\nthey burn; but thou--thou liv'st among them without a scorch.\"\n\n\"Because I am scorched all over, Captain Ahab,\" answered Perth,\nresting for a moment on his hammer; \"I am past scorching; not easily\ncan'st thou scorch a scar.\"\n\n\"Well, well; no more.  Thy shrunk voice sounds too calmly, sanely\nwoeful to me.  In no Paradise myself, I am impatient of all misery in\nothers that is not mad.  Thou should'st go mad, blacksmith; say, why\ndost thou not go mad?  How can'st thou endure without being mad?  Do\nthe heavens yet hate thee, that thou can'st not go mad?--What wert\nthou making there?\"\n\n\"Welding an old pike-head, sir; there were seams and dents in it.\"\n\n\"And can'st thou make it all smooth again, blacksmith, after such\nhard usage as it had?\"\n\n\"I think so, sir.\"\n\n\"And I suppose thou can'st smoothe almost any seams and dents; never\nmind how hard the metal, blacksmith?\"\n\n\"Aye, sir, I think I can; all seams and dents but one.\"\n\n\"Look ye here, then,\" cried Ahab, passionately advancing, and leaning\nwith both hands on Perth's shoulders; \"look ye here--HERE--can ye\nsmoothe out a seam like this, blacksmith,\" sweeping one hand across\nhis ribbed brow; \"if thou could'st, blacksmith, glad enough would I\nlay my head upon thy anvil, and feel thy heaviest hammer between my\neyes.  Answer!  Can'st thou smoothe this seam?\"\n\n\"Oh! that is the one, sir!  Said I not all seams and dents but one?\"\n\n\"Aye, blacksmith, it is the one; aye, man, it is unsmoothable; for\nthough thou only see'st it here in my flesh, it has worked down into\nthe bone of my skull--THAT is all wrinkles!  But, away with child's\nplay; no more gaffs and pikes to-day.  Look ye here!\" jingling the\nleathern bag, as if it were full of gold coins.  \"I, too, want a\nharpoon made; one that a thousand yoke of fiends could not part,\nPerth; something that will stick in a whale like his own fin-bone.\nThere's the stuff,\" flinging the pouch upon the anvil.  \"Look ye,\nblacksmith, these are the gathered nail-stubbs of the steel shoes of\nracing horses.\"\n\n\"Horse-shoe stubbs, sir?  Why, Captain Ahab, thou hast here, then,\nthe best and stubbornest stuff we blacksmiths ever work.\"\n\n\"I know it, old man; these stubbs will weld together like glue from\nthe melted bones of murderers.  Quick! forge me the harpoon.  And\nforge me first, twelve rods for its shank; then wind, and twist, and\nhammer these twelve together like the yarns and strands of a\ntow-line.  Quick!  I'll blow the fire.\"\n\nWhen at last the twelve rods were made, Ahab tried them, one by one,\nby spiralling them, with his own hand, round a long, heavy iron bolt.\n\"A flaw!\" rejecting the last one.  \"Work that over again, Perth.\"\n\nThis done, Perth was about to begin welding the twelve into one, when\nAhab stayed his hand, and said he would weld his own iron.  As, then,\nwith regular, gasping hems, he hammered on the anvil, Perth passing\nto him the glowing rods, one after the other, and the hard pressed\nforge shooting up its intense straight flame, the Parsee passed\nsilently, and bowing over his head towards the fire, seemed invoking\nsome curse or some blessing on the toil.  But, as Ahab looked up, he\nslid aside.\n\n\"What's that bunch of lucifers dodging about there for?\" muttered\nStubb, looking on from the forecastle.  \"That Parsee smells fire like\na fusee; and smells of it himself, like a hot musket's powder-pan.\"\n\nAt last the shank, in one complete rod, received its final heat; and\nas Perth, to temper it, plunged it all hissing into the cask of water\nnear by, the scalding steam shot up into Ahab's bent face.\n\n\"Would'st thou brand me, Perth?\" wincing for a moment with the pain;\n\"have I been but forging my own branding-iron, then?\"\n\n\"Pray God, not that; yet I fear something, Captain Ahab.  Is not this\nharpoon for the White Whale?\"\n\n\"For the white fiend!  But now for the barbs; thou must make them\nthyself, man.  Here are my razors--the best of steel; here, and make\nthe barbs sharp as the needle-sleet of the Icy Sea.\"\n\nFor a moment, the old blacksmith eyed the razors as though he would\nfain not use them.\n\n\"Take them, man, I have no need for them; for I now neither shave,\nsup, nor pray till--but here--to work!\"\n\nFashioned at last into an arrowy shape, and welded by Perth to the\nshank, the steel soon pointed the end of the iron; and as the\nblacksmith was about giving the barbs their final heat, prior to\ntempering them, he cried to Ahab to place the water-cask near.\n\n\"No, no--no water for that; I want it of the true death-temper.\nAhoy, there!  Tashtego, Queequeg, Daggoo!  What say ye, pagans!  Will\nye give me as much blood as will cover this barb?\" holding it high\nup.  A cluster of dark nods replied, Yes.  Three punctures were made\nin the heathen flesh, and the White Whale's barbs were then tempered.\n\n\"Ego non baptizo te in nomine patris, sed in nomine diaboli!\"\ndeliriously howled Ahab, as the malignant iron scorchingly devoured\nthe baptismal blood.\n\nNow, mustering the spare poles from below, and selecting one of\nhickory, with the bark still investing it, Ahab fitted the end to the\nsocket of the iron.  A coil of new tow-line was then unwound, and\nsome fathoms of it taken to the windlass, and stretched to a great\ntension.  Pressing his foot upon it, till the rope hummed like a\nharp-string, then eagerly bending over it, and seeing no strandings,\nAhab exclaimed, \"Good! and now for the seizings.\"\n\nAt one extremity the rope was unstranded, and the separate spread\nyarns were all braided and woven round the socket of the harpoon; the\npole was then driven hard up into the socket; from the lower end the\nrope was traced half-way along the pole's length, and firmly secured\nso, with intertwistings of twine.  This done, pole, iron, and\nrope--like the Three Fates--remained inseparable, and Ahab moodily\nstalked away with the weapon; the sound of his ivory leg, and the\nsound of the hickory pole, both hollowly ringing along every plank.\nBut ere he entered his cabin, light, unnatural, half-bantering, yet\nmost piteous sound was heard.  Oh, Pip! thy wretched laugh, thy\nidle but unresting eye; all thy strange mummeries not unmeaningly\nblended with the black tragedy of the melancholy ship, and mocked it!\n\n\n\nCHAPTER 114\n\nThe Gilder.\n\n\nPenetrating further and further into the heart of the Japanese\ncruising ground, the Pequod was soon all astir in the fishery.\nOften, in mild, pleasant weather, for twelve, fifteen, eighteen, and\ntwenty hours on the stretch, they were engaged in the boats, steadily\npulling, or sailing, or paddling after the whales, or for an\ninterlude of sixty or seventy minutes calmly awaiting their uprising;\nthough with but small success for their pains.\n\nAt such times, under an abated sun; afloat all day upon smooth, slow\nheaving swells; seated in his boat, light as a birch canoe; and so\nsociably mixing with the soft waves themselves, that like\nhearth-stone cats they purr against the gunwale; these are the times\nof dreamy quietude, when beholding the tranquil beauty and brilliancy\nof the ocean's skin, one forgets the tiger heart that pants beneath\nit; and would not willingly remember, that this velvet paw but\nconceals a remorseless fang.\n\nThese are the times, when in his whale-boat the rover softly feels a\ncertain filial, confident, land-like feeling towards the sea; that he\nregards it as so much flowery earth; and the distant ship revealing\nonly the tops of her masts, seems struggling forward, not through\nhigh rolling waves, but through the tall grass of a rolling prairie:\nas when the western emigrants' horses only show their erected ears,\nwhile their hidden bodies widely wade through the amazing verdure.\n\nThe long-drawn virgin vales; the mild blue hill-sides; as over these\nthere steals the hush, the hum; you almost swear that play-wearied\nchildren lie sleeping in these solitudes, in some glad May-time, when\nthe flowers of the woods are plucked.  And all this mixes with your\nmost mystic mood; so that fact and fancy, half-way meeting,\ninterpenetrate, and form one seamless whole.\n\nNor did such soothing scenes, however temporary, fail of at least as\ntemporary an effect on Ahab.  But if these secret golden keys did\nseem to open in him his own secret golden treasuries, yet did his\nbreath upon them prove but tarnishing.\n\nOh, grassy glades! oh, ever vernal endless landscapes in the soul; in\nye,--though long parched by the dead drought of the earthy\nlife,--in ye, men yet may roll, like young horses in new morning\nclover; and for some few fleeting moments, feel the cool dew of the\nlife immortal on them.  Would to God these blessed calms would last.\nBut the mingled, mingling threads of life are woven by warp and woof:\ncalms crossed by storms, a storm for every calm.  There is no steady\nunretracing progress in this life; we do not advance through fixed\ngradations, and at the last one pause:--through infancy's unconscious\nspell, boyhood's thoughtless faith, adolescence' doubt (the common\ndoom), then scepticism, then disbelief, resting at last in manhood's\npondering repose of If.  But once gone through, we trace the round\nagain; and are infants, boys, and men, and Ifs eternally.  Where lies\nthe final harbor, whence we unmoor no more?  In what rapt ether sails\nthe world, of which the weariest will never weary?  Where is the\nfoundling's father hidden?  Our souls are like those orphans whose\nunwedded mothers die in bearing them: the secret of our paternity\nlies in their grave, and we must there to learn it.\n\nAnd that same day, too, gazing far down from his boat's side into\nthat same golden sea, Starbuck lowly murmured:--\n\n\"Loveliness unfathomable, as ever lover saw in his young bride's\neye!--Tell me not of thy teeth-tiered sharks, and thy kidnapping\ncannibal ways.  Let faith oust fact; let fancy oust memory; I look\ndeep down and do believe.\"\n\nAnd Stubb, fish-like, with sparkling scales, leaped up in that same\ngolden light:--\n\n\"I am Stubb, and Stubb has his history; but here Stubb takes oaths\nthat he has always been jolly!\"\n\n\n\nCHAPTER 115\n\nThe Pequod Meets The Bachelor.\n\n\nAnd jolly enough were the sights and the sounds that came bearing\ndown before the wind, some few weeks after Ahab's harpoon had been\nwelded.\n\nIt was a Nantucket ship, the Bachelor, which had just wedged in her\nlast cask of oil, and bolted down her bursting hatches; and now, in\nglad holiday apparel, was joyously, though somewhat vain-gloriously,\nsailing round among the widely-separated ships on the ground,\nprevious to pointing her prow for home.\n\nThe three men at her mast-head wore long streamers of narrow red\nbunting at their hats; from the stern, a whale-boat was suspended,\nbottom down; and hanging captive from the bowsprit was seen the long\nlower jaw of the last whale they had slain.  Signals, ensigns, and\njacks of all colours were flying from her rigging, on every side.\nSideways lashed in each of her three basketed tops were two barrels\nof sperm; above which, in her top-mast cross-trees, you saw slender\nbreakers of the same precious fluid; and nailed to her main truck was\na brazen lamp.\n\nAs was afterwards learned, the Bachelor had met with the most\nsurprising success; all the more wonderful, for that while cruising\nin the same seas numerous other vessels had gone entire months\nwithout securing a single fish.  Not only had barrels of beef and\nbread been given away to make room for the far more valuable sperm,\nbut additional supplemental casks had been bartered for, from the\nships she had met; and these were stowed along the deck, and in the\ncaptain's and officers' state-rooms.  Even the cabin table itself\nhad been knocked into kindling-wood; and the cabin mess dined off the\nbroad head of an oil-butt, lashed down to the floor for a\ncentrepiece.  In the forecastle, the sailors had actually caulked\nand pitched their chests, and filled them; it was humorously added,\nthat the cook had clapped a head on his largest boiler, and filled\nit; that the steward had plugged his spare coffee-pot and filled it;\nthat the harpooneers had headed the sockets of their irons and filled\nthem; that indeed everything was filled with sperm, except the\ncaptain's pantaloons pockets, and those he reserved to thrust his\nhands into, in self-complacent testimony of his entire satisfaction.\n\nAs this glad ship of good luck bore down upon the moody Pequod, the\nbarbarian sound of enormous drums came from her forecastle; and\ndrawing still nearer, a crowd of her men were seen standing round her\nhuge try-pots, which, covered with the parchment-like POKE or stomach\nskin of the black fish, gave forth a loud roar to every stroke of the\nclenched hands of the crew.  On the quarter-deck, the mates and\nharpooneers were dancing with the olive-hued girls who had eloped\nwith them from the Polynesian Isles; while suspended in an\nornamented boat, firmly secured aloft between the foremast and\nmainmast, three Long Island negroes, with glittering fiddle-bows of\nwhale ivory, were presiding over the hilarious jig.  Meanwhile,\nothers of the ship's company were tumultuously busy at the masonry of\nthe try-works, from which the huge pots had been removed.  You would\nhave almost thought they were pulling down the cursed Bastille, such\nwild cries they raised, as the now useless brick and mortar were\nbeing hurled into the sea.\n\nLord and master over all this scene, the captain stood erect on the\nship's elevated quarter-deck, so that the whole rejoicing drama was\nfull before him, and seemed merely contrived for his own individual\ndiversion.\n\nAnd Ahab, he too was standing on his quarter-deck, shaggy and black,\nwith a stubborn gloom; and as the two ships crossed each other's\nwakes--one all jubilations for things passed, the other all\nforebodings as to things to come--their two captains in themselves\nimpersonated the whole striking contrast of the scene.\n\n\"Come aboard, come aboard!\" cried the gay Bachelor's commander,\nlifting a glass and a bottle in the air.\n\n\"Hast seen the White Whale?\" gritted Ahab in reply.\n\n\"No; only heard of him; but don't believe in him at all,\" said the\nother good-humoredly.  \"Come aboard!\"\n\n\"Thou art too damned jolly.  Sail on.  Hast lost any men?\"\n\n\"Not enough to speak of--two islanders, that's all;--but come aboard,\nold hearty, come along.  I'll soon take that black from your brow.\nCome along, will ye (merry's the play); a full ship and\nhomeward-bound.\"\n\n\"How wondrous familiar is a fool!\" muttered Ahab; then aloud, \"Thou\nart a full ship and homeward bound, thou sayst; well, then, call me\nan empty ship, and outward-bound.  So go thy ways, and I will mine.\nForward there!  Set all sail, and keep her to the wind!\"\n\nAnd thus, while the one ship went cheerily before the breeze, the\nother stubbornly fought against it; and so the two vessels parted;\nthe crew of the Pequod looking with grave, lingering glances towards\nthe receding Bachelor; but the Bachelor's men never heeding their\ngaze for the lively revelry they were in.  And as Ahab, leaning over\nthe taffrail, eyed the homewardbound craft, he took from his pocket a\nsmall vial of sand, and then looking from the ship to the vial,\nseemed thereby bringing two remote associations together, for that\nvial was filled with Nantucket soundings.\n\n\n\nCHAPTER 116\n\nThe Dying Whale.\n\n\nNot seldom in this life, when, on the right side, fortune's favourites\nsail close by us, we, though all adroop before, catch somewhat of the\nrushing breeze, and joyfully feel our bagging sails fill out.  So\nseemed it with the Pequod.  For next day after encountering the gay\nBachelor, whales were seen and four were slain; and one of them by\nAhab.\n\nIt was far down the afternoon; and when all the spearings of the\ncrimson fight were done: and floating in the lovely sunset sea and\nsky, sun and whale both stilly died together; then, such a sweetness\nand such plaintiveness, such inwreathing orisons curled up in that\nrosy air, that it almost seemed as if far over from the deep green\nconvent valleys of the Manilla isles, the Spanish land-breeze,\nwantonly turned sailor, had gone to sea, freighted with these vesper\nhymns.\n\nSoothed again, but only soothed to deeper gloom, Ahab, who had\nsterned off from the whale, sat intently watching his final wanings\nfrom the now tranquil boat.  For that strange spectacle observable in\nall sperm whales dying--the turning sunwards of the head, and so\nexpiring--that strange spectacle, beheld of such a placid evening,\nsomehow to Ahab conveyed a wondrousness unknown before.\n\n\"He turns and turns him to it,--how slowly, but how steadfastly, his\nhomage-rendering and invoking brow, with his last dying motions.  He\ntoo worships fire; most faithful, broad, baronial vassal of the\nsun!--Oh that these too-favouring eyes should see these too-favouring\nsights.  Look! here, far water-locked; beyond all hum of human weal\nor woe; in these most candid and impartial seas; where to traditions\nno rocks furnish tablets; where for long Chinese ages, the billows\nhave still rolled on speechless and unspoken to, as stars that shine\nupon the Niger's unknown source; here, too, life dies sunwards full\nof faith; but see! no sooner dead, than death whirls round the\ncorpse, and it heads some other way.\n\n\"Oh, thou dark Hindoo half of nature, who of drowned bones hast\nbuilded thy separate throne somewhere in the heart of these\nunverdured seas; thou art an infidel, thou queen, and too truly\nspeakest to me in the wide-slaughtering Typhoon, and the hushed\nburial of its after calm.  Nor has this thy whale sunwards turned his\ndying head, and then gone round again, without a lesson to me.\n\n\"Oh, trebly hooped and welded hip of power!  Oh, high aspiring,\nrainbowed jet!--that one strivest, this one jettest all in vain!  In\nvain, oh whale, dost thou seek intercedings with yon all-quickening\nsun, that only calls forth life, but gives it not again.  Yet dost\nthou, darker half, rock me with a prouder, if a darker faith.  All\nthy unnamable imminglings float beneath me here; I am buoyed by\nbreaths of once living things, exhaled as air, but water now.\n\n\"Then hail, for ever hail, O sea, in whose eternal tossings the wild\nfowl finds his only rest.  Born of earth, yet suckled by the sea;\nthough hill and valley mothered me, ye billows are my\nfoster-brothers!\"\n\n\n\nCHAPTER 117\n\nThe Whale Watch.\n\n\nThe four whales slain that evening had died wide apart; one, far to\nwindward; one, less distant, to leeward; one ahead; one astern.\nThese last three were brought alongside ere nightfall; but the\nwindward one could not be reached till morning; and the boat that had\nkilled it lay by its side all night; and that boat was Ahab's.\n\nThe waif-pole was thrust upright into the dead whale's spout-hole;\nand the lantern hanging from its top, cast a troubled flickering\nglare upon the black, glossy back, and far out upon the midnight\nwaves, which gently chafed the whale's broad flank, like soft surf\nupon a beach.\n\nAhab and all his boat's crew seemed asleep but the Parsee; who\ncrouching in the bow, sat watching the sharks, that spectrally played\nround the whale, and tapped the light cedar planks with their tails.\nA sound like the moaning in squadrons over Asphaltites of unforgiven\nghosts of Gomorrah, ran shuddering through the air.\n\nStarted from his slumbers, Ahab, face to face, saw the Parsee; and\nhooped round by the gloom of the night they seemed the last men in a\nflooded world.  \"I have dreamed it again,\" said he.\n\n\"Of the hearses?  Have I not said, old man, that neither hearse nor\ncoffin can be thine?\"\n\n\"And who are hearsed that die on the sea?\"\n\n\"But I said, old man, that ere thou couldst die on this voyage, two\nhearses must verily be seen by thee on the sea; the first not made by\nmortal hands; and the visible wood of the last one must be grown in\nAmerica.\"\n\n\"Aye, aye! a strange sight that, Parsee:--a hearse and its plumes\nfloating over the ocean with the waves for the pall-bearers.  Ha!\nSuch a sight we shall not soon see.\"\n\n\"Believe it or not, thou canst not die till it be seen, old man.\"\n\n\"And what was that saying about thyself?\"\n\n\"Though it come to the last, I shall still go before thee thy pilot.\"\n\n\"And when thou art so gone before--if that ever befall--then ere I\ncan follow, thou must still appear to me, to pilot me still?--Was it\nnot so?  Well, then, did I believe all ye say, oh my pilot!  I have\nhere two pledges that I shall yet slay Moby Dick and survive it.\"\n\n\"Take another pledge, old man,\" said the Parsee, as his eyes lighted\nup like fire-flies in the gloom--\"Hemp only can kill thee.\"\n\n\"The gallows, ye mean.--I am immortal then, on land and on sea,\"\ncried Ahab, with a laugh of derision;--\"Immortal on land and on sea!\"\n\nBoth were silent again, as one man.  The grey dawn came on, and the\nslumbering crew arose from the boat's bottom, and ere noon the dead\nwhale was brought to the ship.\n\n\n\nCHAPTER 118\n\nThe Quadrant.\n\n\nThe season for the Line at length drew near; and every day when Ahab,\ncoming from his cabin, cast his eyes aloft, the vigilant helmsman\nwould ostentatiously handle his spokes, and the eager mariners\nquickly run to the braces, and would stand there with all their eyes\ncentrally fixed on the nailed doubloon; impatient for the order to\npoint the ship's prow for the equator.  In good time the order came.\nIt was hard upon high noon; and Ahab, seated in the bows of his\nhigh-hoisted boat, was about taking his wonted daily observation of\nthe sun to determine his latitude.\n\nNow, in that Japanese sea, the days in summer are as freshets of\neffulgences.  That unblinkingly vivid Japanese sun seems the blazing\nfocus of the glassy ocean's immeasurable burning-glass.  The sky\nlooks lacquered; clouds there are none; the horizon floats; and this\nnakedness of unrelieved radiance is as the insufferable splendors of\nGod's throne.  Well that Ahab's quadrant was furnished with coloured\nglasses, through which to take sight of that solar fire.  So,\nswinging his seated form to the roll of the ship, and with his\nastrological-looking instrument placed to his eye, he remained in\nthat posture for some moments to catch the precise instant when the\nsun should gain its precise meridian.  Meantime while his whole\nattention was absorbed, the Parsee was kneeling beneath him on the\nship's deck, and with face thrown up like Ahab's, was eyeing the same\nsun with him; only the lids of his eyes half hooded their orbs, and\nhis wild face was subdued to an earthly passionlessness.  At length\nthe desired observation was taken; and with his pencil upon his ivory\nleg, Ahab soon calculated what his latitude must be at that precise\ninstant.  Then falling into a moment's revery, he again looked up\ntowards the sun and murmured to himself: \"Thou sea-mark! thou high\nand mighty Pilot! thou tellest me truly where I AM--but canst thou\ncast the least hint where I SHALL be?  Or canst thou tell where some\nother thing besides me is this moment living?  Where is Moby Dick?\nThis instant thou must be eyeing him.  These eyes of mine look into\nthe very eye that is even now beholding him; aye, and into the eye\nthat is even now equally beholding the objects on the unknown,\nthither side of thee, thou sun!\"\n\nThen gazing at his quadrant, and handling, one after the other, its\nnumerous cabalistical contrivances, he pondered again, and muttered:\n\"Foolish toy! babies' plaything of haughty Admirals, and Commodores,\nand Captains; the world brags of thee, of thy cunning and might; but\nwhat after all canst thou do, but tell the poor, pitiful point, where\nthou thyself happenest to be on this wide planet, and the hand that\nholds thee: no! not one jot more!  Thou canst not tell where one drop\nof water or one grain of sand will be to-morrow noon; and yet with\nthy impotence thou insultest the sun!  Science!  Curse thee, thou\nvain toy; and cursed be all the things that cast man's eyes aloft to\nthat heaven, whose live vividness but scorches him, as these old eyes\nare even now scorched with thy light, O sun!  Level by nature to this\nearth's horizon are the glances of man's eyes; not shot from the\ncrown of his head, as if God had meant him to gaze on his firmament.\nCurse thee, thou quadrant!\" dashing it to the deck, \"no longer will I\nguide my earthly way by thee; the level ship's compass, and the level\ndeadreckoning, by log and by line; THESE shall conduct me, and show\nme my place on the sea.  Aye,\" lighting from the boat to the deck,\n\"thus I trample on thee, thou paltry thing that feebly pointest on\nhigh; thus I split and destroy thee!\"\n\nAs the frantic old man thus spoke and thus trampled with his live and\ndead feet, a sneering triumph that seemed meant for Ahab, and a\nfatalistic despair that seemed meant for himself--these passed over\nthe mute, motionless Parsee's face.  Unobserved he rose and glided\naway; while, awestruck by the aspect of their commander, the seamen\nclustered together on the forecastle, till Ahab, troubledly pacing\nthe deck, shouted out--\"To the braces!  Up helm!--square in!\"\n\nIn an instant the yards swung round; and as the ship half-wheeled\nupon her heel, her three firm-seated graceful masts erectly poised\nupon her long, ribbed hull, seemed as the three Horatii pirouetting\non one sufficient steed.\n\nStanding between the knight-heads, Starbuck watched the Pequod's\ntumultuous way, and Ahab's also, as he went lurching along the deck.\n\n\"I have sat before the dense coal fire and watched it all aglow, full\nof its tormented flaming life; and I have seen it wane at last, down,\ndown, to dumbest dust.  Old man of oceans! of all this fiery life of\nthine, what will at length remain but one little heap of ashes!\"\n\n\"Aye,\" cried Stubb, \"but sea-coal ashes--mind ye that, Mr.\nStarbuck--sea-coal, not your common charcoal.  Well, well; I heard\nAhab mutter, 'Here some one thrusts these cards into these old hands\nof mine; swears that I must play them, and no others.'  And damn me,\nAhab, but thou actest right; live in the game, and die in it!\"\n\n\n\nCHAPTER 119\n\nThe Candles.\n\n\nWarmest climes but nurse the cruellest fangs: the tiger of Bengal\ncrouches in spiced groves of ceaseless verdure.  Skies the most\neffulgent but basket the deadliest thunders: gorgeous Cuba knows\ntornadoes that never swept tame northern lands.  So, too, it is, that\nin these resplendent Japanese seas the mariner encounters the direst\nof all storms, the Typhoon.  It will sometimes burst from out that\ncloudless sky, like an exploding bomb upon a dazed and sleepy town.\n\nTowards evening of that day, the Pequod was torn of her canvas, and\nbare-poled was left to fight a Typhoon which had struck her directly\nahead.  When darkness came on, sky and sea roared and split with the\nthunder, and blazed with the lightning, that showed the disabled\nmasts fluttering here and there with the rags which the first fury of\nthe tempest had left for its after sport.\n\nHolding by a shroud, Starbuck was standing on the quarter-deck; at\nevery flash of the lightning glancing aloft, to see what additional\ndisaster might have befallen the intricate hamper there; while Stubb\nand Flask were directing the men in the higher hoisting and firmer\nlashing of the boats.  But all their pains seemed naught.  Though\nlifted to the very top of the cranes, the windward quarter boat\n(Ahab's) did not escape.  A great rolling sea, dashing high up\nagainst the reeling ship's high teetering side, stove in the boat's\nbottom at the stern, and left it again, all dripping through like a\nsieve.\n\n\"Bad work, bad work!  Mr. Starbuck,\" said Stubb, regarding the wreck,\n\"but the sea will have its way.  Stubb, for one, can't fight it.  You\nsee, Mr. Starbuck, a wave has such a great long start before it\nleaps, all round the world it runs, and then comes the spring!  But\nas for me, all the start I have to meet it, is just across the deck\nhere.  But never mind; it's all in fun: so the old song\nsays;\"--(SINGS.)\n\nOh! jolly is the gale,\nAnd a joker is the whale,\nA' flourishin' his tail,--\nSuch a funny, sporty, gamy, jesty, joky, hoky-poky lad, is the Ocean, oh!\n\nThe scud all a flyin',\nThat's his flip only foamin';\nWhen he stirs in the spicin',--\nSuch a funny, sporty, gamy, jesty, joky, hoky-poky lad, is the Ocean, oh!\n\nThunder splits the ships,\nBut he only smacks his lips,\nA tastin' of this flip,--\nSuch a funny, sporty, gamy, jesty, joky, hoky-poky lad, is the Ocean, oh!\n\n\n\"Avast Stubb,\" cried Starbuck, \"let the Typhoon sing, and strike his\nharp here in our rigging; but if thou art a brave man thou wilt hold\nthy peace.\"\n\n\"But I am not a brave man; never said I was a brave man; I am a\ncoward; and I sing to keep up my spirits.  And I tell you what it is,\nMr. Starbuck, there's no way to stop my singing in this world but to\ncut my throat.  And when that's done, ten to one I sing ye the\ndoxology for a wind-up.\"\n\n\"Madman! look through my eyes if thou hast none of thine own.\"\n\n\"What! how can you see better of a dark night than anybody else,\nnever mind how foolish?\"\n\n\"Here!\" cried Starbuck, seizing Stubb by the shoulder, and pointing\nhis hand towards the weather bow, \"markest thou not that the gale\ncomes from the eastward, the very course Ahab is to run for Moby\nDick? the very course he swung to this day noon? now mark his boat\nthere; where is that stove?  In the stern-sheets, man; where he is\nwont to stand--his stand-point is stove, man!  Now jump overboard,\nand sing away, if thou must!\n\n\"I don't half understand ye: what's in the wind?\"\n\n\"Yes, yes, round the Cape of Good Hope is the shortest way to\nNantucket,\" soliloquized Starbuck suddenly, heedless of Stubb's\nquestion.  \"The gale that now hammers at us to stave us, we can turn\nit into a fair wind that will drive us towards home.  Yonder, to\nwindward, all is blackness of doom; but to leeward, homeward--I see\nit lightens up there; but not with the lightning.\"\n\nAt that moment in one of the intervals of profound darkness,\nfollowing the flashes, a voice was heard at his side; and almost at\nthe same instant a volley of thunder peals rolled overhead.\n\n\"Who's there?\"\n\n\"Old Thunder!\" said Ahab, groping his way along the bulwarks to his\npivot-hole; but suddenly finding his path made plain to him by\nelbowed lances of fire.\n\nNow, as the lightning rod to a spire on shore is intended to carry\noff the perilous fluid into the soil; so the kindred rod which at sea\nsome ships carry to each mast, is intended to conduct it into the\nwater.  But as this conductor must descend to considerable depth,\nthat its end may avoid all contact with the hull; and as moreover, if\nkept constantly towing there, it would be liable to many mishaps,\nbesides interfering not a little with some of the rigging, and more\nor less impeding the vessel's way in the water; because of all this,\nthe lower parts of a ship's lightning-rods are not always overboard;\nbut are generally made in long slender links, so as to be the more\nreadily hauled up into the chains outside, or thrown down into the\nsea, as occasion may require.\n\n\"The rods! the rods!\" cried Starbuck to the crew, suddenly admonished\nto vigilance by the vivid lightning that had just been darting\nflambeaux, to light Ahab to his post.  \"Are they overboard? drop them\nover, fore and aft.  Quick!\"\n\n\"Avast!\" cried Ahab; \"let's have fair play here, though we be the\nweaker side.  Yet I'll contribute to raise rods on the Himmalehs and\nAndes, that all the world may be secured; but out on privileges!  Let\nthem be, sir.\"\n\n\"Look aloft!\" cried Starbuck.  \"The corpusants! the corpusants!\n\nAll the yard-arms were tipped with a pallid fire; and touched at each\ntri-pointed lightning-rod-end with three tapering white flames, each\nof the three tall masts was silently burning in that sulphurous air,\nlike three gigantic wax tapers before an altar.\n\n\"Blast the boat! let it go!\" cried Stubb at this instant, as a\nswashing sea heaved up under his own little craft, so that its\ngunwale violently jammed his hand, as he was passing a lashing.\n\"Blast it!\"--but slipping backward on the deck, his uplifted eyes\ncaught the flames; and immediately shifting his tone he cried--\"The\ncorpusants have mercy on us all!\"\n\nTo sailors, oaths are household words; they will swear in the trance\nof the calm, and in the teeth of the tempest; they will imprecate\ncurses from the topsail-yard-arms, when most they teeter over to a\nseething sea; but in all my voyagings, seldom have I heard a common\noath when God's burning finger has been laid on the ship; when His\n\"Mene, Mene, Tekel Upharsin\" has been woven into the shrouds and the\ncordage.\n\nWhile this pallidness was burning aloft, few words were heard from\nthe enchanted crew; who in one thick cluster stood on the forecastle,\nall their eyes gleaming in that pale phosphorescence, like a far away\nconstellation of stars.  Relieved against the ghostly light, the\ngigantic jet negro, Daggoo, loomed up to thrice his real stature, and\nseemed the black cloud from which the thunder had come.  The parted\nmouth of Tashtego revealed his shark-white teeth, which strangely\ngleamed as if they too had been tipped by corpusants; while lit up by\nthe preternatural light, Queequeg's tattooing burned like Satanic\nblue flames on his body.\n\nThe tableau all waned at last with the pallidness aloft; and once\nmore the Pequod and every soul on her decks were wrapped in a pall.\nA moment or two passed, when Starbuck, going forward, pushed against\nsome one.  It was Stubb.  \"What thinkest thou now, man; I heard thy\ncry; it was not the same in the song.\"\n\n\"No, no, it wasn't; I said the corpusants have mercy on us all; and I\nhope they will, still.  But do they only have mercy on long\nfaces?--have they no bowels for a laugh?  And look ye, Mr.\nStarbuck--but it's too dark to look.  Hear me, then: I take that\nmast-head flame we saw for a sign of good luck; for those masts are\nrooted in a hold that is going to be chock a' block with sperm-oil,\nd'ye see; and so, all that sperm will work up into the masts, like\nsap in a tree.  Yes, our three masts will yet be as three spermaceti\ncandles--that's the good promise we saw.\"\n\nAt that moment Starbuck caught sight of Stubb's face slowly beginning\nto glimmer into sight.  Glancing upwards, he cried: \"See! see!\" and\nonce more the high tapering flames were beheld with what seemed\nredoubled supernaturalness in their pallor.\n\n\"The corpusants have mercy on us all,\" cried Stubb, again.\n\nAt the base of the mainmast, full beneath the doubloon and the\nflame, the Parsee was kneeling in Ahab's front, but with his head\nbowed away from him; while near by, from the arched and overhanging\nrigging, where they had just been engaged securing a spar, a number\nof the seamen, arrested by the glare, now cohered together, and hung\npendulous, like a knot of numbed wasps from a drooping, orchard twig.\nIn various enchanted attitudes, like the standing, or stepping, or\nrunning skeletons in Herculaneum, others remained rooted to the deck;\nbut all their eyes upcast.\n\n\"Aye, aye, men!\" cried Ahab.  \"Look up at it; mark it well; the white\nflame but lights the way to the White Whale!  Hand me those mainmast\nlinks there; I would fain feel this pulse, and let mine beat against\nit; blood against fire!  So.\"\n\nThen turning--the last link held fast in his left hand, he put his\nfoot upon the Parsee; and with fixed upward eye, and high-flung right\narm, he stood erect before the lofty tri-pointed trinity of flames.\n\n\"Oh! thou clear spirit of clear fire, whom on these seas I as Persian\nonce did worship, till in the sacramental act so burned by thee, that\nto this hour I bear the scar; I now know thee, thou clear spirit, and\nI now know that thy right worship is defiance.  To neither love nor\nreverence wilt thou be kind; and e'en for hate thou canst but kill;\nand all are killed.  No fearless fool now fronts thee.  I own thy\nspeechless, placeless power; but to the last gasp of my earthquake\nlife will dispute its unconditional, unintegral mastery in me.  In the\nmidst of the personified impersonal, a personality stands here.\nThough but a point at best; whencesoe'er I came; wheresoe'er I go;\nyet while I earthly live, the queenly personality lives in me, and\nfeels her royal rights.  But war is pain, and hate is woe.  Come in\nthy lowest form of love, and I will kneel and kiss thee; but at thy\nhighest, come as mere supernal power; and though thou launchest\nnavies of full-freighted worlds, there's that in here that still\nremains indifferent.  Oh, thou clear spirit, of thy fire thou madest\nme, and like a true child of fire, I breathe it back to thee.\"\n\n[SUDDEN, REPEATED FLASHES OF LIGHTNING; THE NINE FLAMES LEAP\nLENGTHWISE TO THRICE THEIR PREVIOUS HEIGHT; AHAB, WITH THE REST,\nCLOSES HIS EYES, HIS RIGHT HAND PRESSED HARD UPON THEM.]\n\n\"I own thy speechless, placeless power; said I not so?  Nor was it\nwrung from me; nor do I now drop these links.  Thou canst blind; but\nI can then grope.  Thou canst consume; but I can then be ashes.  Take\nthe homage of these poor eyes, and shutter-hands.  I would not take\nit.  The lightning flashes through my skull; mine eye-balls ache and\nache; my whole beaten brain seems as beheaded, and rolling on some\nstunning ground.  Oh, oh!  Yet blindfold, yet will I talk to thee.\nLight though thou be, thou leapest out of darkness; but I am darkness\nleaping out of light, leaping out of thee!  The javelins cease; open\neyes; see, or not?  There burn the flames!  Oh, thou magnanimous! now\nI do glory in my genealogy.  But thou art but my fiery father; my\nsweet mother, I know not.  Oh, cruel! what hast thou done with her?\nThere lies my puzzle; but thine is greater.  Thou knowest not how\ncame ye, hence callest thyself unbegotten; certainly knowest not thy\nbeginning, hence callest thyself unbegun.  I know that of me, which\nthou knowest not of thyself, oh, thou omnipotent.  There is some\nunsuffusing thing beyond thee, thou clear spirit, to whom all thy\neternity is but time, all thy creativeness mechanical.  Through thee,\nthy flaming self, my scorched eyes do dimly see it.  Oh, thou\nfoundling fire, thou hermit immemorial, thou too hast thy\nincommunicable riddle, thy unparticipated grief.  Here again with\nhaughty agony, I read my sire.  Leap! leap up, and lick the sky!  I\nleap with thee; I burn with thee; would fain be welded with thee;\ndefyingly I worship thee!\"\n\n\"The boat! the boat!\" cried Starbuck, \"look at thy boat, old man!\"\n\nAhab's harpoon, the one forged at Perth's fire, remained firmly\nlashed in its conspicuous crotch, so that it projected beyond his\nwhale-boat's bow; but the sea that had stove its bottom had caused\nthe loose leather sheath to drop off; and from the keen steel barb\nthere now came a levelled flame of pale, forked fire.  As the silent\nharpoon burned there like a serpent's tongue, Starbuck grasped Ahab\nby the arm--\"God, God is against thee, old man; forbear! 'tis an\nill voyage! ill begun, ill continued; let me square the yards, while\nwe may, old man, and make a fair wind of it homewards, to go on a\nbetter voyage than this.\"\n\nOverhearing Starbuck, the panic-stricken crew instantly ran to the\nbraces--though not a sail was left aloft.  For the moment all the\naghast mate's thoughts seemed theirs; they raised a half mutinous\ncry.  But dashing the rattling lightning links to the deck, and\nsnatching the burning harpoon, Ahab waved it like a torch among them;\nswearing to transfix with it the first sailor that but cast loose a\nrope's end.  Petrified by his aspect, and still more shrinking from\nthe fiery dart that he held, the men fell back in dismay, and Ahab\nagain spoke:--\n\n\"All your oaths to hunt the White Whale are as binding as mine; and\nheart, soul, and body, lungs and life, old Ahab is bound.  And that\nye may know to what tune this heart beats; look ye here; thus I blow\nout the last fear!\"  And with one blast of his breath he extinguished\nthe flame.\n\nAs in the hurricane that sweeps the plain, men fly the neighborhood\nof some lone, gigantic elm, whose very height and strength but render\nit so much the more unsafe, because so much the more a mark for\nthunderbolts; so at those last words of Ahab's many of the mariners\ndid run from him in a terror of dismay.\n\n\n\nCHAPTER 120\n\nThe Deck Towards the End of the First Night Watch.\n\nAHAB STANDING BY THE HELM.  STARBUCK APPROACHING HIM.\n\n\nWe must send down the main-top-sail yard, sir.  The band is working\nloose and the lee lift is half-stranded.  Shall I strike it, sir?\"\n\n\"Strike nothing; lash it.  If I had sky-sail poles, I'd sway them up\nnow.\"\n\n\"Sir!--in God's name!--sir?\"\n\n\"Well.\"\n\n\"The anchors are working, sir.  Shall I get them inboard?\"\n\n\"Strike nothing, and stir nothing, but lash everything.  The wind\nrises, but it has not got up to my table-lands yet.  Quick, and see\nto it.--By masts and keels! he takes me for the hunch-backed skipper\nof some coasting smack.  Send down my main-top-sail yard!  Ho,\ngluepots!  Loftiest trucks were made for wildest winds, and this\nbrain-truck of mine now sails amid the cloud-scud.  Shall I strike\nthat?  Oh, none but cowards send down their brain-trucks in tempest\ntime.  What a hooroosh aloft there!  I would e'en take it for\nsublime, did I not know that the colic is a noisy malady.  Oh, take\nmedicine, take medicine!\"\n\n\n\nCHAPTER 121\n\nMidnight.--The Forecastle Bulwarks.\n\n\nSTUBB AND FLASK MOUNTED ON THEM, AND PASSING ADDITIONAL LASHINGS OVER\nTHE ANCHORS THERE HANGING.\n\n\nNo, Stubb; you may pound that knot there as much as you please, but\nyou will never pound into me what you were just now saying.  And how\nlong ago is it since you said the very contrary?  Didn't you once say\nthat whatever ship Ahab sails in, that ship should pay something\nextra on its insurance policy, just as though it were loaded with\npowder barrels aft and boxes of lucifers forward?  Stop, now; didn't\nyou say so?\"\n\n\"Well, suppose I did?  What then?  I've part changed my flesh since\nthat time, why not my mind?  Besides, supposing we ARE loaded with\npowder barrels aft and lucifers forward; how the devil could the\nlucifers get afire in this drenching spray here?  Why, my little man,\nyou have pretty red hair, but you couldn't get afire now.  Shake\nyourself; you're Aquarius, or the water-bearer, Flask; might fill\npitchers at your coat collar.  Don't you see, then, that for these\nextra risks the Marine Insurance companies have extra guarantees?\nHere are hydrants, Flask.  But hark, again, and I'll answer ye the\nother thing.  First take your leg off from the crown of the anchor\nhere, though, so I can pass the rope; now listen.  What's the mighty\ndifference between holding a mast's lightning-rod in the storm, and\nstanding close by a mast that hasn't got any lightning-rod at all in\na storm?  Don't you see, you timber-head, that no harm can come to\nthe holder of the rod, unless the mast is first struck?  What are you\ntalking about, then?  Not one ship in a hundred carries rods, and\nAhab,--aye, man, and all of us,--were in no more danger then, in my\npoor opinion, than all the crews in ten thousand ships now sailing\nthe seas.  Why, you King-Post, you, I suppose you would have every\nman in the world go about with a small lightning-rod running up the\ncorner of his hat, like a militia officer's skewered feather, and\ntrailing behind like his sash.  Why don't ye be sensible, Flask? it's\neasy to be sensible; why don't ye, then? any man with half an eye can\nbe sensible.\"\n\n\"I don't know that, Stubb.  You sometimes find it rather hard.\"\n\n\"Yes, when a fellow's soaked through, it's hard to be sensible,\nthat's a fact.  And I am about drenched with this spray.  Never mind;\ncatch the turn there, and pass it.  Seems to me we are lashing down\nthese anchors now as if they were never going to be used again.\nTying these two anchors here, Flask, seems like tying a man's hands\nbehind him.  And what big generous hands they are, to be sure.  These\nare your iron fists, hey?  What a hold they have, too!  I wonder,\nFlask, whether the world is anchored anywhere; if she is, she swings\nwith an uncommon long cable, though.  There, hammer that knot down,\nand we've done.  So; next to touching land, lighting on deck is the\nmost satisfactory.  I say, just wring out my jacket skirts, will ye?\nThank ye.  They laugh at long-togs so, Flask; but seems to me, a\nLong tailed coat ought always to be worn in all storms afloat.  The\ntails tapering down that way, serve to carry off the water, d'ye see.\nSame with cocked hats; the cocks form gable-end eave-troughs, Flask.\nNo more monkey-jackets and tarpaulins for me; I must mount a\nswallow-tail, and drive down a beaver; so.  Halloa! whew! there goes\nmy tarpaulin overboard; Lord, Lord, that the winds that come from\nheaven should be so unmannerly!  This is a nasty night, lad.\"\n\n\n\nCHAPTER 122\n\nMidnight Aloft.--Thunder and Lightning.\n\n\nTHE MAIN-TOP-SAIL YARD.--TASHTEGO PASSING NEW LASHINGS AROUND IT.\n\n\n\"Um, um, um.  Stop that thunder!  Plenty too much thunder up here.\nWhat's the use of thunder?  Um, um, um.  We don't want thunder; we\nwant rum; give us a glass of rum.  Um, um, um!\"\n\n\n\nCHAPTER 123\n\nThe Musket.\n\n\nDuring the most violent shocks of the Typhoon, the man at the\nPequod's jaw-bone tiller had several times been reelingly hurled to\nthe deck by its spasmodic motions, even though preventer tackles had\nbeen attached to it--for they were slack--because some play to the\ntiller was indispensable.\n\nIn a severe gale like this, while the ship is but a tossed\nshuttlecock to the blast, it is by no means uncommon to see the\nneedles in the compasses, at intervals, go round and round.  It was\nthus with the Pequod's; at almost every shock the helmsman had not\nfailed to notice the whirling velocity with which they revolved upon\nthe cards; it is a sight that hardly anyone can behold without some\nsort of unwonted emotion.\n\nSome hours after midnight, the Typhoon abated so much, that through\nthe strenuous exertions of Starbuck and Stubb--one engaged forward\nand the other aft--the shivered remnants of the jib and fore and\nmain-top-sails were cut adrift from the spars, and went eddying away\nto leeward, like the feathers of an albatross, which sometimes are\ncast to the winds when that storm-tossed bird is on the wing.\n\nThe three corresponding new sails were now bent and reefed, and a\nstorm-trysail was set further aft; so that the ship soon went through\nthe water with some precision again; and the course--for the present,\nEast-south-east--which he was to steer, if practicable, was once more\ngiven to the helmsman.  For during the violence of the gale, he had\nonly steered according to its vicissitudes.  But as he was now\nbringing the ship as near her course as possible, watching the\ncompass meanwhile, lo! a good sign! the wind seemed coming round\nastern; aye, the foul breeze became fair!\n\nInstantly the yards were squared, to the lively song of \"HO! THE FAIR\nWIND! OH-YE-HO, CHEERLY MEN!\" the crew singing for joy, that so\npromising an event should so soon have falsified the evil portents\npreceding it.\n\nIn compliance with the standing order of his commander--to report\nimmediately, and at any one of the twenty-four hours, any decided\nchange in the affairs of the deck,--Starbuck had no sooner trimmed\nthe yards to the breeze--however reluctantly and gloomily,--than he\nmechanically went below to apprise Captain Ahab of the circumstance.\n\nEre knocking at his state-room, he involuntarily paused before it a\nmoment.  The cabin lamp--taking long swings this way and that--was\nburning fitfully, and casting fitful shadows upon the old man's\nbolted door,--a thin one, with fixed blinds inserted, in place of\nupper panels.  The isolated subterraneousness of the cabin made a\ncertain humming silence to reign there, though it was hooped round by\nall the roar of the elements.  The loaded muskets in the rack were\nshiningly revealed, as they stood upright against the forward\nbulkhead.  Starbuck was an honest, upright man; but out of Starbuck's\nheart, at that instant when he saw the muskets, there strangely\nevolved an evil thought; but so blent with its neutral or good\naccompaniments that for the instant he hardly knew it for itself.\n\n\"He would have shot me once,\" he murmured, \"yes, there's the very\nmusket that he pointed at me;--that one with the studded stock; let\nme touch it--lift it.  Strange, that I, who have handled so many\ndeadly lances, strange, that I should shake so now.  Loaded?  I must\nsee.  Aye, aye; and powder in the pan;--that's not good.  Best spill\nit?--wait.  I'll cure myself of this.  I'll hold the musket boldly\nwhile I think.--I come to report a fair wind to him.  But how fair?\nFair for death and doom,--THAT'S fair for Moby Dick.  It's a fair\nwind that's only fair for that accursed fish.--The very tube he\npointed at me!--the very one; THIS one--I hold it here; he would have\nkilled me with the very thing I handle now.--Aye and he would fain\nkill all his crew.  Does he not say he will not strike his spars to\nany gale?  Has he not dashed his heavenly quadrant? and in these same\nperilous seas, gropes he not his way by mere dead reckoning of the\nerror-abounding log? and in this very Typhoon, did he not swear that\nhe would have no lightning-rods?  But shall this crazed old man be\ntamely suffered to drag a whole ship's company down to doom with\nhim?--Yes, it would make him the wilful murderer of thirty men and\nmore, if this ship come to any deadly harm; and come to deadly harm,\nmy soul swears this ship will, if Ahab have his way.  If, then, he\nwere this instant--put aside, that crime would not be his.  Ha! is he\nmuttering in his sleep?  Yes, just there,--in there, he's sleeping.\nSleeping? aye, but still alive, and soon awake again.  I can't\nwithstand thee, then, old man.  Not reasoning; not remonstrance; not\nentreaty wilt thou hearken to; all this thou scornest.  Flat\nobedience to thy own flat commands, this is all thou breathest.  Aye,\nand say'st the men have vow'd thy vow; say'st all of us are Ahabs.\nGreat God forbid!--But is there no other way? no lawful way?--Make\nhim a prisoner to be taken home?  What! hope to wrest this old man's\nliving power from his own living hands?  Only a fool would try it.\nSay he were pinioned even; knotted all over with ropes and hawsers;\nchained down to ring-bolts on this cabin floor; he would be more\nhideous than a caged tiger, then.  I could not endure the sight;\ncould not possibly fly his howlings; all comfort, sleep itself,\ninestimable reason would leave me on the long intolerable voyage.\nWhat, then, remains?  The land is hundreds of leagues away, and\nlocked Japan the nearest.  I stand alone here upon an open sea, with\ntwo oceans and a whole continent between me and law.--Aye, aye, 'tis\nso.--Is heaven a murderer when its lightning strikes a would-be\nmurderer in his bed, tindering sheets and skin together?--And would I\nbe a murderer, then, if\"--and slowly, stealthily, and half sideways\nlooking, he placed the loaded musket's end against the door.\n\n\"On this level, Ahab's hammock swings within; his head this way.  A\ntouch, and Starbuck may survive to hug his wife and child again.--Oh\nMary!  Mary!--boy! boy! boy!--But if I wake thee not to death, old\nman, who can tell to what unsounded deeps Starbuck's body this day\nweek may sink, with all the crew!  Great God, where art Thou?  Shall\nI? shall I?--The wind has gone down and shifted, sir; the fore and\nmain topsails are reefed and set; she heads her course.\"\n\n\"Stern all!  Oh Moby Dick, I clutch thy heart at last!\"\n\nSuch were the sounds that now came hurtling from out the old man's\ntormented sleep, as if Starbuck's voice had caused the long dumb\ndream to speak.\n\nThe yet levelled musket shook like a drunkard's arm against the\npanel; Starbuck seemed wrestling with an angel; but turning from the\ndoor, he placed the death-tube in its rack, and left the place.\n\n\"He's too sound asleep, Mr. Stubb; go thou down, and wake him, and\ntell him.  I must see to the deck here.  Thou know'st what to say.\"\n\n\n\nCHAPTER 124\n\nThe Needle.\n\n\nNext morning the not-yet-subsided sea rolled in long slow billows of\nmighty bulk, and striving in the Pequod's gurgling track, pushed her\non like giants' palms outspread.  The strong, unstaggering breeze\nabounded so, that sky and air seemed vast outbellying sails; the\nwhole world boomed before the wind.  Muffled in the full morning\nlight, the invisible sun was only known by the spread intensity of\nhis place; where his bayonet rays moved on in stacks.  Emblazonings,\nas of crowned Babylonian kings and queens, reigned over everything.\nThe sea was as a crucible of molten gold, that bubblingly leaps with\nlight and heat.\n\nLong maintaining an enchanted silence, Ahab stood apart; and every\ntime the tetering ship loweringly pitched down her bowsprit, he\nturned to eye the bright sun's rays produced ahead; and when she\nprofoundly settled by the stern, he turned behind, and saw the sun's\nrearward place, and how the same yellow rays were blending with his\nundeviating wake.\n\n\"Ha, ha, my ship! thou mightest well be taken now for the sea-chariot\nof the sun.  Ho, ho! all ye nations before my prow, I bring the sun\nto ye!  Yoke on the further billows; hallo! a tandem, I drive the\nsea!\"\n\nBut suddenly reined back by some counter thought, he hurried towards\nthe helm, huskily demanding how the ship was heading.\n\n\"East-sou-east, sir,\" said the frightened steersman.\n\n\"Thou liest!\" smiting him with his clenched fist.  \"Heading East at\nthis hour in the morning, and the sun astern?\"\n\nUpon this every soul was confounded; for the phenomenon just then\nobserved by Ahab had unaccountably escaped every one else; but its\nvery blinding palpableness must have been the cause.\n\nThrusting his head half way into the binnacle, Ahab caught one\nglimpse of the compasses; his uplifted arm slowly fell; for a moment\nhe almost seemed to stagger.  Standing behind him Starbuck looked,\nand lo! the two compasses pointed East, and the Pequod was as\ninfallibly going West.\n\nBut ere the first wild alarm could get out abroad among the crew, the\nold man with a rigid laugh exclaimed, \"I have it!  It has happened\nbefore.  Mr. Starbuck, last night's thunder turned our\ncompasses--that's all.  Thou hast before now heard of such a thing, I\ntake it.\"\n\n\"Aye; but never before has it happened to me, sir,\" said the pale\nmate, gloomily.\n\nHere, it must needs be said, that accidents like this have in more\nthan one case occurred to ships in violent storms.  The magnetic\nenergy, as developed in the mariner's needle, is, as all know,\nessentially one with the electricity beheld in heaven; hence it is\nnot to be much marvelled at, that such things should be.  Instances\nwhere the lightning has actually struck the vessel, so as to smite\ndown some of the spars and rigging, the effect upon the needle has at\ntimes been still more fatal; all its loadstone virtue being\nannihilated, so that the before magnetic steel was of no more use\nthan an old wife's knitting needle.  But in either case, the needle\nnever again, of itself, recovers the original virtue thus marred or\nlost; and if the binnacle compasses be affected, the same fate\nreaches all the others that may be in the ship; even were the\nlowermost one inserted into the kelson.\n\nDeliberately standing before the binnacle, and eyeing the\ntranspointed compasses, the old man, with the sharp of his extended\nhand, now took the precise bearing of the sun, and satisfied that the\nneedles were exactly inverted, shouted out his orders for the ship's\ncourse to be changed accordingly.  The yards were hard up; and once\nmore the Pequod thrust her undaunted bows into the opposing wind, for\nthe supposed fair one had only been juggling her.\n\nMeanwhile, whatever were his own secret thoughts, Starbuck said\nnothing, but quietly he issued all requisite orders; while Stubb and\nFlask--who in some small degree seemed then to be sharing his\nfeelings--likewise unmurmuringly acquiesced.  As for the men, though\nsome of them lowly rumbled, their fear of Ahab was greater than their\nfear of Fate.  But as ever before, the pagan harpooneers remained\nalmost wholly unimpressed; or if impressed, it was only with a\ncertain magnetism shot into their congenial hearts from inflexible\nAhab's.\n\nFor a space the old man walked the deck in rolling reveries.  But\nchancing to slip with his ivory heel, he saw the crushed copper\nsight-tubes of the quadrant he had the day before dashed to the deck.\n\n\"Thou poor, proud heaven-gazer and sun's pilot! yesterday I wrecked\nthee, and to-day the compasses would fain have wrecked me.  So, so.\nBut Ahab is lord over the level loadstone yet.  Mr. Starbuck--a lance\nwithout a pole; a top-maul, and the smallest of the sail-maker's\nneedles.  Quick!\"\n\nAccessory, perhaps, to the impulse dictating the thing he was now\nabout to do, were certain prudential motives, whose object might have\nbeen to revive the spirits of his crew by a stroke of his subtile\nskill, in a matter so wondrous as that of the inverted compasses.\nBesides, the old man well knew that to steer by transpointed needles,\nthough clumsily practicable, was not a thing to be passed over by\nsuperstitious sailors, without some shudderings and evil portents.\n\n\"Men,\" said he, steadily turning upon the crew, as the mate handed\nhim the things he had demanded, \"my men, the thunder turned old\nAhab's needles; but out of this bit of steel Ahab can make one of his\nown, that will point as true as any.\"\n\nAbashed glances of servile wonder were exchanged by the sailors, as\nthis was said; and with fascinated eyes they awaited whatever magic\nmight follow.  But Starbuck looked away.\n\nWith a blow from the top-maul Ahab knocked off the steel head of the\nlance, and then handing to the mate the long iron rod remaining, bade\nhim hold it upright, without its touching the deck.  Then, with the\nmaul, after repeatedly smiting the upper end of this iron rod, he\nplaced the blunted needle endwise on the top of it, and less strongly\nhammered that, several times, the mate still holding the rod as\nbefore.  Then going through some small strange motions with\nit--whether indispensable to the magnetizing of the steel, or merely\nintended to augment the awe of the crew, is uncertain--he called for\nlinen thread; and moving to the binnacle, slipped out the two\nreversed needles there, and horizontally suspended the sail-needle by\nits middle, over one of the compass-cards.  At first, the steel went\nround and round, quivering and vibrating at either end; but at last\nit settled to its place, when Ahab, who had been intently watching\nfor this result, stepped frankly back from the binnacle, and pointing\nhis stretched arm towards it, exclaimed,--\"Look ye, for yourselves,\nif Ahab be not lord of the level loadstone!  The sun is East, and\nthat compass swears it!\"\n\nOne after another they peered in, for nothing but their own eyes\ncould persuade such ignorance as theirs, and one after another they\nslunk away.\n\nIn his fiery eyes of scorn and triumph, you then saw Ahab in all his\nfatal pride.\n\n\n\nCHAPTER 125\n\nThe Log and Line.\n\n\nWhile now the fated Pequod had been so long afloat this voyage, the\nlog and line had but very seldom been in use.  Owing to a confident\nreliance upon other means of determining the vessel's place, some\nmerchantmen, and many whalemen, especially when cruising, wholly\nneglect to heave the log; though at the same time, and frequently\nmore for form's sake than anything else, regularly putting down upon\nthe customary slate the course steered by the ship, as well as the\npresumed average rate of progression every hour.  It had been thus\nwith the Pequod.  The wooden reel and angular log attached hung, long\nuntouched, just beneath the railing of the after bulwarks.  Rains and\nspray had damped it; sun and wind had warped it; all the elements\nhad combined to rot a thing that hung so idly.  But heedless of all\nthis, his mood seized Ahab, as he happened to glance upon the reel,\nnot many hours after the magnet scene, and he remembered how his\nquadrant was no more, and recalled his frantic oath about the level\nlog and line.  The ship was sailing plungingly; astern the billows\nrolled in riots.\n\n\"Forward, there!  Heave the log!\"\n\nTwo seamen came.  The golden-hued Tahitian and the grizzly Manxman.\n\"Take the reel, one of ye, I'll heave.\"\n\nThey went towards the extreme stern, on the ship's lee side, where\nthe deck, with the oblique energy of the wind, was now almost dipping\ninto the creamy, sidelong-rushing sea.\n\nThe Manxman took the reel, and holding it high up, by the projecting\nhandle-ends of the spindle, round which the spool of line revolved,\nso stood with the angular log hanging downwards, till Ahab advanced\nto him.\n\nAhab stood before him, and was lightly unwinding some thirty or forty\nturns to form a preliminary hand-coil to toss overboard, when the old\nManxman, who was intently eyeing both him and the line, made bold to\nspeak.\n\n\"Sir, I mistrust it; this line looks far gone, long heat and wet have\nspoiled it.\"\n\n\"'Twill hold, old gentleman.  Long heat and wet, have they spoiled\nthee?  Thou seem'st to hold.  Or, truer perhaps, life holds thee;\nnot thou it.\"\n\n\"I hold the spool, sir.  But just as my captain says.  With these\ngrey hairs of mine 'tis not worth while disputing, 'specially with a\nsuperior, who'll ne'er confess.\"\n\n\"What's that?  There now's a patched professor in Queen Nature's\ngranite-founded College; but methinks he's too subservient.  Where\nwert thou born?\"\n\n\"In the little rocky Isle of Man, sir.\"\n\n\"Excellent!  Thou'st hit the world by that.\"\n\n\"I know not, sir, but I was born there.\"\n\n\"In the Isle of Man, hey?  Well, the other way, it's good.  Here's a\nman from Man; a man born in once independent Man, and now unmanned of\nMan; which is sucked in--by what?  Up with the reel!  The dead, blind\nwall butts all inquiring heads at last.  Up with it!  So.\"\n\nThe log was heaved.  The loose coils rapidly straightened out in a\nlong dragging line astern, and then, instantly, the reel began to\nwhirl.  In turn, jerkingly raised and lowered by the rolling billows,\nthe towing resistance of the log caused the old reelman to stagger\nstrangely.\n\n\"Hold hard!\"\n\nSnap! the overstrained line sagged down in one long festoon; the\ntugging log was gone.\n\n\"I crush the quadrant, the thunder turns the needles, and now the mad\nsea parts the log-line.  But Ahab can mend all.  Haul in here,\nTahitian; reel up, Manxman.  And look ye, let the carpenter make\nanother log, and mend thou the line.  See to it.\"\n\n\"There he goes now; to him nothing's happened; but to me, the skewer\nseems loosening out of the middle of the world.  Haul in, haul in,\nTahitian!  These lines run whole, and whirling out: come in broken,\nand dragging slow.  Ha, Pip? come to help; eh, Pip?\"\n\n\"Pip? whom call ye Pip?  Pip jumped from the whale-boat.  Pip's\nmissing.  Let's see now if ye haven't fished him up here, fisherman.\nIt drags hard; I guess he's holding on.  Jerk him, Tahiti!  Jerk him\noff; we haul in no cowards here.  Ho! there's his arm just breaking\nwater.  A hatchet! a hatchet! cut it off--we haul in no cowards here.\nCaptain Ahab! sir, sir! here's Pip, trying to get on board again.\"\n\n\"Peace, thou crazy loon,\" cried the Manxman, seizing him by the arm.\n\"Away from the quarter-deck!\"\n\n\"The greater idiot ever scolds the lesser,\" muttered Ahab, advancing.\n\"Hands off from that holiness!  Where sayest thou Pip was, boy?\n\n\"Astern there, sir, astern!  Lo! lo!\"\n\n\"And who art thou, boy?  I see not my reflection in the vacant pupils\nof thy eyes.  Oh God! that man should be a thing for immortal souls\nto sieve through!  Who art thou, boy?\"\n\n\"Bell-boy, sir; ship's-crier; ding, dong, ding!  Pip!  Pip!  Pip!  One\nhundred pounds of clay reward for Pip; five feet high--looks\ncowardly--quickest known by that!  Ding, dong, ding!  Who's seen Pip\nthe coward?\"\n\n\"There can be no hearts above the snow-line.  Oh, ye frozen heavens!\nlook down here.  Ye did beget this luckless child, and have abandoned\nhim, ye creative libertines.  Here, boy; Ahab's cabin shall be Pip's\nhome henceforth, while Ahab lives.  Thou touchest my inmost centre,\nboy; thou art tied to me by cords woven of my heart-strings.  Come,\nlet's down.\"\n\n\"What's this? here's velvet shark-skin,\" intently gazing at Ahab's\nhand, and feeling it.  \"Ah, now, had poor Pip but felt so kind a\nthing as this, perhaps he had ne'er been lost!  This seems to me,\nsir, as a man-rope; something that weak souls may hold by.  Oh, sir,\nlet old Perth now come and rivet these two hands together; the black\none with the white, for I will not let this go.\"\n\n\"Oh, boy, nor will I thee, unless I should thereby drag thee to worse\nhorrors than are here.  Come, then, to my cabin.  Lo! ye believers in\ngods all goodness, and in man all ill, lo you! see the omniscient\ngods oblivious of suffering man; and man, though idiotic, and knowing\nnot what he does, yet full of the sweet things of love and gratitude.\nCome!  I feel prouder leading thee by thy black hand, than though I\ngrasped an Emperor's!\"\n\n\"There go two daft ones now,\" muttered the old Manxman.  \"One daft\nwith strength, the other daft with weakness.  But here's the end of\nthe rotten line--all dripping, too.  Mend it, eh?  I think we had\nbest have a new line altogether.  I'll see Mr. Stubb about it.\"\n\n\n\nCHAPTER 126\n\nThe Life-Buoy.\n\n\nSteering now south-eastward by Ahab's levelled steel, and her\nprogress solely determined by Ahab's level log and line; the Pequod\nheld on her path towards the Equator.  Making so long a passage\nthrough such unfrequented waters, descrying no ships, and ere long,\nsideways impelled by unvarying trade winds, over waves monotonously\nmild; all these seemed the strange calm things preluding some riotous\nand desperate scene.\n\nAt last, when the ship drew near to the outskirts, as it were, of the\nEquatorial fishing-ground, and in the deep darkness that goes before\nthe dawn, was sailing by a cluster of rocky islets; the watch--then\nheaded by Flask--was startled by a cry so plaintively wild and\nunearthly--like half-articulated wailings of the ghosts of all\nHerod's murdered Innocents--that one and all, they started from their\nreveries, and for the space of some moments stood, or sat, or leaned\nall transfixedly listening, like the carved Roman slave, while that\nwild cry remained within hearing.  The Christian or civilized part of\nthe crew said it was mermaids, and shuddered; but the pagan\nharpooneers remained unappalled.  Yet the grey Manxman--the oldest\nmariner of all--declared that the wild thrilling sounds that were\nheard, were the voices of newly drowned men in the sea.\n\nBelow in his hammock, Ahab did not hear of this till grey dawn, when\nhe came to the deck; it was then recounted to him by Flask, not\nunaccompanied with hinted dark meanings.  He hollowly laughed, and\nthus explained the wonder.\n\nThose rocky islands the ship had passed were the resort of great\nnumbers of seals, and some young seals that had lost their dams, or\nsome dams that had lost their cubs, must have risen nigh the ship and\nkept company with her, crying and sobbing with their human sort of\nwail.  But this only the more affected some of them, because most\nmariners cherish a very superstitious feeling about seals, arising\nnot only from their peculiar tones when in distress, but also from\nthe human look of their round heads and semi-intelligent faces, seen\npeeringly uprising from the water alongside.  In the sea, under\ncertain circumstances, seals have more than once been mistaken for\nmen.\n\nBut the bodings of the crew were destined to receive a most plausible\nconfirmation in the fate of one of their number that morning.  At\nsun-rise this man went from his hammock to his mast-head at the fore;\nand whether it was that he was not yet half waked from his sleep (for\nsailors sometimes go aloft in a transition state), whether it was\nthus with the man, there is now no telling; but, be that as it may,\nhe had not been long at his perch, when a cry was heard--a cry and a\nrushing--and looking up, they saw a falling phantom in the air; and\nlooking down, a little tossed heap of white bubbles in the blue of\nthe sea.\n\nThe life-buoy--a long slender cask--was dropped from the stern, where\nit always hung obedient to a cunning spring; but no hand rose to\nseize it, and the sun having long beat upon this cask it had\nshrunken, so that it slowly filled, and that parched wood also\nfilled at its every pore; and the studded iron-bound cask followed\nthe sailor to the bottom, as if to yield him his pillow, though in\nsooth but a hard one.\n\nAnd thus the first man of the Pequod that mounted the mast to look\nout for the White Whale, on the White Whale's own peculiar ground;\nthat man was swallowed up in the deep.  But few, perhaps, thought of\nthat at the time.  Indeed, in some sort, they were not grieved at\nthis event, at least as a portent; for they regarded it, not as a\nforeshadowing of evil in the future, but as the fulfilment of an\nevil already presaged.  They declared that now they knew the reason\nof those wild shrieks they had heard the night before.  But again the\nold Manxman said nay.\n\nThe lost life-buoy was now to be replaced; Starbuck was directed to\nsee to it; but as no cask of sufficient lightness could be found, and\nas in the feverish eagerness of what seemed the approaching crisis of\nthe voyage, all hands were impatient of any toil but what was\ndirectly connected with its final end, whatever that might prove to\nbe; therefore, they were going to leave the ship's stern unprovided\nwith a buoy, when by certain strange signs and inuendoes Queequeg\nhinted a hint concerning his coffin.\n\n\"A life-buoy of a coffin!\" cried Starbuck, starting.\n\n\"Rather queer, that, I should say,\" said Stubb.\n\n\"It will make a good enough one,\" said Flask, \"the carpenter here can\narrange it easily.\"\n\n\"Bring it up; there's nothing else for it,\" said Starbuck, after a\nmelancholy pause.  \"Rig it, carpenter; do not look at me so--the\ncoffin, I mean.  Dost thou hear me?  Rig it.\"\n\n\"And shall I nail down the lid, sir?\" moving his hand as with a\nhammer.\n\n\"Aye.\"\n\n\"And shall I caulk the seams, sir?\" moving his hand as with a\ncaulking-iron.\n\n\"Aye.\"\n\n\"And shall I then pay over the same with pitch, sir?\" moving his hand\nas with a pitch-pot.\n\n\"Away! what possesses thee to this?  Make a life-buoy of the coffin,\nand no more.--Mr. Stubb, Mr. Flask, come forward with me.\"\n\n\"He goes off in a huff.  The whole he can endure; at the parts he\nbaulks.  Now I don't like this.  I make a leg for Captain Ahab, and\nhe wears it like a gentleman; but I make a bandbox for Queequeg, and\nhe won't put his head into it.  Are all my pains to go for nothing\nwith that coffin?  And now I'm ordered to make a life-buoy of it.\nIt's like turning an old coat; going to bring the flesh on the other\nside now.  I don't like this cobbling sort of business--I don't like\nit at all; it's undignified; it's not my place.  Let tinkers' brats\ndo tinkerings; we are their betters.  I like to take in hand none but\nclean, virgin, fair-and-square mathematical jobs, something that\nregularly begins at the beginning, and is at the middle when midway,\nand comes to an end at the conclusion; not a cobbler's job, that's at\nan end in the middle, and at the beginning at the end.  It's the old\nwoman's tricks to be giving cobbling jobs.  Lord! what an affection\nall old women have for tinkers.  I know an old woman of sixty-five\nwho ran away with a bald-headed young tinker once.  And that's the\nreason I never would work for lonely widow old women ashore, when I\nkept my job-shop in the Vineyard; they might have taken it into their\nlonely old heads to run off with me.  But heigh-ho! there are no caps\nat sea but snow-caps.  Let me see.  Nail down the lid; caulk the\nseams; pay over the same with pitch; batten them down tight, and hang\nit with the snap-spring over the ship's stern.  Were ever such things\ndone before with a coffin?  Some superstitious old carpenters, now,\nwould be tied up in the rigging, ere they would do the job.  But I'm\nmade of knotty Aroostook hemlock; I don't budge.  Cruppered with a\ncoffin!  Sailing about with a grave-yard tray!  But never mind.  We\nworkers in woods make bridal-bedsteads and card-tables, as well as\ncoffins and hearses.  We work by the month, or by the job, or by the\nprofit; not for us to ask the why and wherefore of our work, unless\nit be too confounded cobbling, and then we stash it if we can.  Hem!\nI'll do the job, now, tenderly.  I'll have me--let's see--how many in\nthe ship's company, all told?  But I've forgotten.  Any way, I'll\nhave me thirty separate, Turk's-headed life-lines, each three feet\nlong hanging all round to the coffin.  Then, if the hull go down,\nthere'll be thirty lively fellows all fighting for one coffin, a\nsight not seen very often beneath the sun!  Come hammer,\ncaulking-iron, pitch-pot, and marling-spike!  Let's to it.\"\n\n\n\nCHAPTER 127\n\nThe Deck.\n\n\nTHE COFFIN LAID UPON TWO LINE-TUBS, BETWEEN THE VICE-BENCH AND THE\nOPEN HATCHWAY; THE CARPENTER CAULKING ITS SEAMS; THE STRING OF\nTWISTED OAKUM SLOWLY UNWINDING FROM A LARGE ROLL OF IT PLACED IN THE\nBOSOM OF HIS FROCK.--AHAB COMES SLOWLY FROM THE CABIN-GANGWAY, AND\nHEARS PIP FOLLOWING HIM.\n\n\nBack, lad; I will be with ye again presently.  He goes!  Not this\nhand complies with my humor more genially than that boy.--Middle\naisle of a church!  What's here?\"\n\n\"Life-buoy, sir.  Mr. Starbuck's orders.  Oh, look, sir!  Beware the\nhatchway!\"\n\n\"Thank ye, man.  Thy coffin lies handy to the vault.\"\n\n\"Sir?  The hatchway? oh!  So it does, sir, so it does.\"\n\n\"Art not thou the leg-maker?  Look, did not this stump come from thy\nshop?\"\n\n\"I believe it did, sir; does the ferrule stand, sir?\"\n\n\"Well enough.  But art thou not also the undertaker?\"\n\n\"Aye, sir; I patched up this thing here as a coffin for Queequeg; but\nthey've set me now to turning it into something else.\"\n\n\"Then tell me; art thou not an arrant, all-grasping, intermeddling,\nmonopolising, heathenish old scamp, to be one day making legs, and\nthe next day coffins to clap them in, and yet again life-buoys out of\nthose same coffins?  Thou art as unprincipled as the gods, and as\nmuch of a jack-of-all-trades.\"\n\n\"But I do not mean anything, sir.  I do as I do.\"\n\n\"The gods again.  Hark ye, dost thou not ever sing working about a\ncoffin?  The Titans, they say, hummed snatches when chipping out the\ncraters for volcanoes; and the grave-digger in the play sings, spade\nin hand.  Dost thou never?\"\n\n\"Sing, sir?  Do I sing?  Oh, I'm indifferent enough, sir, for that;\nbut the reason why the grave-digger made music must have been because\nthere was none in his spade, sir.  But the caulking mallet is full of\nit.  Hark to it.\"\n\n\"Aye, and that's because the lid there's a sounding-board; and what\nin all things makes the sounding-board is this--there's naught\nbeneath.  And yet, a coffin with a body in it rings pretty much the\nsame, Carpenter.  Hast thou ever helped carry a bier, and heard the\ncoffin knock against the churchyard gate, going in?\n\n\"Faith, sir, I've--\"\n\n\"Faith?  What's that?\"\n\n\"Why, faith, sir, it's only a sort of exclamation-like--that's all,\nsir.\"\n\n\"Um, um; go on.\"\n\n\"I was about to say, sir, that--\"\n\n\"Art thou a silk-worm?  Dost thou spin thy own shroud out of thyself?\nLook at thy bosom!  Despatch! and get these traps out of sight.\"\n\n\"He goes aft.  That was sudden, now; but squalls come sudden in hot\nlatitudes.  I've heard that the Isle of Albemarle, one of the\nGallipagos, is cut by the Equator right in the middle.  Seems to me\nsome sort of Equator cuts yon old man, too, right in his middle.\nHe's always under the Line--fiery hot, I tell ye!  He's looking this\nway--come, oakum; quick.  Here we go again.  This wooden mallet is\nthe cork, and I'm the professor of musical glasses--tap, tap!\"\n\n(AHAB TO HIMSELF.)\n\n\"There's a sight!  There's a sound!  The grey-headed woodpecker\ntapping the hollow tree!  Blind and dumb might well be envied now.\nSee! that thing rests on two line-tubs, full of tow-lines.  A most\nmalicious wag, that fellow.  Rat-tat!  So man's seconds tick!  Oh!\nhow immaterial are all materials!  What things real are there, but\nimponderable thoughts?  Here now's the very dreaded symbol of grim\ndeath, by a mere hap, made the expressive sign of the help and hope\nof most endangered life.  A life-buoy of a coffin!  Does it go\nfurther?  Can it be that in some spiritual sense the coffin is, after\nall, but an immortality-preserver!  I'll think of that.  But no.  So\nfar gone am I in the dark side of earth, that its other side, the\ntheoretic bright one, seems but uncertain twilight to me.  Will ye\nnever have done, Carpenter, with that accursed sound?  I go below;\nlet me not see that thing here when I return again.  Now, then, Pip,\nwe'll talk this over; I do suck most wondrous philosophies from thee!\nSome unknown conduits from the unknown worlds must empty into thee!\"\n\n\n\nCHAPTER 128\n\nThe Pequod Meets The Rachel.\n\n\nNext day, a large ship, the Rachel, was descried, bearing directly\ndown upon the Pequod, all her spars thickly clustering with men.  At\nthe time the Pequod was making good speed through the water; but as\nthe broad-winged windward stranger shot nigh to her, the boastful\nsails all fell together as blank bladders that are burst, and all\nlife fled from the smitten hull.\n\n\"Bad news; she brings bad news,\" muttered the old Manxman.  But ere\nher commander, who, with trumpet to mouth, stood up in his boat; ere\nhe could hopefully hail, Ahab's voice was heard.\n\n\"Hast seen the White Whale?\"\n\n\"Aye, yesterday.  Have ye seen a whale-boat adrift?\"\n\nThrottling his joy, Ahab negatively answered this unexpected\nquestion; and would then have fain boarded the stranger, when the\nstranger captain himself, having stopped his vessel's way, was seen\ndescending her side.  A few keen pulls, and his boat-hook soon\nclinched the Pequod's main-chains, and he sprang to the deck.\nImmediately he was recognised by Ahab for a Nantucketer he knew.  But\nno formal salutation was exchanged.\n\n\"Where was he?--not killed!--not killed!\" cried Ahab, closely\nadvancing.  \"How was it?\"\n\nIt seemed that somewhat late on the afternoon of the day previous,\nwhile three of the stranger's boats were engaged with a shoal of\nwhales, which had led them some four or five miles from the ship; and\nwhile they were yet in swift chase to windward, the white hump and\nhead of Moby Dick had suddenly loomed up out of the water, not very\nfar to leeward; whereupon, the fourth rigged boat--a reserved\none--had been instantly lowered in chase.  After a keen sail before\nthe wind, this fourth boat--the swiftest keeled of all--seemed to\nhave succeeded in fastening--at least, as well as the man at the\nmast-head could tell anything about it.  In the distance he saw the\ndiminished dotted boat; and then a swift gleam of bubbling white\nwater; and after that nothing more; whence it was concluded that the\nstricken whale must have indefinitely run away with his pursuers, as\noften happens.  There was some apprehension, but no positive alarm,\nas yet.  The recall signals were placed in the rigging; darkness came\non; and forced to pick up her three far to windward boats--ere going\nin quest of the fourth one in the precisely opposite direction--the\nship had not only been necessitated to leave that boat to its fate\ntill near midnight, but, for the time, to increase her distance from\nit.  But the rest of her crew being at last safe aboard, she crowded\nall sail--stunsail on stunsail--after the missing boat; kindling a\nfire in her try-pots for a beacon; and every other man aloft on the\nlook-out.  But though when she had thus sailed a sufficient distance\nto gain the presumed place of the absent ones when last seen; though\nshe then paused to lower her spare boats to pull all around her; and\nnot finding anything, had again dashed on; again paused, and lowered\nher boats; and though she had thus continued doing till daylight;\nyet not the least glimpse of the missing keel had been seen.\n\nThe story told, the stranger Captain immediately went on to reveal\nhis object in boarding the Pequod.  He desired that ship to unite\nwith his own in the search; by sailing over the sea some four or five\nmiles apart, on parallel lines, and so sweeping a double horizon, as\nit were.\n\n\"I will wager something now,\" whispered Stubb to Flask, \"that some\none in that missing boat wore off that Captain's best coat; mayhap,\nhis watch--he's so cursed anxious to get it back.  Who ever heard of\ntwo pious whale-ships cruising after one missing whale-boat in the\nheight of the whaling season?  See, Flask, only see how pale he\nlooks--pale in the very buttons of his eyes--look--it wasn't the\ncoat--it must have been the--\"\n\n\"My boy, my own boy is among them.  For God's sake--I beg, I\nconjure\"--here exclaimed the stranger Captain to Ahab, who thus far\nhad but icily received his petition.  \"For eight-and-forty hours let\nme charter your ship--I will gladly pay for it, and roundly pay for\nit--if there be no other way--for eight-and-forty hours only--only\nthat--you must, oh, you must, and you SHALL do this thing.\"\n\n\"His son!\" cried Stubb, \"oh, it's his son he's lost!  I take back the\ncoat and watch--what says Ahab?  We must save that boy.\"\n\n\"He's drowned with the rest on 'em, last night,\" said the old Manx\nsailor standing behind them; \"I heard; all of ye heard their\nspirits.\"\n\nNow, as it shortly turned out, what made this incident of the\nRachel's the more melancholy, was the circumstance, that not only was\none of the Captain's sons among the number of the missing boat's\ncrew; but among the number of the other boat's crews, at the same\ntime, but on the other hand, separated from the ship during the dark\nvicissitudes of the chase, there had been still another son; as that\nfor a time, the wretched father was plunged to the bottom of the\ncruellest perplexity; which was only solved for him by his chief\nmate's instinctively adopting the ordinary procedure of a whale-ship\nin such emergencies, that is, when placed between jeopardized but\ndivided boats, always to pick up the majority first.  But the\ncaptain, for some unknown constitutional reason, had refrained from\nmentioning all this, and not till forced to it by Ahab's iciness did\nhe allude to his one yet missing boy; a little lad, but twelve years\nold, whose father with the earnest but unmisgiving hardihood of a\nNantucketer's paternal love, had thus early sought to initiate him in\nthe perils and wonders of a vocation almost immemorially the destiny\nof all his race.  Nor does it unfrequently occur, that Nantucket\ncaptains will send a son of such tender age away from them, for a\nprotracted three or four years' voyage in some other ship than their\nown; so that their first knowledge of a whaleman's career shall be\nunenervated by any chance display of a father's natural but untimely\npartiality, or undue apprehensiveness and concern.\n\nMeantime, now the stranger was still beseeching his poor boon of\nAhab; and Ahab still stood like an anvil, receiving every shock, but\nwithout the least quivering of his own.\n\n\"I will not go,\" said the stranger, \"till you say aye to me.  Do to\nme as you would have me do to you in the like case.  For YOU too have\na boy, Captain Ahab--though but a child, and nestling safely at home\nnow--a child of your old age too--Yes, yes, you relent; I see\nit--run, run, men, now, and stand by to square in the yards.\"\n\n\"Avast,\" cried Ahab--\"touch not a rope-yarn\"; then in a voice that\nprolongingly moulded every word--\"Captain Gardiner, I will not do it.\nEven now I lose time.  Good-bye, good-bye.  God bless ye, man, and\nmay I forgive myself, but I must go.  Mr. Starbuck, look at the\nbinnacle watch, and in three minutes from this present instant warn\noff all strangers: then brace forward again, and let the ship sail\nas before.\"\n\nHurriedly turning, with averted face, he descended into his cabin,\nleaving the strange captain transfixed at this unconditional and\nutter rejection of his so earnest suit.  But starting from his\nenchantment, Gardiner silently hurried to the side; more fell than\nstepped into his boat, and returned to his ship.\n\nSoon the two ships diverged their wakes; and long as the strange\nvessel was in view, she was seen to yaw hither and thither at every\ndark spot, however small, on the sea.  This way and that her yards\nwere swung round; starboard and larboard, she continued to tack;\nnow she beat against a head sea; and again it pushed her before it;\nwhile all the while, her masts and yards were thickly clustered with\nmen, as three tall cherry trees, when the boys are cherrying among\nthe boughs.\n\nBut by her still halting course and winding, woeful way, you plainly\nsaw that this ship that so wept with spray, still remained without\ncomfort.  She was Rachel, weeping for her children, because they were\nnot.\n\n\n\nCHAPTER 129\n\nThe Cabin.\n\n\n(AHAB MOVING TO GO ON DECK; PIP CATCHES HIM BY THE HAND TO FOLLOW.)\n\nLad, lad, I tell thee thou must not follow Ahab now.  The hour is\ncoming when Ahab would not scare thee from him, yet would not have\nthee by him.  There is that in thee, poor lad, which I feel too\ncuring to my malady.  Like cures like; and for this hunt, my malady\nbecomes my most desired health.  Do thou abide below here, where they\nshall serve thee, as if thou wert the captain.  Aye, lad, thou shalt\nsit here in my own screwed chair; another screw to it, thou must be.\"\n\n\"No, no, no! ye have not a whole body, sir; do ye but use poor me for\nyour one lost leg; only tread upon me, sir; I ask no more, so I\nremain a part of ye.\"\n\n\"Oh! spite of million villains, this makes me a bigot in the fadeless\nfidelity of man!--and a black! and crazy!--but methinks\nlike-cures-like applies to him too; he grows so sane again.\"\n\n\"They tell me, sir, that Stubb did once desert poor little Pip, whose\ndrowned bones now show white, for all the blackness of his living\nskin.  But I will never desert ye, sir, as Stubb did him.  Sir, I\nmust go with ye.\"\n\n\"If thou speakest thus to me much more, Ahab's purpose keels up in\nhim.  I tell thee no; it cannot be.\"\n\n\"Oh good master, master, master!\n\n\"Weep so, and I will murder thee! have a care, for Ahab too is mad.\nListen, and thou wilt often hear my ivory foot upon the deck, and\nstill know that I am there.  And now I quit thee.  Thy hand!--Met!\nTrue art thou, lad, as the circumference to its centre.  So: God for\never bless thee; and if it come to that,--God for ever save thee, let\nwhat will befall.\"\n\n(AHAB GOES; PIP STEPS ONE STEP FORWARD.)\n\n\n\"Here he this instant stood; I stand in his air,--but I'm alone.\nNow were even poor Pip here I could endure it, but he's missing.\nPip!  Pip!  Ding, dong, ding!  Who's seen Pip?  He must be up here;\nlet's try the door.  What? neither lock, nor bolt, nor bar; and yet\nthere's no opening it.  It must be the spell; he told me to stay\nhere: Aye, and told me this screwed chair was mine.  Here, then, I'll\nseat me, against the transom, in the ship's full middle, all her keel\nand her three masts before me.  Here, our old sailors say, in their\nblack seventy-fours great admirals sometimes sit at table, and lord\nit over rows of captains and lieutenants.  Ha! what's this? epaulets!\nepaulets! the epaulets all come crowding!  Pass round the decanters;\nglad to see ye; fill up, monsieurs!  What an odd feeling, now, when a\nblack boy's host to white men with gold lace upon their\ncoats!--Monsieurs, have ye seen one Pip?--a little negro lad, five\nfeet high, hang-dog look, and cowardly!  Jumped from a whale-boat\nonce;--seen him?  No!  Well then, fill up again, captains, and let's\ndrink shame upon all cowards!  I name no names.  Shame upon them!\nPut one foot upon the table.  Shame upon all cowards.--Hist! above\nthere, I hear ivory--Oh, master! master!  I am indeed down-hearted\nwhen you walk over me.  But here I'll stay, though this stern\nstrikes rocks; and they bulge through; and oysters come to join me.\"\n\n\n\nCHAPTER 130\n\nThe Hat.\n\n\nAnd now that at the proper time and place, after so long and wide a\npreliminary cruise, Ahab,--all other whaling waters swept--seemed to\nhave chased his foe into an ocean-fold, to slay him the more securely\nthere; now, that he found himself hard by the very latitude and\nlongitude where his tormenting wound had been inflicted; now that a\nvessel had been spoken which on the very day preceding had actually\nencountered Moby Dick;--and now that all his successive meetings with\nvarious ships contrastingly concurred to show the demoniac\nindifference with which the white whale tore his hunters, whether\nsinning or sinned against; now it was that there lurked a something\nin the old man's eyes, which it was hardly sufferable for feeble\nsouls to see.  As the unsetting polar star, which through the\nlivelong, arctic, six months' night sustains its piercing, steady,\ncentral gaze; so Ahab's purpose now fixedly gleamed down upon the\nconstant midnight of the gloomy crew.  It domineered above them so,\nthat all their bodings, doubts, misgivings, fears, were fain to hide\nbeneath their souls, and not sprout forth a single spear or leaf.\n\nIn this foreshadowing interval too, all humor, forced or natural,\nvanished.  Stubb no more strove to raise a smile; Starbuck no more\nstrove to check one.  Alike, joy and sorrow, hope and fear, seemed\nground to finest dust, and powdered, for the time, in the clamped\nmortar of Ahab's iron soul.  Like machines, they dumbly moved about\nthe deck, ever conscious that the old man's despot eye was on them.\n\nBut did you deeply scan him in his more secret confidential hours;\nwhen he thought no glance but one was on him; then you would have\nseen that even as Ahab's eyes so awed the crew's, the inscrutable\nParsee's glance awed his; or somehow, at least, in some wild way, at\ntimes affected it.  Such an added, gliding strangeness began to\ninvest the thin Fedallah now; such ceaseless shudderings shook him;\nthat the men looked dubious at him; half uncertain, as it seemed,\nwhether indeed he were a mortal substance, or else a tremulous shadow\ncast upon the deck by some unseen being's body.  And that shadow was\nalways hovering there.  For not by night, even, had Fedallah ever\ncertainly been known to slumber, or go below.  He would stand still\nfor hours: but never sat or leaned; his wan but wondrous eyes did\nplainly say--We two watchmen never rest.\n\nNor, at any time, by night or day could the mariners now step upon\nthe deck, unless Ahab was before them; either standing in his\npivot-hole, or exactly pacing the planks between two undeviating\nlimits,--the main-mast and the mizen; or else they saw him standing\nin the cabin-scuttle,--his living foot advanced upon the deck, as if\nto step; his hat slouched heavily over his eyes; so that however\nmotionless he stood, however the days and nights were added on, that\nhe had not swung in his hammock; yet hidden beneath that slouching\nhat, they could never tell unerringly whether, for all this, his eyes\nwere really closed at times; or whether he was still intently\nscanning them; no matter, though he stood so in the scuttle for a\nwhole hour on the stretch, and the unheeded night-damp gathered in\nbeads of dew upon that stone-carved coat and hat.  The clothes that\nthe night had wet, the next day's sunshine dried upon him; and so,\nday after day, and night after night; he went no more beneath the\nplanks; whatever he wanted from the cabin that thing he sent for.\n\nHe ate in the same open air; that is, his two only meals,--breakfast\nand dinner: supper he never touched; nor reaped his beard; which\ndarkly grew all gnarled, as unearthed roots of trees blown over,\nwhich still grow idly on at naked base, though perished in the upper\nverdure.  But though his whole life was now become one watch on deck;\nand though the Parsee's mystic watch was without intermission as his\nown; yet these two never seemed to speak--one man to the\nother--unless at long intervals some passing unmomentous matter made\nit necessary.  Though such a potent spell seemed secretly to join the\ntwain; openly, and to the awe-struck crew, they seemed pole-like\nasunder.  If by day they chanced to speak one word; by night, dumb\nmen were both, so far as concerned the slightest verbal interchange.\nAt times, for longest hours, without a single hail, they stood far\nparted in the starlight; Ahab in his scuttle, the Parsee by the\nmainmast; but still fixedly gazing upon each other; as if in the\nParsee Ahab saw his forethrown shadow, in Ahab the Parsee his\nabandoned substance.\n\nAnd yet, somehow, did Ahab--in his own proper self, as daily, hourly,\nand every instant, commandingly revealed to his subordinates,--Ahab\nseemed an independent lord; the Parsee but his slave.  Still again\nboth seemed yoked together, and an unseen tyrant driving them; the\nlean shade siding the solid rib.  For be this Parsee what he may, all\nrib and keel was solid Ahab.\n\nAt the first faintest glimmering of the dawn, his iron voice was\nheard from aft,--\"Man the mast-heads!\"--and all through the day,\ntill after sunset and after twilight, the same voice every hour, at\nthe striking of the helmsman's bell, was heard--\"What d'ye\nsee?--sharp! sharp!\"\n\nBut when three or four days had slided by, after meeting the\nchildren-seeking Rachel; and no spout had yet been seen; the\nmonomaniac old man seemed distrustful of his crew's fidelity; at\nleast, of nearly all except the Pagan harpooneers; he seemed to\ndoubt, even, whether Stubb and Flask might not willingly overlook the\nsight he sought.  But if these suspicions were really his, he\nsagaciously refrained from verbally expressing them, however his\nactions might seem to hint them.\n\n\"I will have the first sight of the whale myself,\"--he said.  \"Aye!\nAhab must have the doubloon! and with his own hands he rigged a nest\nof basketed bowlines; and sending a hand aloft, with a single sheaved\nblock, to secure to the main-mast head, he received the two ends of\nthe downward-reeved rope; and attaching one to his basket prepared a\npin for the other end, in order to fasten it at the rail.  This done,\nwith that end yet in his hand and standing beside the pin, he looked\nround upon his crew, sweeping from one to the other; pausing his\nglance long upon Daggoo, Queequeg, Tashtego; but shunning Fedallah;\nand then settling his firm relying eye upon the chief mate,\nsaid,--\"Take the rope, sir--I give it into thy hands, Starbuck.\"\nThen arranging his person in the basket, he gave the word for them to\nhoist him to his perch, Starbuck being the one who secured the rope\nat last; and afterwards stood near it.  And thus, with one hand\nclinging round the royal mast, Ahab gazed abroad upon the sea for\nmiles and miles,--ahead, astern, this side, and that,--within the\nwide expanded circle commanded at so great a height.\n\nWhen in working with his hands at some lofty almost isolated place in\nthe rigging, which chances to afford no foothold, the sailor at sea\nis hoisted up to that spot, and sustained there by the rope; under\nthese circumstances, its fastened end on deck is always given in\nstrict charge to some one man who has the special watch of it.\nBecause in such a wilderness of running rigging, whose various\ndifferent relations aloft cannot always be infallibly discerned by\nwhat is seen of them at the deck; and when the deck-ends of these\nropes are being every few minutes cast down from the fastenings, it\nwould be but a natural fatality, if, unprovided with a constant\nwatchman, the hoisted sailor should by some carelessness of the crew\nbe cast adrift and fall all swooping to the sea.  So Ahab's\nproceedings in this matter were not unusual; the only strange thing\nabout them seemed to be, that Starbuck, almost the one only man who\nhad ever ventured to oppose him with anything in the slightest degree\napproaching to decision--one of those too, whose faithfulness on the\nlook-out he had seemed to doubt somewhat;--it was strange, that this\nwas the very man he should select for his watchman; freely giving his\nwhole life into such an otherwise distrusted person's hands.\n\nNow, the first time Ahab was perched aloft; ere he had been there ten\nminutes; one of those red-billed savage sea-hawks which so often fly\nincommodiously close round the manned mast-heads of whalemen in these\nlatitudes; one of these birds came wheeling and screaming round his\nhead in a maze of untrackably swift circlings.  Then it darted a\nthousand feet straight up into the air; then spiralized downwards,\nand went eddying again round his head.\n\nBut with his gaze fixed upon the dim and distant horizon, Ahab seemed\nnot to mark this wild bird; nor, indeed, would any one else have\nmarked it much, it being no uncommon circumstance; only now almost\nthe least heedful eye seemed to see some sort of cunning meaning in\nalmost every sight.\n\n\"Your hat, your hat, sir!\" suddenly cried the Sicilian seaman, who\nbeing posted at the mizen-mast-head, stood directly behind Ahab,\nthough somewhat lower than his level, and with a deep gulf of air\ndividing them.\n\nBut already the sable wing was before the old man's eyes; the long\nhooked bill at his head: with a scream, the black hawk darted away\nwith his prize.\n\nAn eagle flew thrice round Tarquin's head, removing his cap to\nreplace it, and thereupon Tanaquil, his wife, declared that Tarquin\nwould be king of Rome.  But only by the replacing of the cap was that\nomen accounted good.  Ahab's hat was never restored; the wild hawk\nflew on and on with it; far in advance of the prow: and at last\ndisappeared; while from the point of that disappearance, a minute\nblack spot was dimly discerned, falling from that vast height into\nthe sea.\n\n\n\nCHAPTER 131\n\nThe Pequod Meets The Delight.\n\n\nThe intense Pequod sailed on; the rolling waves and days went by; the\nlife-buoy-coffin still lightly swung; and another ship, most\nmiserably misnamed the Delight, was descried.  As she drew nigh, all\neyes were fixed upon her broad beams, called shears, which, in some\nwhaling-ships, cross the quarter-deck at the height of eight or nine\nfeet; serving to carry the spare, unrigged, or disabled boats.\n\nUpon the stranger's shears were beheld the shattered, white ribs, and\nsome few splintered planks, of what had once been a whale-boat; but\nyou now saw through this wreck, as plainly as you see through the\npeeled, half-unhinged, and bleaching skeleton of a horse.\n\n\"Hast seen the White Whale?\"\n\n\"Look!\" replied the hollow-cheeked captain from his taffrail; and\nwith his trumpet he pointed to the wreck.\n\n\"Hast killed him?\"\n\n\"The harpoon is not yet forged that ever will do that,\" answered the\nother, sadly glancing upon a rounded hammock on the deck, whose\ngathered sides some noiseless sailors were busy in sewing together.\n\n\"Not forged!\" and snatching Perth's levelled iron from the crotch,\nAhab held it out, exclaiming--\"Look ye, Nantucketer; here in this\nhand I hold his death!  Tempered in blood, and tempered by lightning\nare these barbs; and I swear to temper them triply in that hot place\nbehind the fin, where the White Whale most feels his accursed life!\"\n\n\"Then God keep thee, old man--see'st thou that\"--pointing to the\nhammock--\"I bury but one of five stout men, who were alive only\nyesterday; but were dead ere night.  Only THAT one I bury; the rest\nwere buried before they died; you sail upon their tomb.\"  Then\nturning to his crew--\"Are ye ready there? place the plank then on the\nrail, and lift the body; so, then--Oh!  God\"--advancing towards the\nhammock with uplifted hands--\"may the resurrection and the life--\"\n\n\"Brace forward!  Up helm!\" cried Ahab like lightning to his men.\n\nBut the suddenly started Pequod was not quick enough to escape the\nsound of the splash that the corpse soon made as it struck the sea;\nnot so quick, indeed, but that some of the flying bubbles might have\nsprinkled her hull with their ghostly baptism.\n\nAs Ahab now glided from the dejected Delight, the strange life-buoy\nhanging at the Pequod's stern came into conspicuous relief.\n\n\"Ha! yonder! look yonder, men!\" cried a foreboding voice in her wake.\n\"In vain, oh, ye strangers, ye fly our sad burial; ye but turn us\nyour taffrail to show us your coffin!\"\n\n\n\nCHAPTER 132\n\nThe Symphony.\n\n\nIt was a clear steel-blue day.  The firmaments of air and sea were\nhardly separable in that all-pervading azure; only, the pensive air\nwas transparently pure and soft, with a woman's look, and the robust\nand man-like sea heaved with long, strong, lingering swells, as\nSamson's chest in his sleep.\n\nHither, and thither, on high, glided the snow-white wings of small,\nunspeckled birds; these were the gentle thoughts of the feminine air;\nbut to and fro in the deeps, far down in the bottomless blue, rushed\nmighty leviathans, sword-fish, and sharks; and these were the strong,\ntroubled, murderous thinkings of the masculine sea.\n\nBut though thus contrasting within, the contrast was only in shades\nand shadows without; those two seemed one; it was only the sex, as it\nwere, that distinguished them.\n\nAloft, like a royal czar and king, the sun seemed giving this gentle\nair to this bold and rolling sea; even as bride to groom.  And at the\ngirdling line of the horizon, a soft and tremulous motion--most seen\nhere at the Equator--denoted the fond, throbbing trust, the loving\nalarms, with which the poor bride gave her bosom away.\n\nTied up and twisted; gnarled and knotted with wrinkles; haggardly\nfirm and unyielding; his eyes glowing like coals, that still glow in\nthe ashes of ruin; untottering Ahab stood forth in the clearness of\nthe morn; lifting his splintered helmet of a brow to the fair girl's\nforehead of heaven.\n\nOh, immortal infancy, and innocency of the azure!  Invisible winged\ncreatures that frolic all round us!  Sweet childhood of air and sky!\nhow oblivious were ye of old Ahab's close-coiled woe!  But so have I\nseen little Miriam and Martha, laughing-eyed elves, heedlessly gambol\naround their old sire; sporting with the circle of singed locks which\ngrew on the marge of that burnt-out crater of his brain.\n\nSlowly crossing the deck from the scuttle, Ahab leaned over the side\nand watched how his shadow in the water sank and sank to his gaze,\nthe more and the more that he strove to pierce the profundity.  But\nthe lovely aromas in that enchanted air did at last seem to dispel,\nfor a moment, the cankerous thing in his soul.  That glad, happy air,\nthat winsome sky, did at last stroke and caress him; the step-mother\nworld, so long cruel--forbidding--now threw affectionate arms round\nhis stubborn neck, and did seem to joyously sob over him, as if over\none, that however wilful and erring, she could yet find it in her\nheart to save and to bless.  From beneath his slouched hat Ahab\ndropped a tear into the sea; nor did all the Pacific contain such\nwealth as that one wee drop.\n\nStarbuck saw the old man; saw him, how he heavily leaned over the\nside; and he seemed to hear in his own true heart the measureless\nsobbing that stole out of the centre of the serenity around.  Careful\nnot to touch him, or be noticed by him, he yet drew near to him, and\nstood there.\n\nAhab turned.\n\n\"Starbuck!\"\n\n\"Sir.\"\n\n\"Oh, Starbuck! it is a mild, mild wind, and a mild looking sky.  On\nsuch a day--very much such a sweetness as this--I struck my first\nwhale--a boy-harpooneer of eighteen!  Forty--forty--forty years\nago!--ago!  Forty years of continual whaling! forty years of\nprivation, and peril, and storm-time! forty years on the pitiless\nsea! for forty years has Ahab forsaken the peaceful land, for forty\nyears to make war on the horrors of the deep!  Aye and yes, Starbuck,\nout of those forty years I have not spent three ashore.  When I think\nof this life I have led; the desolation of solitude it has been; the\nmasoned, walled-town of a Captain's exclusiveness, which admits but\nsmall entrance to any sympathy from the green country without--oh,\nweariness! heaviness!  Guinea-coast slavery of solitary\ncommand!--when I think of all this; only half-suspected, not so\nkeenly known to me before--and how for forty years I have fed upon\ndry salted fare--fit emblem of the dry nourishment of my soil!--when\nthe poorest landsman has had fresh fruit to his daily hand, and\nbroken the world's fresh bread to my mouldy crusts--away, whole\noceans away, from that young girl-wife I wedded past fifty, and\nsailed for Cape Horn the next day, leaving but one dent in my\nmarriage pillow--wife? wife?--rather a widow with her husband alive!\nAye, I widowed that poor girl when I married her, Starbuck; and\nthen, the madness, the frenzy, the boiling blood and the smoking\nbrow, with which, for a thousand lowerings old Ahab has furiously,\nfoamingly chased his prey--more a demon than a man!--aye, aye! what a\nforty years' fool--fool--old fool, has old Ahab been!  Why this\nstrife of the chase? why weary, and palsy the arm at the oar, and the\niron, and the lance? how the richer or better is Ahab now?  Behold.\nOh, Starbuck! is it not hard, that with this weary load I bear, one\npoor leg should have been snatched from under me?  Here, brush this\nold hair aside; it blinds me, that I seem to weep.  Locks so grey did\nnever grow but from out some ashes!  But do I look very old, so very,\nvery old, Starbuck?  I feel deadly faint, bowed, and humped, as\nthough I were Adam, staggering beneath the piled centuries since\nParadise.  God!  God!  God!--crack my heart!--stave my\nbrain!--mockery! mockery! bitter, biting mockery of grey hairs, have\nI lived enough joy to wear ye; and seem and feel thus intolerably\nold?  Close! stand close to me, Starbuck; let me look into a human\neye; it is better than to gaze into sea or sky; better than to gaze\nupon God.  By the green land; by the bright hearth-stone! this is the\nmagic glass, man; I see my wife and my child in thine eye.  No, no;\nstay on board, on board!--lower not when I do; when branded Ahab\ngives chase to Moby Dick.  That hazard shall not be thine.  No, no!\nnot with the far away home I see in that eye!\"\n\n\"Oh, my Captain! my Captain! noble soul! grand old heart, after all!\nwhy should any one give chase to that hated fish!  Away with me! let\nus fly these deadly waters! let us home!  Wife and child, too, are\nStarbuck's--wife and child of his brotherly, sisterly, play-fellow\nyouth; even as thine, sir, are the wife and child of thy loving,\nlonging, paternal old age!  Away! let us away!--this instant let me\nalter the course!  How cheerily, how hilariously, O my Captain, would\nwe bowl on our way to see old Nantucket again!  I think, sir, they\nhave some such mild blue days, even as this, in Nantucket.\"\n\n\"They have, they have.  I have seen them--some summer days in the\nmorning.  About this time--yes, it is his noon nap now--the boy\nvivaciously wakes; sits up in bed; and his mother tells him of me, of\ncannibal old me; how I am abroad upon the deep, but will yet come\nback to dance him again.\"\n\n\"'Tis my Mary, my Mary herself!  She promised that my boy, every\nmorning, should be carried to the hill to catch the first glimpse of\nhis father's sail!  Yes, yes! no more! it is done! we head for\nNantucket!  Come, my Captain, study out the course, and let us away!\nSee, see! the boy's face from the window! the boy's hand on the\nhill!\"\n\nBut Ahab's glance was averted; like a blighted fruit tree he shook,\nand cast his last, cindered apple to the soil.\n\n\"What is it, what nameless, inscrutable, unearthly thing is it; what\ncozening, hidden lord and master, and cruel, remorseless emperor\ncommands me; that against all natural lovings and longings, I so keep\npushing, and crowding, and jamming myself on all the time; recklessly\nmaking me ready to do what in my own proper, natural heart, I durst\nnot so much as dare?  Is Ahab, Ahab?  Is it I, God, or who, that\nlifts this arm?  But if the great sun move not of himself; but is as an\nerrand-boy in heaven; nor one single star can revolve, but by some\ninvisible power; how then can this one small heart beat; this one\nsmall brain think thoughts; unless God does that beating, does that\nthinking, does that living, and not I.  By heaven, man, we are turned\nround and round in this world, like yonder windlass, and Fate is the\nhandspike.  And all the time, lo! that smiling sky, and this\nunsounded sea!  Look! see yon Albicore! who put it into him to chase\nand fang that flying-fish?  Where do murderers go, man!  Who's to\ndoom, when the judge himself is dragged to the bar?  But it is a\nmild, mild wind, and a mild looking sky; and the air smells now, as\nif it blew from a far-away meadow; they have been making hay\nsomewhere under the slopes of the Andes, Starbuck, and the mowers are\nsleeping among the new-mown hay.  Sleeping?  Aye, toil we how we may,\nwe all sleep at last on the field.  Sleep?  Aye, and rust amid\ngreenness; as last year's scythes flung down, and left in the half-cut\nswaths--Starbuck!\"\n\nBut blanched to a corpse's hue with despair, the Mate had stolen\naway.\n\nAhab crossed the deck to gaze over on the other side; but started at\ntwo reflected, fixed eyes in the water there.  Fedallah was\nmotionlessly leaning over the same rail.\n\n\n\nCHAPTER 133\n\nThe Chase--First Day.\n\n\nThat night, in the mid-watch, when the old man--as his wont at\nintervals--stepped forth from the scuttle in which he leaned, and\nwent to his pivot-hole, he suddenly thrust out his face fiercely,\nsnuffing up the sea air as a sagacious ship's dog will, in drawing\nnigh to some barbarous isle.  He declared that a whale must be near.\nSoon that peculiar odor, sometimes to a great distance given forth by\nthe living sperm whale, was palpable to all the watch; nor was any\nmariner surprised when, after inspecting the compass, and then the\ndog-vane, and then ascertaining the precise bearing of the odor as\nnearly as possible, Ahab rapidly ordered the ship's course to be\nslightly altered, and the sail to be shortened.\n\nThe acute policy dictating these movements was sufficiently\nvindicated at daybreak, by the sight of a long sleek on the sea\ndirectly and lengthwise ahead, smooth as oil, and resembling in the\npleated watery wrinkles bordering it, the polished metallic-like\nmarks of some swift tide-rip, at the mouth of a deep, rapid stream.\n\n\"Man the mast-heads!  Call all hands!\"\n\nThundering with the butts of three clubbed handspikes on the\nforecastle deck, Daggoo roused the sleepers with such judgment claps\nthat they seemed to exhale from the scuttle, so instantaneously did\nthey appear with their clothes in their hands.\n\n\"What d'ye see?\" cried Ahab, flattening his face to the sky.\n\n\"Nothing, nothing sir!\" was the sound hailing down in reply.\n\n\"T'gallant sails!--stunsails! alow and aloft, and on both sides!\"\n\nAll sail being set, he now cast loose the life-line, reserved for\nswaying him to the main royal-mast head; and in a few moments they\nwere hoisting him thither, when, while but two thirds of the way\naloft, and while peering ahead through the horizontal vacancy between\nthe main-top-sail and top-gallant-sail, he raised a gull-like cry in\nthe air.  \"There she blows!--there she blows!  A hump like a\nsnow-hill!  It is Moby Dick!\"\n\nFired by the cry which seemed simultaneously taken up by the three\nlook-outs, the men on deck rushed to the rigging to behold the famous\nwhale they had so long been pursuing.  Ahab had now gained his final\nperch, some feet above the other look-outs, Tashtego standing just\nbeneath him on the cap of the top-gallant-mast, so that the Indian's\nhead was almost on a level with Ahab's heel.  From this height the\nwhale was now seen some mile or so ahead, at every roll of the sea\nrevealing his high sparkling hump, and regularly jetting his silent\nspout into the air.  To the credulous mariners it seemed the same\nsilent spout they had so long ago beheld in the moonlit Atlantic and\nIndian Oceans.\n\n\"And did none of ye see it before?\" cried Ahab, hailing the perched\nmen all around him.\n\n\"I saw him almost that same instant, sir, that Captain Ahab did, and\nI cried out,\" said Tashtego.\n\n\"Not the same instant; not the same--no, the doubloon is mine, Fate\nreserved the doubloon for me.  I only; none of ye could have raised\nthe White Whale first.  There she blows!--there she blows!--there\nshe blows!  There again!--there again!\" he cried, in long-drawn,\nlingering, methodic tones, attuned to the gradual prolongings of the\nwhale's visible jets.  \"He's going to sound!  In stunsails!  Down\ntop-gallant-sails!  Stand by three boats.  Mr. Starbuck, remember,\nstay on board, and keep the ship.  Helm there!  Luff, luff a point!\nSo; steady, man, steady!  There go flukes!  No, no; only black water!\nAll ready the boats there?  Stand by, stand by!  Lower me, Mr.\nStarbuck; lower, lower,--quick, quicker!\" and he slid through the air\nto the deck.\n\n\"He is heading straight to leeward, sir,\" cried Stubb, \"right away\nfrom us; cannot have seen the ship yet.\"\n\n\"Be dumb, man!  Stand by the braces!  Hard down the helm!--brace up!\nShiver her!--shiver her!--So; well that!  Boats, boats!\"\n\nSoon all the boats but Starbuck's were dropped; all the boat-sails\nset--all the paddles plying; with rippling swiftness, shooting to\nleeward; and Ahab heading the onset.  A pale, death-glimmer lit up\nFedallah's sunken eyes; a hideous motion gnawed his mouth.\n\nLike noiseless nautilus shells, their light prows sped through the\nsea; but only slowly they neared the foe.  As they neared him, the\nocean grew still more smooth; seemed drawing a carpet over its waves;\nseemed a noon-meadow, so serenely it spread.  At length the\nbreathless hunter came so nigh his seemingly unsuspecting prey, that his\nentire dazzling hump was distinctly visible, sliding along the sea as\nif an isolated thing, and continually set in a revolving ring of\nfinest, fleecy, greenish foam.  He saw the vast, involved wrinkles of\nthe slightly projecting head beyond.  Before it, far out on the soft\nTurkish-rugged waters, went the glistening white shadow from his\nbroad, milky forehead, a musical rippling playfully accompanying the\nshade; and behind, the blue waters interchangeably flowed over into\nthe moving valley of his steady wake; and on either hand bright\nbubbles arose and danced by his side.  But these were broken again by\nthe light toes of hundreds of gay fowl softly feathering the sea,\nalternate with their fitful flight; and like to some flag-staff\nrising from the painted hull of an argosy, the tall but shattered\npole of a recent lance projected from the white whale's back; and at\nintervals one of the cloud of soft-toed fowls hovering, and to and\nfro skimming like a canopy over the fish, silently perched and rocked\non this pole, the long tail feathers streaming like pennons.\n\nA gentle joyousness--a mighty mildness of repose in swiftness,\ninvested the gliding whale.  Not the white bull Jupiter swimming away\nwith ravished Europa clinging to his graceful horns; his lovely,\nleering eyes sideways intent upon the maid; with smooth bewitching\nfleetness, rippling straight for the nuptial bower in Crete; not\nJove, not that great majesty Supreme! did surpass the glorified White\nWhale as he so divinely swam.\n\nOn each soft side--coincident with the parted swell, that but once\nleaving him, then flowed so wide away--on each bright side, the whale\nshed off enticings.  No wonder there had been some among the hunters\nwho namelessly transported and allured by all this serenity, had\nventured to assail it; but had fatally found that quietude but the\nvesture of tornadoes.  Yet calm, enticing calm, oh, whale! thou\nglidest on, to all who for the first time eye thee, no matter how\nmany in that same way thou may'st have bejuggled and destroyed\nbefore.\n\nAnd thus, through the serene tranquillities of the tropical sea,\namong waves whose hand-clappings were suspended by exceeding rapture,\nMoby Dick moved on, still withholding from sight the full terrors of\nhis submerged trunk, entirely hiding the wrenched hideousness of his\njaw.  But soon the fore part of him slowly rose from the water; for\nan instant his whole marbleized body formed a high arch, like\nVirginia's Natural Bridge, and warningly waving his bannered flukes\nin the air, the grand god revealed himself, sounded, and went out of\nsight.  Hoveringly halting, and dipping on the wing, the white\nsea-fowls longingly lingered over the agitated pool that he left.\n\nWith oars apeak, and paddles down, the sheets of their sails adrift,\nthe three boats now stilly floated, awaiting Moby Dick's\nreappearance.\n\n\"An hour,\" said Ahab, standing rooted in his boat's stern; and he\ngazed beyond the whale's place, towards the dim blue spaces and wide\nwooing vacancies to leeward.  It was only an instant; for again his\neyes seemed whirling round in his head as he swept the watery circle.\nThe breeze now freshened; the sea began to swell.\n\n\"The birds!--the birds!\" cried Tashtego.\n\nIn long Indian file, as when herons take wing, the white birds were\nnow all flying towards Ahab's boat; and when within a few yards began\nfluttering over the water there, wheeling round and round, with\njoyous, expectant cries.  Their vision was keener than man's; Ahab\ncould discover no sign in the sea.  But suddenly as he peered down\nand down into its depths, he profoundly saw a white living spot no\nbigger than a white weasel, with wonderful celerity uprising, and\nmagnifying as it rose, till it turned, and then there were plainly\nrevealed two long crooked rows of white, glistening teeth, floating\nup from the undiscoverable bottom.  It was Moby Dick's open mouth and\nscrolled jaw; his vast, shadowed bulk still half blending with the\nblue of the sea.  The glittering mouth yawned beneath the boat like\nan open-doored marble tomb; and giving one sidelong sweep with his\nsteering oar, Ahab whirled the craft aside from this tremendous\napparition.  Then, calling upon Fedallah to change places with him,\nwent forward to the bows, and seizing Perth's harpoon, commanded his\ncrew to grasp their oars and stand by to stern.\n\nNow, by reason of this timely spinning round the boat upon its axis,\nits bow, by anticipation, was made to face the whale's head while yet\nunder water.  But as if perceiving this stratagem, Moby Dick, with\nthat malicious intelligence ascribed to him, sidelingly transplanted\nhimself, as it were, in an instant, shooting his pleated head\nlengthwise beneath the boat.\n\nThrough and through; through every plank and each rib, it thrilled\nfor an instant, the whale obliquely lying on his back, in the manner\nof a biting shark, slowly and feelingly taking its bows full within\nhis mouth, so that the long, narrow, scrolled lower jaw curled high\nup into the open air, and one of the teeth caught in a row-lock.  The\nbluish pearl-white of the inside of the jaw was within six inches of\nAhab's head, and reached higher than that.  In this attitude the\nWhite Whale now shook the slight cedar as a mildly cruel cat her\nmouse.  With unastonished eyes Fedallah gazed, and crossed his arms;\nbut the tiger-yellow crew were tumbling over each other's heads to\ngain the uttermost stern.\n\nAnd now, while both elastic gunwales were springing in and out, as\nthe whale dallied with the doomed craft in this devilish way; and\nfrom his body being submerged beneath the boat, he could not be\ndarted at from the bows, for the bows were almost inside of him, as\nit were; and while the other boats involuntarily paused, as before a\nquick crisis impossible to withstand, then it was that monomaniac\nAhab, furious with this tantalizing vicinity of his foe, which placed\nhim all alive and helpless in the very jaws he hated; frenzied with\nall this, he seized the long bone with his naked hands, and wildly\nstrove to wrench it from its gripe.  As now he thus vainly strove,\nthe jaw slipped from him; the frail gunwales bent in, collapsed, and\nsnapped, as both jaws, like an enormous shears, sliding further aft,\nbit the craft completely in twain, and locked themselves fast again\nin the sea, midway between the two floating wrecks.  These floated\naside, the broken ends drooping, the crew at the stern-wreck clinging\nto the gunwales, and striving to hold fast to the oars to lash them\nacross.\n\nAt that preluding moment, ere the boat was yet snapped, Ahab, the\nfirst to perceive the whale's intent, by the crafty upraising of his\nhead, a movement that loosed his hold for the time; at that moment\nhis hand had made one final effort to push the boat out of the bite.\nBut only slipping further into the whale's mouth, and tilting over\nsideways as it slipped, the boat had shaken off his hold on the jaw;\nspilled him out of it, as he leaned to the push; and so he fell\nflat-faced upon the sea.\n\nRipplingly withdrawing from his prey, Moby Dick now lay at a little\ndistance, vertically thrusting his oblong white head up and down in\nthe billows; and at the same time slowly revolving his whole spindled\nbody; so that when his vast wrinkled forehead rose--some twenty or\nmore feet out of the water--the now rising swells, with all their\nconfluent waves, dazzlingly broke against it; vindictively tossing\ntheir shivered spray still higher into the air.*  So, in a gale, the\nbut half baffled Channel billows only recoil from the base of the\nEddystone, triumphantly to overleap its summit with their scud.\n\n\n*This motion is peculiar to the sperm whale.  It receives its\ndesignation (pitchpoling) from its being likened to that preliminary\nup-and-down poise of the whale-lance, in the exercise called\npitchpoling, previously described.  By this motion the whale must\nbest and most comprehensively view whatever objects may be encircling\nhim.\n\n\nBut soon resuming his horizontal attitude, Moby Dick swam swiftly\nround and round the wrecked crew; sideways churning the water in his\nvengeful wake, as if lashing himself up to still another and more\ndeadly assault.  The sight of the splintered boat seemed to madden\nhim, as the blood of grapes and mulberries cast before Antiochus's\nelephants in the book of Maccabees.  Meanwhile Ahab half smothered in\nthe foam of the whale's insolent tail, and too much of a cripple to\nswim,--though he could still keep afloat, even in the heart of such a\nwhirlpool as that; helpless Ahab's head was seen, like a tossed\nbubble which the least chance shock might burst.  From the boat's\nfragmentary stern, Fedallah incuriously and mildly eyed him; the\nclinging crew, at the other drifting end, could not succor him; more\nthan enough was it for them to look to themselves.  For so\nrevolvingly appalling was the White Whale's aspect, and so\nplanetarily swift the ever-contracting circles he made, that he\nseemed horizontally swooping upon them.  And though the other boats,\nunharmed, still hovered hard by; still they dared not pull into the\neddy to strike, lest that should be the signal for the instant\ndestruction of the jeopardized castaways, Ahab and all; nor in that\ncase could they themselves hope to escape.  With straining eyes,\nthen, they remained on the outer edge of the direful zone, whose\ncentre had now become the old man's head.\n\nMeantime, from the beginning all this had been descried from the\nship's mast heads; and squaring her yards, she had borne down upon\nthe scene; and was now so nigh, that Ahab in the water hailed\nher!--\"Sail on the\"--but that moment a breaking sea dashed on him\nfrom Moby Dick, and whelmed him for the time.  But struggling out of\nit again, and chancing to rise on a towering crest, he\nshouted,--\"Sail on the whale!--Drive him off!\"\n\nThe Pequod's prows were pointed; and breaking up the charmed circle,\nshe effectually parted the white whale from his victim.  As he\nsullenly swam off, the boats flew to the rescue.\n\nDragged into Stubb's boat with blood-shot, blinded eyes, the white\nbrine caking in his wrinkles; the long tension of Ahab's bodily\nstrength did crack, and helplessly he yielded to his body's doom: for\na time, lying all crushed in the bottom of Stubb's boat, like one\ntrodden under foot of herds of elephants.  Far inland, nameless wails\ncame from him, as desolate sounds from out ravines.\n\nBut this intensity of his physical prostration did but so much the\nmore abbreviate it.  In an instant's compass, great hearts sometimes\ncondense to one deep pang, the sum total of those shallow pains\nkindly diffused through feebler men's whole lives.  And so, such\nhearts, though summary in each one suffering; still, if the gods\ndecree it, in their life-time aggregate a whole age of woe, wholly\nmade up of instantaneous intensities; for even in their pointless\ncentres, those noble natures contain the entire circumferences of\ninferior souls.\n\n\"The harpoon,\" said Ahab, half way rising, and draggingly leaning on\none bended arm--\"is it safe?\"\n\n\"Aye, sir, for it was not darted; this is it,\" said Stubb, showing\nit.\n\n\"Lay it before me;--any missing men?\"\n\n\"One, two, three, four, five;--there were five oars, sir, and here\nare five men.\"\n\n\"That's good.--Help me, man; I wish to stand.  So, so, I see him!\nthere! there! going to leeward still; what a leaping spout!--Hands\noff from me!  The eternal sap runs up in Ahab's bones again!  Set the\nsail; out oars; the helm!\"\n\nIt is often the case that when a boat is stove, its crew, being\npicked up by another boat, help to work that second boat; and the\nchase is thus continued with what is called double-banked oars.  It\nwas thus now.  But the added power of the boat did not equal the\nadded power of the whale, for he seemed to have treble-banked his\nevery fin; swimming with a velocity which plainly showed, that if\nnow, under these circumstances, pushed on, the chase would prove an\nindefinitely prolonged, if not a hopeless one; nor could any crew\nendure for so long a period, such an unintermitted, intense straining\nat the oar; a thing barely tolerable only in some one brief\nvicissitude.  The ship itself, then, as it sometimes happens, offered\nthe most promising intermediate means of overtaking the chase.\nAccordingly, the boats now made for her, and were soon swayed up to\ntheir cranes--the two parts of the wrecked boat having been\npreviously secured by her--and then hoisting everything to her side,\nand stacking her canvas high up, and sideways outstretching it with\nstun-sails, like the double-jointed wings of an albatross; the Pequod\nbore down in the leeward wake of Moby-Dick.  At the well known,\nmethodic intervals, the whale's glittering spout was regularly\nannounced from the manned mast-heads; and when he would be reported\nas just gone down, Ahab would take the time, and then pacing the\ndeck, binnacle-watch in hand, so soon as the last second of the\nallotted hour expired, his voice was heard.--\"Whose is the doubloon\nnow?  D'ye see him?\" and if the reply was, No, sir! straightway he\ncommanded them to lift him to his perch.  In this way the day wore\non; Ahab, now aloft and motionless; anon, unrestingly pacing the\nplanks.\n\nAs he was thus walking, uttering no sound, except to hail the men\naloft, or to bid them hoist a sail still higher, or to spread one to\na still greater breadth--thus to and fro pacing, beneath his slouched\nhat, at every turn he passed his own wrecked boat, which had been\ndropped upon the quarter-deck, and lay there reversed; broken bow to\nshattered stern.  At last he paused before it; and as in an already\nover-clouded sky fresh troops of clouds will sometimes sail across,\nso over the old man's face there now stole some such added gloom as\nthis.\n\nStubb saw him pause; and perhaps intending, not vainly, though, to\nevince his own unabated fortitude, and thus keep up a valiant place\nin his Captain's mind, he advanced, and eyeing the wreck\nexclaimed--\"The thistle the ass refused; it pricked his mouth too\nkeenly, sir; ha! ha!\"\n\n\"What soulless thing is this that laughs before a wreck?  Man, man!\ndid I not know thee brave as fearless fire (and as mechanical) I\ncould swear thou wert a poltroon.  Groan nor laugh should be heard\nbefore a wreck.\"\n\n\"Aye, sir,\" said Starbuck drawing near, \"'tis a solemn sight; an\nomen, and an ill one.\"\n\n\"Omen? omen?--the dictionary!  If the gods think to speak outright to\nman, they will honourably speak outright; not shake their heads, and\ngive an old wives' darkling hint.--Begone!  Ye two are the opposite\npoles of one thing; Starbuck is Stubb reversed, and Stubb is\nStarbuck; and ye two are all mankind; and Ahab stands alone among the\nmillions of the peopled earth, nor gods nor men his neighbors!  Cold,\ncold--I shiver!--How now?  Aloft there!  D'ye see him?  Sing out for\nevery spout, though he spout ten times a second!\"\n\nThe day was nearly done; only the hem of his golden robe was\nrustling.  Soon, it was almost dark, but the look-out men still\nremained unset.\n\n\"Can't see the spout now, sir;--too dark\"--cried a voice from the\nair.\n\n\"How heading when last seen?\"\n\n\"As before, sir,--straight to leeward.\"\n\n\"Good! he will travel slower now 'tis night.  Down royals and\ntop-gallant stun-sails, Mr. Starbuck.  We must not run over him\nbefore morning; he's making a passage now, and may heave-to a while.\nHelm there! keep her full before the wind!--Aloft! come down!--Mr.\nStubb, send a fresh hand to the fore-mast head, and see it manned\ntill morning.\"--Then advancing towards the doubloon in the\nmain-mast--\"Men, this gold is mine, for I earned it; but I shall let\nit abide here till the White Whale is dead; and then, whosoever of ye\nfirst raises him, upon the day he shall be killed, this gold is that\nman's; and if on that day I shall again raise him, then, ten times\nits sum shall be divided among all of ye!  Away now!--the deck is\nthine, sir!\"\n\nAnd so saying, he placed himself half way within the scuttle, and\nslouching his hat, stood there till dawn, except when at intervals\nrousing himself to see how the night wore on.\n\n\n\nCHAPTER 134\n\nThe Chase--Second Day.\n\n\nAt day-break, the three mast-heads were punctually manned afresh.\n\n\"D'ye see him?\" cried Ahab after allowing a little space for the\nlight to spread.\n\n\"See nothing, sir.\"\n\n\"Turn up all hands and make sail! he travels faster than I thought\nfor;--the top-gallant sails!--aye, they should have been kept on her\nall night.  But no matter--'tis but resting for the rush.\"\n\nHere be it said, that this pertinacious pursuit of one particular\nwhale, continued through day into night, and through night into day,\nis a thing by no means unprecedented in the South sea fishery.  For\nsuch is the wonderful skill, prescience of experience, and invincible\nconfidence acquired by some great natural geniuses among the\nNantucket commanders; that from the simple observation of a whale\nwhen last descried, they will, under certain given circumstances,\npretty accurately foretell both the direction in which he will\ncontinue to swim for a time, while out of sight, as well as his\nprobable rate of progression during that period.  And, in these\ncases, somewhat as a pilot, when about losing sight of a coast, whose\ngeneral trending he well knows, and which he desires shortly to\nreturn to again, but at some further point; like as this pilot stands\nby his compass, and takes the precise bearing of the cape at present\nvisible, in order the more certainly to hit aright the remote, unseen\nheadland, eventually to be visited: so does the fisherman, at his\ncompass, with the whale; for after being chased, and diligently\nmarked, through several hours of daylight, then, when night obscures\nthe fish, the creature's future wake through the darkness is almost\nas established to the sagacious mind of the hunter, as the pilot's\ncoast is to him.  So that to this hunter's wondrous skill, the\nproverbial evanescence of a thing writ in water, a wake, is to all\ndesired purposes well nigh as reliable as the steadfast land.  And as\nthe mighty iron Leviathan of the modern railway is so familiarly\nknown in its every pace, that, with watches in their hands, men time\nhis rate as doctors that of a baby's pulse; and lightly say of it,\nthe up train or the down train will reach such or such a spot, at\nsuch or such an hour; even so, almost, there are occasions when these\nNantucketers time that other Leviathan of the deep, according to the\nobserved humor of his speed; and say to themselves, so many hours\nhence this whale will have gone two hundred miles, will have about\nreached this or that degree of latitude or longitude.  But to render\nthis acuteness at all successful in the end, the wind and the sea\nmust be the whaleman's allies; for of what present avail to the\nbecalmed or windbound mariner is the skill that assures him he is\nexactly ninety-three leagues and a quarter from his port?  Inferable\nfrom these statements, are many collateral subtile matters touching\nthe chase of whales.\n\nThe ship tore on; leaving such a furrow in the sea as when a\ncannon-ball, missent, becomes a plough-share and turns up the level\nfield.\n\n\"By salt and hemp!\" cried Stubb, \"but this swift motion of the deck\ncreeps up one's legs and tingles at the heart.  This ship and I are\ntwo brave fellows!--Ha, ha!  Some one take me up, and launch me,\nspine-wise, on the sea,--for by live-oaks! my spine's a keel.  Ha,\nha! we go the gait that leaves no dust behind!\"\n\n\"There she blows--she blows!--she blows!--right ahead!\" was now the\nmast-head cry.\n\n\"Aye, aye!\" cried Stubb, \"I knew it--ye can't escape--blow on and\nsplit your spout, O whale! the mad fiend himself is after ye! blow\nyour trump--blister your lungs!--Ahab will dam off your blood, as a\nmiller shuts his watergate upon the stream!\"\n\nAnd Stubb did but speak out for well nigh all that crew.  The\nfrenzies of the chase had by this time worked them bubblingly up,\nlike old wine worked anew.  Whatever pale fears and forebodings some\nof them might have felt before; these were not only now kept out of\nsight through the growing awe of Ahab, but they were broken up, and\non all sides routed, as timid prairie hares that scatter before the\nbounding bison.  The hand of Fate had snatched all their souls; and\nby the stirring perils of the previous day; the rack of the past\nnight's suspense; the fixed, unfearing, blind, reckless way in which\ntheir wild craft went plunging towards its flying mark; by all these\nthings, their hearts were bowled along.  The wind that made great\nbellies of their sails, and rushed the vessel on by arms invisible as\nirresistible; this seemed the symbol of that unseen agency which so\nenslaved them to the race.\n\nThey were one man, not thirty.  For as the one ship that held them\nall; though it was put together of all contrasting things--oak, and\nmaple, and pine wood; iron, and pitch, and hemp--yet all these ran\ninto each other in the one concrete hull, which shot on its way, both\nbalanced and directed by the long central keel; even so, all the\nindividualities of the crew, this man's valor, that man's fear; guilt\nand guiltiness, all varieties were welded into oneness, and were all\ndirected to that fatal goal which Ahab their one lord and keel did\npoint to.\n\nThe rigging lived.  The mast-heads, like the tops of tall palms, were\noutspreadingly tufted with arms and legs.  Clinging to a spar with\none hand, some reached forth the other with impatient wavings;\nothers, shading their eyes from the vivid sunlight, sat far out on\nthe rocking yards; all the spars in full bearing of mortals, ready\nand ripe for their fate.  Ah! how they still strove through that\ninfinite blueness to seek out the thing that might destroy them!\n\n\"Why sing ye not out for him, if ye see him?\" cried Ahab, when, after\nthe lapse of some minutes since the first cry, no more had been\nheard.  \"Sway me up, men; ye have been deceived; not Moby Dick casts\none odd jet that way, and then disappears.\"\n\nIt was even so; in their headlong eagerness, the men had mistaken\nsome other thing for the whale-spout, as the event itself soon\nproved; for hardly had Ahab reached his perch; hardly was the rope\nbelayed to its pin on deck, when he struck the key-note to an\norchestra, that made the air vibrate as with the combined discharges\nof rifles.  The triumphant halloo of thirty buckskin lungs was heard,\nas--much nearer to the ship than the place of the imaginary jet, less\nthan a mile ahead--Moby Dick bodily burst into view!  For not by any\ncalm and indolent spoutings; not by the peaceable gush of that mystic\nfountain in his head, did the White Whale now reveal his vicinity;\nbut by the far more wondrous phenomenon of breaching.  Rising with\nhis utmost velocity from the furthest depths, the Sperm Whale thus\nbooms his entire bulk into the pure element of air, and piling up a\nmountain of dazzling foam, shows his place to the distance of seven\nmiles and more.  In those moments, the torn, enraged waves he shakes\noff, seem his mane; in some cases, this breaching is his act of\ndefiance.\n\n\"There she breaches! there she breaches!\" was the cry, as in his\nimmeasurable bravadoes the White Whale tossed himself salmon-like to\nHeaven.  So suddenly seen in the blue plain of the sea, and relieved\nagainst the still bluer margin of the sky, the spray that he raised,\nfor the moment, intolerably glittered and glared like a glacier; and\nstood there gradually fading and fading away from its first sparkling\nintensity, to the dim mistiness of an advancing shower in a vale.\n\n\"Aye, breach your last to the sun, Moby Dick!\" cried Ahab, \"thy hour\nand thy harpoon are at hand!--Down! down all of ye, but one man at\nthe fore.  The boats!--stand by!\"\n\nUnmindful of the tedious rope-ladders of the shrouds, the men, like\nshooting stars, slid to the deck, by the isolated backstays and\nhalyards; while Ahab, less dartingly, but still rapidly was dropped\nfrom his perch.\n\n\"Lower away,\" he cried, so soon as he had reached his boat--a spare\none, rigged the afternoon previous.  \"Mr. Starbuck, the ship is\nthine--keep away from the boats, but keep near them.  Lower, all!\"\n\nAs if to strike a quick terror into them, by this time being the\nfirst assailant himself, Moby Dick had turned, and was now coming for\nthe three crews.  Ahab's boat was central; and cheering his men, he\ntold them he would take the whale head-and-head,--that is, pull\nstraight up to his forehead,--a not uncommon thing; for when within a\ncertain limit, such a course excludes the coming onset from the\nwhale's sidelong vision.  But ere that close limit was gained, and\nwhile yet all three boats were plain as the ship's three masts to his\neye; the White Whale churning himself into furious speed, almost in\nan instant as it were, rushing among the boats with open jaws, and a\nlashing tail, offered appalling battle on every side; and heedless of\nthe irons darted at him from every boat, seemed only intent on\nannihilating each separate plank of which those boats were made.  But\nskilfully manoeuvred, incessantly wheeling like trained chargers in\nthe field; the boats for a while eluded him; though, at times, but by\na plank's breadth; while all the time, Ahab's unearthly slogan tore\nevery other cry but his to shreds.\n\nBut at last in his untraceable evolutions, the White Whale so crossed\nand recrossed, and in a thousand ways entangled the slack of the\nthree lines now fast to him, that they foreshortened, and, of\nthemselves, warped the devoted boats towards the planted irons in\nhim; though now for a moment the whale drew aside a little, as if to\nrally for a more tremendous charge.  Seizing that opportunity, Ahab\nfirst paid out more line: and then was rapidly hauling and jerking\nin upon it again--hoping that way to disencumber it of some\nsnarls--when lo!--a sight more savage than the embattled teeth of\nsharks!\n\nCaught and twisted--corkscrewed in the mazes of the line, loose\nharpoons and lances, with all their bristling barbs and points, came\nflashing and dripping up to the chocks in the bows of Ahab's boat.\nOnly one thing could be done.  Seizing the boat-knife, he critically\nreached within--through--and then, without--the rays of steel;\ndragged in the line beyond, passed it, inboard, to the bowsman, and\nthen, twice sundering the rope near the chocks--dropped the\nintercepted fagot of steel into the sea; and was all fast again.\nThat instant, the White Whale made a sudden rush among the remaining\ntangles of the other lines; by so doing, irresistibly dragged the\nmore involved boats of Stubb and Flask towards his flukes; dashed\nthem together like two rolling husks on a surf-beaten beach, and\nthen, diving down into the sea, disappeared in a boiling maelstrom,\nin which, for a space, the odorous cedar chips of the wrecks danced\nround and round, like the grated nutmeg in a swiftly stirred bowl of\npunch.\n\nWhile the two crews were yet circling in the waters, reaching out\nafter the revolving line-tubs, oars, and other floating furniture,\nwhile aslope little Flask bobbed up and down like an empty vial,\ntwitching his legs upwards to escape the dreaded jaws of sharks; and\nStubb was lustily singing out for some one to ladle him up; and while\nthe old man's line--now parting--admitted of his pulling into the\ncreamy pool to rescue whom he could;--in that wild simultaneousness\nof a thousand concreted perils,--Ahab's yet unstricken boat seemed\ndrawn up towards Heaven by invisible wires,--as, arrow-like, shooting\nperpendicularly from the sea, the White Whale dashed his broad\nforehead against its bottom, and sent it, turning over and over, into\nthe air; till it fell again--gunwale downwards--and Ahab and his men\nstruggled out from under it, like seals from a sea-side cave.\n\nThe first uprising momentum of the whale--modifying its direction as\nhe struck the surface--involuntarily launched him along it, to a\nlittle distance from the centre of the destruction he had made; and\nwith his back to it, he now lay for a moment slowly feeling with his\nflukes from side to side; and whenever a stray oar, bit of plank, the\nleast chip or crumb of the boats touched his skin, his tail swiftly\ndrew back, and came sideways smiting the sea.  But soon, as if\nsatisfied that his work for that time was done, he pushed his pleated\nforehead through the ocean, and trailing after him the intertangled\nlines, continued his leeward way at a traveller's methodic pace.\n\nAs before, the attentive ship having descried the whole fight, again\ncame bearing down to the rescue, and dropping a boat, picked up the\nfloating mariners, tubs, oars, and whatever else could be caught at,\nand safely landed them on her decks.  Some sprained shoulders,\nwrists, and ankles; livid contusions; wrenched harpoons and lances;\ninextricable intricacies of rope; shattered oars and planks; all\nthese were there; but no fatal or even serious ill seemed to have\nbefallen any one.  As with Fedallah the day before, so Ahab was now\nfound grimly clinging to his boat's broken half, which afforded a\ncomparatively easy float; nor did it so exhaust him as the previous\nday's mishap.\n\nBut when he was helped to the deck, all eyes were fastened upon him;\nas instead of standing by himself he still half-hung upon the\nshoulder of Starbuck, who had thus far been the foremost to assist\nhim.  His ivory leg had been snapped off, leaving but one short sharp\nsplinter.\n\n\"Aye, aye, Starbuck, 'tis sweet to lean sometimes, be the leaner who\nhe will; and would old Ahab had leaned oftener than he has.\"\n\n\"The ferrule has not stood, sir,\" said the carpenter, now coming up;\n\"I put good work into that leg.\"\n\n\"But no bones broken, sir, I hope,\" said Stubb with true concern.\n\n\"Aye! and all splintered to pieces, Stubb!--d'ye see it.--But even\nwith a broken bone, old Ahab is untouched; and I account no living\nbone of mine one jot more me, than this dead one that's lost.  Nor\nwhite whale, nor man, nor fiend, can so much as graze old Ahab in his\nown proper and inaccessible being.  Can any lead touch yonder floor,\nany mast scrape yonder roof?--Aloft there! which way?\"\n\n\"Dead to leeward, sir.\"\n\n\"Up helm, then; pile on the sail again, ship keepers! down the rest\nof the spare boats and rig them--Mr. Starbuck away, and muster the\nboat's crews.\"\n\n\"Let me first help thee towards the bulwarks, sir.\"\n\n\"Oh, oh, oh! how this splinter gores me now!  Accursed fate! that the\nunconquerable captain in the soul should have such a craven mate!\"\n\n\"Sir?\"\n\n\"My body, man, not thee.  Give me something for a cane--there, that\nshivered lance will do.  Muster the men.  Surely I have not seen him\nyet.  By heaven it cannot be!--missing?--quick! call them all.\"\n\nThe old man's hinted thought was true.  Upon mustering the company,\nthe Parsee was not there.\n\n\"The Parsee!\" cried Stubb--\"he must have been caught in--\"\n\n\"The black vomit wrench thee!--run all of ye above, alow, cabin,\nforecastle--find him--not gone--not gone!\"\n\nBut quickly they returned to him with the tidings that the Parsee was\nnowhere to be found.\n\n\"Aye, sir,\" said Stubb--\"caught among the tangles of your line--I\nthought I saw him dragging under.\"\n\n\"MY line! MY line?  Gone?--gone?  What means that little word?--What\ndeath-knell rings in it, that old Ahab shakes as if he were the\nbelfry.  The harpoon, too!--toss over the litter there,--d'ye see\nit?--the forged iron, men, the white whale's--no, no, no,--blistered\nfool! this hand did dart it!--'tis in the fish!--Aloft there!  Keep\nhim nailed--Quick!--all hands to the rigging of the boats--collect\nthe oars--harpooneers! the irons, the irons!--hoist the royals higher--a\npull on all the sheets!--helm there! steady, steady for your life!\nI'll ten times girdle the unmeasured globe; yea and dive straight\nthrough it, but I'll slay him yet!\n\n\"Great God! but for one single instant show thyself,\" cried Starbuck;\n\"never, never wilt thou capture him, old man--In Jesus' name no more\nof this, that's worse than devil's madness.  Two days chased; twice\nstove to splinters; thy very leg once more snatched from under thee;\nthy evil shadow gone--all good angels mobbing thee with warnings:--\nwhat more wouldst thou have?--Shall we keep chasing this murderous\nfish till he swamps the last man?  Shall we be dragged by him to the\nbottom of the sea?  Shall we be towed by him to the infernal world?\nOh, oh,--Impiety and blasphemy to hunt him more!\"\n\n\"Starbuck, of late I've felt strangely moved to thee; ever since that\nhour we both saw--thou know'st what, in one another's eyes.  But in\nthis matter of the whale, be the front of thy face to me as the palm\nof this hand--a lipless, unfeatured blank.  Ahab is for ever Ahab,\nman.  This whole act's immutably decreed.  'Twas rehearsed by thee\nand me a billion years before this ocean rolled.  Fool!  I am the\nFates' lieutenant; I act under orders.  Look thou, underling! that\nthou obeyest mine.--Stand round me, men.  Ye see an old man cut down\nto the stump; leaning on a shivered lance; propped up on a lonely\nfoot.  'Tis Ahab--his body's part; but Ahab's soul's a centipede,\nthat moves upon a hundred legs.  I feel strained, half stranded, as\nropes that tow dismasted frigates in a gale; and I may look so.  But\nere I break, yell hear me crack; and till ye hear THAT, know that\nAhab's hawser tows his purpose yet.  Believe ye, men, in the things\ncalled omens?  Then laugh aloud, and cry encore!  For ere they drown,\ndrowning things will twice rise to the surface; then rise again, to\nsink for evermore.  So with Moby Dick--two days he's floated--tomorrow\nwill be the third.  Aye, men, he'll rise once more,--but only to\nspout his last!  D'ye feel brave men, brave?\"\n\n\"As fearless fire,\" cried Stubb.\n\n\"And as mechanical,\" muttered Ahab.  Then as the men went forward, he\nmuttered on: \"The things called omens!  And yesterday I talked the\nsame to Starbuck there, concerning my broken boat.  Oh! how valiantly\nI seek to drive out of others' hearts what's clinched so fast in\nmine!--The Parsee--the Parsee!--gone, gone? and he was to go\nbefore:--but still was to be seen again ere I could perish--How's\nthat?--There's a riddle now might baffle all the lawyers backed by\nthe ghosts of the whole line of judges:--like a hawk's beak it pecks\nmy brain.  I'LL, I'LL solve it, though!\"\n\nWhen dusk descended, the whale was still in sight to leeward.\n\nSo once more the sail was shortened, and everything passed nearly as\non the previous night; only, the sound of hammers, and the hum of the\ngrindstone was heard till nearly daylight, as the men toiled by\nlanterns in the complete and careful rigging of the spare boats and\nsharpening their fresh weapons for the morrow.  Meantime, of the\nbroken keel of Ahab's wrecked craft the carpenter made him another\nleg; while still as on the night before, slouched Ahab stood fixed\nwithin his scuttle; his hid, heliotrope glance anticipatingly gone\nbackward on its dial; sat due eastward for the earliest sun.\n\n\n\nCHAPTER 135\n\nThe Chase.--Third Day.\n\n\nThe morning of the third day dawned fair and fresh, and once more the\nsolitary night-man at the fore-mast-head was relieved by crowds of\nthe daylight look-outs, who dotted every mast and almost every spar.\n\n\"D'ye see him?\" cried Ahab; but the whale was not yet in sight.\n\n\"In his infallible wake, though; but follow that wake, that's all.\nHelm there; steady, as thou goest, and hast been going.  What a\nlovely day again! were it a new-made world, and made for a\nsummer-house to the angels, and this morning the first of its\nthrowing open to them, a fairer day could not dawn upon that world.\nHere's food for thought, had Ahab time to think; but Ahab never\nthinks; he only feels, feels, feels; THAT'S tingling enough for\nmortal man! to think's audacity.  God only has that right and\nprivilege.  Thinking is, or ought to be, a coolness and a calmness;\nand our poor hearts throb, and our poor brains beat too much for\nthat.  And yet, I've sometimes thought my brain was very calm--frozen\ncalm, this old skull cracks so, like a glass in which the contents\nturned to ice, and shiver it.  And still this hair is growing now;\nthis moment growing, and heat must breed it; but no, it's like that\nsort of common grass that will grow anywhere, between the earthy\nclefts of Greenland ice or in Vesuvius lava.  How the wild winds blow\nit; they whip it about me as the torn shreds of split sails lash the\ntossed ship they cling to.  A vile wind that has no doubt blown ere\nthis through prison corridors and cells, and wards of hospitals, and\nventilated them, and now comes blowing hither as innocent as fleeces.\nOut upon it!--it's tainted.  Were I the wind, I'd blow no more on\nsuch a wicked, miserable world.  I'd crawl somewhere to a cave, and\nslink there.  And yet, 'tis a noble and heroic thing, the wind! who\never conquered it?  In every fight it has the last and bitterest\nblow.  Run tilting at it, and you but run through it.  Ha! a coward\nwind that strikes stark naked men, but will not stand to receive a\nsingle blow.  Even Ahab is a braver thing--a nobler thing than THAT.\nWould now the wind but had a body; but all the things that most\nexasperate and outrage mortal man, all these things are bodiless, but\nonly bodiless as objects, not as agents.  There's a most special, a\nmost cunning, oh, a most malicious difference!  And yet, I say again,\nand swear it now, that there's something all glorious and gracious in\nthe wind.  These warm Trade Winds, at least, that in the clear\nheavens blow straight on, in strong and steadfast, vigorous mildness;\nand veer not from their mark, however the baser currents of the sea\nmay turn and tack, and mightiest Mississippies of the land swift and\nswerve about, uncertain where to go at last.  And by the eternal\nPoles! these same Trades that so directly blow my good ship on; these\nTrades, or something like them--something so unchangeable, and full\nas strong, blow my keeled soul along!  To it!  Aloft there!  What\nd'ye see?\"\n\n\"Nothing, sir.\"\n\n\"Nothing! and noon at hand!  The doubloon goes a-begging!  See the\nsun!  Aye, aye, it must be so.  I've oversailed him.  How, got the\nstart?  Aye, he's chasing ME now; not I, HIM--that's bad; I might\nhave known it, too.  Fool! the lines--the harpoons he's towing.  Aye,\naye, I have run him by last night.  About! about!  Come down, all of\nye, but the regular look outs!  Man the braces!\"\n\nSteering as she had done, the wind had been somewhat on the Pequod's\nquarter, so that now being pointed in the reverse direction, the\nbraced ship sailed hard upon the breeze as she rechurned the cream in\nher own white wake.\n\n\"Against the wind he now steers for the open jaw,\" murmured Starbuck\nto himself, as he coiled the new-hauled main-brace upon the rail.\n\"God keep us, but already my bones feel damp within me, and from the\ninside wet my flesh.  I misdoubt me that I disobey my God in obeying\nhim!\"\n\n\"Stand by to sway me up!\" cried Ahab, advancing to the hempen basket.\n\"We should meet him soon.\"\n\n\"Aye, aye, sir,\" and straightway Starbuck did Ahab's bidding, and\nonce more Ahab swung on high.\n\nA whole hour now passed; gold-beaten out to ages.  Time itself now\nheld long breaths with keen suspense.  But at last, some three points\noff the weather bow, Ahab descried the spout again, and instantly\nfrom the three mast-heads three shrieks went up as if the tongues of\nfire had voiced it.\n\n\"Forehead to forehead I meet thee, this third time, Moby Dick!  On\ndeck there!--brace sharper up; crowd her into the wind's eye.  He's\ntoo far off to lower yet, Mr. Starbuck.  The sails shake!  Stand over\nthat helmsman with a top-maul!  So, so; he travels fast, and I must\ndown.  But let me have one more good round look aloft here at the\nsea; there's time for that.  An old, old sight, and yet somehow so\nyoung; aye, and not changed a wink since I first saw it, a boy, from\nthe sand-hills of Nantucket!  The same!--the same!--the same to Noah\nas to me.  There's a soft shower to leeward.  Such lovely\nleewardings!  They must lead somewhere--to something else than common\nland, more palmy than the palms.  Leeward! the white whale goes that\nway; look to windward, then; the better if the bitterer quarter.  But\ngood bye, good bye, old mast-head!  What's this?--green? aye, tiny\nmosses in these warped cracks.  No such green weather stains on\nAhab's head!  There's the difference now between man's old age and\nmatter's.  But aye, old mast, we both grow old together; sound in our\nhulls, though, are we not, my ship?  Aye, minus a leg, that's all.\nBy heaven this dead wood has the better of my live flesh every way.\nI can't compare with it; and I've known some ships made of dead trees\noutlast the lives of men made of the most vital stuff of vital\nfathers.  What's that he said? he should still go before me, my\npilot; and yet to be seen again?  But where?  Will I have eyes at the\nbottom of the sea, supposing I descend those endless stairs? and all\nnight I've been sailing from him, wherever he did sink to.  Aye, aye,\nlike many more thou told'st direful truth as touching thyself, O\nParsee; but, Ahab, there thy shot fell short.  Good-bye,\nmast-head--keep a good eye upon the whale, the while I'm gone.  We'll\ntalk to-morrow, nay, to-night, when the white whale lies down there,\ntied by head and tail.\"\n\nHe gave the word; and still gazing round him, was steadily lowered\nthrough the cloven blue air to the deck.\n\nIn due time the boats were lowered; but as standing in his shallop's\nstern, Ahab just hovered upon the point of the descent, he waved to\nthe mate,--who held one of the tackle-ropes on deck--and bade him\npause.\n\n\"Starbuck!\"\n\n\"Sir?\"\n\n\"For the third time my soul's ship starts upon this voyage,\nStarbuck.\"\n\n\"Aye, sir, thou wilt have it so.\"\n\n\"Some ships sail from their ports, and ever afterwards are missing,\nStarbuck!\"\n\n\"Truth, sir: saddest truth.\"\n\n\"Some men die at ebb tide; some at low water; some at the full of the\nflood;--and I feel now like a billow that's all one crested comb,\nStarbuck.  I am old;--shake hands with me, man.\"\n\nTheir hands met; their eyes fastened; Starbuck's tears the glue.\n\n\"Oh, my captain, my captain!--noble heart--go not--go not!--see, it's\na brave man that weeps; how great the agony of the persuasion then!\"\n\n\"Lower away!\"--cried Ahab, tossing the mate's arm from him.  \"Stand\nby the crew!\"\n\nIn an instant the boat was pulling round close under the stern.\n\n\"The sharks! the sharks!\" cried a voice from the low cabin-window\nthere; \"O master, my master, come back!\"\n\nBut Ahab heard nothing; for his own voice was high-lifted then; and\nthe boat leaped on.\n\nYet the voice spake true; for scarce had he pushed from the ship,\nwhen numbers of sharks, seemingly rising from out the dark waters\nbeneath the hull, maliciously snapped at the blades of the oars,\nevery time they dipped in the water; and in this way accompanied the\nboat with their bites.  It is a thing not uncommonly happening to the\nwhale-boats in those swarming seas; the sharks at times apparently\nfollowing them in the same prescient way that vultures hover over the\nbanners of marching regiments in the east.  But these were the first\nsharks that had been observed by the Pequod since the White Whale had\nbeen first descried; and whether it was that Ahab's crew were all\nsuch tiger-yellow barbarians, and therefore their flesh more musky to\nthe senses of the sharks--a matter sometimes well known to affect\nthem,--however it was, they seemed to follow that one boat without\nmolesting the others.\n\n\"Heart of wrought steel!\" murmured Starbuck gazing over the side, and\nfollowing with his eyes the receding boat--\"canst thou yet ring\nboldly to that sight?--lowering thy keel among ravening sharks, and\nfollowed by them, open-mouthed to the chase; and this the critical\nthird day?--For when three days flow together in one continuous\nintense pursuit; be sure the first is the morning, the second the\nnoon, and the third the evening and the end of that thing--be that\nend what it may.  Oh! my God! what is this that shoots through me,\nand leaves me so deadly calm, yet expectant,--fixed at the top of a\nshudder!  Future things swim before me, as in empty outlines and\nskeletons; all the past is somehow grown dim.  Mary, girl! thou\nfadest in pale glories behind me; boy!  I seem to see but thy eyes\ngrown wondrous blue.  Strangest problems of life seem clearing; but\nclouds sweep between--Is my journey's end coming?  My legs feel\nfaint; like his who has footed it all day.  Feel thy heart,--beats\nit yet?  Stir thyself, Starbuck!--stave it off--move, move! speak\naloud!--Mast-head there!  See ye my boy's hand on the\nhill?--Crazed;--aloft there!--keep thy keenest eye upon the boats:--\nmark well the whale!--Ho! again!--drive off that hawk! see! he\npecks--he tears the vane\"--pointing to the red flag flying at the\nmain-truck--\"Ha! he soars away with it!--Where's the old man now?\nsee'st thou that sight, oh Ahab!--shudder, shudder!\"\n\nThe boats had not gone very far, when by a signal from the\nmast-heads--a downward pointed arm, Ahab knew that the whale had\nsounded; but intending to be near him at the next rising, he held on\nhis way a little sideways from the vessel; the becharmed crew\nmaintaining the profoundest silence, as the head-beat waves hammered\nand hammered against the opposing bow.\n\n\"Drive, drive in your nails, oh ye waves! to their uttermost heads\ndrive them in! ye but strike a thing without a lid; and no coffin and\nno hearse can be mine:--and hemp only can kill me!  Ha! ha!\"\n\nSuddenly the waters around them slowly swelled in broad circles; then\nquickly upheaved, as if sideways sliding from a submerged berg of\nice, swiftly rising to the surface.  A low rumbling sound was heard;\na subterraneous hum; and then all held their breaths; as bedraggled\nwith trailing ropes, and harpoons, and lances, a vast form shot\nlengthwise, but obliquely from the sea.  Shrouded in a thin drooping\nveil of mist, it hovered for a moment in the rainbowed air; and then\nfell swamping back into the deep.  Crushed thirty feet upwards, the\nwaters flashed for an instant like heaps of fountains, then brokenly\nsank in a shower of flakes, leaving the circling surface creamed like\nnew milk round the marble trunk of the whale.\n\n\"Give way!\" cried Ahab to the oarsmen, and the boats darted forward\nto the attack; but maddened by yesterday's fresh irons that corroded\nin him, Moby Dick seemed combinedly possessed by all the angels that\nfell from heaven.  The wide tiers of welded tendons overspreading his\nbroad white forehead, beneath the transparent skin, looked knitted\ntogether; as head on, he came churning his tail among the boats; and\nonce more flailed them apart; spilling out the irons and lances from\nthe two mates' boats, and dashing in one side of the upper part of\ntheir bows, but leaving Ahab's almost without a scar.\n\nWhile Daggoo and Queequeg were stopping the strained planks; and as\nthe whale swimming out from them, turned, and showed one entire flank\nas he shot by them again; at that moment a quick cry went up.  Lashed\nround and round to the fish's back; pinioned in the turns upon turns\nin which, during the past night, the whale had reeled the involutions\nof the lines around him, the half torn body of the Parsee was seen;\nhis sable raiment frayed to shreds; his distended eyes turned full\nupon old Ahab.\n\nThe harpoon dropped from his hand.\n\n\"Befooled, befooled!\"--drawing in a long lean breath--\"Aye, Parsee!\nI see thee again.--Aye, and thou goest before; and this, THIS then is\nthe hearse that thou didst promise.  But I hold thee to the last\nletter of thy word.  Where is the second hearse?  Away, mates, to the\nship! those boats are useless now; repair them if ye can in time, and\nreturn to me; if not, Ahab is enough to die--Down, men! the first\nthing that but offers to jump from this boat I stand in, that thing I\nharpoon.  Ye are not other men, but my arms and my legs; and so obey\nme.--Where's the whale? gone down again?\"\n\nBut he looked too nigh the boat; for as if bent upon escaping with\nthe corpse he bore, and as if the particular place of the last\nencounter had been but a stage in his leeward voyage, Moby Dick was\nnow again steadily swimming forward; and had almost passed the\nship,--which thus far had been sailing in the contrary direction to\nhim, though for the present her headway had been stopped.  He seemed\nswimming with his utmost velocity, and now only intent upon pursuing\nhis own straight path in the sea.\n\n\"Oh!  Ahab,\" cried Starbuck, \"not too late is it, even now, the third\nday, to desist.  See!  Moby Dick seeks thee not.  It is thou, thou,\nthat madly seekest him!\"\n\nSetting sail to the rising wind, the lonely boat was swiftly impelled\nto leeward, by both oars and canvas.  And at last when Ahab was\nsliding by the vessel, so near as plainly to distinguish Starbuck's\nface as he leaned over the rail, he hailed him to turn the vessel\nabout, and follow him, not too swiftly, at a judicious interval.\nGlancing upwards, he saw Tashtego, Queequeg, and Daggoo, eagerly\nmounting to the three mast-heads; while the oarsmen were rocking in\nthe two staved boats which had but just been hoisted to the side, and\nwere busily at work in repairing them.  One after the other, through\nthe port-holes, as he sped, he also caught flying glimpses of Stubb\nand Flask, busying themselves on deck among bundles of new irons and\nlances.  As he saw all this; as he heard the hammers in the broken\nboats; far other hammers seemed driving a nail into his heart.  But\nhe rallied.  And now marking that the vane or flag was gone from the\nmain-mast-head, he shouted to Tashtego, who had just gained that\nperch, to descend again for another flag, and a hammer and nails, and\nso nail it to the mast.\n\nWhether fagged by the three days' running chase, and the resistance\nto his swimming in the knotted hamper he bore; or whether it was some\nlatent deceitfulness and malice in him: whichever was true, the White\nWhale's way now began to abate, as it seemed, from the boat so\nrapidly nearing him once more; though indeed the whale's last start\nhad not been so long a one as before.  And still as Ahab glided over\nthe waves the unpitying sharks accompanied him; and so pertinaciously\nstuck to the boat; and so continually bit at the plying oars, that\nthe blades became jagged and crunched, and left small splinters in\nthe sea, at almost every dip.\n\n\"Heed them not! those teeth but give new rowlocks to your oars.  Pull\non! 'tis the better rest, the shark's jaw than the yielding water.\"\n\n\"But at every bite, sir, the thin blades grow smaller and smaller!\"\n\n\"They will last long enough! pull on!--But who can tell\"--he\nmuttered--\"whether these sharks swim to feast on the whale or on\nAhab?--But pull on!  Aye, all alive, now--we near him.  The helm!\ntake the helm! let me pass,\"--and so saying two of the oarsmen helped\nhim forward to the bows of the still flying boat.\n\nAt length as the craft was cast to one side, and ran ranging along\nwith the White Whale's flank, he seemed strangely oblivious of its\nadvance--as the whale sometimes will--and Ahab was fairly within the\nsmoky mountain mist, which, thrown off from the whale's spout, curled\nround his great, Monadnock hump; he was even thus close to him; when,\nwith body arched back, and both arms lengthwise high-lifted to the\npoise, he darted his fierce iron, and his far fiercer curse into the\nhated whale.  As both steel and curse sank to the socket, as if\nsucked into a morass, Moby Dick sideways writhed; spasmodically\nrolled his nigh flank against the bow, and, without staving a hole in\nit, so suddenly canted the boat over, that had it not been for the\nelevated part of the gunwale to which he then clung, Ahab would once\nmore have been tossed into the sea.  As it was, three of the\noarsmen--who foreknew not the precise instant of the dart, and were\ntherefore unprepared for its effects--these were flung out; but so\nfell, that, in an instant two of them clutched the gunwale again, and\nrising to its level on a combing wave, hurled themselves bodily\ninboard again; the third man helplessly dropping astern, but still\nafloat and swimming.\n\nAlmost simultaneously, with a mighty volition of ungraduated,\ninstantaneous swiftness, the White Whale darted through the weltering\nsea.  But when Ahab cried out to the steersman to take new turns with\nthe line, and hold it so; and commanded the crew to turn round on\ntheir seats, and tow the boat up to the mark; the moment the\ntreacherous line felt that double strain and tug, it snapped in the\nempty air!\n\n\"What breaks in me?  Some sinew cracks!--'tis whole again; oars!\noars!  Burst in upon him!\"\n\nHearing the tremendous rush of the sea-crashing boat, the whale\nwheeled round to present his blank forehead at bay; but in that\nevolution, catching sight of the nearing black hull of the ship;\nseemingly seeing in it the source of all his persecutions; bethinking\nit--it may be--a larger and nobler foe; of a sudden, he bore down\nupon its advancing prow, smiting his jaws amid fiery showers of foam.\n\nAhab staggered; his hand smote his forehead.  \"I grow blind; hands!\nstretch out before me that I may yet grope my way.  Is't night?\"\n\n\"The whale!  The ship!\" cried the cringing oarsmen.\n\n\"Oars! oars!  Slope downwards to thy depths, O sea, that ere it be\nfor ever too late, Ahab may slide this last, last time upon his\nmark!  I see: the ship! the ship!  Dash on, my men!  Will ye not\nsave my ship?\"\n\nBut as the oarsmen violently forced their boat through the\nsledge-hammering seas, the before whale-smitten bow-ends of two\nplanks burst through, and in an instant almost, the temporarily\ndisabled boat lay nearly level with the waves; its half-wading,\nsplashing crew, trying hard to stop the gap and bale out the pouring\nwater.\n\nMeantime, for that one beholding instant, Tashtego's mast-head hammer\nremained suspended in his hand; and the red flag, half-wrapping him\nas with a plaid, then streamed itself straight out from him, as his\nown forward-flowing heart; while Starbuck and Stubb, standing upon\nthe bowsprit beneath, caught sight of the down-coming monster just as\nsoon as he.\n\n\"The whale, the whale!  Up helm, up helm!  Oh, all ye sweet powers of\nair, now hug me close!  Let not Starbuck die, if die he must, in a\nwoman's fainting fit.  Up helm, I say--ye fools, the jaw! the jaw!\nIs this the end of all my bursting prayers? all my life-long\nfidelities?  Oh, Ahab, Ahab, lo, thy work.  Steady! helmsman, steady.\nNay, nay!  Up helm again!  He turns to meet us!  Oh, his\nunappeasable brow drives on towards one, whose duty tells him he\ncannot depart.  My God, stand by me now!\"\n\n\"Stand not by me, but stand under me, whoever you are that will now\nhelp Stubb; for Stubb, too, sticks here.  I grin at thee, thou\ngrinning whale!  Who ever helped Stubb, or kept Stubb awake, but\nStubb's own unwinking eye?  And now poor Stubb goes to bed upon a\nmattrass that is all too soft; would it were stuffed with brushwood!\nI grin at thee, thou grinning whale!  Look ye, sun, moon, and stars!\nI call ye assassins of as good a fellow as ever spouted up his ghost.\nFor all that, I would yet ring glasses with ye, would ye but hand\nthe cup!  Oh, oh! oh, oh! thou grinning whale, but there'll be plenty\nof gulping soon!  Why fly ye not, O Ahab!  For me, off shoes and\njacket to it; let Stubb die in his drawers!  A most mouldy and over\nsalted death, though;--cherries! cherries! cherries!  Oh, Flask, for\none red cherry ere we die!\"\n\n\"Cherries?  I only wish that we were where they grow.  Oh, Stubb, I\nhope my poor mother's drawn my part-pay ere this; if not, few coppers\nwill now come to her, for the voyage is up.\"\n\nFrom the ship's bows, nearly all the seamen now hung inactive;\nhammers, bits of plank, lances, and harpoons, mechanically retained\nin their hands, just as they had darted from their various\nemployments; all their enchanted eyes intent upon the whale, which\nfrom side to side strangely vibrating his predestinating head, sent a\nbroad band of overspreading semicircular foam before him as he\nrushed.  Retribution, swift vengeance, eternal malice were in his\nwhole aspect, and spite of all that mortal man could do, the solid\nwhite buttress of his forehead smote the ship's starboard bow, till\nmen and timbers reeled.  Some fell flat upon their faces.  Like\ndislodged trucks, the heads of the harpooneers aloft shook on their\nbull-like necks.  Through the breach, they heard the waters pour, as\nmountain torrents down a flume.\n\n\"The ship!  The hearse!--the second hearse!\" cried Ahab from the\nboat; \"its wood could only be American!\"\n\nDiving beneath the settling ship, the whale ran quivering along its\nkeel; but turning under water, swiftly shot to the surface again, far\noff the other bow, but within a few yards of Ahab's boat, where, for\na time, he lay quiescent.\n\n\"I turn my body from the sun.  What ho, Tashtego! let me hear thy\nhammer.  Oh! ye three unsurrendered spires of mine; thou uncracked\nkeel; and only god-bullied hull; thou firm deck, and haughty helm,\nand Pole-pointed prow,--death-glorious ship! must ye then perish,\nand without me?  Am I cut off from the last fond pride of meanest\nshipwrecked captains?  Oh, lonely death on lonely life!  Oh, now I\nfeel my topmost greatness lies in my topmost grief.  Ho, ho! from all\nyour furthest bounds, pour ye now in, ye bold billows of my whole\nforegone life, and top this one piled comber of my death!  Towards\nthee I roll, thou all-destroying but unconquering whale; to the last\nI grapple with thee; from hell's heart I stab at thee; for hate's\nsake I spit my last breath at thee.  Sink all coffins and all hearses\nto one common pool! and since neither can be mine, let me then tow to\npieces, while still chasing thee, though tied to thee, thou damned\nwhale!  THUS, I give up the spear!\"\n\nThe harpoon was darted; the stricken whale flew forward; with\nigniting velocity the line ran through the grooves;--ran foul.  Ahab\nstooped to clear it; he did clear it; but the flying turn caught him\nround the neck, and voicelessly as Turkish mutes bowstring their\nvictim, he was shot out of the boat, ere the crew knew he was gone.\nNext instant, the heavy eye-splice in the rope's final end flew out\nof the stark-empty tub, knocked down an oarsman, and smiting the sea,\ndisappeared in its depths.\n\nFor an instant, the tranced boat's crew stood still; then turned.\n\"The ship?  Great God, where is the ship?\"  Soon they through dim,\nbewildering mediums saw her sidelong fading phantom, as in the\ngaseous Fata Morgana; only the uppermost masts out of water; while\nfixed by infatuation, or fidelity, or fate, to their once lofty\nperches, the pagan harpooneers still maintained their sinking\nlookouts on the sea.  And now, concentric circles seized the lone\nboat itself, and all its crew, and each floating oar, and every\nlance-pole, and spinning, animate and inanimate, all round and round\nin one vortex, carried the smallest chip of the Pequod out of sight.\n\nBut as the last whelmings intermixingly poured themselves over the\nsunken head of the Indian at the mainmast, leaving a few inches of\nthe erect spar yet visible, together with long streaming yards of the\nflag, which calmly undulated, with ironical coincidings, over the\ndestroying billows they almost touched;--at that instant, a red arm\nand a hammer hovered backwardly uplifted in the open air, in the act\nof nailing the flag faster and yet faster to the subsiding spar.  A\nsky-hawk that tauntingly had followed the main-truck downwards from\nits natural home among the stars, pecking at the flag, and\nincommoding Tashtego there; this bird now chanced to intercept its\nbroad fluttering wing between the hammer and the wood; and\nsimultaneously feeling that etherial thrill, the submerged savage\nbeneath, in his death-gasp, kept his hammer frozen there; and so the\nbird of heaven, with archangelic shrieks, and his imperial beak\nthrust upwards, and his whole captive form folded in the flag of\nAhab, went down with his ship, which, like Satan, would not sink to\nhell till she had dragged a living part of heaven along with her, and\nhelmeted herself with it.\n\nNow small fowls flew screaming over the yet yawning gulf; a sullen\nwhite surf beat against its steep sides; then all collapsed, and the\ngreat shroud of the sea rolled on as it rolled five thousand years\nago.\n\n\n\nEpilogue\n\n\"AND I ONLY AM ESCAPED ALONE TO TELL THEE\"\nJob.\n\nThe drama's done.  Why then here does any one step forth?--Because\none did survive the wreck.\n\nIt so chanced, that after the Parsee's disappearance, I was he whom\nthe Fates ordained to take the place of Ahab's bowsman, when that\nbowsman assumed the vacant post; the same, who, when on the last day\nthe three men were tossed from out of the rocking boat, was dropped\nastern.  So, floating on the margin of the ensuing scene, and in full\nsight of it, when the halfspent suction of the sunk ship reached me,\nI was then, but slowly, drawn towards the closing vortex.  When I\nreached it, it had subsided to a creamy pool.  Round and round, then,\nand ever contracting towards the button-like black bubble at the axis\nof that slowly wheeling circle, like another Ixion I did revolve.\nTill, gaining that vital centre, the black bubble upward burst; and\nnow, liberated by reason of its cunning spring, and, owing to its\ngreat buoyancy, rising with great force, the coffin life-buoy shot\nlengthwise from the sea, fell over, and floated by my side.  Buoyed\nup by that coffin, for almost one whole day and night, I floated on a\nsoft and dirgelike main.  The unharming sharks, they glided by as if\nwith padlocks on their mouths; the savage sea-hawks sailed with\nsheathed beaks.  On the second day, a sail drew near, nearer, and\npicked me up at last.  It was the devious-cruising Rachel, that in\nher retracing search after her missing children, only found another\norphan.\n\n\n\n\nEnd of this Project Gutenberg etext of Moby Dick, by Herman Melville\n\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week7/yahooFinantial/info.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <style>\n    td {\n      padding: 7px;\n    }\n  </style>\n</head>\n<body>\n  <table border=\"1\">\n    <tr>\n      <th>Date</th>\n      <th>Open</th>\n      <th>High</th>\n      <th>Low</th>\n      <th>Close</th>\n      <th>Volume</th>\n      <th>Adj Close</th>\n    </tr>\n    <tr>\n      <td>2015-07-09</td>\n      <td>523.119995</td>\n      <td>523.770020</td>\n      <td>520.349976</td>\n      <td>520.679993</td>\n      <td>1839400</td>\n      <td>520.679993</td>\n    </tr>\n    <tr>\n      <td>2015-07-08</td>\n      <td>521.049988</td>\n      <td>522.734009</td>\n      <td>516.109985</td>\n      <td>516.830017</td>\n      <td>1264600</td>\n      <td>516.830017</td>\n    </tr>\n    <tr>\n      <td>2015-07-07</td>\n      <td>523.130005</td>\n      <td>526.179993</td>\n      <td>515.179993</td>\n      <td>525.020020</td>\n      <td>1595700</td>\n      <td>525.020020</td>\n    </tr>\n    <tr>\n      <td>2015-07-06</td>\n      <td>519.500000</td>\n      <td>525.250000</td>\n      <td>519.000000</td>\n      <td>522.859985</td>\n      <td>1276500</td>\n      <td>522.859985</td>\n    </tr>\n    <tr>\n      <td>2015-07-02</td>\n      <td>521.080017</td>\n      <td>524.650024</td>\n      <td>521.080017</td>\n      <td>523.400024</td>\n      <td>1234000</td>\n      <td>523.400024</td>\n    </tr>\n    <tr>\n      <td>2015-07-01</td>\n      <td>524.729980</td>\n      <td>525.690002</td>\n      <td>518.229980</td>\n      <td>521.840027</td>\n      <td>1961000</td>\n      <td>521.840027</td>\n    </tr>\n    <tr>\n      <td>2015-06-30</td>\n      <td>526.020020</td>\n      <td>526.250000</td>\n      <td>520.500000</td>\n      <td>520.510010</td>\n      <td>2217200</td>\n      <td>520.510010</td>\n    </tr>\n    <tr>\n      <td>2015-06-29</td>\n      <td>525.010010</td>\n      <td>528.609985</td>\n      <td>520.539978</td>\n      <td>521.520020</td>\n      <td>1930900</td>\n      <td>521.520020</td>\n    </tr>\n    <tr>\n      <td>2015-06-26</td>\n      <td>537.260010</td>\n      <td>537.760010</td>\n      <td>531.349976</td>\n      <td>531.690002</td>\n      <td>2011500</td>\n      <td>531.690002</td>\n    </tr>\n    <tr>\n      <td>2015-06-25</td>\n      <td>538.869995</td>\n      <td>540.900024</td>\n      <td>535.229980</td>\n      <td>535.229980</td>\n      <td>1331500</td>\n      <td>535.229980</td>\n    </tr>\n    <tr>\n      <td>2015-06-24</td>\n      <td>540.000000</td>\n      <td>540.000000</td>\n      <td>535.659973</td>\n      <td>537.840027</td>\n      <td>1283400</td>\n      <td>537.840027</td>\n    </tr>\n    <tr>\n      <td>2015-06-23</td>\n      <td>539.640015</td>\n      <td>541.499023</td>\n      <td>535.250000</td>\n      <td>540.479980</td>\n      <td>1196000</td>\n      <td>540.479980</td>\n    </tr>\n    <tr>\n      <td>2015-06-22</td>\n      <td>539.590027</td>\n      <td>543.739990</td>\n      <td>537.530029</td>\n      <td>538.190002</td>\n      <td>1242500</td>\n      <td>538.190002</td>\n    </tr>\n    <tr>\n      <td>2015-06-19</td>\n      <td>537.210022</td>\n      <td>538.250000</td>\n      <td>533.010010</td>\n      <td>536.690002</td>\n      <td>1885700</td>\n      <td>536.690002</td>\n    </tr>\n    <tr>\n      <td>2015-06-18</td>\n      <td>531.000000</td>\n      <td>538.150024</td>\n      <td>530.789978</td>\n      <td>536.729980</td>\n      <td>1828100</td>\n      <td>536.729980</td>\n    </tr>\n    <tr>\n      <td>2015-06-17</td>\n      <td>529.369995</td>\n      <td>530.979980</td>\n      <td>525.099976</td>\n      <td>529.260010</td>\n      <td>1268600</td>\n      <td>529.260010</td>\n    </tr>\n    <tr>\n      <td>2015-06-16</td>\n      <td>528.400024</td>\n      <td>529.640015</td>\n      <td>525.559998</td>\n      <td>528.150024</td>\n      <td>1069300</td>\n      <td>528.150024</td>\n    </tr>\n    <tr>\n      <td>2015-06-15</td>\n      <td>528.000000</td>\n      <td>528.299988</td>\n      <td>524.000000</td>\n      <td>527.200012</td>\n      <td>1630700</td>\n      <td>527.200012</td>\n    </tr>\n    <tr>\n      <td>2015-06-12</td>\n      <td>531.599976</td>\n      <td>533.119995</td>\n      <td>530.159973</td>\n      <td>532.330017</td>\n      <td>952400</td>\n      <td>532.330017</td>\n    </tr>\n    <tr>\n      <td>2015-06-11</td>\n      <td>538.424988</td>\n      <td>538.979980</td>\n      <td>533.020020</td>\n      <td>534.609985</td>\n      <td>1205000</td>\n      <td>534.609985</td>\n    </tr>\n    <tr>\n      <td>2015-06-10</td>\n      <td>529.359985</td>\n      <td>538.359985</td>\n      <td>529.349976</td>\n      <td>536.690002</td>\n      <td>1811400</td>\n      <td>536.690002</td>\n    </tr>\n    <tr>\n      <td>2015-06-09</td>\n      <td>527.559998</td>\n      <td>529.200012</td>\n      <td>523.010010</td>\n      <td>526.690002</td>\n      <td>1441600</td>\n      <td>526.690002</td>\n    </tr>\n    <tr>\n      <td>2015-06-08</td>\n      <td>533.309998</td>\n      <td>534.119995</td>\n      <td>526.239990</td>\n      <td>526.830017</td>\n      <td>1520600</td>\n      <td>526.830017</td>\n    </tr>\n    <tr>\n      <td>2015-06-05</td>\n      <td>536.349976</td>\n      <td>537.200012</td>\n      <td>532.520020</td>\n      <td>533.330017</td>\n      <td>1375000</td>\n      <td>533.330017</td>\n    </tr>\n    <tr>\n      <td>2015-06-04</td>\n      <td>537.760010</td>\n      <td>540.590027</td>\n      <td>534.320007</td>\n      <td>536.700012</td>\n      <td>1335600</td>\n      <td>536.700012</td>\n    </tr>\n    <tr>\n      <td>2015-06-03</td>\n      <td>539.909973</td>\n      <td>543.500000</td>\n      <td>537.109985</td>\n      <td>540.309998</td>\n      <td>1714500</td>\n      <td>540.309998</td>\n    </tr>\n    <tr>\n      <td>2015-06-02</td>\n      <td>532.929993</td>\n      <td>543.000000</td>\n      <td>531.330017</td>\n      <td>539.179993</td>\n      <td>1934700</td>\n      <td>539.179993</td>\n    </tr>\n    <tr>\n      <td>2015-06-01</td>\n      <td>536.789978</td>\n      <td>536.789978</td>\n      <td>529.760010</td>\n      <td>533.989990</td>\n      <td>1899600</td>\n      <td>533.989990</td>\n    </tr>\n    <tr>\n      <td>2015-05-29</td>\n      <td>537.369995</td>\n      <td>538.630005</td>\n      <td>531.450012</td>\n      <td>532.109985</td>\n      <td>2584900</td>\n      <td>532.109985</td>\n    </tr>\n    <tr>\n      <td>2015-05-28</td>\n      <td>538.010010</td>\n      <td>540.609985</td>\n      <td>536.250000</td>\n      <td>539.780029</td>\n      <td>1027900</td>\n      <td>539.780029</td>\n    </tr>\n    <tr>\n      <td>2015-05-27</td>\n      <td>532.799988</td>\n      <td>540.549988</td>\n      <td>531.710022</td>\n      <td>539.789978</td>\n      <td>1520400</td>\n      <td>539.789978</td>\n    </tr>\n    <tr>\n      <td>2015-05-26</td>\n      <td>538.119995</td>\n      <td>539.000000</td>\n      <td>529.880005</td>\n      <td>532.320007</td>\n      <td>2403400</td>\n      <td>532.320007</td>\n    </tr>\n    <tr>\n      <td>2015-05-22</td>\n      <td>540.150024</td>\n      <td>544.190002</td>\n      <td>539.510010</td>\n      <td>540.109985</td>\n      <td>1173300</td>\n      <td>540.109985</td>\n    </tr>\n    <tr>\n      <td>2015-05-21</td>\n      <td>537.950012</td>\n      <td>543.840027</td>\n      <td>535.979980</td>\n      <td>542.510010</td>\n      <td>1461400</td>\n      <td>542.510010</td>\n    </tr>\n    <tr>\n      <td>2015-05-20</td>\n      <td>538.489990</td>\n      <td>542.919983</td>\n      <td>532.971985</td>\n      <td>539.270020</td>\n      <td>1429100</td>\n      <td>539.270020</td>\n    </tr>\n    <tr>\n      <td>2015-05-19</td>\n      <td>533.979980</td>\n      <td>540.659973</td>\n      <td>533.039978</td>\n      <td>537.359985</td>\n      <td>1963300</td>\n      <td>537.359985</td>\n    </tr>\n    <tr>\n      <td>2015-05-18</td>\n      <td>532.010010</td>\n      <td>534.820007</td>\n      <td>528.849976</td>\n      <td>532.299988</td>\n      <td>1998600</td>\n      <td>532.299988</td>\n    </tr>\n    <tr>\n      <td>2015-05-15</td>\n      <td>539.179993</td>\n      <td>539.273987</td>\n      <td>530.380005</td>\n      <td>533.849976</td>\n      <td>1962700</td>\n      <td>533.849976</td>\n    </tr>\n    <tr>\n      <td>2015-05-14</td>\n      <td>533.770020</td>\n      <td>539.000000</td>\n      <td>532.409973</td>\n      <td>538.400024</td>\n      <td>1399100</td>\n      <td>538.400024</td>\n    </tr>\n    <tr>\n      <td>2015-05-13</td>\n      <td>530.559998</td>\n      <td>534.322021</td>\n      <td>528.655029</td>\n      <td>529.619995</td>\n      <td>1252300</td>\n      <td>529.619995</td>\n    </tr>\n    <tr>\n      <td>2015-05-12</td>\n      <td>531.599976</td>\n      <td>533.208984</td>\n      <td>525.260010</td>\n      <td>529.039978</td>\n      <td>1625400</td>\n      <td>529.039978</td>\n    </tr>\n    <tr>\n      <td>2015-05-11</td>\n      <td>538.369995</td>\n      <td>541.979980</td>\n      <td>535.400024</td>\n      <td>535.700012</td>\n      <td>905300</td>\n      <td>535.700012</td>\n    </tr>\n    <tr>\n      <td>2015-05-08</td>\n      <td>536.650024</td>\n      <td>541.150024</td>\n      <td>525.000000</td>\n      <td>538.219971</td>\n      <td>1527600</td>\n      <td>538.219971</td>\n    </tr>\n    <tr>\n      <td>2015-05-07</td>\n      <td>523.989990</td>\n      <td>533.460022</td>\n      <td>521.750000</td>\n      <td>530.700012</td>\n      <td>1546300</td>\n      <td>530.700012</td>\n    </tr>\n    <tr>\n      <td>2015-05-06</td>\n      <td>531.239990</td>\n      <td>532.380005</td>\n      <td>521.085022</td>\n      <td>524.219971</td>\n      <td>1567000</td>\n      <td>524.219971</td>\n    </tr>\n    <tr>\n      <td>2015-05-05</td>\n      <td>538.210022</td>\n      <td>539.739990</td>\n      <td>530.390991</td>\n      <td>530.799988</td>\n      <td>1383100</td>\n      <td>530.799988</td>\n    </tr>\n    <tr>\n      <td>2015-05-04</td>\n      <td>538.530029</td>\n      <td>544.070007</td>\n      <td>535.059998</td>\n      <td>540.780029</td>\n      <td>1308000</td>\n      <td>540.780029</td>\n    </tr>\n    <tr>\n      <td>2015-05-01</td>\n      <td>538.429993</td>\n      <td>539.539978</td>\n      <td>532.099976</td>\n      <td>537.900024</td>\n      <td>1768200</td>\n      <td>537.900024</td>\n    </tr>\n    <tr>\n      <td>2015-04-30</td>\n      <td>547.869995</td>\n      <td>548.590027</td>\n      <td>535.049988</td>\n      <td>537.340027</td>\n      <td>2082200</td>\n      <td>537.340027</td>\n    </tr>\n    <tr>\n      <td>2015-04-29</td>\n      <td>550.469971</td>\n      <td>553.679993</td>\n      <td>546.905029</td>\n      <td>549.080017</td>\n      <td>1698800</td>\n      <td>549.080017</td>\n    </tr>\n    <tr>\n      <td>2015-04-28</td>\n      <td>554.640015</td>\n      <td>556.020020</td>\n      <td>550.366028</td>\n      <td>553.679993</td>\n      <td>1491000</td>\n      <td>553.679993</td>\n    </tr>\n    <tr>\n      <td>2015-04-27</td>\n      <td>563.390015</td>\n      <td>565.950012</td>\n      <td>553.200012</td>\n      <td>555.369995</td>\n      <td>2398000</td>\n      <td>555.369995</td>\n    </tr>\n    <tr>\n      <td>2015-04-24</td>\n      <td>566.102522</td>\n      <td>571.142590</td>\n      <td>557.252507</td>\n      <td>565.062561</td>\n      <td>4932500</td>\n      <td>565.062561</td>\n    </tr>\n    <tr>\n      <td>2015-04-23</td>\n      <td>541.002435</td>\n      <td>550.962490</td>\n      <td>540.232440</td>\n      <td>547.002472</td>\n      <td>4184900</td>\n      <td>547.002472</td>\n    </tr>\n    <tr>\n      <td>2015-04-22</td>\n      <td>534.402426</td>\n      <td>541.082489</td>\n      <td>531.752397</td>\n      <td>539.367458</td>\n      <td>1593600</td>\n      <td>539.367458</td>\n    </tr>\n    <tr>\n      <td>2015-04-21</td>\n      <td>537.512456</td>\n      <td>539.392429</td>\n      <td>533.677415</td>\n      <td>533.972413</td>\n      <td>1844800</td>\n      <td>533.972413</td>\n    </tr>\n    <tr>\n      <td>2015-04-20</td>\n      <td>525.602352</td>\n      <td>536.092424</td>\n      <td>524.502350</td>\n      <td>535.382408</td>\n      <td>1679300</td>\n      <td>535.382408</td>\n    </tr>\n    <tr>\n      <td>2015-04-17</td>\n      <td>528.662379</td>\n      <td>529.842435</td>\n      <td>521.012371</td>\n      <td>524.052386</td>\n      <td>2144100</td>\n      <td>524.052386</td>\n    </tr>\n    <tr>\n      <td>2015-04-16</td>\n      <td>529.902414</td>\n      <td>535.592457</td>\n      <td>529.612373</td>\n      <td>533.802391</td>\n      <td>1299900</td>\n      <td>533.802391</td>\n    </tr>\n    <tr>\n      <td>2015-04-15</td>\n      <td>528.702406</td>\n      <td>534.732432</td>\n      <td>523.222350</td>\n      <td>532.532429</td>\n      <td>2318800</td>\n      <td>532.532429</td>\n    </tr>\n    <tr>\n      <td>2015-04-14</td>\n      <td>536.252409</td>\n      <td>537.572435</td>\n      <td>528.094354</td>\n      <td>530.392405</td>\n      <td>2604100</td>\n      <td>530.392405</td>\n    </tr>\n    <tr>\n      <td>2015-04-13</td>\n      <td>538.412385</td>\n      <td>544.062463</td>\n      <td>537.312445</td>\n      <td>539.172404</td>\n      <td>1645300</td>\n      <td>539.172404</td>\n    </tr>\n    <tr>\n      <td>2015-04-10</td>\n      <td>542.292411</td>\n      <td>542.292411</td>\n      <td>537.312445</td>\n      <td>540.012477</td>\n      <td>1409500</td>\n      <td>540.012477</td>\n    </tr>\n    <tr>\n      <td>2015-04-09</td>\n      <td>541.032486</td>\n      <td>541.952490</td>\n      <td>535.492390</td>\n      <td>540.782472</td>\n      <td>1557900</td>\n      <td>540.782472</td>\n    </tr>\n    <tr>\n      <td>2015-04-08</td>\n      <td>538.382457</td>\n      <td>543.852415</td>\n      <td>538.382457</td>\n      <td>541.612446</td>\n      <td>1178500</td>\n      <td>541.612446</td>\n    </tr>\n    <tr>\n      <td>2015-04-07</td>\n      <td>538.082440</td>\n      <td>542.692434</td>\n      <td>536.002395</td>\n      <td>537.022465</td>\n      <td>1302900</td>\n      <td>537.022465</td>\n    </tr>\n    <tr>\n      <td>2015-04-06</td>\n      <td>532.222375</td>\n      <td>538.412385</td>\n      <td>529.572407</td>\n      <td>536.767432</td>\n      <td>1324400</td>\n      <td>536.767432</td>\n    </tr>\n    <tr>\n      <td>2015-04-02</td>\n      <td>540.852427</td>\n      <td>540.852427</td>\n      <td>533.849395</td>\n      <td>535.532478</td>\n      <td>1716400</td>\n      <td>535.532478</td>\n    </tr>\n    <tr>\n      <td>2015-04-01</td>\n      <td>548.602441</td>\n      <td>551.142488</td>\n      <td>539.502472</td>\n      <td>542.562439</td>\n      <td>1963100</td>\n      <td>542.562439</td>\n    </tr>\n    <tr>\n      <td>2015-03-31</td>\n      <td>550.002460</td>\n      <td>554.712521</td>\n      <td>546.722468</td>\n      <td>548.002468</td>\n      <td>1588000</td>\n      <td>548.002468</td>\n    </tr>\n    <tr>\n      <td>2015-03-30</td>\n      <td>551.622503</td>\n      <td>553.472487</td>\n      <td>548.172490</td>\n      <td>552.032502</td>\n      <td>1287500</td>\n      <td>552.032502</td>\n    </tr>\n    <tr>\n      <td>2015-03-27</td>\n      <td>553.002509</td>\n      <td>555.282565</td>\n      <td>548.132463</td>\n      <td>548.342512</td>\n      <td>1897500</td>\n      <td>548.342512</td>\n    </tr>\n    <tr>\n      <td>2015-03-26</td>\n      <td>557.592550</td>\n      <td>558.902540</td>\n      <td>550.652497</td>\n      <td>555.172522</td>\n      <td>1572600</td>\n      <td>555.172522</td>\n    </tr>\n    <tr>\n      <td>2015-03-25</td>\n      <td>570.502590</td>\n      <td>572.262605</td>\n      <td>558.742494</td>\n      <td>558.787478</td>\n      <td>2152300</td>\n      <td>558.787478</td>\n    </tr>\n    <tr>\n      <td>2015-03-24</td>\n      <td>562.562541</td>\n      <td>574.592603</td>\n      <td>561.212586</td>\n      <td>570.192597</td>\n      <td>2583300</td>\n      <td>570.192597</td>\n    </tr>\n    <tr>\n      <td>2015-03-23</td>\n      <td>560.432554</td>\n      <td>562.362529</td>\n      <td>555.832536</td>\n      <td>558.812510</td>\n      <td>1643800</td>\n      <td>558.812510</td>\n    </tr>\n    <tr>\n      <td>2015-03-20</td>\n      <td>561.652574</td>\n      <td>561.722529</td>\n      <td>559.052548</td>\n      <td>560.362537</td>\n      <td>2616900</td>\n      <td>560.362537</td>\n    </tr>\n    <tr>\n      <td>2015-03-19</td>\n      <td>559.392531</td>\n      <td>560.802526</td>\n      <td>556.147548</td>\n      <td>557.992512</td>\n      <td>1197300</td>\n      <td>557.992512</td>\n    </tr>\n    <tr>\n      <td>2015-03-18</td>\n      <td>552.502480</td>\n      <td>559.782578</td>\n      <td>547.002472</td>\n      <td>559.502513</td>\n      <td>2134500</td>\n      <td>559.502513</td>\n    </tr>\n    <tr>\n      <td>2015-03-17</td>\n      <td>551.712533</td>\n      <td>553.802493</td>\n      <td>548.002468</td>\n      <td>550.842532</td>\n      <td>1805500</td>\n      <td>550.842532</td>\n    </tr>\n    <tr>\n      <td>2015-03-16</td>\n      <td>550.952514</td>\n      <td>556.852484</td>\n      <td>546.002476</td>\n      <td>554.512509</td>\n      <td>1641000</td>\n      <td>554.512509</td>\n    </tr>\n    <tr>\n      <td>2015-03-13</td>\n      <td>553.502537</td>\n      <td>558.402572</td>\n      <td>544.222448</td>\n      <td>547.322503</td>\n      <td>1703600</td>\n      <td>547.322503</td>\n    </tr>\n    <tr>\n      <td>2015-03-12</td>\n      <td>553.512513</td>\n      <td>556.372530</td>\n      <td>550.462523</td>\n      <td>555.512505</td>\n      <td>1389600</td>\n      <td>555.512505</td>\n    </tr>\n    <tr>\n      <td>2015-03-11</td>\n      <td>555.142533</td>\n      <td>558.142521</td>\n      <td>550.682486</td>\n      <td>551.182515</td>\n      <td>1820800</td>\n      <td>551.182515</td>\n    </tr>\n    <tr>\n      <td>2015-03-10</td>\n      <td>564.252539</td>\n      <td>564.852512</td>\n      <td>554.732473</td>\n      <td>555.012538</td>\n      <td>1792300</td>\n      <td>555.012538</td>\n    </tr>\n    <tr>\n      <td>2015-03-09</td>\n      <td>566.862541</td>\n      <td>570.272589</td>\n      <td>563.537504</td>\n      <td>568.852557</td>\n      <td>1062100</td>\n      <td>568.852557</td>\n    </tr>\n    <tr>\n      <td>2015-03-06</td>\n      <td>574.882583</td>\n      <td>576.682625</td>\n      <td>566.762597</td>\n      <td>567.687558</td>\n      <td>1659100</td>\n      <td>567.687558</td>\n    </tr>\n    <tr>\n      <td>2015-03-05</td>\n      <td>575.022616</td>\n      <td>577.912621</td>\n      <td>573.412548</td>\n      <td>575.332609</td>\n      <td>1389600</td>\n      <td>575.332609</td>\n    </tr>\n    <tr>\n      <td>2015-03-04</td>\n      <td>571.872558</td>\n      <td>577.112576</td>\n      <td>568.012607</td>\n      <td>573.372583</td>\n      <td>1876800</td>\n      <td>573.372583</td>\n    </tr>\n    <tr>\n      <td>2015-03-03</td>\n      <td>570.452587</td>\n      <td>575.392649</td>\n      <td>566.522559</td>\n      <td>573.642610</td>\n      <td>1704800</td>\n      <td>573.642610</td>\n    </tr>\n    <tr>\n      <td>2015-03-02</td>\n      <td>560.532559</td>\n      <td>572.152623</td>\n      <td>558.752531</td>\n      <td>571.342601</td>\n      <td>2129600</td>\n      <td>571.342601</td>\n    </tr>\n    <tr>\n      <td>2015-02-27</td>\n      <td>554.242482</td>\n      <td>564.712602</td>\n      <td>552.902503</td>\n      <td>558.402572</td>\n      <td>2410200</td>\n      <td>558.402572</td>\n    </tr>\n    <tr>\n      <td>2015-02-26</td>\n      <td>543.212476</td>\n      <td>556.142529</td>\n      <td>541.502464</td>\n      <td>555.482516</td>\n      <td>2311500</td>\n      <td>555.482516</td>\n    </tr>\n    <tr>\n      <td>2015-02-25</td>\n      <td>535.902450</td>\n      <td>546.222440</td>\n      <td>535.447406</td>\n      <td>543.872489</td>\n      <td>1826000</td>\n      <td>543.872489</td>\n    </tr>\n    <tr>\n      <td>2015-02-24</td>\n      <td>530.002419</td>\n      <td>536.792403</td>\n      <td>528.252381</td>\n      <td>536.092424</td>\n      <td>1005100</td>\n      <td>536.092424</td>\n    </tr>\n    <tr>\n      <td>2015-02-23</td>\n      <td>536.052398</td>\n      <td>536.441465</td>\n      <td>529.412361</td>\n      <td>531.912381</td>\n      <td>1457900</td>\n      <td>531.912381</td>\n    </tr>\n    <tr>\n      <td>2015-02-20</td>\n      <td>543.132484</td>\n      <td>543.752470</td>\n      <td>535.802444</td>\n      <td>538.952441</td>\n      <td>1444400</td>\n      <td>538.952441</td>\n    </tr>\n    <tr>\n      <td>2015-02-19</td>\n      <td>538.042413</td>\n      <td>543.112470</td>\n      <td>538.012424</td>\n      <td>542.872432</td>\n      <td>989100</td>\n      <td>542.872432</td>\n    </tr>\n    <tr>\n      <td>2015-02-18</td>\n      <td>541.402458</td>\n      <td>545.492471</td>\n      <td>537.512456</td>\n      <td>539.702422</td>\n      <td>1453100</td>\n      <td>539.702422</td>\n    </tr>\n    <tr>\n      <td>2015-02-17</td>\n      <td>546.832511</td>\n      <td>550.002460</td>\n      <td>541.092465</td>\n      <td>542.842504</td>\n      <td>1616800</td>\n      <td>542.842504</td>\n    </tr>\n    <tr>\n      <td>2015-02-13</td>\n      <td>543.352447</td>\n      <td>549.912491</td>\n      <td>543.132484</td>\n      <td>549.012501</td>\n      <td>1900300</td>\n      <td>549.012501</td>\n    </tr>\n    <tr>\n      <td>2015-02-12</td>\n      <td>537.252405</td>\n      <td>544.822482</td>\n      <td>534.675391</td>\n      <td>542.932472</td>\n      <td>1620200</td>\n      <td>542.932472</td>\n    </tr>\n    <tr>\n      <td>2015-02-11</td>\n      <td>535.302416</td>\n      <td>538.452473</td>\n      <td>533.380397</td>\n      <td>535.972405</td>\n      <td>1377800</td>\n      <td>535.972405</td>\n    </tr>\n    <tr>\n      <td>2015-02-10</td>\n      <td>529.302379</td>\n      <td>537.702431</td>\n      <td>526.922378</td>\n      <td>536.942412</td>\n      <td>1749900</td>\n      <td>536.942412</td>\n    </tr>\n    <tr>\n      <td>2015-02-09</td>\n      <td>528.002366</td>\n      <td>532.002411</td>\n      <td>526.022388</td>\n      <td>527.832406</td>\n      <td>1267800</td>\n      <td>527.832406</td>\n    </tr>\n    <tr>\n      <td>2015-02-06</td>\n      <td>527.642431</td>\n      <td>537.202463</td>\n      <td>526.412373</td>\n      <td>531.002415</td>\n      <td>1749400</td>\n      <td>531.002415</td>\n    </tr>\n    <tr>\n      <td>2015-02-05</td>\n      <td>523.792334</td>\n      <td>528.502395</td>\n      <td>522.092359</td>\n      <td>527.582391</td>\n      <td>1849800</td>\n      <td>527.582391</td>\n    </tr>\n    <tr>\n      <td>2015-02-04</td>\n      <td>529.242400</td>\n      <td>532.674420</td>\n      <td>521.272361</td>\n      <td>522.762349</td>\n      <td>1663700</td>\n      <td>522.762349</td>\n    </tr>\n    <tr>\n      <td>2015-02-03</td>\n      <td>528.002366</td>\n      <td>533.402430</td>\n      <td>523.262377</td>\n      <td>529.242400</td>\n      <td>2038700</td>\n      <td>529.242400</td>\n    </tr>\n    <tr>\n      <td>2015-02-02</td>\n      <td>531.732383</td>\n      <td>533.002407</td>\n      <td>518.552316</td>\n      <td>528.482381</td>\n      <td>2849800</td>\n      <td>528.482381</td>\n    </tr>\n    <tr>\n      <td>2015-01-30</td>\n      <td>515.862322</td>\n      <td>539.872444</td>\n      <td>515.522339</td>\n      <td>534.522445</td>\n      <td>5606400</td>\n      <td>534.522445</td>\n    </tr>\n    <tr>\n      <td>2015-01-29</td>\n      <td>511.002313</td>\n      <td>511.092313</td>\n      <td>501.202274</td>\n      <td>510.662331</td>\n      <td>4186400</td>\n      <td>510.662331</td>\n    </tr>\n    <tr>\n      <td>2015-01-28</td>\n      <td>522.782423</td>\n      <td>522.992349</td>\n      <td>510.002318</td>\n      <td>510.002318</td>\n      <td>1683800</td>\n      <td>510.002318</td>\n    </tr>\n    <tr>\n      <td>2015-01-27</td>\n      <td>529.972369</td>\n      <td>530.702398</td>\n      <td>518.192381</td>\n      <td>518.632370</td>\n      <td>1904000</td>\n      <td>518.632370</td>\n    </tr>\n    <tr>\n      <td>2015-01-26</td>\n      <td>538.532466</td>\n      <td>539.002444</td>\n      <td>529.672413</td>\n      <td>535.212448</td>\n      <td>1543700</td>\n      <td>535.212448</td>\n    </tr>\n    <tr>\n      <td>2015-01-23</td>\n      <td>535.592457</td>\n      <td>542.172453</td>\n      <td>533.002407</td>\n      <td>539.952437</td>\n      <td>2281700</td>\n      <td>539.952437</td>\n    </tr>\n    <tr>\n      <td>2015-01-22</td>\n      <td>521.482349</td>\n      <td>536.332463</td>\n      <td>519.702382</td>\n      <td>534.392450</td>\n      <td>2676900</td>\n      <td>534.392450</td>\n    </tr>\n    <tr>\n      <td>2015-01-21</td>\n      <td>507.252283</td>\n      <td>519.282407</td>\n      <td>506.202315</td>\n      <td>518.042312</td>\n      <td>2268700</td>\n      <td>518.042312</td>\n    </tr>\n    <tr>\n      <td>2015-01-20</td>\n      <td>511.002313</td>\n      <td>512.502307</td>\n      <td>506.018277</td>\n      <td>506.902294</td>\n      <td>2227900</td>\n      <td>506.902294</td>\n    </tr>\n    <tr>\n      <td>2015-01-16</td>\n      <td>500.012273</td>\n      <td>508.192300</td>\n      <td>500.002267</td>\n      <td>508.082288</td>\n      <td>2298300</td>\n      <td>508.082288</td>\n    </tr>\n    <tr>\n      <td>2015-01-15</td>\n      <td>505.572291</td>\n      <td>505.682273</td>\n      <td>497.762267</td>\n      <td>501.792271</td>\n      <td>2715800</td>\n      <td>501.792271</td>\n    </tr>\n    <tr>\n      <td>2015-01-14</td>\n      <td>494.652237</td>\n      <td>503.232286</td>\n      <td>493.002234</td>\n      <td>500.872267</td>\n      <td>2235700</td>\n      <td>500.872267</td>\n    </tr>\n    <tr>\n      <td>2015-01-13</td>\n      <td>498.842256</td>\n      <td>502.982302</td>\n      <td>492.392254</td>\n      <td>496.182251</td>\n      <td>2370500</td>\n      <td>496.182251</td>\n    </tr>\n    <tr>\n      <td>2015-01-12</td>\n      <td>494.942247</td>\n      <td>495.978261</td>\n      <td>487.562205</td>\n      <td>492.552209</td>\n      <td>2322400</td>\n      <td>492.552209</td>\n    </tr>\n    <tr>\n      <td>2015-01-09</td>\n      <td>504.762300</td>\n      <td>504.922285</td>\n      <td>494.792239</td>\n      <td>496.172274</td>\n      <td>2069400</td>\n      <td>496.172274</td>\n    </tr>\n    <tr>\n      <td>2015-01-08</td>\n      <td>497.992238</td>\n      <td>503.482300</td>\n      <td>491.002212</td>\n      <td>502.682255</td>\n      <td>3353600</td>\n      <td>502.682255</td>\n    </tr>\n    <tr>\n      <td>2015-01-07</td>\n      <td>507.002299</td>\n      <td>507.246285</td>\n      <td>499.652247</td>\n      <td>501.102268</td>\n      <td>2065100</td>\n      <td>501.102268</td>\n    </tr>\n    <tr>\n      <td>2015-01-06</td>\n      <td>515.002358</td>\n      <td>516.177334</td>\n      <td>501.052266</td>\n      <td>501.962262</td>\n      <td>2899900</td>\n      <td>501.962262</td>\n    </tr>\n    <tr>\n      <td>2015-01-05</td>\n      <td>523.262377</td>\n      <td>524.332389</td>\n      <td>513.062315</td>\n      <td>513.872306</td>\n      <td>2059800</td>\n      <td>513.872306</td>\n    </tr>\n    <tr>\n      <td>2015-01-02</td>\n      <td>529.012399</td>\n      <td>531.272443</td>\n      <td>524.102327</td>\n      <td>524.812404</td>\n      <td>1447600</td>\n      <td>524.812404</td>\n    </tr>\n    <tr>\n      <td>2014-12-31</td>\n      <td>531.252429</td>\n      <td>532.602384</td>\n      <td>525.802363</td>\n      <td>526.402397</td>\n      <td>1368200</td>\n      <td>526.402397</td>\n    </tr>\n    <tr>\n      <td>2014-12-30</td>\n      <td>528.092396</td>\n      <td>531.152424</td>\n      <td>527.132366</td>\n      <td>530.422394</td>\n      <td>876300</td>\n      <td>530.422394</td>\n    </tr>\n    <tr>\n      <td>2014-12-29</td>\n      <td>532.192446</td>\n      <td>535.482414</td>\n      <td>530.013375</td>\n      <td>530.332426</td>\n      <td>2278500</td>\n      <td>530.332426</td>\n    </tr>\n    <tr>\n      <td>2014-12-26</td>\n      <td>528.772422</td>\n      <td>534.252417</td>\n      <td>527.312364</td>\n      <td>534.032454</td>\n      <td>1036000</td>\n      <td>534.032454</td>\n    </tr>\n    <tr>\n      <td>2014-12-24</td>\n      <td>530.512424</td>\n      <td>531.761394</td>\n      <td>527.022384</td>\n      <td>528.772422</td>\n      <td>705900</td>\n      <td>528.772422</td>\n    </tr>\n    <tr>\n      <td>2014-12-23</td>\n      <td>527.002370</td>\n      <td>534.562410</td>\n      <td>526.292354</td>\n      <td>530.592416</td>\n      <td>2197600</td>\n      <td>530.592416</td>\n    </tr>\n    <tr>\n      <td>2014-12-22</td>\n      <td>516.082347</td>\n      <td>526.462376</td>\n      <td>516.082347</td>\n      <td>524.872383</td>\n      <td>2723800</td>\n      <td>524.872383</td>\n    </tr>\n    <tr>\n      <td>2014-12-19</td>\n      <td>511.512318</td>\n      <td>517.722342</td>\n      <td>506.913310</td>\n      <td>516.352313</td>\n      <td>3690200</td>\n      <td>516.352313</td>\n    </tr>\n    <tr>\n      <td>2014-12-18</td>\n      <td>512.952333</td>\n      <td>513.872306</td>\n      <td>504.702290</td>\n      <td>511.102319</td>\n      <td>2926700</td>\n      <td>511.102319</td>\n    </tr>\n    <tr>\n      <td>2014-12-17</td>\n      <td>497.002248</td>\n      <td>507.002299</td>\n      <td>496.812244</td>\n      <td>504.892295</td>\n      <td>2883200</td>\n      <td>504.892295</td>\n    </tr>\n    <tr>\n      <td>2014-12-16</td>\n      <td>511.562321</td>\n      <td>513.052308</td>\n      <td>489.002220</td>\n      <td>495.392273</td>\n      <td>3964300</td>\n      <td>495.392273</td>\n    </tr>\n    <tr>\n      <td>2014-12-15</td>\n      <td>522.742335</td>\n      <td>523.102331</td>\n      <td>513.272333</td>\n      <td>513.802290</td>\n      <td>2813400</td>\n      <td>513.802290</td>\n    </tr>\n    <tr>\n      <td>2014-12-12</td>\n      <td>523.512391</td>\n      <td>528.502395</td>\n      <td>518.662298</td>\n      <td>518.662298</td>\n      <td>1994600</td>\n      <td>518.662298</td>\n    </tr>\n    <tr>\n      <td>2014-12-11</td>\n      <td>527.802355</td>\n      <td>533.922411</td>\n      <td>527.102376</td>\n      <td>528.342410</td>\n      <td>1610800</td>\n      <td>528.342410</td>\n    </tr>\n    <tr>\n      <td>2014-12-10</td>\n      <td>533.082399</td>\n      <td>536.332463</td>\n      <td>525.562386</td>\n      <td>526.062353</td>\n      <td>1712300</td>\n      <td>526.062353</td>\n    </tr>\n    <tr>\n      <td>2014-12-09</td>\n      <td>522.142362</td>\n      <td>534.192438</td>\n      <td>520.502366</td>\n      <td>533.372440</td>\n      <td>1871300</td>\n      <td>533.372440</td>\n    </tr>\n    <tr>\n      <td>2014-12-08</td>\n      <td>527.132366</td>\n      <td>531.002415</td>\n      <td>523.792334</td>\n      <td>526.982357</td>\n      <td>2329400</td>\n      <td>526.982357</td>\n    </tr>\n    <tr>\n      <td>2014-12-05</td>\n      <td>531.002415</td>\n      <td>532.892425</td>\n      <td>524.282386</td>\n      <td>525.262369</td>\n      <td>2565600</td>\n      <td>525.262369</td>\n    </tr>\n    <tr>\n      <td>2014-12-04</td>\n      <td>531.162400</td>\n      <td>537.342434</td>\n      <td>528.592424</td>\n      <td>537.312445</td>\n      <td>1392100</td>\n      <td>537.312445</td>\n    </tr>\n    <tr>\n      <td>2014-12-03</td>\n      <td>531.442404</td>\n      <td>535.998416</td>\n      <td>529.262414</td>\n      <td>531.322384</td>\n      <td>1278000</td>\n      <td>531.322384</td>\n    </tr>\n    <tr>\n      <td>2014-12-02</td>\n      <td>533.512412</td>\n      <td>535.502427</td>\n      <td>529.802408</td>\n      <td>533.752389</td>\n      <td>1525800</td>\n      <td>533.752389</td>\n    </tr>\n    <tr>\n      <td>2014-12-01</td>\n      <td>538.902438</td>\n      <td>541.412434</td>\n      <td>531.862379</td>\n      <td>533.802391</td>\n      <td>2115400</td>\n      <td>533.802391</td>\n    </tr>\n    <tr>\n      <td>2014-11-28</td>\n      <td>540.622426</td>\n      <td>542.002431</td>\n      <td>536.602429</td>\n      <td>541.832471</td>\n      <td>1148300</td>\n      <td>541.832471</td>\n    </tr>\n    <tr>\n      <td>2014-11-26</td>\n      <td>540.882478</td>\n      <td>541.552406</td>\n      <td>537.044437</td>\n      <td>540.372412</td>\n      <td>1523000</td>\n      <td>540.372412</td>\n    </tr>\n    <tr>\n      <td>2014-11-25</td>\n      <td>539.002444</td>\n      <td>543.982410</td>\n      <td>538.604440</td>\n      <td>541.082489</td>\n      <td>1789100</td>\n      <td>541.082489</td>\n    </tr>\n    <tr>\n      <td>2014-11-24</td>\n      <td>537.652489</td>\n      <td>542.702471</td>\n      <td>535.622446</td>\n      <td>539.272471</td>\n      <td>1706000</td>\n      <td>539.272471</td>\n    </tr>\n    <tr>\n      <td>2014-11-21</td>\n      <td>541.612446</td>\n      <td>542.142464</td>\n      <td>536.562402</td>\n      <td>537.502419</td>\n      <td>2223700</td>\n      <td>537.502419</td>\n    </tr>\n    <tr>\n      <td>2014-11-20</td>\n      <td>531.252429</td>\n      <td>535.112381</td>\n      <td>531.082408</td>\n      <td>534.832438</td>\n      <td>1562000</td>\n      <td>534.832438</td>\n    </tr>\n    <tr>\n      <td>2014-11-19</td>\n      <td>535.002399</td>\n      <td>538.242425</td>\n      <td>530.082412</td>\n      <td>536.992415</td>\n      <td>1391600</td>\n      <td>536.992415</td>\n    </tr>\n    <tr>\n      <td>2014-11-18</td>\n      <td>537.502419</td>\n      <td>541.942452</td>\n      <td>534.172425</td>\n      <td>535.032449</td>\n      <td>1962700</td>\n      <td>535.032449</td>\n    </tr>\n    <tr>\n      <td>2014-11-17</td>\n      <td>543.582448</td>\n      <td>543.792436</td>\n      <td>534.063361</td>\n      <td>536.512461</td>\n      <td>1725800</td>\n      <td>536.512461</td>\n    </tr>\n    <tr>\n      <td>2014-11-14</td>\n      <td>546.682442</td>\n      <td>546.682442</td>\n      <td>542.152501</td>\n      <td>544.402507</td>\n      <td>1289200</td>\n      <td>544.402507</td>\n    </tr>\n    <tr>\n      <td>2014-11-13</td>\n      <td>549.802448</td>\n      <td>549.802448</td>\n      <td>543.482442</td>\n      <td>545.382490</td>\n      <td>1339400</td>\n      <td>545.382490</td>\n    </tr>\n    <tr>\n      <td>2014-11-12</td>\n      <td>550.392507</td>\n      <td>550.462523</td>\n      <td>545.172441</td>\n      <td>547.312465</td>\n      <td>1129400</td>\n      <td>547.312465</td>\n    </tr>\n    <tr>\n      <td>2014-11-11</td>\n      <td>548.492459</td>\n      <td>551.942473</td>\n      <td>546.302493</td>\n      <td>550.292440</td>\n      <td>965500</td>\n      <td>550.292440</td>\n    </tr>\n    <tr>\n      <td>2014-11-10</td>\n      <td>541.462498</td>\n      <td>549.592522</td>\n      <td>541.022449</td>\n      <td>547.492463</td>\n      <td>1134600</td>\n      <td>547.492463</td>\n    </tr>\n    <tr>\n      <td>2014-11-07</td>\n      <td>546.212525</td>\n      <td>546.212525</td>\n      <td>538.672437</td>\n      <td>541.012473</td>\n      <td>1633800</td>\n      <td>541.012473</td>\n    </tr>\n    <tr>\n      <td>2014-11-06</td>\n      <td>545.502448</td>\n      <td>546.887472</td>\n      <td>540.972385</td>\n      <td>542.042458</td>\n      <td>1333300</td>\n      <td>542.042458</td>\n    </tr>\n    <tr>\n      <td>2014-11-05</td>\n      <td>556.802481</td>\n      <td>556.802481</td>\n      <td>544.052426</td>\n      <td>545.922423</td>\n      <td>2032300</td>\n      <td>545.922423</td>\n    </tr>\n    <tr>\n      <td>2014-11-04</td>\n      <td>553.002509</td>\n      <td>555.502529</td>\n      <td>549.302481</td>\n      <td>554.112486</td>\n      <td>1244200</td>\n      <td>554.112486</td>\n    </tr>\n    <tr>\n      <td>2014-11-03</td>\n      <td>555.502529</td>\n      <td>557.902544</td>\n      <td>553.232510</td>\n      <td>555.222464</td>\n      <td>1382300</td>\n      <td>555.222464</td>\n    </tr>\n    <tr>\n      <td>2014-10-31</td>\n      <td>559.352504</td>\n      <td>559.572529</td>\n      <td>554.752486</td>\n      <td>559.082538</td>\n      <td>2035100</td>\n      <td>559.082538</td>\n    </tr>\n    <tr>\n      <td>2014-10-30</td>\n      <td>548.952522</td>\n      <td>552.802497</td>\n      <td>543.512493</td>\n      <td>550.312514</td>\n      <td>1455500</td>\n      <td>550.312514</td>\n    </tr>\n    <tr>\n      <td>2014-10-29</td>\n      <td>550.002460</td>\n      <td>554.192540</td>\n      <td>546.982459</td>\n      <td>549.332532</td>\n      <td>1770500</td>\n      <td>549.332532</td>\n    </tr>\n    <tr>\n      <td>2014-10-28</td>\n      <td>543.002488</td>\n      <td>548.982450</td>\n      <td>541.622422</td>\n      <td>548.902519</td>\n      <td>1271000</td>\n      <td>548.902519</td>\n    </tr>\n    <tr>\n      <td>2014-10-27</td>\n      <td>537.032441</td>\n      <td>544.412422</td>\n      <td>537.032441</td>\n      <td>540.772496</td>\n      <td>1185300</td>\n      <td>540.772496</td>\n    </tr>\n    <tr>\n      <td>2014-10-24</td>\n      <td>544.362480</td>\n      <td>544.882461</td>\n      <td>535.792407</td>\n      <td>539.782476</td>\n      <td>1973100</td>\n      <td>539.782476</td>\n    </tr>\n    <tr>\n      <td>2014-10-23</td>\n      <td>539.322474</td>\n      <td>547.222436</td>\n      <td>535.852386</td>\n      <td>543.982410</td>\n      <td>2348800</td>\n      <td>543.982410</td>\n    </tr>\n    <tr>\n      <td>2014-10-22</td>\n      <td>529.892437</td>\n      <td>539.802428</td>\n      <td>528.802351</td>\n      <td>532.712427</td>\n      <td>2919300</td>\n      <td>532.712427</td>\n    </tr>\n    <tr>\n      <td>2014-10-21</td>\n      <td>525.192353</td>\n      <td>526.792383</td>\n      <td>519.112324</td>\n      <td>526.542369</td>\n      <td>2336300</td>\n      <td>526.542369</td>\n    </tr>\n    <tr>\n      <td>2014-10-20</td>\n      <td>509.452317</td>\n      <td>521.762353</td>\n      <td>508.102301</td>\n      <td>520.842410</td>\n      <td>2607500</td>\n      <td>520.842410</td>\n    </tr>\n    <tr>\n      <td>2014-10-17</td>\n      <td>527.252385</td>\n      <td>530.982402</td>\n      <td>508.532313</td>\n      <td>511.172335</td>\n      <td>5539400</td>\n      <td>511.172335</td>\n    </tr>\n    <tr>\n      <td>2014-10-16</td>\n      <td>519.002342</td>\n      <td>529.432374</td>\n      <td>515.002358</td>\n      <td>524.512387</td>\n      <td>3708600</td>\n      <td>524.512387</td>\n    </tr>\n    <tr>\n      <td>2014-10-15</td>\n      <td>531.012391</td>\n      <td>532.802396</td>\n      <td>518.302363</td>\n      <td>530.032409</td>\n      <td>3719400</td>\n      <td>530.032409</td>\n    </tr>\n    <tr>\n      <td>2014-10-14</td>\n      <td>538.902438</td>\n      <td>547.192507</td>\n      <td>533.172368</td>\n      <td>537.942408</td>\n      <td>2222600</td>\n      <td>537.942408</td>\n    </tr>\n    <tr>\n      <td>2014-10-13</td>\n      <td>544.992443</td>\n      <td>549.502492</td>\n      <td>533.102413</td>\n      <td>533.212456</td>\n      <td>2581700</td>\n      <td>533.212456</td>\n    </tr>\n    <tr>\n      <td>2014-10-10</td>\n      <td>557.722484</td>\n      <td>565.132577</td>\n      <td>544.052426</td>\n      <td>544.492476</td>\n      <td>3081900</td>\n      <td>544.492476</td>\n    </tr>\n    <tr>\n      <td>2014-10-09</td>\n      <td>571.182555</td>\n      <td>571.492549</td>\n      <td>559.062524</td>\n      <td>560.882579</td>\n      <td>2524800</td>\n      <td>560.882579</td>\n    </tr>\n    <tr>\n      <td>2014-10-08</td>\n      <td>565.572566</td>\n      <td>573.882587</td>\n      <td>557.492484</td>\n      <td>572.502582</td>\n      <td>1990900</td>\n      <td>572.502582</td>\n    </tr>\n    <tr>\n      <td>2014-10-07</td>\n      <td>574.402629</td>\n      <td>575.272630</td>\n      <td>563.742534</td>\n      <td>563.742534</td>\n      <td>1911300</td>\n      <td>563.742534</td>\n    </tr>\n    <tr>\n      <td>2014-10-06</td>\n      <td>578.802574</td>\n      <td>581.002639</td>\n      <td>574.442595</td>\n      <td>577.352614</td>\n      <td>1214600</td>\n      <td>577.352614</td>\n    </tr>\n    <tr>\n      <td>2014-10-03</td>\n      <td>573.052613</td>\n      <td>577.227576</td>\n      <td>572.502582</td>\n      <td>575.282606</td>\n      <td>1141700</td>\n      <td>575.282606</td>\n    </tr>\n    <tr>\n      <td>2014-10-02</td>\n      <td>567.312567</td>\n      <td>571.912585</td>\n      <td>563.322559</td>\n      <td>570.082615</td>\n      <td>1178400</td>\n      <td>570.082615</td>\n    </tr>\n    <tr>\n      <td>2014-10-01</td>\n      <td>576.012635</td>\n      <td>577.582615</td>\n      <td>567.012550</td>\n      <td>568.272597</td>\n      <td>1445500</td>\n      <td>568.272597</td>\n    </tr>\n    <tr>\n      <td>2014-09-30</td>\n      <td>576.932578</td>\n      <td>579.852634</td>\n      <td>572.852541</td>\n      <td>577.362590</td>\n      <td>1621700</td>\n      <td>577.362590</td>\n    </tr>\n    <tr>\n      <td>2014-09-29</td>\n      <td>571.752600</td>\n      <td>578.192625</td>\n      <td>571.172579</td>\n      <td>576.362594</td>\n      <td>1282400</td>\n      <td>576.362594</td>\n    </tr>\n    <tr>\n      <td>2014-09-26</td>\n      <td>576.062638</td>\n      <td>579.252600</td>\n      <td>574.662558</td>\n      <td>577.102600</td>\n      <td>1443700</td>\n      <td>577.102600</td>\n    </tr>\n    <tr>\n      <td>2014-09-25</td>\n      <td>587.552646</td>\n      <td>587.982658</td>\n      <td>574.182604</td>\n      <td>575.062581</td>\n      <td>1926000</td>\n      <td>575.062581</td>\n    </tr>\n    <tr>\n      <td>2014-09-24</td>\n      <td>581.462641</td>\n      <td>589.632691</td>\n      <td>580.522624</td>\n      <td>587.992634</td>\n      <td>1728100</td>\n      <td>587.992634</td>\n    </tr>\n    <tr>\n      <td>2014-09-23</td>\n      <td>586.852606</td>\n      <td>586.852606</td>\n      <td>581.002639</td>\n      <td>581.132634</td>\n      <td>1471400</td>\n      <td>581.132634</td>\n    </tr>\n    <tr>\n      <td>2014-09-22</td>\n      <td>593.822710</td>\n      <td>593.951665</td>\n      <td>583.462694</td>\n      <td>587.372648</td>\n      <td>1689500</td>\n      <td>587.372648</td>\n    </tr>\n    <tr>\n      <td>2014-09-19</td>\n      <td>591.502688</td>\n      <td>596.482654</td>\n      <td>589.502696</td>\n      <td>596.082692</td>\n      <td>3736600</td>\n      <td>596.082692</td>\n    </tr>\n    <tr>\n      <td>2014-09-18</td>\n      <td>587.002675</td>\n      <td>589.542661</td>\n      <td>585.002622</td>\n      <td>589.272695</td>\n      <td>1444600</td>\n      <td>589.272695</td>\n    </tr>\n    <tr>\n      <td>2014-09-17</td>\n      <td>580.012619</td>\n      <td>587.522656</td>\n      <td>578.777665</td>\n      <td>584.772683</td>\n      <td>1692800</td>\n      <td>584.772683</td>\n    </tr>\n    <tr>\n      <td>2014-09-16</td>\n      <td>572.762572</td>\n      <td>581.502606</td>\n      <td>572.662566</td>\n      <td>579.952640</td>\n      <td>1480400</td>\n      <td>579.952640</td>\n    </tr>\n    <tr>\n      <td>2014-09-15</td>\n      <td>572.942570</td>\n      <td>574.952599</td>\n      <td>568.212618</td>\n      <td>573.102555</td>\n      <td>1597600</td>\n      <td>573.102555</td>\n    </tr>\n    <tr>\n      <td>2014-09-12</td>\n      <td>581.002639</td>\n      <td>581.642639</td>\n      <td>574.462608</td>\n      <td>575.622589</td>\n      <td>1601700</td>\n      <td>575.622589</td>\n    </tr>\n    <tr>\n      <td>2014-09-11</td>\n      <td>580.362639</td>\n      <td>581.812599</td>\n      <td>576.262588</td>\n      <td>581.352598</td>\n      <td>1221000</td>\n      <td>581.352598</td>\n    </tr>\n    <tr>\n      <td>2014-09-10</td>\n      <td>581.502606</td>\n      <td>583.502659</td>\n      <td>576.942615</td>\n      <td>583.102636</td>\n      <td>977400</td>\n      <td>583.102636</td>\n    </tr>\n    <tr>\n      <td>2014-09-09</td>\n      <td>588.902723</td>\n      <td>589.002667</td>\n      <td>580.002643</td>\n      <td>581.012615</td>\n      <td>1287200</td>\n      <td>581.012615</td>\n    </tr>\n    <tr>\n      <td>2014-09-08</td>\n      <td>586.602653</td>\n      <td>591.772715</td>\n      <td>586.302635</td>\n      <td>589.722659</td>\n      <td>1431000</td>\n      <td>589.722659</td>\n    </tr>\n    <tr>\n      <td>2014-09-05</td>\n      <td>583.982613</td>\n      <td>586.552650</td>\n      <td>581.952632</td>\n      <td>586.082672</td>\n      <td>1632400</td>\n      <td>586.082672</td>\n    </tr>\n    <tr>\n      <td>2014-09-04</td>\n      <td>580.002643</td>\n      <td>586.002680</td>\n      <td>579.222611</td>\n      <td>581.982621</td>\n      <td>1458200</td>\n      <td>581.982621</td>\n    </tr>\n    <tr>\n      <td>2014-09-03</td>\n      <td>580.002643</td>\n      <td>582.992655</td>\n      <td>575.002602</td>\n      <td>577.942611</td>\n      <td>1215100</td>\n      <td>577.942611</td>\n    </tr>\n    <tr>\n      <td>2014-09-02</td>\n      <td>571.852545</td>\n      <td>577.832629</td>\n      <td>571.192593</td>\n      <td>577.332662</td>\n      <td>1578400</td>\n      <td>577.332662</td>\n    </tr>\n    <tr>\n      <td>2014-08-29</td>\n      <td>571.332625</td>\n      <td>572.042580</td>\n      <td>567.071550</td>\n      <td>571.602530</td>\n      <td>1083800</td>\n      <td>571.602530</td>\n    </tr>\n    <tr>\n      <td>2014-08-28</td>\n      <td>569.562573</td>\n      <td>573.252563</td>\n      <td>567.102518</td>\n      <td>569.202577</td>\n      <td>1292900</td>\n      <td>569.202577</td>\n    </tr>\n    <tr>\n      <td>2014-08-27</td>\n      <td>577.272622</td>\n      <td>578.492581</td>\n      <td>570.105627</td>\n      <td>571.002557</td>\n      <td>1703400</td>\n      <td>571.002557</td>\n    </tr>\n    <tr>\n      <td>2014-08-26</td>\n      <td>581.262629</td>\n      <td>581.802623</td>\n      <td>576.582619</td>\n      <td>577.862619</td>\n      <td>1639700</td>\n      <td>577.862619</td>\n    </tr>\n    <tr>\n      <td>2014-08-25</td>\n      <td>584.722619</td>\n      <td>585.002622</td>\n      <td>579.002647</td>\n      <td>580.202654</td>\n      <td>1361400</td>\n      <td>580.202654</td>\n    </tr>\n    <tr>\n      <td>2014-08-22</td>\n      <td>583.592689</td>\n      <td>585.238682</td>\n      <td>580.642643</td>\n      <td>582.562642</td>\n      <td>789100</td>\n      <td>582.562642</td>\n    </tr>\n    <tr>\n      <td>2014-08-21</td>\n      <td>583.822628</td>\n      <td>584.502655</td>\n      <td>581.142671</td>\n      <td>583.372664</td>\n      <td>914800</td>\n      <td>583.372664</td>\n    </tr>\n    <tr>\n      <td>2014-08-20</td>\n      <td>585.882660</td>\n      <td>586.702658</td>\n      <td>582.572618</td>\n      <td>584.492618</td>\n      <td>1036700</td>\n      <td>584.492618</td>\n    </tr>\n    <tr>\n      <td>2014-08-19</td>\n      <td>585.002622</td>\n      <td>587.342658</td>\n      <td>584.002627</td>\n      <td>586.862643</td>\n      <td>978700</td>\n      <td>586.862643</td>\n    </tr>\n    <tr>\n      <td>2014-08-18</td>\n      <td>576.112580</td>\n      <td>584.512631</td>\n      <td>576.002598</td>\n      <td>582.162619</td>\n      <td>1284100</td>\n      <td>582.162619</td>\n    </tr>\n    <tr>\n      <td>2014-08-15</td>\n      <td>577.862619</td>\n      <td>579.382595</td>\n      <td>570.522603</td>\n      <td>573.482564</td>\n      <td>1519200</td>\n      <td>573.482564</td>\n    </tr>\n    <tr>\n      <td>2014-08-14</td>\n      <td>576.182596</td>\n      <td>577.902645</td>\n      <td>570.882599</td>\n      <td>574.652643</td>\n      <td>985500</td>\n      <td>574.652643</td>\n    </tr>\n    <tr>\n      <td>2014-08-13</td>\n      <td>567.312567</td>\n      <td>575.002602</td>\n      <td>565.752564</td>\n      <td>574.782639</td>\n      <td>1441800</td>\n      <td>574.782639</td>\n    </tr>\n    <tr>\n      <td>2014-08-12</td>\n      <td>564.522567</td>\n      <td>565.902572</td>\n      <td>560.882579</td>\n      <td>562.732562</td>\n      <td>1542000</td>\n      <td>562.732562</td>\n    </tr>\n    <tr>\n      <td>2014-08-11</td>\n      <td>569.992585</td>\n      <td>570.492553</td>\n      <td>566.002578</td>\n      <td>567.882551</td>\n      <td>1214700</td>\n      <td>567.882551</td>\n    </tr>\n    <tr>\n      <td>2014-08-08</td>\n      <td>563.562536</td>\n      <td>570.252576</td>\n      <td>560.352500</td>\n      <td>568.772626</td>\n      <td>1494800</td>\n      <td>568.772626</td>\n    </tr>\n    <tr>\n      <td>2014-08-07</td>\n      <td>568.002570</td>\n      <td>569.892580</td>\n      <td>561.102482</td>\n      <td>563.362525</td>\n      <td>1110900</td>\n      <td>563.362525</td>\n    </tr>\n    <tr>\n      <td>2014-08-06</td>\n      <td>561.782569</td>\n      <td>570.702601</td>\n      <td>560.002541</td>\n      <td>566.376589</td>\n      <td>1334400</td>\n      <td>566.376589</td>\n    </tr>\n    <tr>\n      <td>2014-08-05</td>\n      <td>570.052564</td>\n      <td>571.982601</td>\n      <td>562.612543</td>\n      <td>565.072598</td>\n      <td>1551200</td>\n      <td>565.072598</td>\n    </tr>\n    <tr>\n      <td>2014-08-04</td>\n      <td>569.042531</td>\n      <td>575.352561</td>\n      <td>564.102531</td>\n      <td>573.152619</td>\n      <td>1427300</td>\n      <td>573.152619</td>\n    </tr>\n    <tr>\n      <td>2014-08-01</td>\n      <td>570.402584</td>\n      <td>575.962633</td>\n      <td>562.852520</td>\n      <td>566.072594</td>\n      <td>1955300</td>\n      <td>566.072594</td>\n    </tr>\n    <tr>\n      <td>2014-07-31</td>\n      <td>580.602616</td>\n      <td>583.652668</td>\n      <td>570.002561</td>\n      <td>571.602530</td>\n      <td>2102800</td>\n      <td>571.602530</td>\n    </tr>\n    <tr>\n      <td>2014-07-30</td>\n      <td>586.552650</td>\n      <td>589.502696</td>\n      <td>584.002627</td>\n      <td>587.422650</td>\n      <td>1016500</td>\n      <td>587.422650</td>\n    </tr>\n    <tr>\n      <td>2014-07-29</td>\n      <td>588.752653</td>\n      <td>589.702707</td>\n      <td>583.517654</td>\n      <td>585.612633</td>\n      <td>1349900</td>\n      <td>585.612633</td>\n    </tr>\n    <tr>\n      <td>2014-07-28</td>\n      <td>588.072688</td>\n      <td>592.502683</td>\n      <td>584.755668</td>\n      <td>590.602636</td>\n      <td>986800</td>\n      <td>590.602636</td>\n    </tr>\n    <tr>\n      <td>2014-07-25</td>\n      <td>590.402686</td>\n      <td>591.862684</td>\n      <td>587.032665</td>\n      <td>589.022681</td>\n      <td>932500</td>\n      <td>589.022681</td>\n    </tr>\n    <tr>\n      <td>2014-07-24</td>\n      <td>596.452725</td>\n      <td>599.502716</td>\n      <td>591.772715</td>\n      <td>593.352671</td>\n      <td>1035100</td>\n      <td>593.352671</td>\n    </tr>\n    <tr>\n      <td>2014-07-23</td>\n      <td>593.232652</td>\n      <td>597.852683</td>\n      <td>592.502683</td>\n      <td>595.982686</td>\n      <td>1233200</td>\n      <td>595.982686</td>\n    </tr>\n    <tr>\n      <td>2014-07-22</td>\n      <td>590.722655</td>\n      <td>599.652725</td>\n      <td>590.602636</td>\n      <td>594.742652</td>\n      <td>1699200</td>\n      <td>594.742652</td>\n    </tr>\n    <tr>\n      <td>2014-07-21</td>\n      <td>591.752702</td>\n      <td>594.402731</td>\n      <td>585.235622</td>\n      <td>589.472645</td>\n      <td>2062100</td>\n      <td>589.472645</td>\n    </tr>\n    <tr>\n      <td>2014-07-18</td>\n      <td>593.002712</td>\n      <td>596.802684</td>\n      <td>582.002635</td>\n      <td>595.082696</td>\n      <td>4014200</td>\n      <td>595.082696</td>\n    </tr>\n    <tr>\n      <td>2014-07-17</td>\n      <td>579.532665</td>\n      <td>580.992601</td>\n      <td>568.612580</td>\n      <td>573.732579</td>\n      <td>3016600</td>\n      <td>573.732579</td>\n    </tr>\n    <tr>\n      <td>2014-07-16</td>\n      <td>588.002671</td>\n      <td>588.402694</td>\n      <td>582.202646</td>\n      <td>582.662587</td>\n      <td>1397100</td>\n      <td>582.662587</td>\n    </tr>\n    <tr>\n      <td>2014-07-15</td>\n      <td>585.742628</td>\n      <td>585.807626</td>\n      <td>576.562606</td>\n      <td>584.782659</td>\n      <td>1623000</td>\n      <td>584.782659</td>\n    </tr>\n    <tr>\n      <td>2014-07-14</td>\n      <td>582.602608</td>\n      <td>585.212671</td>\n      <td>578.032641</td>\n      <td>584.872627</td>\n      <td>1854100</td>\n      <td>584.872627</td>\n    </tr>\n    <tr>\n      <td>2014-07-11</td>\n      <td>571.912585</td>\n      <td>580.852630</td>\n      <td>571.422594</td>\n      <td>579.182645</td>\n      <td>1621700</td>\n      <td>579.182645</td>\n    </tr>\n    <tr>\n      <td>2014-07-10</td>\n      <td>565.912548</td>\n      <td>576.592656</td>\n      <td>565.012558</td>\n      <td>571.102563</td>\n      <td>1356700</td>\n      <td>571.102563</td>\n    </tr>\n    <tr>\n      <td>2014-07-09</td>\n      <td>571.582578</td>\n      <td>576.722590</td>\n      <td>569.378536</td>\n      <td>576.082652</td>\n      <td>1116800</td>\n      <td>576.082652</td>\n    </tr>\n    <tr>\n      <td>2014-07-08</td>\n      <td>577.662607</td>\n      <td>579.530645</td>\n      <td>566.137592</td>\n      <td>571.092587</td>\n      <td>1909500</td>\n      <td>571.092587</td>\n    </tr>\n    <tr>\n      <td>2014-07-07</td>\n      <td>583.762650</td>\n      <td>586.432631</td>\n      <td>579.592644</td>\n      <td>582.252649</td>\n      <td>1064600</td>\n      <td>582.252649</td>\n    </tr>\n    <tr>\n      <td>2014-07-03</td>\n      <td>583.352589</td>\n      <td>585.012660</td>\n      <td>580.922585</td>\n      <td>584.732656</td>\n      <td>714200</td>\n      <td>584.732656</td>\n    </tr>\n    <tr>\n      <td>2014-07-02</td>\n      <td>583.352589</td>\n      <td>585.442672</td>\n      <td>580.392628</td>\n      <td>582.337660</td>\n      <td>1056400</td>\n      <td>582.337660</td>\n    </tr>\n    <tr>\n      <td>2014-07-01</td>\n      <td>578.322620</td>\n      <td>584.402649</td>\n      <td>576.652635</td>\n      <td>582.672624</td>\n      <td>1448000</td>\n      <td>582.672624</td>\n    </tr>\n    <tr>\n      <td>2014-06-30</td>\n      <td>578.662603</td>\n      <td>579.572631</td>\n      <td>574.752588</td>\n      <td>575.282606</td>\n      <td>1313800</td>\n      <td>575.282606</td>\n    </tr>\n    <tr>\n      <td>2014-06-27</td>\n      <td>577.182592</td>\n      <td>579.872648</td>\n      <td>573.802595</td>\n      <td>577.242632</td>\n      <td>2236900</td>\n      <td>577.242632</td>\n    </tr>\n    <tr>\n      <td>2014-06-26</td>\n      <td>581.002639</td>\n      <td>582.452660</td>\n      <td>571.852545</td>\n      <td>576.002598</td>\n      <td>1742000</td>\n      <td>576.002598</td>\n    </tr>\n    <tr>\n      <td>2014-06-25</td>\n      <td>565.262572</td>\n      <td>579.962616</td>\n      <td>565.222546</td>\n      <td>578.652627</td>\n      <td>1969400</td>\n      <td>578.652627</td>\n    </tr>\n    <tr>\n      <td>2014-06-24</td>\n      <td>565.192556</td>\n      <td>572.648612</td>\n      <td>561.012574</td>\n      <td>564.622572</td>\n      <td>2207100</td>\n      <td>564.622572</td>\n    </tr>\n    <tr>\n      <td>2014-06-23</td>\n      <td>555.152509</td>\n      <td>565.002582</td>\n      <td>554.252519</td>\n      <td>564.952579</td>\n      <td>1536800</td>\n      <td>564.952579</td>\n    </tr>\n    <tr>\n      <td>2014-06-20</td>\n      <td>556.852484</td>\n      <td>557.582513</td>\n      <td>550.394526</td>\n      <td>556.362492</td>\n      <td>4508300</td>\n      <td>556.362492</td>\n    </tr>\n    <tr>\n      <td>2014-06-19</td>\n      <td>554.242482</td>\n      <td>555.002500</td>\n      <td>548.512473</td>\n      <td>554.902556</td>\n      <td>2456800</td>\n      <td>554.902556</td>\n    </tr>\n    <tr>\n      <td>2014-06-18</td>\n      <td>544.862448</td>\n      <td>553.562516</td>\n      <td>544.002484</td>\n      <td>553.372481</td>\n      <td>1741800</td>\n      <td>553.372481</td>\n    </tr>\n    <tr>\n      <td>2014-06-17</td>\n      <td>544.202496</td>\n      <td>545.322450</td>\n      <td>539.332450</td>\n      <td>543.012465</td>\n      <td>1444600</td>\n      <td>543.012465</td>\n    </tr>\n    <tr>\n      <td>2014-06-16</td>\n      <td>549.262515</td>\n      <td>549.622450</td>\n      <td>541.522477</td>\n      <td>544.282488</td>\n      <td>1702600</td>\n      <td>544.282488</td>\n    </tr>\n    <tr>\n      <td>2014-06-13</td>\n      <td>552.262503</td>\n      <td>552.302469</td>\n      <td>545.562488</td>\n      <td>551.762536</td>\n      <td>1220500</td>\n      <td>551.762536</td>\n    </tr>\n    <tr>\n      <td>2014-06-12</td>\n      <td>557.302509</td>\n      <td>557.992512</td>\n      <td>548.462531</td>\n      <td>551.352476</td>\n      <td>1458500</td>\n      <td>551.352476</td>\n    </tr>\n    <tr>\n      <td>2014-06-11</td>\n      <td>558.002549</td>\n      <td>559.882522</td>\n      <td>555.022514</td>\n      <td>558.842561</td>\n      <td>1100100</td>\n      <td>558.842561</td>\n    </tr>\n    <tr>\n      <td>2014-06-10</td>\n      <td>560.512546</td>\n      <td>563.602502</td>\n      <td>557.902544</td>\n      <td>560.552511</td>\n      <td>1351700</td>\n      <td>560.552511</td>\n    </tr>\n    <tr>\n      <td>2014-06-09</td>\n      <td>557.152562</td>\n      <td>562.902584</td>\n      <td>556.042523</td>\n      <td>562.122552</td>\n      <td>1467500</td>\n      <td>562.122552</td>\n    </tr>\n    <tr>\n      <td>2014-06-06</td>\n      <td>558.062528</td>\n      <td>558.062528</td>\n      <td>548.932448</td>\n      <td>556.332564</td>\n      <td>1736800</td>\n      <td>556.332564</td>\n    </tr>\n    <tr>\n      <td>2014-06-05</td>\n      <td>546.402499</td>\n      <td>554.952498</td>\n      <td>544.452449</td>\n      <td>553.902560</td>\n      <td>1689100</td>\n      <td>553.902560</td>\n    </tr>\n    <tr>\n      <td>2014-06-04</td>\n      <td>541.502464</td>\n      <td>548.612478</td>\n      <td>538.752429</td>\n      <td>544.662436</td>\n      <td>1816500</td>\n      <td>544.662436</td>\n    </tr>\n    <tr>\n      <td>2014-06-03</td>\n      <td>550.992480</td>\n      <td>552.342557</td>\n      <td>542.552463</td>\n      <td>544.942501</td>\n      <td>1866600</td>\n      <td>544.942501</td>\n    </tr>\n    <tr>\n      <td>2014-06-02</td>\n      <td>560.702581</td>\n      <td>560.902593</td>\n      <td>545.732448</td>\n      <td>553.932488</td>\n      <td>1435000</td>\n      <td>553.932488</td>\n    </tr>\n    <tr>\n      <td>2014-05-30</td>\n      <td>560.802526</td>\n      <td>561.352496</td>\n      <td>555.912467</td>\n      <td>559.892559</td>\n      <td>1771100</td>\n      <td>559.892559</td>\n    </tr>\n    <tr>\n      <td>2014-05-29</td>\n      <td>563.352549</td>\n      <td>564.002525</td>\n      <td>558.712565</td>\n      <td>560.082534</td>\n      <td>1354100</td>\n      <td>560.082534</td>\n    </tr>\n    <tr>\n      <td>2014-05-28</td>\n      <td>564.572570</td>\n      <td>567.842585</td>\n      <td>561.002537</td>\n      <td>561.682502</td>\n      <td>1652000</td>\n      <td>561.682502</td>\n    </tr>\n    <tr>\n      <td>2014-05-27</td>\n      <td>556.002496</td>\n      <td>566.002578</td>\n      <td>554.352463</td>\n      <td>565.952575</td>\n      <td>2104200</td>\n      <td>565.952575</td>\n    </tr>\n    <tr>\n      <td>2014-05-23</td>\n      <td>547.262462</td>\n      <td>553.642508</td>\n      <td>543.702467</td>\n      <td>552.702492</td>\n      <td>1932200</td>\n      <td>552.702492</td>\n    </tr>\n    <tr>\n      <td>2014-05-22</td>\n      <td>541.132431</td>\n      <td>547.602445</td>\n      <td>540.782472</td>\n      <td>545.062459</td>\n      <td>1615800</td>\n      <td>545.062459</td>\n    </tr>\n    <tr>\n      <td>2014-05-21</td>\n      <td>532.902462</td>\n      <td>539.185441</td>\n      <td>531.912381</td>\n      <td>538.942465</td>\n      <td>1196300</td>\n      <td>538.942465</td>\n    </tr>\n    <tr>\n      <td>2014-05-20</td>\n      <td>529.742368</td>\n      <td>536.232396</td>\n      <td>526.302392</td>\n      <td>529.772418</td>\n      <td>1784800</td>\n      <td>529.772418</td>\n    </tr>\n    <tr>\n      <td>2014-05-19</td>\n      <td>519.702382</td>\n      <td>529.782456</td>\n      <td>517.585370</td>\n      <td>528.862391</td>\n      <td>1277800</td>\n      <td>528.862391</td>\n    </tr>\n    <tr>\n      <td>2014-05-16</td>\n      <td>521.392380</td>\n      <td>521.802379</td>\n      <td>515.442347</td>\n      <td>520.632362</td>\n      <td>1485300</td>\n      <td>520.632362</td>\n    </tr>\n    <tr>\n      <td>2014-05-15</td>\n      <td>525.702357</td>\n      <td>525.872379</td>\n      <td>517.422325</td>\n      <td>519.982324</td>\n      <td>1704400</td>\n      <td>519.982324</td>\n    </tr>\n    <tr>\n      <td>2014-05-14</td>\n      <td>533.002407</td>\n      <td>533.002407</td>\n      <td>525.292358</td>\n      <td>526.652412</td>\n      <td>1191800</td>\n      <td>526.652412</td>\n    </tr>\n    <tr>\n      <td>2014-05-13</td>\n      <td>530.892433</td>\n      <td>536.072411</td>\n      <td>529.512428</td>\n      <td>533.092437</td>\n      <td>1653400</td>\n      <td>533.092437</td>\n    </tr>\n    <tr>\n      <td>2014-05-12</td>\n      <td>523.512391</td>\n      <td>530.192393</td>\n      <td>519.012379</td>\n      <td>529.922366</td>\n      <td>1912500</td>\n      <td>529.922366</td>\n    </tr>\n    <tr>\n      <td>2014-05-09</td>\n      <td>510.752330</td>\n      <td>519.902393</td>\n      <td>504.202292</td>\n      <td>518.732314</td>\n      <td>2439500</td>\n      <td>518.732314</td>\n    </tr>\n    <tr>\n      <td>2014-05-08</td>\n      <td>508.462297</td>\n      <td>517.232290</td>\n      <td>506.452298</td>\n      <td>511.002313</td>\n      <td>2021300</td>\n      <td>511.002313</td>\n    </tr>\n    <tr>\n      <td>2014-05-07</td>\n      <td>515.792305</td>\n      <td>516.682320</td>\n      <td>503.302272</td>\n      <td>509.962291</td>\n      <td>3224300</td>\n      <td>509.962291</td>\n    </tr>\n    <tr>\n      <td>2014-05-06</td>\n      <td>525.232379</td>\n      <td>526.812396</td>\n      <td>515.062337</td>\n      <td>515.142330</td>\n      <td>1689000</td>\n      <td>515.142330</td>\n    </tr>\n    <tr>\n      <td>2014-05-05</td>\n      <td>524.822381</td>\n      <td>528.902418</td>\n      <td>521.322364</td>\n      <td>527.812392</td>\n      <td>1024100</td>\n      <td>527.812392</td>\n    </tr>\n    <tr>\n      <td>2014-05-02</td>\n      <td>533.762426</td>\n      <td>534.002403</td>\n      <td>525.612389</td>\n      <td>527.932411</td>\n      <td>1688500</td>\n      <td>527.932411</td>\n    </tr>\n    <tr>\n      <td>2014-05-01</td>\n      <td>527.112352</td>\n      <td>532.932391</td>\n      <td>523.882364</td>\n      <td>531.352374</td>\n      <td>1905500</td>\n      <td>531.352374</td>\n    </tr>\n    <tr>\n      <td>2014-04-30</td>\n      <td>527.602343</td>\n      <td>528.002366</td>\n      <td>522.522372</td>\n      <td>526.662388</td>\n      <td>1751200</td>\n      <td>526.662388</td>\n    </tr>\n    <tr>\n      <td>2014-04-29</td>\n      <td>516.902344</td>\n      <td>529.462425</td>\n      <td>516.322324</td>\n      <td>527.702410</td>\n      <td>2699100</td>\n      <td>527.702410</td>\n    </tr>\n    <tr>\n      <td>2014-04-28</td>\n      <td>517.182348</td>\n      <td>518.602319</td>\n      <td>502.802274</td>\n      <td>517.152359</td>\n      <td>3335500</td>\n      <td>517.152359</td>\n    </tr>\n    <tr>\n      <td>2014-04-25</td>\n      <td>522.512395</td>\n      <td>524.702361</td>\n      <td>515.422333</td>\n      <td>516.182352</td>\n      <td>2100400</td>\n      <td>516.182352</td>\n    </tr>\n    <tr>\n      <td>2014-04-24</td>\n      <td>530.072374</td>\n      <td>531.652452</td>\n      <td>522.122349</td>\n      <td>525.162363</td>\n      <td>1883200</td>\n      <td>525.162363</td>\n    </tr>\n    <tr>\n      <td>2014-04-23</td>\n      <td>533.792415</td>\n      <td>533.872408</td>\n      <td>526.252389</td>\n      <td>526.942391</td>\n      <td>2052300</td>\n      <td>526.942391</td>\n    </tr>\n    <tr>\n      <td>2014-04-22</td>\n      <td>528.642427</td>\n      <td>537.232391</td>\n      <td>527.512375</td>\n      <td>534.812425</td>\n      <td>2365400</td>\n      <td>534.812425</td>\n    </tr>\n    <tr>\n      <td>2014-04-21</td>\n      <td>536.102400</td>\n      <td>536.702435</td>\n      <td>525.602352</td>\n      <td>528.622414</td>\n      <td>2566700</td>\n      <td>528.622414</td>\n    </tr>\n    <tr>\n      <td>2014-04-17</td>\n      <td>548.812490</td>\n      <td>549.502492</td>\n      <td>531.152424</td>\n      <td>536.102400</td>\n      <td>6809500</td>\n      <td>536.102400</td>\n    </tr>\n    <tr>\n      <td>2014-04-16</td>\n      <td>543.002488</td>\n      <td>557.002492</td>\n      <td>540.002440</td>\n      <td>556.542490</td>\n      <td>4893300</td>\n      <td>556.542490</td>\n    </tr>\n    <tr>\n      <td>2014-04-15</td>\n      <td>536.822454</td>\n      <td>538.452473</td>\n      <td>518.462348</td>\n      <td>536.442444</td>\n      <td>3855100</td>\n      <td>536.442444</td>\n    </tr>\n    <tr>\n      <td>2014-04-14</td>\n      <td>538.252462</td>\n      <td>544.102429</td>\n      <td>529.562370</td>\n      <td>532.522453</td>\n      <td>2575100</td>\n      <td>532.522453</td>\n    </tr>\n    <tr>\n      <td>2014-04-11</td>\n      <td>532.552381</td>\n      <td>540.002440</td>\n      <td>526.532392</td>\n      <td>530.602392</td>\n      <td>3924800</td>\n      <td>530.602392</td>\n    </tr>\n    <tr>\n      <td>2014-04-10</td>\n      <td>565.002582</td>\n      <td>565.002582</td>\n      <td>539.902495</td>\n      <td>540.952433</td>\n      <td>4036900</td>\n      <td>540.952433</td>\n    </tr>\n    <tr>\n      <td>2014-04-09</td>\n      <td>559.622532</td>\n      <td>565.372554</td>\n      <td>552.952506</td>\n      <td>564.142557</td>\n      <td>3330800</td>\n      <td>564.142557</td>\n    </tr>\n    <tr>\n      <td>2014-04-08</td>\n      <td>542.602466</td>\n      <td>555.002500</td>\n      <td>541.612446</td>\n      <td>554.902556</td>\n      <td>3151200</td>\n      <td>554.902556</td>\n    </tr>\n    <tr>\n      <td>2014-04-07</td>\n      <td>540.742445</td>\n      <td>548.482483</td>\n      <td>527.152440</td>\n      <td>538.152456</td>\n      <td>4401700</td>\n      <td>538.152456</td>\n    </tr>\n    <tr>\n      <td>2014-04-04</td>\n      <td>574.652643</td>\n      <td>577.772650</td>\n      <td>543.002488</td>\n      <td>543.142460</td>\n      <td>6369300</td>\n      <td>543.142460</td>\n    </tr>\n    <tr>\n      <td>2014-04-03</td>\n      <td>569.852553</td>\n      <td>587.282679</td>\n      <td>564.132581</td>\n      <td>569.742571</td>\n      <td>5099200</td>\n      <td>569.742571</td>\n    </tr>\n    <tr>\n      <td>2014-04-02</td>\n      <td>599.992707</td>\n      <td>604.832763</td>\n      <td>562.192568</td>\n      <td>567.002574</td>\n      <td>147100</td>\n      <td>567.002574</td>\n    </tr>\n    <tr>\n      <td>2014-04-01</td>\n      <td>558.712565</td>\n      <td>568.452595</td>\n      <td>558.712565</td>\n      <td>567.162558</td>\n      <td>7900</td>\n      <td>567.162558</td>\n    </tr>\n    <tr>\n      <td>2014-03-31</td>\n      <td>566.892592</td>\n      <td>567.002574</td>\n      <td>556.932537</td>\n      <td>556.972503</td>\n      <td>10800</td>\n      <td>556.972503</td>\n    </tr>\n    <tr>\n      <td>2014-03-28</td>\n      <td>561.202549</td>\n      <td>566.432590</td>\n      <td>558.672477</td>\n      <td>559.992504</td>\n      <td>41200</td>\n      <td>559.992504</td>\n    </tr>\n    <tr>\n      <td>2014-03-27</td>\n      <td>568.002570</td>\n      <td>568.002570</td>\n      <td>552.922516</td>\n      <td>558.462551</td>\n      <td>13100</td>\n      <td>558.462551</td>\n    </tr>\n  </table>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week7/yahooFinantial/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"strconv\"\n)\n\ntype information struct {\n\tdate      string\n\topen      float64\n\thigh      float64\n\tlow       float64\n\tcloseData float64\n\tvolume    int64\n\tadjClose  float64\n}\n\nfunc parseHeader(row []string) map[string]int {\n\tcolumns := map[string]int{}\n\tfor i, v := range row {\n\t\tcolumns[v] = i\n\t}\n\treturn columns\n}\n\nfunc parseRow(columns map[string]int, row []string) (*information, error) {\n\tdate := row[columns[\"Date\"]]\n\n\tdata := row[columns[\"Open\"]]\n\topen, err := strconv.ParseFloat(data, 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdata = row[columns[\"High\"]]\n\thigh, err := strconv.ParseFloat(data, 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdata = row[columns[\"Low\"]]\n\tlow, err := strconv.ParseFloat(data, 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdata = row[columns[\"Close\"]]\n\tcloseData, err := strconv.ParseFloat(data, 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdata = row[columns[\"Volume\"]]\n\tvolume, err := strconv.ParseInt(data, 10, 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdata = row[columns[\"Adj Close\"]]\n\tadjClose, err := strconv.ParseFloat(data, 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &information{\n\t\tdate:      date,\n\t\topen:      open,\n\t\thigh:      high,\n\t\tlow:       low,\n\t\tcloseData: closeData,\n\t\tvolume:    volume,\n\t\tadjClose:  adjClose,\n\t}, nil\n}\n\nfunc readTable(rdr io.Reader) ([]information, error) {\n\tcsvReader := csv.NewReader(rdr)\n\tvar columns map[string]int\n\tinfo := []information{}\n\tfor i := 0; ; i++ {\n\t\trow, err := csvReader.Read()\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif i == 0 {\n\t\t\tcolumns = parseHeader(row)\n\t\t} else {\n\t\t\tnewData, err := parseRow(columns, row)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tinfo = append(info, *newData)\n\t\t}\n\t}\n\treturn info, nil\n}\n\nfunc main() {\n\tfile, err := os.Open(\"table.csv\")\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\tdefer file.Close()\n\n\tinfo, err := readTable(file)\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\n\tfmt.Println(`<!DOCTYPE html>\n<html>\n<head>\n  <style>\n    td {\n      padding: 7px;\n    }\n  </style>\n</head>\n<body>\n  <table border=\"1\">\n    <tr>\n      <th>Date</th>\n      <th>Open</th>\n      <th>High</th>\n      <th>Low</th>\n      <th>Close</th>\n      <th>Volume</th>\n      <th>Adj Close</th>\n    </tr>`)\n\tfor _, v := range info {\n\t\tfmt.Printf(`    <tr>\n      <td>%s</td>\n      <td>%f</td>\n      <td>%f</td>\n      <td>%f</td>\n      <td>%f</td>\n      <td>%d</td>\n      <td>%f</td>\n    </tr>\n`, v.date, v.open, v.high, v.low, v.closeData, v.volume, v.adjClose)\n\t}\n\tfmt.Println(`  </table>\n</body>\n</html>`)\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week7/yahooFinantial/table.csv",
    "content": "Date,Open,High,Low,Close,Volume,Adj Close\n2015-07-09,523.119995,523.77002,520.349976,520.679993,1839400,520.679993\n2015-07-08,521.049988,522.734009,516.109985,516.830017,1264600,516.830017\n2015-07-07,523.130005,526.179993,515.179993,525.02002,1595700,525.02002\n2015-07-06,519.50,525.25,519.00,522.859985,1276500,522.859985\n2015-07-02,521.080017,524.650024,521.080017,523.400024,1234000,523.400024\n2015-07-01,524.72998,525.690002,518.22998,521.840027,1961000,521.840027\n2015-06-30,526.02002,526.25,520.50,520.51001,2217200,520.51001\n2015-06-29,525.01001,528.609985,520.539978,521.52002,1930900,521.52002\n2015-06-26,537.26001,537.76001,531.349976,531.690002,2011500,531.690002\n2015-06-25,538.869995,540.900024,535.22998,535.22998,1331500,535.22998\n2015-06-24,540.00,540.00,535.659973,537.840027,1283400,537.840027\n2015-06-23,539.640015,541.499023,535.25,540.47998,1196000,540.47998\n2015-06-22,539.590027,543.73999,537.530029,538.190002,1242500,538.190002\n2015-06-19,537.210022,538.25,533.01001,536.690002,1885700,536.690002\n2015-06-18,531.00,538.150024,530.789978,536.72998,1828100,536.72998\n2015-06-17,529.369995,530.97998,525.099976,529.26001,1268600,529.26001\n2015-06-16,528.400024,529.640015,525.559998,528.150024,1069300,528.150024\n2015-06-15,528.00,528.299988,524.00,527.200012,1630700,527.200012\n2015-06-12,531.599976,533.119995,530.159973,532.330017,952400,532.330017\n2015-06-11,538.424988,538.97998,533.02002,534.609985,1205000,534.609985\n2015-06-10,529.359985,538.359985,529.349976,536.690002,1811400,536.690002\n2015-06-09,527.559998,529.200012,523.01001,526.690002,1441600,526.690002\n2015-06-08,533.309998,534.119995,526.23999,526.830017,1520600,526.830017\n2015-06-05,536.349976,537.200012,532.52002,533.330017,1375000,533.330017\n2015-06-04,537.76001,540.590027,534.320007,536.700012,1335600,536.700012\n2015-06-03,539.909973,543.50,537.109985,540.309998,1714500,540.309998\n2015-06-02,532.929993,543.00,531.330017,539.179993,1934700,539.179993\n2015-06-01,536.789978,536.789978,529.76001,533.98999,1899600,533.98999\n2015-05-29,537.369995,538.630005,531.450012,532.109985,2584900,532.109985\n2015-05-28,538.01001,540.609985,536.25,539.780029,1027900,539.780029\n2015-05-27,532.799988,540.549988,531.710022,539.789978,1520400,539.789978\n2015-05-26,538.119995,539.00,529.880005,532.320007,2403400,532.320007\n2015-05-22,540.150024,544.190002,539.51001,540.109985,1173300,540.109985\n2015-05-21,537.950012,543.840027,535.97998,542.51001,1461400,542.51001\n2015-05-20,538.48999,542.919983,532.971985,539.27002,1429100,539.27002\n2015-05-19,533.97998,540.659973,533.039978,537.359985,1963300,537.359985\n2015-05-18,532.01001,534.820007,528.849976,532.299988,1998600,532.299988\n2015-05-15,539.179993,539.273987,530.380005,533.849976,1962700,533.849976\n2015-05-14,533.77002,539.00,532.409973,538.400024,1399100,538.400024\n2015-05-13,530.559998,534.322021,528.655029,529.619995,1252300,529.619995\n2015-05-12,531.599976,533.208984,525.26001,529.039978,1625400,529.039978\n2015-05-11,538.369995,541.97998,535.400024,535.700012,905300,535.700012\n2015-05-08,536.650024,541.150024,525.00,538.219971,1527600,538.219971\n2015-05-07,523.98999,533.460022,521.75,530.700012,1546300,530.700012\n2015-05-06,531.23999,532.380005,521.085022,524.219971,1567000,524.219971\n2015-05-05,538.210022,539.73999,530.390991,530.799988,1383100,530.799988\n2015-05-04,538.530029,544.070007,535.059998,540.780029,1308000,540.780029\n2015-05-01,538.429993,539.539978,532.099976,537.900024,1768200,537.900024\n2015-04-30,547.869995,548.590027,535.049988,537.340027,2082200,537.340027\n2015-04-29,550.469971,553.679993,546.905029,549.080017,1698800,549.080017\n2015-04-28,554.640015,556.02002,550.366028,553.679993,1491000,553.679993\n2015-04-27,563.390015,565.950012,553.200012,555.369995,2398000,555.369995\n2015-04-24,566.102522,571.14259,557.252507,565.062561,4932500,565.062561\n2015-04-23,541.002435,550.96249,540.23244,547.002472,4184900,547.002472\n2015-04-22,534.402426,541.082489,531.752397,539.367458,1593600,539.367458\n2015-04-21,537.512456,539.392429,533.677415,533.972413,1844800,533.972413\n2015-04-20,525.602352,536.092424,524.50235,535.382408,1679300,535.382408\n2015-04-17,528.662379,529.842435,521.012371,524.052386,2144100,524.052386\n2015-04-16,529.902414,535.592457,529.612373,533.802391,1299900,533.802391\n2015-04-15,528.702406,534.732432,523.22235,532.532429,2318800,532.532429\n2015-04-14,536.252409,537.572435,528.094354,530.392405,2604100,530.392405\n2015-04-13,538.412385,544.062463,537.312445,539.172404,1645300,539.172404\n2015-04-10,542.292411,542.292411,537.312445,540.012477,1409500,540.012477\n2015-04-09,541.032486,541.95249,535.49239,540.782472,1557900,540.782472\n2015-04-08,538.382457,543.852415,538.382457,541.612446,1178500,541.612446\n2015-04-07,538.08244,542.692434,536.002395,537.022465,1302900,537.022465\n2015-04-06,532.222375,538.412385,529.572407,536.767432,1324400,536.767432\n2015-04-02,540.852427,540.852427,533.849395,535.532478,1716400,535.532478\n2015-04-01,548.602441,551.142488,539.502472,542.562439,1963100,542.562439\n2015-03-31,550.00246,554.712521,546.722468,548.002468,1588000,548.002468\n2015-03-30,551.622503,553.472487,548.17249,552.032502,1287500,552.032502\n2015-03-27,553.002509,555.282565,548.132463,548.342512,1897500,548.342512\n2015-03-26,557.59255,558.90254,550.652497,555.172522,1572600,555.172522\n2015-03-25,570.50259,572.262605,558.742494,558.787478,2152300,558.787478\n2015-03-24,562.562541,574.592603,561.212586,570.192597,2583300,570.192597\n2015-03-23,560.432554,562.362529,555.832536,558.81251,1643800,558.81251\n2015-03-20,561.652574,561.722529,559.052548,560.362537,2616900,560.362537\n2015-03-19,559.392531,560.802526,556.147548,557.992512,1197300,557.992512\n2015-03-18,552.50248,559.782578,547.002472,559.502513,2134500,559.502513\n2015-03-17,551.712533,553.802493,548.002468,550.842532,1805500,550.842532\n2015-03-16,550.952514,556.852484,546.002476,554.512509,1641000,554.512509\n2015-03-13,553.502537,558.402572,544.222448,547.322503,1703600,547.322503\n2015-03-12,553.512513,556.37253,550.462523,555.512505,1389600,555.512505\n2015-03-11,555.142533,558.142521,550.682486,551.182515,1820800,551.182515\n2015-03-10,564.252539,564.852512,554.732473,555.012538,1792300,555.012538\n2015-03-09,566.862541,570.272589,563.537504,568.852557,1062100,568.852557\n2015-03-06,574.882583,576.682625,566.762597,567.687558,1659100,567.687558\n2015-03-05,575.022616,577.912621,573.412548,575.332609,1389600,575.332609\n2015-03-04,571.872558,577.112576,568.012607,573.372583,1876800,573.372583\n2015-03-03,570.452587,575.392649,566.522559,573.64261,1704800,573.64261\n2015-03-02,560.532559,572.152623,558.752531,571.342601,2129600,571.342601\n2015-02-27,554.242482,564.712602,552.902503,558.402572,2410200,558.402572\n2015-02-26,543.212476,556.142529,541.502464,555.482516,2311500,555.482516\n2015-02-25,535.90245,546.22244,535.447406,543.872489,1826000,543.872489\n2015-02-24,530.002419,536.792403,528.252381,536.092424,1005100,536.092424\n2015-02-23,536.052398,536.441465,529.412361,531.912381,1457900,531.912381\n2015-02-20,543.132484,543.75247,535.802444,538.952441,1444400,538.952441\n2015-02-19,538.042413,543.11247,538.012424,542.872432,989100,542.872432\n2015-02-18,541.402458,545.492471,537.512456,539.702422,1453100,539.702422\n2015-02-17,546.832511,550.00246,541.092465,542.842504,1616800,542.842504\n2015-02-13,543.352447,549.912491,543.132484,549.012501,1900300,549.012501\n2015-02-12,537.252405,544.822482,534.675391,542.932472,1620200,542.932472\n2015-02-11,535.302416,538.452473,533.380397,535.972405,1377800,535.972405\n2015-02-10,529.302379,537.702431,526.922378,536.942412,1749900,536.942412\n2015-02-09,528.002366,532.002411,526.022388,527.832406,1267800,527.832406\n2015-02-06,527.642431,537.202463,526.412373,531.002415,1749400,531.002415\n2015-02-05,523.792334,528.502395,522.092359,527.582391,1849800,527.582391\n2015-02-04,529.2424,532.67442,521.272361,522.762349,1663700,522.762349\n2015-02-03,528.002366,533.40243,523.262377,529.2424,2038700,529.2424\n2015-02-02,531.732383,533.002407,518.552316,528.482381,2849800,528.482381\n2015-01-30,515.862322,539.872444,515.522339,534.522445,5606400,534.522445\n2015-01-29,511.002313,511.092313,501.202274,510.662331,4186400,510.662331\n2015-01-28,522.782423,522.992349,510.002318,510.002318,1683800,510.002318\n2015-01-27,529.972369,530.702398,518.192381,518.63237,1904000,518.63237\n2015-01-26,538.532466,539.002444,529.672413,535.212448,1543700,535.212448\n2015-01-23,535.592457,542.172453,533.002407,539.952437,2281700,539.952437\n2015-01-22,521.482349,536.332463,519.702382,534.39245,2676900,534.39245\n2015-01-21,507.252283,519.282407,506.202315,518.042312,2268700,518.042312\n2015-01-20,511.002313,512.502307,506.018277,506.902294,2227900,506.902294\n2015-01-16,500.012273,508.1923,500.002267,508.082288,2298300,508.082288\n2015-01-15,505.572291,505.682273,497.762267,501.792271,2715800,501.792271\n2015-01-14,494.652237,503.232286,493.002234,500.872267,2235700,500.872267\n2015-01-13,498.842256,502.982302,492.392254,496.182251,2370500,496.182251\n2015-01-12,494.942247,495.978261,487.562205,492.552209,2322400,492.552209\n2015-01-09,504.7623,504.922285,494.792239,496.172274,2069400,496.172274\n2015-01-08,497.992238,503.4823,491.002212,502.682255,3353600,502.682255\n2015-01-07,507.002299,507.246285,499.652247,501.102268,2065100,501.102268\n2015-01-06,515.002358,516.177334,501.052266,501.962262,2899900,501.962262\n2015-01-05,523.262377,524.332389,513.062315,513.872306,2059800,513.872306\n2015-01-02,529.012399,531.272443,524.102327,524.812404,1447600,524.812404\n2014-12-31,531.252429,532.602384,525.802363,526.402397,1368200,526.402397\n2014-12-30,528.092396,531.152424,527.132366,530.422394,876300,530.422394\n2014-12-29,532.192446,535.482414,530.013375,530.332426,2278500,530.332426\n2014-12-26,528.772422,534.252417,527.312364,534.032454,1036000,534.032454\n2014-12-24,530.512424,531.761394,527.022384,528.772422,705900,528.772422\n2014-12-23,527.00237,534.56241,526.292354,530.592416,2197600,530.592416\n2014-12-22,516.082347,526.462376,516.082347,524.872383,2723800,524.872383\n2014-12-19,511.512318,517.722342,506.91331,516.352313,3690200,516.352313\n2014-12-18,512.952333,513.872306,504.70229,511.102319,2926700,511.102319\n2014-12-17,497.002248,507.002299,496.812244,504.892295,2883200,504.892295\n2014-12-16,511.562321,513.052308,489.00222,495.392273,3964300,495.392273\n2014-12-15,522.742335,523.102331,513.272333,513.80229,2813400,513.80229\n2014-12-12,523.512391,528.502395,518.662298,518.662298,1994600,518.662298\n2014-12-11,527.802355,533.922411,527.102376,528.34241,1610800,528.34241\n2014-12-10,533.082399,536.332463,525.562386,526.062353,1712300,526.062353\n2014-12-09,522.142362,534.192438,520.502366,533.37244,1871300,533.37244\n2014-12-08,527.132366,531.002415,523.792334,526.982357,2329400,526.982357\n2014-12-05,531.002415,532.892425,524.282386,525.262369,2565600,525.262369\n2014-12-04,531.1624,537.342434,528.592424,537.312445,1392100,537.312445\n2014-12-03,531.442404,535.998416,529.262414,531.322384,1278000,531.322384\n2014-12-02,533.512412,535.502427,529.802408,533.752389,1525800,533.752389\n2014-12-01,538.902438,541.412434,531.862379,533.802391,2115400,533.802391\n2014-11-28,540.622426,542.002431,536.602429,541.832471,1148300,541.832471\n2014-11-26,540.882478,541.552406,537.044437,540.372412,1523000,540.372412\n2014-11-25,539.002444,543.98241,538.60444,541.082489,1789100,541.082489\n2014-11-24,537.652489,542.702471,535.622446,539.272471,1706000,539.272471\n2014-11-21,541.612446,542.142464,536.562402,537.502419,2223700,537.502419\n2014-11-20,531.252429,535.112381,531.082408,534.832438,1562000,534.832438\n2014-11-19,535.002399,538.242425,530.082412,536.992415,1391600,536.992415\n2014-11-18,537.502419,541.942452,534.172425,535.032449,1962700,535.032449\n2014-11-17,543.582448,543.792436,534.063361,536.512461,1725800,536.512461\n2014-11-14,546.682442,546.682442,542.152501,544.402507,1289200,544.402507\n2014-11-13,549.802448,549.802448,543.482442,545.38249,1339400,545.38249\n2014-11-12,550.392507,550.462523,545.172441,547.312465,1129400,547.312465\n2014-11-11,548.492459,551.942473,546.302493,550.29244,965500,550.29244\n2014-11-10,541.462498,549.592522,541.022449,547.492463,1134600,547.492463\n2014-11-07,546.212525,546.212525,538.672437,541.012473,1633800,541.012473\n2014-11-06,545.502448,546.887472,540.972385,542.042458,1333300,542.042458\n2014-11-05,556.802481,556.802481,544.052426,545.922423,2032300,545.922423\n2014-11-04,553.002509,555.502529,549.302481,554.112486,1244200,554.112486\n2014-11-03,555.502529,557.902544,553.23251,555.222464,1382300,555.222464\n2014-10-31,559.352504,559.572529,554.752486,559.082538,2035100,559.082538\n2014-10-30,548.952522,552.802497,543.512493,550.312514,1455500,550.312514\n2014-10-29,550.00246,554.19254,546.982459,549.332532,1770500,549.332532\n2014-10-28,543.002488,548.98245,541.622422,548.902519,1271000,548.902519\n2014-10-27,537.032441,544.412422,537.032441,540.772496,1185300,540.772496\n2014-10-24,544.36248,544.882461,535.792407,539.782476,1973100,539.782476\n2014-10-23,539.322474,547.222436,535.852386,543.98241,2348800,543.98241\n2014-10-22,529.892437,539.802428,528.802351,532.712427,2919300,532.712427\n2014-10-21,525.192353,526.792383,519.112324,526.542369,2336300,526.542369\n2014-10-20,509.452317,521.762353,508.102301,520.84241,2607500,520.84241\n2014-10-17,527.252385,530.982402,508.532313,511.172335,5539400,511.172335\n2014-10-16,519.002342,529.432374,515.002358,524.512387,3708600,524.512387\n2014-10-15,531.012391,532.802396,518.302363,530.032409,3719400,530.032409\n2014-10-14,538.902438,547.192507,533.172368,537.942408,2222600,537.942408\n2014-10-13,544.992443,549.502492,533.102413,533.212456,2581700,533.212456\n2014-10-10,557.722484,565.132577,544.052426,544.492476,3081900,544.492476\n2014-10-09,571.182555,571.492549,559.062524,560.882579,2524800,560.882579\n2014-10-08,565.572566,573.882587,557.492484,572.502582,1990900,572.502582\n2014-10-07,574.402629,575.27263,563.742534,563.742534,1911300,563.742534\n2014-10-06,578.802574,581.002639,574.442595,577.352614,1214600,577.352614\n2014-10-03,573.052613,577.227576,572.502582,575.282606,1141700,575.282606\n2014-10-02,567.312567,571.912585,563.322559,570.082615,1178400,570.082615\n2014-10-01,576.012635,577.582615,567.01255,568.272597,1445500,568.272597\n2014-09-30,576.932578,579.852634,572.852541,577.36259,1621700,577.36259\n2014-09-29,571.7526,578.192625,571.172579,576.362594,1282400,576.362594\n2014-09-26,576.062638,579.2526,574.662558,577.1026,1443700,577.1026\n2014-09-25,587.552646,587.982658,574.182604,575.062581,1926000,575.062581\n2014-09-24,581.462641,589.632691,580.522624,587.992634,1728100,587.992634\n2014-09-23,586.852606,586.852606,581.002639,581.132634,1471400,581.132634\n2014-09-22,593.82271,593.951665,583.462694,587.372648,1689500,587.372648\n2014-09-19,591.502688,596.482654,589.502696,596.082692,3736600,596.082692\n2014-09-18,587.002675,589.542661,585.002622,589.272695,1444600,589.272695\n2014-09-17,580.012619,587.522656,578.777665,584.772683,1692800,584.772683\n2014-09-16,572.762572,581.502606,572.662566,579.95264,1480400,579.95264\n2014-09-15,572.94257,574.952599,568.212618,573.102555,1597600,573.102555\n2014-09-12,581.002639,581.642639,574.462608,575.622589,1601700,575.622589\n2014-09-11,580.362639,581.812599,576.262588,581.352598,1221000,581.352598\n2014-09-10,581.502606,583.502659,576.942615,583.102636,977400,583.102636\n2014-09-09,588.902723,589.002667,580.002643,581.012615,1287200,581.012615\n2014-09-08,586.602653,591.772715,586.302635,589.722659,1431000,589.722659\n2014-09-05,583.982613,586.55265,581.952632,586.082672,1632400,586.082672\n2014-09-04,580.002643,586.00268,579.222611,581.982621,1458200,581.982621\n2014-09-03,580.002643,582.992655,575.002602,577.942611,1215100,577.942611\n2014-09-02,571.852545,577.832629,571.192593,577.332662,1578400,577.332662\n2014-08-29,571.332625,572.04258,567.07155,571.60253,1083800,571.60253\n2014-08-28,569.562573,573.252563,567.102518,569.202577,1292900,569.202577\n2014-08-27,577.272622,578.492581,570.105627,571.002557,1703400,571.002557\n2014-08-26,581.262629,581.802623,576.582619,577.862619,1639700,577.862619\n2014-08-25,584.722619,585.002622,579.002647,580.202654,1361400,580.202654\n2014-08-22,583.592689,585.238682,580.642643,582.562642,789100,582.562642\n2014-08-21,583.822628,584.502655,581.142671,583.372664,914800,583.372664\n2014-08-20,585.88266,586.702658,582.572618,584.492618,1036700,584.492618\n2014-08-19,585.002622,587.342658,584.002627,586.862643,978700,586.862643\n2014-08-18,576.11258,584.512631,576.002598,582.162619,1284100,582.162619\n2014-08-15,577.862619,579.382595,570.522603,573.482564,1519200,573.482564\n2014-08-14,576.182596,577.902645,570.882599,574.652643,985500,574.652643\n2014-08-13,567.312567,575.002602,565.752564,574.782639,1441800,574.782639\n2014-08-12,564.522567,565.902572,560.882579,562.732562,1542000,562.732562\n2014-08-11,569.992585,570.492553,566.002578,567.882551,1214700,567.882551\n2014-08-08,563.562536,570.252576,560.3525,568.772626,1494800,568.772626\n2014-08-07,568.00257,569.89258,561.102482,563.362525,1110900,563.362525\n2014-08-06,561.782569,570.702601,560.002541,566.376589,1334400,566.376589\n2014-08-05,570.052564,571.982601,562.612543,565.072598,1551200,565.072598\n2014-08-04,569.042531,575.352561,564.102531,573.152619,1427300,573.152619\n2014-08-01,570.402584,575.962633,562.85252,566.072594,1955300,566.072594\n2014-07-31,580.602616,583.652668,570.002561,571.60253,2102800,571.60253\n2014-07-30,586.55265,589.502696,584.002627,587.42265,1016500,587.42265\n2014-07-29,588.752653,589.702707,583.517654,585.612633,1349900,585.612633\n2014-07-28,588.072688,592.502683,584.755668,590.602636,986800,590.602636\n2014-07-25,590.402686,591.862684,587.032665,589.022681,932500,589.022681\n2014-07-24,596.452725,599.502716,591.772715,593.352671,1035100,593.352671\n2014-07-23,593.232652,597.852683,592.502683,595.982686,1233200,595.982686\n2014-07-22,590.722655,599.652725,590.602636,594.742652,1699200,594.742652\n2014-07-21,591.752702,594.402731,585.235622,589.472645,2062100,589.472645\n2014-07-18,593.002712,596.802684,582.002635,595.082696,4014200,595.082696\n2014-07-17,579.532665,580.992601,568.61258,573.732579,3016600,573.732579\n2014-07-16,588.002671,588.402694,582.202646,582.662587,1397100,582.662587\n2014-07-15,585.742628,585.807626,576.562606,584.782659,1623000,584.782659\n2014-07-14,582.602608,585.212671,578.032641,584.872627,1854100,584.872627\n2014-07-11,571.912585,580.85263,571.422594,579.182645,1621700,579.182645\n2014-07-10,565.912548,576.592656,565.012558,571.102563,1356700,571.102563\n2014-07-09,571.582578,576.72259,569.378536,576.082652,1116800,576.082652\n2014-07-08,577.662607,579.530645,566.137592,571.092587,1909500,571.092587\n2014-07-07,583.76265,586.432631,579.592644,582.252649,1064600,582.252649\n2014-07-03,583.352589,585.01266,580.922585,584.732656,714200,584.732656\n2014-07-02,583.352589,585.442672,580.392628,582.33766,1056400,582.33766\n2014-07-01,578.32262,584.402649,576.652635,582.672624,1448000,582.672624\n2014-06-30,578.662603,579.572631,574.752588,575.282606,1313800,575.282606\n2014-06-27,577.182592,579.872648,573.802595,577.242632,2236900,577.242632\n2014-06-26,581.002639,582.45266,571.852545,576.002598,1742000,576.002598\n2014-06-25,565.262572,579.962616,565.222546,578.652627,1969400,578.652627\n2014-06-24,565.192556,572.648612,561.012574,564.622572,2207100,564.622572\n2014-06-23,555.152509,565.002582,554.252519,564.952579,1536800,564.952579\n2014-06-20,556.852484,557.582513,550.394526,556.362492,4508300,556.362492\n2014-06-19,554.242482,555.0025,548.512473,554.902556,2456800,554.902556\n2014-06-18,544.862448,553.562516,544.002484,553.372481,1741800,553.372481\n2014-06-17,544.202496,545.32245,539.33245,543.012465,1444600,543.012465\n2014-06-16,549.262515,549.62245,541.522477,544.282488,1702600,544.282488\n2014-06-13,552.262503,552.302469,545.562488,551.762536,1220500,551.762536\n2014-06-12,557.302509,557.992512,548.462531,551.352476,1458500,551.352476\n2014-06-11,558.002549,559.882522,555.022514,558.842561,1100100,558.842561\n2014-06-10,560.512546,563.602502,557.902544,560.552511,1351700,560.552511\n2014-06-09,557.152562,562.902584,556.042523,562.122552,1467500,562.122552\n2014-06-06,558.062528,558.062528,548.932448,556.332564,1736800,556.332564\n2014-06-05,546.402499,554.952498,544.452449,553.90256,1689100,553.90256\n2014-06-04,541.502464,548.612478,538.752429,544.662436,1816500,544.662436\n2014-06-03,550.99248,552.342557,542.552463,544.942501,1866600,544.942501\n2014-06-02,560.702581,560.902593,545.732448,553.932488,1435000,553.932488\n2014-05-30,560.802526,561.352496,555.912467,559.892559,1771100,559.892559\n2014-05-29,563.352549,564.002525,558.712565,560.082534,1354100,560.082534\n2014-05-28,564.57257,567.842585,561.002537,561.682502,1652000,561.682502\n2014-05-27,556.002496,566.002578,554.352463,565.952575,2104200,565.952575\n2014-05-23,547.262462,553.642508,543.702467,552.702492,1932200,552.702492\n2014-05-22,541.132431,547.602445,540.782472,545.062459,1615800,545.062459\n2014-05-21,532.902462,539.185441,531.912381,538.942465,1196300,538.942465\n2014-05-20,529.742368,536.232396,526.302392,529.772418,1784800,529.772418\n2014-05-19,519.702382,529.782456,517.58537,528.862391,1277800,528.862391\n2014-05-16,521.39238,521.802379,515.442347,520.632362,1485300,520.632362\n2014-05-15,525.702357,525.872379,517.422325,519.982324,1704400,519.982324\n2014-05-14,533.002407,533.002407,525.292358,526.652412,1191800,526.652412\n2014-05-13,530.892433,536.072411,529.512428,533.092437,1653400,533.092437\n2014-05-12,523.512391,530.192393,519.012379,529.922366,1912500,529.922366\n2014-05-09,510.75233,519.902393,504.202292,518.732314,2439500,518.732314\n2014-05-08,508.462297,517.23229,506.452298,511.002313,2021300,511.002313\n2014-05-07,515.792305,516.68232,503.302272,509.962291,3224300,509.962291\n2014-05-06,525.232379,526.812396,515.062337,515.14233,1689000,515.14233\n2014-05-05,524.822381,528.902418,521.322364,527.812392,1024100,527.812392\n2014-05-02,533.762426,534.002403,525.612389,527.932411,1688500,527.932411\n2014-05-01,527.112352,532.932391,523.882364,531.352374,1905500,531.352374\n2014-04-30,527.602343,528.002366,522.522372,526.662388,1751200,526.662388\n2014-04-29,516.902344,529.462425,516.322324,527.70241,2699100,527.70241\n2014-04-28,517.182348,518.602319,502.802274,517.152359,3335500,517.152359\n2014-04-25,522.512395,524.702361,515.422333,516.182352,2100400,516.182352\n2014-04-24,530.072374,531.652452,522.122349,525.162363,1883200,525.162363\n2014-04-23,533.792415,533.872408,526.252389,526.942391,2052300,526.942391\n2014-04-22,528.642427,537.232391,527.512375,534.812425,2365400,534.812425\n2014-04-21,536.1024,536.702435,525.602352,528.622414,2566700,528.622414\n2014-04-17,548.81249,549.502492,531.152424,536.1024,6809500,536.1024\n2014-04-16,543.002488,557.002492,540.00244,556.54249,4893300,556.54249\n2014-04-15,536.822454,538.452473,518.462348,536.442444,3855100,536.442444\n2014-04-14,538.252462,544.102429,529.56237,532.522453,2575100,532.522453\n2014-04-11,532.552381,540.00244,526.532392,530.602392,3924800,530.602392\n2014-04-10,565.002582,565.002582,539.902495,540.952433,4036900,540.952433\n2014-04-09,559.622532,565.372554,552.952506,564.142557,3330800,564.142557\n2014-04-08,542.602466,555.0025,541.612446,554.902556,3151200,554.902556\n2014-04-07,540.742445,548.482483,527.15244,538.152456,4401700,538.152456\n2014-04-04,574.652643,577.77265,543.002488,543.14246,6369300,543.14246\n2014-04-03,569.852553,587.282679,564.132581,569.742571,5099200,569.742571\n2014-04-02,599.992707,604.832763,562.192568,567.002574,147100,567.002574\n2014-04-01,558.712565,568.452595,558.712565,567.162558,7900,567.162558\n2014-03-31,566.892592,567.002574,556.932537,556.972503,10800,556.972503\n2014-03-28,561.202549,566.43259,558.672477,559.992504,41200,559.992504\n2014-03-27,568.00257,568.00257,552.922516,558.462551,13100,558.462551\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/chatRoom/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\n\t\"github.com/ttacon/chalk\"\n)\n\n// User holds a user of the chat room\ntype User struct {\n\tName   string\n\tOutput chan Message\n}\n\n// Message holds a message for the chat room\ntype Message struct {\n\tUsername string\n\tText     string\n}\n\n// ChatServer holds all the data about the current state of the chat room\ntype ChatServer struct {\n\tUsers map[string]User\n\tJoin  chan User\n\tLeave chan User\n\tInput chan Message\n}\n\n// Run runs the server\nfunc (cs *ChatServer) Run() {\n\tfor {\n\t\tselect {\n\t\tcase user := <-cs.Join:\n\t\t\tcs.Users[user.Name] = user\n\t\t\tgo func() {\n\t\t\t\tcs.Input <- Message{\n\t\t\t\t\tUsername: \"SYSTEM\",\n\t\t\t\t\tText:     fmt.Sprintf(\"%s joined\", user.Name),\n\t\t\t\t}\n\t\t\t}()\n\t\tcase user := <-cs.Leave:\n\t\t\tdelete(cs.Users, user.Name)\n\t\t\tgo func() {\n\t\t\t\tcs.Input <- Message{\n\t\t\t\t\tUsername: \"SYSTEM\",\n\t\t\t\t\tText:     fmt.Sprintf(\"%s left\", user.Name),\n\t\t\t\t}\n\t\t\t}()\n\t\tcase msg := <-cs.Input:\n\t\t\tfor _, user := range cs.Users {\n\t\t\t\tselect {\n\t\t\t\tcase user.Output <- msg:\n\t\t\t\tdefault:\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc handleConn(chatServer *ChatServer, conn net.Conn) {\n\tdefer conn.Close()\n\n\tio.WriteString(conn, \"Enter your username: \")\n\tscanner := bufio.NewScanner(conn)\n\tscanner.Scan()\n\n\tuser := User{\n\t\tName:   scanner.Text(),\n\t\tOutput: make(chan Message, 10),\n\t}\n\n\tchatServer.Join <- user\n\tdefer func() {\n\t\tchatServer.Leave <- user\n\t}()\n\n\tgo func() {\n\t\tscanner := bufio.NewScanner(conn)\n\t\tfor scanner.Scan() {\n\t\t\tln := scanner.Text()\n\t\t\tchatServer.Input <- Message{user.Name, ln}\n\t\t}\n\t\tclose(user.Output)\n\t}()\n\n\tfor msg := range user.Output {\n\t\t_, err := fmt.Fprintf(conn, \"%s%s: %s%s%s\\n\", chalk.Yellow, msg.Username, chalk.White, msg.Text, chalk.ResetColor)\n\t\tif err != nil {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\nfunc main() {\n\tlnr, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer lnr.Close()\n\n\tchatServer := &ChatServer{\n\t\tUsers: make(map[string]User),\n\t\tJoin:  make(chan User),\n\t\tLeave: make(chan User),\n\t\tInput: make(chan Message),\n\t}\n\n\tgo chatServer.Run()\n\n\tfor {\n\t\tconn, err := lnr.Accept()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tgo handleConn(chatServer, conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/colors/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ttacon/chalk\"\n)\n\nfunc main() {\n\tstrange := chalk.Red.NewStyle()\n\tstrange.WithBackground(chalk.Blue).WithTextStyle(chalk.Underline)\n\tfmt.Println(strange.Style(\"Hello Color World!\"))\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/csv-convert/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc readHeader(row []string) []string {\n\theaders := []string{}\n\tfor _, v := range row {\n\t\theaders = append(headers, v)\n\t}\n\treturn headers\n}\n\nfunc readRow(row []string, header []string) (map[string]string, error) {\n\tif len(row) != len(header) {\n\t\treturn nil, errors.New(\"row and header do not have the same lengths\")\n\t}\n\tnewRow := map[string]string{}\n\tfor i := range row {\n\t\tnewRow[header[i]] = row[i]\n\t}\n\treturn newRow, nil\n}\n\nfunc readCsv(filename string) ([]map[string]string, error) {\n\tf, err := os.Open(os.Args[1])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer f.Close()\n\n\trdr := csv.NewReader(f)\n\tdataBytes, err := rdr.ReadAll()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdata := []map[string]string{}\n\n\theaders := readHeader(dataBytes[0])\n\n\tfor _, v := range dataBytes[1:] {\n\t\tnewRow, err := readRow(v, headers)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdata = append(data, newRow)\n\t}\n\n\treturn data, nil\n}\n\nfunc main() {\n\tif len(os.Args) < 2 {\n\t\tlog.Fatalln(\"Usage:\", os.Args[0], \"<csv filename>\")\n\t}\n\n\tw, err := os.Create(\"table.json\")\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\tdefer w.Close()\n\n\tdata, err := readCsv(os.Args[1])\n\n\terr = json.NewEncoder(w).Encode(data)\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/csv-convert/table.csv",
    "content": "Date,Open,High,Low,Close,Volume,Adj Close\n2015-07-09,523.119995,523.77002,520.349976,520.679993,1839400,520.679993\n2015-07-08,521.049988,522.734009,516.109985,516.830017,1264600,516.830017\n2015-07-07,523.130005,526.179993,515.179993,525.02002,1595700,525.02002\n2015-07-06,519.50,525.25,519.00,522.859985,1276500,522.859985\n2015-07-02,521.080017,524.650024,521.080017,523.400024,1234000,523.400024\n2015-07-01,524.72998,525.690002,518.22998,521.840027,1961000,521.840027\n2015-06-30,526.02002,526.25,520.50,520.51001,2217200,520.51001\n2015-06-29,525.01001,528.609985,520.539978,521.52002,1930900,521.52002\n2015-06-26,537.26001,537.76001,531.349976,531.690002,2011500,531.690002\n2015-06-25,538.869995,540.900024,535.22998,535.22998,1331500,535.22998\n2015-06-24,540.00,540.00,535.659973,537.840027,1283400,537.840027\n2015-06-23,539.640015,541.499023,535.25,540.47998,1196000,540.47998\n2015-06-22,539.590027,543.73999,537.530029,538.190002,1242500,538.190002\n2015-06-19,537.210022,538.25,533.01001,536.690002,1885700,536.690002\n2015-06-18,531.00,538.150024,530.789978,536.72998,1828100,536.72998\n2015-06-17,529.369995,530.97998,525.099976,529.26001,1268600,529.26001\n2015-06-16,528.400024,529.640015,525.559998,528.150024,1069300,528.150024\n2015-06-15,528.00,528.299988,524.00,527.200012,1630700,527.200012\n2015-06-12,531.599976,533.119995,530.159973,532.330017,952400,532.330017\n2015-06-11,538.424988,538.97998,533.02002,534.609985,1205000,534.609985\n2015-06-10,529.359985,538.359985,529.349976,536.690002,1811400,536.690002\n2015-06-09,527.559998,529.200012,523.01001,526.690002,1441600,526.690002\n2015-06-08,533.309998,534.119995,526.23999,526.830017,1520600,526.830017\n2015-06-05,536.349976,537.200012,532.52002,533.330017,1375000,533.330017\n2015-06-04,537.76001,540.590027,534.320007,536.700012,1335600,536.700012\n2015-06-03,539.909973,543.50,537.109985,540.309998,1714500,540.309998\n2015-06-02,532.929993,543.00,531.330017,539.179993,1934700,539.179993\n2015-06-01,536.789978,536.789978,529.76001,533.98999,1899600,533.98999\n2015-05-29,537.369995,538.630005,531.450012,532.109985,2584900,532.109985\n2015-05-28,538.01001,540.609985,536.25,539.780029,1027900,539.780029\n2015-05-27,532.799988,540.549988,531.710022,539.789978,1520400,539.789978\n2015-05-26,538.119995,539.00,529.880005,532.320007,2403400,532.320007\n2015-05-22,540.150024,544.190002,539.51001,540.109985,1173300,540.109985\n2015-05-21,537.950012,543.840027,535.97998,542.51001,1461400,542.51001\n2015-05-20,538.48999,542.919983,532.971985,539.27002,1429100,539.27002\n2015-05-19,533.97998,540.659973,533.039978,537.359985,1963300,537.359985\n2015-05-18,532.01001,534.820007,528.849976,532.299988,1998600,532.299988\n2015-05-15,539.179993,539.273987,530.380005,533.849976,1962700,533.849976\n2015-05-14,533.77002,539.00,532.409973,538.400024,1399100,538.400024\n2015-05-13,530.559998,534.322021,528.655029,529.619995,1252300,529.619995\n2015-05-12,531.599976,533.208984,525.26001,529.039978,1625400,529.039978\n2015-05-11,538.369995,541.97998,535.400024,535.700012,905300,535.700012\n2015-05-08,536.650024,541.150024,525.00,538.219971,1527600,538.219971\n2015-05-07,523.98999,533.460022,521.75,530.700012,1546300,530.700012\n2015-05-06,531.23999,532.380005,521.085022,524.219971,1567000,524.219971\n2015-05-05,538.210022,539.73999,530.390991,530.799988,1383100,530.799988\n2015-05-04,538.530029,544.070007,535.059998,540.780029,1308000,540.780029\n2015-05-01,538.429993,539.539978,532.099976,537.900024,1768200,537.900024\n2015-04-30,547.869995,548.590027,535.049988,537.340027,2082200,537.340027\n2015-04-29,550.469971,553.679993,546.905029,549.080017,1698800,549.080017\n2015-04-28,554.640015,556.02002,550.366028,553.679993,1491000,553.679993\n2015-04-27,563.390015,565.950012,553.200012,555.369995,2398000,555.369995\n2015-04-24,566.102522,571.14259,557.252507,565.062561,4932500,565.062561\n2015-04-23,541.002435,550.96249,540.23244,547.002472,4184900,547.002472\n2015-04-22,534.402426,541.082489,531.752397,539.367458,1593600,539.367458\n2015-04-21,537.512456,539.392429,533.677415,533.972413,1844800,533.972413\n2015-04-20,525.602352,536.092424,524.50235,535.382408,1679300,535.382408\n2015-04-17,528.662379,529.842435,521.012371,524.052386,2144100,524.052386\n2015-04-16,529.902414,535.592457,529.612373,533.802391,1299900,533.802391\n2015-04-15,528.702406,534.732432,523.22235,532.532429,2318800,532.532429\n2015-04-14,536.252409,537.572435,528.094354,530.392405,2604100,530.392405\n2015-04-13,538.412385,544.062463,537.312445,539.172404,1645300,539.172404\n2015-04-10,542.292411,542.292411,537.312445,540.012477,1409500,540.012477\n2015-04-09,541.032486,541.95249,535.49239,540.782472,1557900,540.782472\n2015-04-08,538.382457,543.852415,538.382457,541.612446,1178500,541.612446\n2015-04-07,538.08244,542.692434,536.002395,537.022465,1302900,537.022465\n2015-04-06,532.222375,538.412385,529.572407,536.767432,1324400,536.767432\n2015-04-02,540.852427,540.852427,533.849395,535.532478,1716400,535.532478\n2015-04-01,548.602441,551.142488,539.502472,542.562439,1963100,542.562439\n2015-03-31,550.00246,554.712521,546.722468,548.002468,1588000,548.002468\n2015-03-30,551.622503,553.472487,548.17249,552.032502,1287500,552.032502\n2015-03-27,553.002509,555.282565,548.132463,548.342512,1897500,548.342512\n2015-03-26,557.59255,558.90254,550.652497,555.172522,1572600,555.172522\n2015-03-25,570.50259,572.262605,558.742494,558.787478,2152300,558.787478\n2015-03-24,562.562541,574.592603,561.212586,570.192597,2583300,570.192597\n2015-03-23,560.432554,562.362529,555.832536,558.81251,1643800,558.81251\n2015-03-20,561.652574,561.722529,559.052548,560.362537,2616900,560.362537\n2015-03-19,559.392531,560.802526,556.147548,557.992512,1197300,557.992512\n2015-03-18,552.50248,559.782578,547.002472,559.502513,2134500,559.502513\n2015-03-17,551.712533,553.802493,548.002468,550.842532,1805500,550.842532\n2015-03-16,550.952514,556.852484,546.002476,554.512509,1641000,554.512509\n2015-03-13,553.502537,558.402572,544.222448,547.322503,1703600,547.322503\n2015-03-12,553.512513,556.37253,550.462523,555.512505,1389600,555.512505\n2015-03-11,555.142533,558.142521,550.682486,551.182515,1820800,551.182515\n2015-03-10,564.252539,564.852512,554.732473,555.012538,1792300,555.012538\n2015-03-09,566.862541,570.272589,563.537504,568.852557,1062100,568.852557\n2015-03-06,574.882583,576.682625,566.762597,567.687558,1659100,567.687558\n2015-03-05,575.022616,577.912621,573.412548,575.332609,1389600,575.332609\n2015-03-04,571.872558,577.112576,568.012607,573.372583,1876800,573.372583\n2015-03-03,570.452587,575.392649,566.522559,573.64261,1704800,573.64261\n2015-03-02,560.532559,572.152623,558.752531,571.342601,2129600,571.342601\n2015-02-27,554.242482,564.712602,552.902503,558.402572,2410200,558.402572\n2015-02-26,543.212476,556.142529,541.502464,555.482516,2311500,555.482516\n2015-02-25,535.90245,546.22244,535.447406,543.872489,1826000,543.872489\n2015-02-24,530.002419,536.792403,528.252381,536.092424,1005100,536.092424\n2015-02-23,536.052398,536.441465,529.412361,531.912381,1457900,531.912381\n2015-02-20,543.132484,543.75247,535.802444,538.952441,1444400,538.952441\n2015-02-19,538.042413,543.11247,538.012424,542.872432,989100,542.872432\n2015-02-18,541.402458,545.492471,537.512456,539.702422,1453100,539.702422\n2015-02-17,546.832511,550.00246,541.092465,542.842504,1616800,542.842504\n2015-02-13,543.352447,549.912491,543.132484,549.012501,1900300,549.012501\n2015-02-12,537.252405,544.822482,534.675391,542.932472,1620200,542.932472\n2015-02-11,535.302416,538.452473,533.380397,535.972405,1377800,535.972405\n2015-02-10,529.302379,537.702431,526.922378,536.942412,1749900,536.942412\n2015-02-09,528.002366,532.002411,526.022388,527.832406,1267800,527.832406\n2015-02-06,527.642431,537.202463,526.412373,531.002415,1749400,531.002415\n2015-02-05,523.792334,528.502395,522.092359,527.582391,1849800,527.582391\n2015-02-04,529.2424,532.67442,521.272361,522.762349,1663700,522.762349\n2015-02-03,528.002366,533.40243,523.262377,529.2424,2038700,529.2424\n2015-02-02,531.732383,533.002407,518.552316,528.482381,2849800,528.482381\n2015-01-30,515.862322,539.872444,515.522339,534.522445,5606400,534.522445\n2015-01-29,511.002313,511.092313,501.202274,510.662331,4186400,510.662331\n2015-01-28,522.782423,522.992349,510.002318,510.002318,1683800,510.002318\n2015-01-27,529.972369,530.702398,518.192381,518.63237,1904000,518.63237\n2015-01-26,538.532466,539.002444,529.672413,535.212448,1543700,535.212448\n2015-01-23,535.592457,542.172453,533.002407,539.952437,2281700,539.952437\n2015-01-22,521.482349,536.332463,519.702382,534.39245,2676900,534.39245\n2015-01-21,507.252283,519.282407,506.202315,518.042312,2268700,518.042312\n2015-01-20,511.002313,512.502307,506.018277,506.902294,2227900,506.902294\n2015-01-16,500.012273,508.1923,500.002267,508.082288,2298300,508.082288\n2015-01-15,505.572291,505.682273,497.762267,501.792271,2715800,501.792271\n2015-01-14,494.652237,503.232286,493.002234,500.872267,2235700,500.872267\n2015-01-13,498.842256,502.982302,492.392254,496.182251,2370500,496.182251\n2015-01-12,494.942247,495.978261,487.562205,492.552209,2322400,492.552209\n2015-01-09,504.7623,504.922285,494.792239,496.172274,2069400,496.172274\n2015-01-08,497.992238,503.4823,491.002212,502.682255,3353600,502.682255\n2015-01-07,507.002299,507.246285,499.652247,501.102268,2065100,501.102268\n2015-01-06,515.002358,516.177334,501.052266,501.962262,2899900,501.962262\n2015-01-05,523.262377,524.332389,513.062315,513.872306,2059800,513.872306\n2015-01-02,529.012399,531.272443,524.102327,524.812404,1447600,524.812404\n2014-12-31,531.252429,532.602384,525.802363,526.402397,1368200,526.402397\n2014-12-30,528.092396,531.152424,527.132366,530.422394,876300,530.422394\n2014-12-29,532.192446,535.482414,530.013375,530.332426,2278500,530.332426\n2014-12-26,528.772422,534.252417,527.312364,534.032454,1036000,534.032454\n2014-12-24,530.512424,531.761394,527.022384,528.772422,705900,528.772422\n2014-12-23,527.00237,534.56241,526.292354,530.592416,2197600,530.592416\n2014-12-22,516.082347,526.462376,516.082347,524.872383,2723800,524.872383\n2014-12-19,511.512318,517.722342,506.91331,516.352313,3690200,516.352313\n2014-12-18,512.952333,513.872306,504.70229,511.102319,2926700,511.102319\n2014-12-17,497.002248,507.002299,496.812244,504.892295,2883200,504.892295\n2014-12-16,511.562321,513.052308,489.00222,495.392273,3964300,495.392273\n2014-12-15,522.742335,523.102331,513.272333,513.80229,2813400,513.80229\n2014-12-12,523.512391,528.502395,518.662298,518.662298,1994600,518.662298\n2014-12-11,527.802355,533.922411,527.102376,528.34241,1610800,528.34241\n2014-12-10,533.082399,536.332463,525.562386,526.062353,1712300,526.062353\n2014-12-09,522.142362,534.192438,520.502366,533.37244,1871300,533.37244\n2014-12-08,527.132366,531.002415,523.792334,526.982357,2329400,526.982357\n2014-12-05,531.002415,532.892425,524.282386,525.262369,2565600,525.262369\n2014-12-04,531.1624,537.342434,528.592424,537.312445,1392100,537.312445\n2014-12-03,531.442404,535.998416,529.262414,531.322384,1278000,531.322384\n2014-12-02,533.512412,535.502427,529.802408,533.752389,1525800,533.752389\n2014-12-01,538.902438,541.412434,531.862379,533.802391,2115400,533.802391\n2014-11-28,540.622426,542.002431,536.602429,541.832471,1148300,541.832471\n2014-11-26,540.882478,541.552406,537.044437,540.372412,1523000,540.372412\n2014-11-25,539.002444,543.98241,538.60444,541.082489,1789100,541.082489\n2014-11-24,537.652489,542.702471,535.622446,539.272471,1706000,539.272471\n2014-11-21,541.612446,542.142464,536.562402,537.502419,2223700,537.502419\n2014-11-20,531.252429,535.112381,531.082408,534.832438,1562000,534.832438\n2014-11-19,535.002399,538.242425,530.082412,536.992415,1391600,536.992415\n2014-11-18,537.502419,541.942452,534.172425,535.032449,1962700,535.032449\n2014-11-17,543.582448,543.792436,534.063361,536.512461,1725800,536.512461\n2014-11-14,546.682442,546.682442,542.152501,544.402507,1289200,544.402507\n2014-11-13,549.802448,549.802448,543.482442,545.38249,1339400,545.38249\n2014-11-12,550.392507,550.462523,545.172441,547.312465,1129400,547.312465\n2014-11-11,548.492459,551.942473,546.302493,550.29244,965500,550.29244\n2014-11-10,541.462498,549.592522,541.022449,547.492463,1134600,547.492463\n2014-11-07,546.212525,546.212525,538.672437,541.012473,1633800,541.012473\n2014-11-06,545.502448,546.887472,540.972385,542.042458,1333300,542.042458\n2014-11-05,556.802481,556.802481,544.052426,545.922423,2032300,545.922423\n2014-11-04,553.002509,555.502529,549.302481,554.112486,1244200,554.112486\n2014-11-03,555.502529,557.902544,553.23251,555.222464,1382300,555.222464\n2014-10-31,559.352504,559.572529,554.752486,559.082538,2035100,559.082538\n2014-10-30,548.952522,552.802497,543.512493,550.312514,1455500,550.312514\n2014-10-29,550.00246,554.19254,546.982459,549.332532,1770500,549.332532\n2014-10-28,543.002488,548.98245,541.622422,548.902519,1271000,548.902519\n2014-10-27,537.032441,544.412422,537.032441,540.772496,1185300,540.772496\n2014-10-24,544.36248,544.882461,535.792407,539.782476,1973100,539.782476\n2014-10-23,539.322474,547.222436,535.852386,543.98241,2348800,543.98241\n2014-10-22,529.892437,539.802428,528.802351,532.712427,2919300,532.712427\n2014-10-21,525.192353,526.792383,519.112324,526.542369,2336300,526.542369\n2014-10-20,509.452317,521.762353,508.102301,520.84241,2607500,520.84241\n2014-10-17,527.252385,530.982402,508.532313,511.172335,5539400,511.172335\n2014-10-16,519.002342,529.432374,515.002358,524.512387,3708600,524.512387\n2014-10-15,531.012391,532.802396,518.302363,530.032409,3719400,530.032409\n2014-10-14,538.902438,547.192507,533.172368,537.942408,2222600,537.942408\n2014-10-13,544.992443,549.502492,533.102413,533.212456,2581700,533.212456\n2014-10-10,557.722484,565.132577,544.052426,544.492476,3081900,544.492476\n2014-10-09,571.182555,571.492549,559.062524,560.882579,2524800,560.882579\n2014-10-08,565.572566,573.882587,557.492484,572.502582,1990900,572.502582\n2014-10-07,574.402629,575.27263,563.742534,563.742534,1911300,563.742534\n2014-10-06,578.802574,581.002639,574.442595,577.352614,1214600,577.352614\n2014-10-03,573.052613,577.227576,572.502582,575.282606,1141700,575.282606\n2014-10-02,567.312567,571.912585,563.322559,570.082615,1178400,570.082615\n2014-10-01,576.012635,577.582615,567.01255,568.272597,1445500,568.272597\n2014-09-30,576.932578,579.852634,572.852541,577.36259,1621700,577.36259\n2014-09-29,571.7526,578.192625,571.172579,576.362594,1282400,576.362594\n2014-09-26,576.062638,579.2526,574.662558,577.1026,1443700,577.1026\n2014-09-25,587.552646,587.982658,574.182604,575.062581,1926000,575.062581\n2014-09-24,581.462641,589.632691,580.522624,587.992634,1728100,587.992634\n2014-09-23,586.852606,586.852606,581.002639,581.132634,1471400,581.132634\n2014-09-22,593.82271,593.951665,583.462694,587.372648,1689500,587.372648\n2014-09-19,591.502688,596.482654,589.502696,596.082692,3736600,596.082692\n2014-09-18,587.002675,589.542661,585.002622,589.272695,1444600,589.272695\n2014-09-17,580.012619,587.522656,578.777665,584.772683,1692800,584.772683\n2014-09-16,572.762572,581.502606,572.662566,579.95264,1480400,579.95264\n2014-09-15,572.94257,574.952599,568.212618,573.102555,1597600,573.102555\n2014-09-12,581.002639,581.642639,574.462608,575.622589,1601700,575.622589\n2014-09-11,580.362639,581.812599,576.262588,581.352598,1221000,581.352598\n2014-09-10,581.502606,583.502659,576.942615,583.102636,977400,583.102636\n2014-09-09,588.902723,589.002667,580.002643,581.012615,1287200,581.012615\n2014-09-08,586.602653,591.772715,586.302635,589.722659,1431000,589.722659\n2014-09-05,583.982613,586.55265,581.952632,586.082672,1632400,586.082672\n2014-09-04,580.002643,586.00268,579.222611,581.982621,1458200,581.982621\n2014-09-03,580.002643,582.992655,575.002602,577.942611,1215100,577.942611\n2014-09-02,571.852545,577.832629,571.192593,577.332662,1578400,577.332662\n2014-08-29,571.332625,572.04258,567.07155,571.60253,1083800,571.60253\n2014-08-28,569.562573,573.252563,567.102518,569.202577,1292900,569.202577\n2014-08-27,577.272622,578.492581,570.105627,571.002557,1703400,571.002557\n2014-08-26,581.262629,581.802623,576.582619,577.862619,1639700,577.862619\n2014-08-25,584.722619,585.002622,579.002647,580.202654,1361400,580.202654\n2014-08-22,583.592689,585.238682,580.642643,582.562642,789100,582.562642\n2014-08-21,583.822628,584.502655,581.142671,583.372664,914800,583.372664\n2014-08-20,585.88266,586.702658,582.572618,584.492618,1036700,584.492618\n2014-08-19,585.002622,587.342658,584.002627,586.862643,978700,586.862643\n2014-08-18,576.11258,584.512631,576.002598,582.162619,1284100,582.162619\n2014-08-15,577.862619,579.382595,570.522603,573.482564,1519200,573.482564\n2014-08-14,576.182596,577.902645,570.882599,574.652643,985500,574.652643\n2014-08-13,567.312567,575.002602,565.752564,574.782639,1441800,574.782639\n2014-08-12,564.522567,565.902572,560.882579,562.732562,1542000,562.732562\n2014-08-11,569.992585,570.492553,566.002578,567.882551,1214700,567.882551\n2014-08-08,563.562536,570.252576,560.3525,568.772626,1494800,568.772626\n2014-08-07,568.00257,569.89258,561.102482,563.362525,1110900,563.362525\n2014-08-06,561.782569,570.702601,560.002541,566.376589,1334400,566.376589\n2014-08-05,570.052564,571.982601,562.612543,565.072598,1551200,565.072598\n2014-08-04,569.042531,575.352561,564.102531,573.152619,1427300,573.152619\n2014-08-01,570.402584,575.962633,562.85252,566.072594,1955300,566.072594\n2014-07-31,580.602616,583.652668,570.002561,571.60253,2102800,571.60253\n2014-07-30,586.55265,589.502696,584.002627,587.42265,1016500,587.42265\n2014-07-29,588.752653,589.702707,583.517654,585.612633,1349900,585.612633\n2014-07-28,588.072688,592.502683,584.755668,590.602636,986800,590.602636\n2014-07-25,590.402686,591.862684,587.032665,589.022681,932500,589.022681\n2014-07-24,596.452725,599.502716,591.772715,593.352671,1035100,593.352671\n2014-07-23,593.232652,597.852683,592.502683,595.982686,1233200,595.982686\n2014-07-22,590.722655,599.652725,590.602636,594.742652,1699200,594.742652\n2014-07-21,591.752702,594.402731,585.235622,589.472645,2062100,589.472645\n2014-07-18,593.002712,596.802684,582.002635,595.082696,4014200,595.082696\n2014-07-17,579.532665,580.992601,568.61258,573.732579,3016600,573.732579\n2014-07-16,588.002671,588.402694,582.202646,582.662587,1397100,582.662587\n2014-07-15,585.742628,585.807626,576.562606,584.782659,1623000,584.782659\n2014-07-14,582.602608,585.212671,578.032641,584.872627,1854100,584.872627\n2014-07-11,571.912585,580.85263,571.422594,579.182645,1621700,579.182645\n2014-07-10,565.912548,576.592656,565.012558,571.102563,1356700,571.102563\n2014-07-09,571.582578,576.72259,569.378536,576.082652,1116800,576.082652\n2014-07-08,577.662607,579.530645,566.137592,571.092587,1909500,571.092587\n2014-07-07,583.76265,586.432631,579.592644,582.252649,1064600,582.252649\n2014-07-03,583.352589,585.01266,580.922585,584.732656,714200,584.732656\n2014-07-02,583.352589,585.442672,580.392628,582.33766,1056400,582.33766\n2014-07-01,578.32262,584.402649,576.652635,582.672624,1448000,582.672624\n2014-06-30,578.662603,579.572631,574.752588,575.282606,1313800,575.282606\n2014-06-27,577.182592,579.872648,573.802595,577.242632,2236900,577.242632\n2014-06-26,581.002639,582.45266,571.852545,576.002598,1742000,576.002598\n2014-06-25,565.262572,579.962616,565.222546,578.652627,1969400,578.652627\n2014-06-24,565.192556,572.648612,561.012574,564.622572,2207100,564.622572\n2014-06-23,555.152509,565.002582,554.252519,564.952579,1536800,564.952579\n2014-06-20,556.852484,557.582513,550.394526,556.362492,4508300,556.362492\n2014-06-19,554.242482,555.0025,548.512473,554.902556,2456800,554.902556\n2014-06-18,544.862448,553.562516,544.002484,553.372481,1741800,553.372481\n2014-06-17,544.202496,545.32245,539.33245,543.012465,1444600,543.012465\n2014-06-16,549.262515,549.62245,541.522477,544.282488,1702600,544.282488\n2014-06-13,552.262503,552.302469,545.562488,551.762536,1220500,551.762536\n2014-06-12,557.302509,557.992512,548.462531,551.352476,1458500,551.352476\n2014-06-11,558.002549,559.882522,555.022514,558.842561,1100100,558.842561\n2014-06-10,560.512546,563.602502,557.902544,560.552511,1351700,560.552511\n2014-06-09,557.152562,562.902584,556.042523,562.122552,1467500,562.122552\n2014-06-06,558.062528,558.062528,548.932448,556.332564,1736800,556.332564\n2014-06-05,546.402499,554.952498,544.452449,553.90256,1689100,553.90256\n2014-06-04,541.502464,548.612478,538.752429,544.662436,1816500,544.662436\n2014-06-03,550.99248,552.342557,542.552463,544.942501,1866600,544.942501\n2014-06-02,560.702581,560.902593,545.732448,553.932488,1435000,553.932488\n2014-05-30,560.802526,561.352496,555.912467,559.892559,1771100,559.892559\n2014-05-29,563.352549,564.002525,558.712565,560.082534,1354100,560.082534\n2014-05-28,564.57257,567.842585,561.002537,561.682502,1652000,561.682502\n2014-05-27,556.002496,566.002578,554.352463,565.952575,2104200,565.952575\n2014-05-23,547.262462,553.642508,543.702467,552.702492,1932200,552.702492\n2014-05-22,541.132431,547.602445,540.782472,545.062459,1615800,545.062459\n2014-05-21,532.902462,539.185441,531.912381,538.942465,1196300,538.942465\n2014-05-20,529.742368,536.232396,526.302392,529.772418,1784800,529.772418\n2014-05-19,519.702382,529.782456,517.58537,528.862391,1277800,528.862391\n2014-05-16,521.39238,521.802379,515.442347,520.632362,1485300,520.632362\n2014-05-15,525.702357,525.872379,517.422325,519.982324,1704400,519.982324\n2014-05-14,533.002407,533.002407,525.292358,526.652412,1191800,526.652412\n2014-05-13,530.892433,536.072411,529.512428,533.092437,1653400,533.092437\n2014-05-12,523.512391,530.192393,519.012379,529.922366,1912500,529.922366\n2014-05-09,510.75233,519.902393,504.202292,518.732314,2439500,518.732314\n2014-05-08,508.462297,517.23229,506.452298,511.002313,2021300,511.002313\n2014-05-07,515.792305,516.68232,503.302272,509.962291,3224300,509.962291\n2014-05-06,525.232379,526.812396,515.062337,515.14233,1689000,515.14233\n2014-05-05,524.822381,528.902418,521.322364,527.812392,1024100,527.812392\n2014-05-02,533.762426,534.002403,525.612389,527.932411,1688500,527.932411\n2014-05-01,527.112352,532.932391,523.882364,531.352374,1905500,531.352374\n2014-04-30,527.602343,528.002366,522.522372,526.662388,1751200,526.662388\n2014-04-29,516.902344,529.462425,516.322324,527.70241,2699100,527.70241\n2014-04-28,517.182348,518.602319,502.802274,517.152359,3335500,517.152359\n2014-04-25,522.512395,524.702361,515.422333,516.182352,2100400,516.182352\n2014-04-24,530.072374,531.652452,522.122349,525.162363,1883200,525.162363\n2014-04-23,533.792415,533.872408,526.252389,526.942391,2052300,526.942391\n2014-04-22,528.642427,537.232391,527.512375,534.812425,2365400,534.812425\n2014-04-21,536.1024,536.702435,525.602352,528.622414,2566700,528.622414\n2014-04-17,548.81249,549.502492,531.152424,536.1024,6809500,536.1024\n2014-04-16,543.002488,557.002492,540.00244,556.54249,4893300,556.54249\n2014-04-15,536.822454,538.452473,518.462348,536.442444,3855100,536.442444\n2014-04-14,538.252462,544.102429,529.56237,532.522453,2575100,532.522453\n2014-04-11,532.552381,540.00244,526.532392,530.602392,3924800,530.602392\n2014-04-10,565.002582,565.002582,539.902495,540.952433,4036900,540.952433\n2014-04-09,559.622532,565.372554,552.952506,564.142557,3330800,564.142557\n2014-04-08,542.602466,555.0025,541.612446,554.902556,3151200,554.902556\n2014-04-07,540.742445,548.482483,527.15244,538.152456,4401700,538.152456\n2014-04-04,574.652643,577.77265,543.002488,543.14246,6369300,543.14246\n2014-04-03,569.852553,587.282679,564.132581,569.742571,5099200,569.742571\n2014-04-02,599.992707,604.832763,562.192568,567.002574,147100,567.002574\n2014-04-01,558.712565,568.452595,558.712565,567.162558,7900,567.162558\n2014-03-31,566.892592,567.002574,556.932537,556.972503,10800,556.972503\n2014-03-28,561.202549,566.43259,558.672477,559.992504,41200,559.992504\n2014-03-27,568.00257,568.00257,552.922516,558.462551,13100,558.462551\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/customHttpServer/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"strings\"\n)\n\nfunc handleConn(conn net.Conn) {\n\tdefer conn.Close()\n\n\tscanner := bufio.NewScanner(conn)\n\t// var url string\n\theaders := map[string]string{}\n\tfor i := 0; scanner.Scan(); i++ {\n\t\tline := scanner.Text()\n\n\t\tif i == 0 {\n\t\t\tfields := strings.Fields(line)\n\t\t\tmethod := fields[0]\n\t\t\tif method != \"GET\" {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\t// url = fields[1]\n\t\t} else {\n\t\t\tif line == \"\" {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tdata := strings.SplitN(line, \": \", 2)\n\t\t\theaders[data[0]] = data[1]\n\t\t}\n\t}\n\tbody := `<!DOCTYPE html>\n<html>\n<head></head>\n<body>\n  <form method=\"POST\">\n    <input type=\"text\" name=\"KEY\">\n    <input type=\"submit\">\n  </form>\n</body>\n</html>`\n\n\tgo func() {\n\t\tfor scanner.Scan() {\n\t\t\tfmt.Println(scanner.Text())\n\t\t}\n\t}()\n\n\tio.WriteString(conn, \"HTTP/1.1 200 OK\\r\\n\")\n\tfmt.Fprintf(conn, \"Content-Length: %d\\r\\n\", len(body)+2)\n\tio.WriteString(conn, \"\\r\\n\")\n\tfmt.Fprintf(conn, \"%s\\r\\n\", body)\n}\n\nfunc main() {\n\tlnr, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer lnr.Close()\n\n\tfor {\n\t\tconn, err := lnr.Accept()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\n\t\tgo handleConn(conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/echoServer/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n)\n\nfunc handleConn(conn net.Conn) {\n\tdefer conn.Close()\n\tscn := bufio.NewScanner(conn)\n\tfor scn.Scan() {\n\t\tline := scn.Text()\n\t\tbs := []byte(line)\n\t\tresult := make([]byte, len(bs))\n\t\tfor i, v := range bs {\n\t\t\tif v <= 'z' && v >= 'a' {\n\t\t\t\tresult[i] = v + 13\n\t\t\t\tif result[i] > 'z' {\n\t\t\t\t\tresult[i] -= 26\n\t\t\t\t}\n\t\t\t} else if v <= 'Z' && v >= 'A' {\n\t\t\t\tresult[i] = v + 13\n\t\t\t\tif result[i] > 'Z' {\n\t\t\t\t\tresult[i] -= 26\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tresult[i] = v\n\t\t\t}\n\t\t}\n\t\tfmt.Fprintf(conn, \"%s\\n%s\\n\", result, bs)\n\t}\n}\n\nfunc main() {\n\tserver, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\tdefer server.Close()\n\n\tfor {\n\t\tconn, err := server.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err.Error())\n\t\t}\n\t\tgo handleConn(conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/firstAppEngine/app.yaml",
    "content": "application: xenon-petal-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  login: required\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/firstAppEngine/hello.go",
    "content": "package hello\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/memcache\"\n\t\"google.golang.org/appengine/user\"\n)\n\nfunc init() {\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.HandleFunc(\"/\", handler)\n}\n\nfunc handler(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tglobalCounter, err := memcache.Increment(ctx, \"globalCounter\", 1, 0)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t}\n\tcurrentUser := user.Current(ctx)\n\tuserCounter, err := memcache.Increment(ctx, currentUser.Email+\"-Counter\", 1, 0)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t}\n\tfmt.Fprintf(res, \"Hello World! You are visitor #%d, and you have visited %d times!\", globalCounter, userCounter)\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/firstTemplate/main.go",
    "content": "package main\n\nimport (\n\t\"html/template\"\n\t\"net/http\"\n)\n\nfunc getTemplate(res http.ResponseWriter, req *http.Request) {\n\ttpl, err := template.ParseFiles(\"tpl.gohtml\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\ttpl.Execute(res, req.URL.Path)\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", getTemplate)\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/firstTemplate/tpl.gohtml",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n</head>\n<body>\n  {{ . }}\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/formExample/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc handleForm(res http.ResponseWriter, req *http.Request) {\n\tfirst := req.FormValue(\"first\")\n\tlast := req.FormValue(\"last\")\n\n\trdr, hdr, err := req.FormFile(\"file\")\n\tif rdr != nil {\n\t\tif err != nil {\n\t\t\thttp.Error(res, \"Error reading file\", 500)\n\t\t\tfmt.Println(err)\n\t\t\treturn\n\t\t}\n\t\tdefer rdr.Close()\n\t\twtr, err := os.Create(hdr.Filename)\n\t\tif err != nil {\n\t\t\thttp.Error(res, \"Error writing file\", 500)\n\t\t\treturn\n\t\t}\n\t\tdefer wtr.Close()\n\t\tio.Copy(wtr, rdr)\n\t}\n\n\tres.Header().Set(\"Content-Type\", \"text/html\")\n\tif first != \"\" && last != \"\" {\n\t\tfmt.Fprintf(res, \"<p>Hello %s %s</p>\", first, last)\n\t}\n\tio.WriteString(res, `<form method=\"POST\" enctype=\"multipart/form-data\">\n  <input type=\"text\" name=\"first\" placeholder=\"First name\" required>\n  <input type=\"text\" name=\"last\" placeholder=\"Last name\" required>\n  <input type=\"file\" name=\"file\">\n  <input type=\"submit\">\n</form>`)\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", handleForm)\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/httpAnimals/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc catHandler(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <body>\n    <img src=\"http://lorempixel.com/400/400/cats\" alt=\"Cat Image\">\n  </body>\n</html>`)\n}\n\nfunc dogHandler(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <body>\n    <img src=\"http://lorempixel.com/400/400/animals/8\" alt=\"Dog Image\">\n  </body>\n</html>`)\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/cat/\", catHandler)\n\thttp.HandleFunc(\"/dog/\", dogHandler)\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/json-example/data.json",
    "content": "[1,2,3,4]\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/json-example/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n)\n\ntype dataType struct {\n\tName string `json:\"name\"`\n\tAge  int    `json:\"age\"`\n\tJob  string `json:\"job\"`\n}\n\nfunc main() {\n\tdata := dataType{\"Daniel\", 22, \"Student\"}\n\tjson.NewEncoder(os.Stdout).Encode(data)\n\n\tf, err := os.Open(\"data.json\")\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\tdefer f.Close()\n\tvar readData []float64\n\terr = json.NewDecoder(f).Decode(&readData)\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\tfmt.Println(readData)\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/photoBlog/adminSite.gohtml",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Upload</title>\n  <link rel=\"stylesheet\" href=\"/style.css\">\n</head>\n<body>\n  <nav class=\"right-align\">\n    <a href=\"/\" class=\"button\">Main Page</a>\n  </nav>\n  <section class=\"center-content\">\n    <section class=\"upload-container\">\n      {{if .}}\n      <p>File Uploaded</p>\n      {{end}}\n      <form method=\"post\" enctype=\"multipart/form-data\">\n        <input type=\"file\" name=\"image\" accept=\"image/*\" required>\n        <input type=\"submit\" value=\"Upload\">\n      </form>\n    </section>\n  </section>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/photoBlog/app.yaml",
    "content": "application: photo-blog-1008\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /admin\n  secure: always\n  login: admin\n  script: _go_app\n- url: /(style.css|favicon.ico)\n  secure: optional\n  script: _go_app\n- url: /.*\n  secure: never\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/photoBlog/main.go",
    "content": "package photo\n\nimport (\n\t\"crypto/md5\"\n\t\"encoding/hex\"\n\t\"html/template\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"time\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n)\n\ntype fileTimes []time.Time\n\nfunc (ft *fileTimes) Len() int {\n\treturn len(*ft)\n}\n\nfunc (ft *fileTimes) Less(i, j int) bool {\n\treturn (*ft)[i].After((*ft)[j])\n}\n\nfunc (ft *fileTimes) Swap(i, j int) {\n\t(*ft)[i], (*ft)[j] = (*ft)[j], (*ft)[i]\n}\n\nfunc mainSite(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\ttpl, err := template.ParseFiles(\"mainSite.gohtml\")\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n\ttimes := fileTimes{}\n\timages := map[time.Time]string{}\n\tfilepath.Walk(\"images\", func(path string, info os.FileInfo, err error) error {\n\t\tif !info.IsDir() {\n\t\t\tfileTime := info.ModTime()\n\t\t\timages[fileTime] = filepath.ToSlash(\"/\" + path)\n\t\t\ttimes = append(times, fileTime)\n\t\t}\n\t\treturn nil\n\t})\n\tsort.Sort(&times)\n\tsortedImages := make([]string, len(times))\n\tfor i, v := range times {\n\t\tsortedImages[i] = images[v]\n\t}\n\terr = tpl.Execute(res, sortedImages)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n}\n\nfunc adminSite(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tgotFile := false\n\tif req.Method == \"POST\" {\n\t\tfile, _, err := req.FormFile(\"image\")\n\t\tif err != nil {\n\t\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\t\tlog.Errorf(ctx, err.Error())\n\t\t\treturn\n\t\t}\n\t\tdefer file.Close()\n\n\t\tckSum := md5.New()\n\t\tio.Copy(ckSum, file)\n\t\tfilename := \"images/\" + hex.EncodeToString(ckSum.Sum(nil))\n\t\twtr, err := os.Create(filename)\n\t\tif err != nil {\n\t\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\t\tlog.Errorf(ctx, err.Error())\n\t\t\treturn\n\t\t}\n\t\tdefer wtr.Close()\n\n\t\t_, err = file.Seek(0, 0)\n\t\tif err != nil {\n\t\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\t\tlog.Errorf(ctx, err.Error())\n\t\t\treturn\n\t\t}\n\n\t\t_, err = io.Copy(wtr, file)\n\t\tif err != nil {\n\t\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\t\tlog.Errorf(ctx, err.Error())\n\t\t\treturn\n\t\t}\n\n\t\tgotFile = true\n\t}\n\n\ttpl, err := template.ParseFiles(\"adminSite.gohtml\")\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n\n\terr = tpl.Execute(res, gotFile)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n}\n\nfunc getCSS(res http.ResponseWriter, req *http.Request) {\n\thttp.ServeFile(res, req, \"style.css\")\n}\n\nfunc init() {\n\timagesHandler := http.StripPrefix(\"/images/\", http.FileServer(http.Dir(\"images/\")))\n\n\thttp.HandleFunc(\"/\", mainSite)\n\thttp.HandleFunc(\"/admin\", adminSite)\n\thttp.Handle(\"/images/\", imagesHandler)\n\thttp.HandleFunc(\"/style.css\", getCSS)\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/photoBlog/mainSite.gohtml",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Photo Blog</title>\n  <link rel=\"stylesheet\" href=\"/style.css\">\n</head>\n<body>\n  <a class=\"button right-align\" href=\"/admin\">Upload</a>\n  <section class=\"image-container\">\n    {{range .}}\n    <a href=\"{{.}}\" download><img src=\"{{.}}\" alt=\"{{.}}\"></a>\n    {{end}}\n  </section>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/photoBlog/style.css",
    "content": "* {\n  box-sizing: border-box;\n}\n\nhtml {\n  background-color: #77f;\n}\n\n.right-align {\n  position: absolute;\n  right: 20px;\n}\n\n.button {\n  text-decoration: none;\n  color: white;\n  background-color: blue;\n  padding: 7px;\n  border-radius: 7px;\n  box-shadow: 1px 1px 3px 1px black;\n}\n\n.image-container {\n  background-color: lightblue;\n  border-radius: 10px;\n  display: flex;\n  flex-flow: row wrap;\n  justify-content: center;\n  align-content: center;\n  box-shadow: 1px 2px 3px 1px black\n}\n\n.image-container img {\n  border: 2px solid black\n}\n\n.center-content {\n  width: 98vw;\n  height: 97vh;\n  display: flex;\n  flex-flow: row wrap;\n  justify-content: center;\n  align-items: center;\n}\n\n.error-message {\n  color: yellow;\n  background-color: #999;\n  padding: 2px;\n  border-radius: 5px;\n}\n\n.login {\n  display: flex;\n  flex-flow: column nowrap;\n  max-width: 300px;\n  height: 8em\n}\n\n.upload-container {\n  text-align: center;\n  background-color: lightblue;\n  padding: 20px;\n  border-radius: 3px;\n}\n\n.upload-container p {\n  margin: 5px;\n}\n\nimg {\n  width: 150px;\n  height: 150px;\n  border-radius: 10px;\n  margin: 5px;\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/profile/app.yaml",
    "content": "application: xenon-petal-100822\nversion: profile\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  login: required\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/profile/createProfile.gohtml",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Create Profile</title>\n</head>\n<body>\n  <form method=\"post\">\n    <input type=\"text\" name=\"firstname\" placeholder=\"First Name\" required>\n    <input type=\"text\" name=\"lastname\" placeholder=\"Last Name\" required>\n    <input type=\"submit\">\n  </form>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/profile/main.go",
    "content": "package profile\n\nimport (\n\t\"html/template\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/user\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handle)\n\thttp.HandleFunc(\"/createProfile\", createProfile)\n}\n\n// Profile holds user profiles\ntype Profile struct {\n\tEmail     string\n\tFirstName string\n\tLastName  string\n}\n\nfunc handle(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path != \"/\" {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\tkey := datastore.NewKey(ctx, \"Profile\", u.Email, 0, nil)\n\tvar profile Profile\n\terr := datastore.Get(ctx, key, &profile)\n\tif err == datastore.ErrNoSuchEntity {\n\t\thttp.Redirect(res, req, \"/createProfile\", http.StatusSeeOther)\n\t\treturn\n\t} else if err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n\n\ttpl, err := template.ParseFiles(\"viewProfile.gohtml\")\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n\terr = tpl.Execute(res, &profile)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n}\n\nfunc createProfile(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tif req.Method == \"POST\" {\n\t\tu := user.Current(ctx)\n\t\tprofile := Profile{\n\t\t\tEmail:     u.Email,\n\t\t\tFirstName: req.FormValue(\"firstname\"),\n\t\t\tLastName:  req.FormValue(\"lastname\"),\n\t\t}\n\t\tkey := datastore.NewKey(ctx, \"Profile\", u.Email, 0, nil)\n\t\t_, err := datastore.Put(ctx, key, &profile)\n\t\tif err != nil {\n\t\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\t\tlog.Errorf(ctx, err.Error())\n\t\t\treturn\n\t\t}\n\t\thttp.Redirect(res, req, \"/\", http.StatusSeeOther)\n\t}\n\tf, err := os.Open(\"createProfile.gohtml\")\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n\tio.Copy(res, f)\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/profile/viewProfile.gohtml",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>{{.FirstName}} {{.LastName}}</title>\n</head>\n<body>\n  <p>Name: {{.FirstName}} {{.LastName}}</p>\n  <p>Email: {{.Email}}\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/redisDatabase/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"io\"\n\t\"net\"\n\t\"strings\"\n)\n\ntype databaseRequest struct {\n\trequestType, key, value string\n\tresultChannel           chan<- string\n}\n\nfunc handleDatabase(requestChannel <-chan databaseRequest) {\n\tvar db = map[string]string{}\n\tfor request := range requestChannel {\n\t\tswitch request.requestType {\n\t\tcase \"GET\":\n\t\t\trequest.resultChannel <- db[request.key]\n\t\tcase \"SET\":\n\t\t\tdb[request.key] = request.value\n\t\t\trequest.resultChannel <- \"Set \" + request.value + \" to key \" + request.key + \" successful\"\n\t\tcase \"DEL\":\n\t\t\tdelete(db, request.key)\n\t\t\trequest.resultChannel <- \"Delete of key \" + request.key + \" successful\"\n\t\tdefault:\n\t\t\trequest.resultChannel <- \"Unknown command: \" + request.requestType\n\t\t}\n\t\tclose(request.resultChannel)\n\t}\n}\n\nfunc handleConn(conn net.Conn, requestChannel chan<- databaseRequest) {\n\tdefer conn.Close()\n\n\tscn := bufio.NewScanner(conn)\n\tfor scn.Scan() {\n\t\tline := scn.Text()\n\t\tif len(line) == 0 {\n\t\t\tcontinue\n\t\t} else if len(line) < 4 {\n\t\t\tio.WriteString(conn, \"Unknown command: \"+line+\"\\n\")\n\t\t\tcontinue\n\t\t}\n\t\trequestValues := line[4:]\n\t\tpayload := strings.SplitN(requestValues, \" \", 2)\n\t\tresultChannel := make(chan string)\n\t\trequest := databaseRequest{\n\t\t\trequestType:   line[:3],\n\t\t\tkey:           payload[0],\n\t\t\tresultChannel: resultChannel,\n\t\t}\n\n\t\tif len(payload) > 1 {\n\t\t\trequest.value = payload[1]\n\t\t}\n\n\t\trequestChannel <- request\n\t\tdata := <-resultChannel\n\t\tio.WriteString(conn, data+\"\\n\")\n\t}\n}\n\nfunc main() {\n\tserver, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer server.Close()\n\n\trequestChannel := make(chan databaseRequest)\n\tgo handleDatabase(requestChannel)\n\n\tfor {\n\t\tconn, err := server.Accept()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\n\t\tgo handleConn(conn, requestChannel)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/secureHello/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc getPage(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, \"Hello World!\")\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", getPage)\n\thttp.ListenAndServeTLS(\":9000\", \"cert.pem\", \"key.pem\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/static-http/main.go",
    "content": "package main\n\nimport \"net/http\"\n\nfunc main() {\n\thttp.ListenAndServe(\":9000\", http.FileServer(http.Dir(\".\")))\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/testExample/example.go",
    "content": "package example\n\n// Sum finds the sum of all inputs.\nfunc Sum(xs ...int) int {\n\tsum := 0\n\tfor _, v := range xs {\n\t\tsum += v\n\t}\n\treturn sum\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/testExample/example_test.go",
    "content": "package example\n\nimport \"testing\"\n\nfunc TestSum(t *testing.T) {\n\ttests := []struct {\n\t\tinput    []int\n\t\texpected int\n\t}{\n\t\t{[]int{1, 2, 3}, 6},\n\t\t{[]int{5, 10}, 15},\n\t}\n\n\tfor _, c := range tests {\n\t\tres := Sum(c.input...)\n\t\tif res != c.expected {\n\t\t\tt.Logf(\"Expected %d, but got %d\", c.expected, res)\n\t\t\tt.Fail()\n\t\t}\n\t}\n}\n\nfunc BenchmarkSum(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tSum(1, 2, 3)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/todolist/app.yaml",
    "content": "application: xenon-petal-100822\nversion: todo\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  login: required\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/todolist/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <link rel=\"stylesheet\" href=\"style.css\">\n</head>\n<body>\n  <section class=\"center-page\">\n    <section id=\"todo-list\"></section>\n    <form name=\"newitem\">\n      <input type=\"text\" name=\"itemtext\" placeholder=\"Item text\" required>\n      <input type=\"submit\" value=\"Create Item\">\n    </form>\n  </section>\n  <script src=\"script.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/todolist/index.yaml",
    "content": "indexes:\n\n# AUTOGENERATED\n\n# This index.yaml is automatically updated whenever the dev_appserver\n# detects that a new type of query is run.  If you want to manage the\n# index.yaml file manually, remove the above marker line (the line\n# saying \"# AUTOGENERATED\").  If you want to manage some indexes\n# manually, move them above the marker line.  The index.yaml file is\n# automatically uploaded to the admin console when you next deploy\n# your application using appcfg.py.\n\n- kind: List\n  properties:\n  - name: Owner\n  - name: Time\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/todolist/main.go",
    "content": "package todo\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/user\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handle)\n\thttp.HandleFunc(\"/todo.json\", jsonServe)\n}\n\nfunc handle(res http.ResponseWriter, req *http.Request) {\n\tswitch req.URL.Path {\n\tcase \"/\":\n\t\thttp.ServeFile(res, req, \"index.html\")\n\tcase \"/style.css\":\n\t\thttp.ServeFile(res, req, \"style.css\")\n\tcase \"/script.js\":\n\t\thttp.ServeFile(res, req, \"script.js\")\n\tdefault:\n\t\thttp.NotFound(res, req)\n\t}\n}\n\ntype dataItem struct {\n\tValue  string\n\tKeyVal string\n}\n\ntype list struct {\n\tValue string\n\tOwner string\n\tTime  time.Time\n}\n\nfunc jsonServe(res http.ResponseWriter, req *http.Request) {\n\tswitch req.Method {\n\tcase \"POST\":\n\t\tif len(req.FormValue(\"keyVal\")) > 0 {\n\t\t\tdeleteData(res, req)\n\t\t} else {\n\t\t\tsaveJSON(res, req)\n\t\t}\n\tcase \"GET\":\n\t\tgetJSON(res, req)\n\tdefault:\n\t\tctx := appengine.NewContext(req)\n\t\thttp.Error(res, \"Bad HTTP method\", http.StatusBadRequest)\n\t\tlog.Warningf(ctx, \"Attempted HTTP method %s from %s\", req.Method, req.RemoteAddr)\n\t}\n}\n\nfunc deleteData(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\tkeyVal := req.FormValue(\"keyVal\")\n\tkey, err := datastore.DecodeKey(keyVal)\n\tif err != nil {\n\t\thttp.Error(res, \"Invalid data\", http.StatusBadRequest)\n\t\tlog.Warningf(ctx, err.Error())\n\t\treturn\n\t}\n\tvar l list\n\terr = datastore.Get(ctx, key, &l)\n\tif err != nil {\n\t\thttp.Error(res, \"Invalid data\", http.StatusBadRequest)\n\t\tlog.Warningf(ctx, err.Error())\n\t\treturn\n\t}\n\tif l.Owner != u.Email {\n\t\thttp.Error(res, \"Not authorized to delete this entry\", http.StatusUnauthorized)\n\t\tlog.Warningf(ctx, err.Error())\n\t\treturn\n\t}\n\terr = datastore.Delete(ctx, key)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n}\n\nfunc getQuery(email string) *datastore.Query {\n\treturn datastore.NewQuery(\"List\").\n\t\tFilter(\"Owner =\", email).\n\t\tOrder(\"Time\")\n}\n\nfunc saveJSON(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\tdecoder := json.NewDecoder(req.Body)\n\tkey := datastore.NewIncompleteKey(ctx, \"List\", nil)\n\tvar l list\n\terr := decoder.Decode(&l)\n\tif err != nil {\n\t\thttp.Error(res, \"Invalid data\", http.StatusBadRequest)\n\t\tlog.Warningf(ctx, err.Error())\n\t\treturn\n\t}\n\tl.Owner = u.Email\n\tl.Time = time.Now()\n\t_, err = datastore.Put(ctx, key, &l)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n}\n\nfunc getJSON(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\tquery := getQuery(u.Email)\n\tl := []list{}\n\tkeys, err := query.GetAll(ctx, &l)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n\titems := make([]dataItem, len(l))\n\tfor i := range l {\n\t\titems[i].Value = l[i].Value\n\t\titems[i].KeyVal = keys[i].Encode()\n\t}\n\tenc := json.NewEncoder(res)\n\terr = enc.Encode(items)\n\tif err != nil {\n\t\thttp.Error(res, \"Server Error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, err.Error())\n\t\treturn\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/todolist/script.js",
    "content": "function deleteButton(keyVal) {\n  var xhr = new XMLHttpRequest();\n  xhr.open('POST', '/todo.json');\n  xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');\n  xhr.addEventListener('readystatechange', function() {\n    if (xhr.readyState === 4) {\n      getData();\n    }\n  });\n  xhr.send('keyVal=' + keyVal);\n}\n\nfunction getData() {\n  var xhr = new XMLHttpRequest();\n  xhr.open('GET', '/todo.json');\n  xhr.addEventListener('readystatechange', function() {\n    if (xhr.readyState === 4) {\n      var data = JSON.parse(xhr.responseText);\n      newHTML = '';\n      for (var i = 0; i < data.length; i++) {\n        newHTML += '<p>' + data[i].Value + '</p>' + '<button onclick=\"deleteButton(\\'' + data[i].KeyVal + '\\');\">Delete</button>';\n      }\n      document.querySelector('#todo-list').innerHTML = newHTML;\n    }\n  });\n  xhr.send();\n}\n\nfunction sendData(dataObj, callback) {\n  var xhr = new XMLHttpRequest();\n  xhr.open('POST', '/todo.json');\n  var data = JSON.stringify(dataObj);\n  xhr.setRequestHeader('Content-Type', 'application/json');\n  if (callback) {\n    xhr.addEventListener('readystatechange', function() {\n      if (xhr.readyState === 4) {\n        callback();\n      }\n    });\n  }\n  xhr.send(data);\n}\n\ndocument.forms.newitem.addEventListener('submit', function(e) {\n  e.preventDefault();\n  var data = {Value: e.target.itemtext.value};\n  sendData(data, function() {\n    e.target.itemtext.value = '';\n    getData();\n  });\n});\n\ngetData();\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week8/todolist/style.css",
    "content": ".center-page {\n  display: flex;\n  flex-flow: column nowrap;\n  width: 98vw;\n  height: 97vh;\n  justify-content: center;\n  align-items: center;\n}\n\n#todo-list {\n  background-color: #ddf;\n  border-radius: 5px;\n  padding: 0;\n}\n\np {\n  padding: 0;\n  margin: 10px;\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week9/chat-example/app.yaml",
    "content": "application: xenon-petal-100822\nversion: chat\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  login: required\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week9/chat-example/handlers.go",
    "content": "package chat\n\nimport (\n\t\"crypto/md5\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"golang.org/x/net/context\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/channel\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/user\"\n)\n\n// API is the API\ntype API struct {\n\troot string\n}\n\nfunc newAPI(root string) *API {\n\treturn &API{\n\t\troot: root,\n\t}\n}\n\nfunc (api *API) ServeHTTP(res http.ResponseWriter, req *http.Request) {\n\tendpoint := req.URL.Path[len(api.root):]\n\tmethod := req.Method\n\n\tvar err error\n\tswitch endpoint {\n\tcase \"channels\":\n\t\tswitch method {\n\t\tcase \"POST\":\n\t\t\terr = api.handlePostChannel(res, req)\n\t\tdefault:\n\t\t\thttp.Error(res, \"Method Not Allowed\", http.StatusMethodNotAllowed)\n\t\t\treturn\n\t\t}\n\tcase \"messages\":\n\t\tswitch method {\n\t\tcase \"POST\":\n\t\t\terr = api.handlePostMessage(res, req)\n\t\tdefault:\n\t\t\thttp.Error(res, \"Method Not Allowed\", http.StatusMethodNotAllowed)\n\t\t\treturn\n\t\t}\n\tdefault:\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t}\n\n\tif err != nil {\n\t\tres.WriteHeader(http.StatusInternalServerError)\n\t\tjson.NewEncoder(res).Encode(err.Error())\n\t}\n}\n\nfunc getClientID(email string) string {\n\thash := md5.New()\n\tio.WriteString(hash, email)\n\tsum := hash.Sum(nil)\n\treturn hex.EncodeToString(sum)\n}\n\nfunc saveNewConnection(ctx context.Context, clientID string) error {\n\tkey := datastore.NewKey(ctx, \"connection\", clientID, 0, nil)\n\tval := struct{ Value string }{clientID}\n\t_, err := datastore.Put(ctx, key, &val)\n\treturn err\n}\n\nfunc (api *API) handlePostChannel(res http.ResponseWriter, req *http.Request) error {\n\tctx := appengine.NewContext(req)\n\tu := user.Current(ctx)\n\tclientID := getClientID(u.Email)\n\ttoken, err := channel.Create(ctx, clientID)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = saveNewConnection(ctx, clientID)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn json.NewEncoder(res).Encode(token)\n}\n\nfunc (api *API) handlePostMessage(res http.ResponseWriter, req *http.Request) error {\n\tctx := appengine.NewContext(req)\n\n\tvar message struct{ Text string }\n\terr := json.NewDecoder(req.Body).Decode(&message)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tquery := datastore.NewQuery(\"connection\")\n\tit := query.Run(ctx)\n\tfor {\n\t\tvar conn struct{ Value string }\n\t\t_, err := it.Next(&conn)\n\t\tif err == datastore.Done {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\treturn err\n\t\t}\n\t\terr = channel.SendJSON(ctx, conn.Value, message)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week9/chat-example/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Chat Example</title>\n</head>\n<body>\n  <div class=\"chat-window\">\n    <div id=\"messages\"></div>\n    <form action=\"\" id=\"controls\">\n      <input type=\"text\" id=\"text-input\">\n      <input type=\"submit\">\n    </form>\n  </div>\n  <script src=\"/_ah/channel/jsapi\"></script>\n  <script src=\"/main.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week9/chat-example/public/main.js",
    "content": "var channel;\n\nfunction apiRequest(method, endpoint, data, callback) {\n  var xhr = new XMLHttpRequest();\n  xhr.open(method, '/api/' + endpoint);\n  xhr.addEventListener('readystatechange', function() {\n    if (xhr.readyState === 4) {\n      if (Math.floor(xhr.status / 100) === 2) {\n        if (callback) {\n          callback(JSON.parse(xhr.responseText), null);\n        }\n      } else {\n        var msg;\n        try {\n          msg = JSON.parse(xhr.responseText);\n        } catch(e) {\n          msg = xhr.responseText;\n        }\n        if (callback) {\n          callback(null, msg);\n        }\n      }\n    }\n  });\n  xhr.send(JSON.stringify(data));\n}\n\nfunction sendMessage(text, callback) {\n  apiRequest('POST', 'messages', {\n    Text: text\n  }, callback);\n}\n\nfunction getChannel() {\n  apiRequest('POST', 'channels', {}, function(res, err) {\n    if (err) {\n      alert('Unable to get channel: ' + err);\n      return;\n    }\n    channel = new goog.appengine.Channel(res);\n    sock = channel.open();\n    sock.onmessage = function(msg) {\n      var data = JSON.parse(msg.data);\n      onMessage(data);\n    };\n    sock.onerror = function() {\n      alert('An error occured with the connection.');\n    };\n  });\n}\n\nfunction onMessage(message) {\n  var el = document.querySelector('#messages');\n  var p = document.createElement('p');\n  p.textContent = message.Text;\n  el.appendChild(p);\n}\n\n(function() {\n  getChannel();\n  var controls = document.querySelector('#controls');\n  controls.addEventListener('submit', function(e) {\n    e.preventDefault();\n    var textInput = document.querySelector('#text-input');\n    var text = textInput.value;\n    sendMessage(text, function(res, err) {\n      if (err) {\n        alert(err);\n      }\n    });\n    textInput.value = '';\n  });\n})();\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week9/chat-example/routes.go",
    "content": "package chat\n\nimport \"net/http\"\n\nfunc init() {\n\thttp.Handle(\"/\", http.FileServer(http.Dir(\"public/\")))\n\thttp.Handle(\"/api/\", newAPI(\"/api/\"))\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week9/movie-search/app.yaml",
    "content": "application: xenon-petal-100822\nversion: search\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  login: required\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week9/movie-search/data.go",
    "content": "package search\n\nimport (\n\t\"html/template\"\n\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/appengine/datastore\"\n)\n\nfunc getRecentMovies(ctx context.Context, maxItems int) ([]movie, error) {\n\tq := datastore.NewQuery(\"Movie\").Project(\"Name\", \"URL\").Limit(maxItems)\n\tvar movies []movie\n\t_, err := q.GetAll(ctx, &movies)\n\treturn movies, err\n}\n\nfunc addMovie(ctx context.Context, mov *movie) error {\n\tkey := datastore.NewKey(ctx, \"Movie\", mov.URL, 0, nil)\n\t_, err := datastore.Put(ctx, key, mov)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn addToIndex(ctx, mov)\n}\n\ntype templateMovie struct {\n\tName    string\n\tURL     string\n\tSummary template.HTML\n}\n\nfunc getMovie(ctx context.Context, URL string) (*templateMovie, error) {\n\tkey := datastore.NewKey(ctx, \"Movie\", URL, 0, nil)\n\tvar mov templateMovie\n\terr := datastore.Get(ctx, key, &mov)\n\treturn &mov, err\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week9/movie-search/details.go",
    "content": "package search\n\nimport (\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/datastore\"\n\t\"google.golang.org/appengine/log\"\n)\n\nfunc handleMovieDetails(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tmov, err := getMovie(ctx, req.URL.Path[1:])\n\tif err == datastore.ErrNoSuchEntity {\n\t\thttp.NotFound(res, req)\n\t\treturn\n\t} else if err != nil {\n\t\thttp.Error(res, \"Server error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, \"%v\\n\", err)\n\t\treturn\n\t}\n\terr = tpl.ExecuteTemplate(res, \"details\", mov)\n\tif err != nil {\n\t\thttp.Error(res, \"Server error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, \"%v\\n\", err)\n\t\treturn\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week9/movie-search/index.go",
    "content": "package search\n\nimport (\n\t\"net/http\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n)\n\nfunc handleIndex(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path != \"/\" {\n\t\thandleMovieDetails(res, req)\n\t\treturn\n\t}\n\n\tctx := appengine.NewContext(req)\n\tdata := struct {\n\t\tMovies []movie\n\t}{}\n\tm, err := getRecentMovies(ctx, 15)\n\tif err != nil {\n\t\thttp.Error(res, \"Server error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, \"%v\\n\", err)\n\t\treturn\n\t}\n\tdata.Movies = m\n\n\terr = tpl.ExecuteTemplate(res, \"index\", data)\n\tif err != nil {\n\t\thttp.Error(res, \"Server error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, \"%v\\n\", err)\n\t\treturn\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week9/movie-search/index.yaml",
    "content": "indexes:\n\n# AUTOGENERATED\n\n# This index.yaml is automatically updated whenever the dev_appserver\n# detects that a new type of query is run.  If you want to manage the\n# index.yaml file manually, remove the above marker line (the line\n# saying \"# AUTOGENERATED\").  If you want to manage some indexes\n# manually, move them above the marker line.  The index.yaml file is\n# automatically uploaded to the admin console when you next deploy\n# your application using appcfg.py.\n\n- kind: Movie\n  properties:\n  - name: Name\n  - name: URL\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week9/movie-search/movie.go",
    "content": "package search\n\nimport (\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"golang.org/x/net/context\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/search\"\n\t\"google.golang.org/appengine/urlfetch\"\n)\n\ntype movie struct {\n\tName    string\n\tURL     string\n\tSummary search.HTML\n}\n\nfunc handleAdd(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tvar err error\n\n\tif req.Method == \"POST\" {\n\t\tname := strings.TrimSpace(req.FormValue(\"name\"))\n\t\tsummary, err := getHTML(ctx, req.FormValue(\"summary\"))\n\t\tif err != nil {\n\t\t\thttp.Error(res, \"Server error\", http.StatusInternalServerError)\n\t\t\tlog.Errorf(ctx, \"%v\\n\", err)\n\t\t\treturn\n\t\t}\n\n\t\tmov := &movie{\n\t\t\tName:    name,\n\t\t\tSummary: summary,\n\t\t\tURL:     strings.ToLower(strings.Replace(name, \" \", \"\", -1)),\n\t\t}\n\t\terr = addMovie(ctx, mov)\n\t\tif err != nil {\n\t\t\thttp.Error(res, \"Server error\", http.StatusInternalServerError)\n\t\t\tlog.Errorf(ctx, \"%v\\n\", err)\n\t\t\treturn\n\t\t}\n\t\thttp.Redirect(res, req, \"/\", http.StatusSeeOther)\n\t\treturn\n\t}\n\n\terr = tpl.ExecuteTemplate(res, \"addMovie\", nil)\n\tif err != nil {\n\t\thttp.Error(res, \"Server error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, \"%v\\n\", err)\n\t\treturn\n\t}\n}\n\nfunc getHTML(ctx context.Context, markdown string) (search.HTML, error) {\n\tclient := urlfetch.Client(ctx)\n\tresp, err := client.Post(\"https://api.github.com/markdown/raw\", \"text/plain\", strings.NewReader(markdown))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer resp.Body.Close()\n\tbts, err := ioutil.ReadAll(resp.Body)\n\treturn search.HTML(bts), err\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week9/movie-search/route.go",
    "content": "package search\n\nimport \"net/http\"\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handleIndex)\n\thttp.HandleFunc(\"/addMovie\", handleAdd)\n\thttp.HandleFunc(\"/search\", handleSearch)\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week9/movie-search/search.go",
    "content": "package search\n\nimport (\n\t\"net/http\"\n\n\t\"golang.org/x/net/context\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/log\"\n\t\"google.golang.org/appengine/search\"\n)\n\nfunc handleSearch(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\n\tmovies, err := searchMovies(ctx, req.FormValue(\"q\"))\n\tif err != nil {\n\t\thttp.Error(res, \"Server error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, \"%v\\n\", err)\n\t\treturn\n\t}\n\n\terr = tpl.ExecuteTemplate(res, \"search\", movies)\n\tif err != nil {\n\t\thttp.Error(res, \"Server error\", http.StatusInternalServerError)\n\t\tlog.Errorf(ctx, \"%v\\n\", err)\n\t\treturn\n\t}\n}\n\nfunc addToIndex(ctx context.Context, mov *movie) error {\n\tidx, err := search.Open(\"movies\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = idx.Put(ctx, \"\", mov)\n\treturn err\n}\n\nfunc searchMovies(ctx context.Context, query string) ([]movie, error) {\n\tidx, err := search.Open(\"movies\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tit := idx.Search(ctx, query, nil)\n\tmovies := []movie{}\n\tfor {\n\t\tvar mov movie\n\t\t_, err := it.Next(&mov)\n\t\tif err == search.Done {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tmovies = append(movies, mov)\n\t}\n\treturn movies, nil\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week9/movie-search/template.go",
    "content": "package search\n\nimport \"html/template\"\n\nvar tpl *template.Template\n\nfunc init() {\n\ttpl = template.Must(template.New(\"\").ParseGlob(\"templates/*.gohtml\"))\n}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week9/movie-search/templates/addMovie.gohtml",
    "content": "{{define \"addMovie\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Add a movie</title>\n</head>\n<body>\n  {{template \"header\"}}\n  <form method=\"post\">\n    <label for=\"name\">Name</label>\n    <input type=\"text\" id=\"name\" name=\"name\" placeholder=\"Movie Name\">\n    <label for=\"summary\">Summary</label>\n    <textarea id=\"summary\" name=\"summary\" rows=\"8\" cols=\"40\"></textarea>\n    <input type=\"submit\" value=\"Add\">\n  </form>\n</body>\n</html>\n{{end}}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week9/movie-search/templates/details.gohtml",
    "content": "{{define \"details\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>{{.Name}}</title>\n</head>\n<body>\n  {{template \"header\"}}\n  <section>\n    {{template \"movieDetails\" .}}\n  </section>\n</body>\n</html>\n{{end}}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week9/movie-search/templates/header.gohtml",
    "content": "{{define \"header\"}}\n<a href=\"/\">Main page</a>\n<a href=\"/addMovie\">Add a movie</a>\n<form action=\"/search\" method=\"GET\">\n  <input type=\"text\" name=\"q\" placeholder=\"Search\">\n  <input type=\"submit\" value=\"Search\">\n</form>\n{{end}}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week9/movie-search/templates/index.gohtml",
    "content": "{{define \"index\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Movie</title>\n</head>\n<body>\n  {{template \"header\"}}\n  <h1>Movies</h1>\n  <ul>\n    {{range .Movies}}\n    <li>{{template \"movieItem\" .}}</li>\n    {{end}}\n  </ul>\n</body>\n</html>\n{{end}}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week9/movie-search/templates/movie.gohtml",
    "content": "{{define \"movieItem\"}}\n<a href=\"/{{.URL}}\">{{.Name}}</a>\n{{end}}\n\n{{define \"movieDetails\"}}\n<h2>{{.Name}}</h2>\n<p>{{.Summary}}</p>\n{{end}}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week9/movie-search/templates/search.gohtml",
    "content": "{{define \"search\"}}<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Search</title>\n</head>\n<body>\n  {{template \"header\"}}\n  <h2>Results</h2>\n  <ul>\n    {{range .}}\n    <li>{{template \"movieItem\" .}}</li>\n    {{end}}\n  </ul>\n</body>\n</html>\n{{end}}\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week9/storageExample/app.yaml",
    "content": "application: astute-curve-100822\nversion: 1\nruntime: go\napi_version: go1\n\nhandlers:\n- url: /.*\n  script: _go_app\n"
  },
  {
    "path": "27_code-in-process/98-good-student-code/daniel/Week9/storageExample/storage.go",
    "content": "package storage\n\nimport (\n\t\"html/template\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"golang.org/x/net/context\"\n\t\"golang.org/x/oauth2\"\n\t\"golang.org/x/oauth2/google\"\n\n\t\"google.golang.org/appengine\"\n\t\"google.golang.org/appengine/urlfetch\"\n\t\"google.golang.org/cloud\"\n\t\"google.golang.org/cloud/storage\"\n)\n\nconst (\n\tbucket = \"golang-bootcamp\"\n\tprefix = \"Oralordos/\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/put\", handlePut)\n\thttp.HandleFunc(\"/get\", handleGet)\n\thttp.HandleFunc(\"/\", handleList)\n}\n\nfunc getCloudContext(ctx context.Context) context.Context {\n\thc := &http.Client{\n\t\tTransport: &oauth2.Transport{\n\t\t\tSource: google.AppEngineTokenSource(ctx, storage.ScopeFullControl),\n\t\t\tBase:   &urlfetch.Transport{Context: ctx},\n\t\t},\n\t}\n\n\treturn cloud.NewContext(appengine.AppID(ctx), hc)\n}\n\nfunc handlePut(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tcctx := getCloudContext(ctx)\n\n\tif req.Method != \"POST\" {\n\t\thttp.Error(res, \"Must send a file\", http.StatusMethodNotAllowed)\n\t\treturn\n\t}\n\n\tfile, hdr, err := req.FormFile(\"f\")\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\n\tfilename := hdr.Filename\n\n\twriter := storage.NewWriter(cctx, bucket, prefix+filename)\n\tio.Copy(writer, file)\n\terr = writer.Close()\n\tif err != nil {\n\t\thttp.Error(res, \"ERROR WRITING TO BUCKET: \"+err.Error(), 500)\n\t\treturn\n\t}\n\thttp.Redirect(res, req, \"/\", http.StatusSeeOther)\n}\n\nfunc handleGet(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tcctx := getCloudContext(ctx)\n\n\tfilename := req.FormValue(\"f\")\n\n\trdr, err := storage.NewReader(cctx, bucket, prefix+filename)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tdefer rdr.Close()\n\n\tio.Copy(res, rdr)\n}\n\nfunc handleList(res http.ResponseWriter, req *http.Request) {\n\tctx := appengine.NewContext(req)\n\tcctx := getCloudContext(ctx)\n\n\tquery := &storage.Query{\n\t\tPrefix: prefix,\n\t}\n\tobjs, err := storage.ListObjects(cctx, bucket, query)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tt, err := template.New(\"\").Parse(`<li><a href=\"/get?f={{.}}\">{{.}}</a></li>`)\n\tif err != nil {\n\t\thttp.Error(res, err.Error(), 500)\n\t\treturn\n\t}\n\tres.Header().Set(\"Content-Type\", \"text/html\")\n\tio.WriteString(res, `<form action=\"put\" method=\"POST\" enctype=\"multipart/form-data\"><input name=\"f\" type=\"file\"><input type=\"submit\"></form> <ul>`)\n\tfor _, obj := range objs.Results {\n\t\terr := t.Execute(res, obj.Name[len(prefix):])\n\t\tif err != nil {\n\t\t\thttp.Error(res, err.Error(), 500)\n\t\t\treturn\n\t\t}\n\t}\n\tio.WriteString(res, `</ul>`)\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/01_string-to-html/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tname := \"Todd McLeod\"\n\tfmt.Println(`\n\t<!DOCTYPE html>\n\t<html lang=\"en\">\n\t<head>\n\t<meta charset=\"UTF-8\">\n\t<title>Go Rocks!</title>\n\t</head>\n\t<body>\n\t<h1>` +\n\t\tname +\n\t\t`</h1>\n\t</body>\n\t</html>\n\t`)\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/02_os-args/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n)\n\nfunc main() {\n\n\tname := os.Args[1]\n\n\tfmt.Println(`\n\t<!DOCTYPE html>\n\t<html lang=\"en\">\n\t<head>\n\t<meta charset=\"UTF-8\">\n\t<title>Go Rocks!</title>\n\t</head>\n\t<body>\n\t<h1>` +\n\t\tname +\n\t\t`</h1>\n\t</body>\n\t</html>\n\t`)\n}\n\n/*\ngo build\n./02_string-to-html Todd > index.html\n*/\n"
  },
  {
    "path": "27_code-in-process/99_svcc/03_text-template/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"text/template\"\n)\n\nfunc main() {\n\ttpl, err := template.ParseFiles(\"tpl.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\terr = tpl.Execute(os.Stdout, nil)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n\n/*\nParseFiles || ParseGlob\nExecute || ExecuteTemplate\n*/\n"
  },
  {
    "path": "27_code-in-process/99_svcc/03_text-template/tpl.gohtml",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Document</title>\n</head>\n<body>\n<h1>Hello</h1>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/99_svcc/04_pipeline/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"text/template\"\n)\n\nfunc main() {\n\ttpl, err := template.ParseFiles(\"tpl.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\terr = tpl.Execute(os.Stdout, 5*5)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n\n/*\nIn software engineering, a pipeline consists of a chain of processing elements\n(processes, threads, coroutines, functions, etc.), arranged so that\nthe output of each element is the input of the next;\n*/\n"
  },
  {
    "path": "27_code-in-process/99_svcc/04_pipeline/tpl.gohtml",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Document</title>\n</head>\n<body>\n<h1>{{.}}</h1>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/99_svcc/05_pipeline-range/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"text/template\"\n)\n\nfunc main() {\n\ttpl, err := template.ParseFiles(\"tpl.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\terr = tpl.Execute(os.Stdout, []int{1, 2, 3, 4, 5})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/05_pipeline-range/tpl.gohtml",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Document</title>\n</head>\n<body>\n<ul>\n    {{ range . }}\n    <li>{{ . }}</li>\n    {{ end }}\n</ul>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/99_svcc/06_pipeline-range-else/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"text/template\"\n)\n\nfunc main() {\n\ttpl, err := template.ParseFiles(\"tpl.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\terr = tpl.Execute(os.Stdout, []int{})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/06_pipeline-range-else/tpl.gohtml",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Document</title>\n</head>\n<body>\n<ul>\n    {{ range . }}\n    <li>{{ . }}</li>\n    {{ else }}\n    <li>NO ITEMS</li>\n    {{ end }}\n</ul>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/99_svcc/07_composition/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"text/template\"\n)\n\ntype Person struct {\n\tName string\n\tAge  int\n}\n\nfunc main() {\n\tp1 := Person{\n\t\tName: \"James Bond\",\n\t\tAge:  23,\n\t}\n\n\ttpl, err := template.ParseFiles(\"tpl.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\terr = tpl.Execute(os.Stdout, p1)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/07_composition/tpl.gohtml",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Composition</title>\n</head>\n<body>\n\n<h1>{{ .Name }}</h1>\n<h2>{{ .Age }}</h2>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/99_svcc/08_composition-conditional/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"text/template\"\n)\n\ntype Person struct {\n\tName string\n\tAge  int\n}\n\ntype DoubleZero struct {\n\tPerson\n\tLicenseToKill bool\n}\n\nfunc main() {\n\tp1 := DoubleZero{\n\t\tPerson: Person{\n\t\t\tName: \"Miss MoneyPenny\",\n\t\t\tAge:  19,\n\t\t},\n\t\tLicenseToKill: false,\n\t}\n\n\ttpl, err := template.ParseFiles(\"tpl.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\terr = tpl.Execute(os.Stdout, p1)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/08_composition-conditional/tpl.gohtml",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Composition</title>\n</head>\n<body>\n\n<h1>{{ .Name }}</h1>\n<h2>{{ .Age }}</h2>\n{{ if .LicenseToKill}}\n<h3>License To Kill</h3>\n{{else}}\n<h3>License To chill</h3>\n{{end}}\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/99_svcc/09_methods/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\ntype Person struct {\n\tName string\n\tAge  int\n}\n\ntype DoubleZero struct {\n\tPerson\n\tLicenseToKill bool\n}\n\nfunc (p Person) Greeting() {\n\tfmt.Println(\"I'm just a regular person.\")\n}\n\nfunc (dz DoubleZero) Greeting() {\n\tfmt.Println(\"Miss Moneypenny, so good to see you.\")\n}\n\nfunc main() {\n\tp1 := Person{\n\t\tName: \"Ian Flemming\",\n\t\tAge:  44,\n\t}\n\n\tp2 := DoubleZero{\n\t\tPerson: Person{\n\t\t\tName: \"James Bond\",\n\t\t\tAge:  23,\n\t\t},\n\t\tLicenseToKill: true,\n\t}\n\tp1.Greeting()\n\tp2.Greeting()\n}\n\n/*\n\tp1.Greeting()\n\tp2.Person.Greeting()\n\tfmt.Println(p2.Name)\n\tfmt.Println(p2.Person.Name)\n\n*/\n"
  },
  {
    "path": "27_code-in-process/99_svcc/10_xss/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Nothing Escaped</title>\n</head>\n    <body>\n        <h1>Nothing is escaped with text/template</h1>\n        <script>alert(\"Yow!\");</script>\n    </body>\n</html>"
  },
  {
    "path": "27_code-in-process/99_svcc/10_xss/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"text/template\"\n)\n\ntype Page struct {\n\tTitle   string\n\tHeading string\n\tInput   string\n}\n\nfunc main() {\n\n\thome := Page{\n\t\tTitle:   \"Nothing Escaped\",\n\t\tHeading: \"Nothing is escaped with text/template\",\n\t\tInput:   `<script>alert(\"Yow!\");</script>`,\n\t}\n\n\ttpl, err := template.ParseFiles(\"tpl.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\terr = tpl.Execute(os.Stdout, home)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/10_xss/tpl.gohtml",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>{{ .Title }}</title>\n</head>\n    <body>\n        <h1>{{ .Heading}}</h1>\n        {{ .Input }}\n    </body>\n</html>"
  },
  {
    "path": "27_code-in-process/99_svcc/11_html-templates/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Nothing Escaped</title>\n</head>\n    <body>\n        <h1>Danger is escaped with html/template</h1>\n        &lt;script&gt;alert(&#34;Yow!&#34;);&lt;/script&gt;\n    </body>\n</html>"
  },
  {
    "path": "27_code-in-process/99_svcc/11_html-templates/main.go",
    "content": "package main\n\nimport (\n\t\"html/template\"\n\t\"log\"\n\t\"os\"\n)\n\ntype Page struct {\n\tTitle   string\n\tHeading string\n\tInput   string\n}\n\nfunc main() {\n\n\thome := Page{\n\t\tTitle:   \"Nothing Escaped\",\n\t\tHeading: \"Danger is escaped with html/template\",\n\t\tInput:   `<script>alert(\"Yow!\");</script>`,\n\t}\n\n\ttpl, err := template.ParseFiles(\"tpl.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\terr = tpl.Execute(os.Stdout, home)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/11_html-templates/tpl.gohtml",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>{{ .Title }}</title>\n</head>\n    <body>\n        <h1>{{ .Heading}}</h1>\n        {{ .Input }}\n    </body>\n</html>"
  },
  {
    "path": "27_code-in-process/99_svcc/12_parsefiles/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"html/template\"\n\t\"log\"\n\t\"os\"\n)\n\ntype Page struct {\n\tTitle string\n\tBody  string\n}\n\nfunc main() {\n\n\ttpl, err := template.ParseFiles(\"tpl.gohtml\", \"tpl2.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\terr = tpl.Execute(os.Stdout, Page{\n\t\tTitle: \"Which file?\",\n\t\tBody:  \"hello page 1\",\n\t})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tfmt.Println(\"\\n***************\")\n\n\terr = tpl.ExecuteTemplate(os.Stdout, \"tpl.gohtml\", Page{\n\t\tTitle: \"specifying tpl.gohtml\",\n\t\tBody:  \"hello page 1\",\n\t})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tfmt.Println(\"\\n***************\")\n\n\terr = tpl.ExecuteTemplate(os.Stdout, \"tpl2.gohtml\", Page{\n\t\tTitle: \"specifying tpl2.gohtml\",\n\t\tBody:  \"hello page 2\",\n\t})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/12_parsefiles/tpl.gohtml",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>{{ .Title }}</title>\n</head>\n<body>\n<p>from tpl: {{ .Title}}</p>\n<p>from tpl: {{ .Body }}</p>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/99_svcc/12_parsefiles/tpl2.gohtml",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>{{ .Title }}</title>\n</head>\n<body>\n<p>This is the title from tpl2: {{ .Title}}</p>\n<p>This is the body from tpl2: {{ .Body }}</p>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/99_svcc/13_ParseGlob/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"html/template\"\n\t\"log\"\n\t\"os\"\n)\n\ntype Page struct {\n\tTitle string\n\tBody  string\n}\n\nfunc main() {\n\n\ttpl, err := template.ParseGlob(\"templates/*.gohtml\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\terr = tpl.Execute(os.Stdout, Page{\n\t\tTitle: \"Which file?\",\n\t\tBody:  \"hello page 1\",\n\t})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tfmt.Println(\"\\n***************\")\n\n\terr = tpl.ExecuteTemplate(os.Stdout, \"tpl.gohtml\", Page{\n\t\tTitle: \"specifying tpl.gohtml\",\n\t\tBody:  \"hello page 1\",\n\t})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tfmt.Println(\"\\n***************\")\n\n\terr = tpl.ExecuteTemplate(os.Stdout, \"tpl2.gohtml\", Page{\n\t\tTitle: \"specifying tpl2.gohtml\",\n\t\tBody:  \"hello page 2\",\n\t})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/13_ParseGlob/templates/tpl.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>{{ .Title }}</title>\n</head>\n<body>\n<p>from tpl: {{ .Title}}</p>\n<p>from tpl: {{ .Body }}</p>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/99_svcc/13_ParseGlob/templates/tpl2.gohtml",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>{{ .Title }}</title>\n</head>\n<body>\n<p>This is the title from tpl2: {{ .Title}}</p>\n<p>This is the body from tpl2: {{ .Body }}</p>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/99_svcc/14_tcp_echo-server/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net\"\n)\n\nfunc main() {\n\tln, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer ln.Close()\n\n\tfor {\n\t\tconn, err := ln.Accept()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\n\t\t// handles only one connection\n\t\tio.Copy(conn, conn)\n\t\tconn.Close()\n\t}\n}\n\n/*\nstart main.go (go run main.go) then ...\ntelnet localhost 9000\n*/\n"
  },
  {
    "path": "27_code-in-process/99_svcc/15_tcp_echo-server/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n)\n\nfunc handle(conn net.Conn) {\n\tdefer conn.Close()\n\n\t// NewScanner returns a new Scanner to read from r.\n\t// The split function defaults to ScanLines.\n\tscanner := bufio.NewScanner(conn)\n\t// Scan advances the Scanner to the next token, which will then be\n\t// available through the Bytes or Text method.\n\tfor scanner.Scan() {\n\t\t// Text returns the most recent token generated by a call to Scan\n\t\t// as a newly allocated string holding its bytes.\n\t\tln := scanner.Text()\n\t\tfmt.Println(ln)\n\t\tfmt.Printf(\"TYPE: %T\\n\", ln)\n\t\tln = fmt.Sprint(\"FROM SERVER: \" + ln)\n\t\tfmt.Fprintln(conn, ln)\n\t}\n}\n\nfunc main() {\n\tli, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer li.Close()\n\n\tfor {\n\t\tconn, err := li.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\t\thandle(conn)\n\t}\n}\n\n/*\nstart main.go (go run main.go) then ...\ntelnet localhost 9000\n*/\n"
  },
  {
    "path": "27_code-in-process/99_svcc/16_redis-clone_step-2/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n)\n\nfunc handle(conn net.Conn) {\n\tdefer conn.Close()\n\n\t// NewScanner returns a new Scanner to read from r.\n\t// The split function defaults to ScanLines.\n\tscanner := bufio.NewScanner(conn)\n\t// Scan advances the Scanner to the next token, which will then be\n\t// available through the Bytes or Text method.\n\tfor scanner.Scan() {\n\t\t// Text returns the most recent token generated by a call to Scan\n\t\t// as a newly allocated string holding its bytes.\n\t\tln := scanner.Text()\n\t\t// Fields splits the string s around each instance of one or more consecutive white space\n\t\t// characters, as defined by unicode.IsSpace, returning an array of substrings of s or an\n\t\t// empty list if s contains only white space.\n\t\tfs := strings.Fields(ln)\n\t\t// skip blank lines\n\t\tif len(fs) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tswitch fs[0] {\n\t\tcase \"GET\":\n\t\tcase \"SET\":\n\t\tcase \"DEL\":\n\t\tdefault:\n\t\t\tfmt.Println(ln)\n\t\t\tln = fmt.Sprint(\"FROM SERVER - USAGE <GET | SET | DEL> <KEY> [VAL]\")\n\t\t\tfmt.Fprintln(conn, ln)\n\t\t\tio.WriteString(conn, ln)\n\t\t}\n\t}\n}\n\nfunc main() {\n\tli, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer li.Close()\n\n\tfor {\n\t\tconn, err := li.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\t\thandle(conn)\n\t}\n}\n\n/*\nstart main.go (go run main.go) then ...\ntelnet localhost 9000\n*/\n"
  },
  {
    "path": "27_code-in-process/99_svcc/17_redis-clone_step-5/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n)\n\nvar data = make(map[string]string)\n\nfunc handle(conn net.Conn) {\n\tdefer conn.Close()\n\n\t// NewScanner returns a new Scanner to read from r.\n\t// The split function defaults to ScanLines.\n\tscanner := bufio.NewScanner(conn)\n\t// Scan advances the Scanner to the next token, which will then be\n\t// available through the Bytes or Text method.\n\tfor scanner.Scan() {\n\t\t// Text returns the most recent token generated by a call to Scan\n\t\t// as a newly allocated string holding its bytes.\n\t\tln := scanner.Text()\n\t\t// Fields splits the string s around each instance of one or more consecutive white space\n\t\t// characters, as defined by unicode.IsSpace, returning an array of substrings of s or an\n\t\t// empty list if s contains only white space.\n\t\tfs := strings.Fields(ln)\n\t\t// skip blank lines\n\t\tif len(fs) < 2 {\n\t\t\tfmt.Fprintln(conn, \"FROM SERVER - USAGE <GET | SET | DEL> <KEY> [VAL]\")\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch fs[0] {\n\t\tcase \"GET\":\n\t\t\tkey := fs[1]\n\t\t\tvalue := data[key]\n\t\t\tfmt.Fprintf(conn, \"%s\\n\", value)\n\t\tcase \"SET\":\n\t\t\tif len(fs) != 3 {\n\t\t\t\tio.WriteString(conn, \"EXPECTED VALUE\\n\")\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tkey := fs[1]\n\t\t\tvalue := fs[2]\n\t\t\tdata[key] = value\n\t\tcase \"DEL\":\n\t\t\tkey := fs[1]\n\t\t\tdelete(data, key)\n\t\tdefault:\n\t\t\tfmt.Println(ln)\n\t\t\tln = fmt.Sprint(\"FROM SERVER - USAGE <GET | SET | DEL> <KEY> [VAL]\\n\" +\n\t\t\t\t\"INVALID COMMAND: \" + fs[0] + \"\\n\\n\")\n\t\t\tio.WriteString(conn, ln)\n\t\t}\n\t}\n}\n\nfunc main() {\n\tli, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer li.Close()\n\n\tfor {\n\t\tconn, err := li.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\t\thandle(conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/18_rot13/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n)\n\nfunc handle(conn net.Conn) {\n\tdefer conn.Close()\n\t// NewScanner returns a new Scanner to read from r.\n\t// The split function defaults to ScanLines.\n\tscanner := bufio.NewScanner(conn)\n\t// Scan advances the Scanner to the next token, which will then be\n\t// available through the Bytes or Text method.\n\tfor scanner.Scan() {\n\t\t// Text returns the most recent token generated by a call to Scan\n\t\t// as a newly allocated string holding its bytes.\n\t\tln := scanner.Text()\n\t\tln = strings.ToLower(ln)\n\t\tbs := []byte(ln)\n\t\tvar rot13 = make([]byte, len(bs))\n\t\tfor k, v := range bs {\n\t\t\t// ascii 97 - 122\n\t\t\t/// 109 + 13 = 122\n\t\t\tif v <= 109 {\n\t\t\t\trot13[k] = v + 13\n\t\t\t} else {\n\t\t\t\t// 110 + 13 = 123\n\t\t\t\t//123 - 26 = 97\n\t\t\t\trot13[k] = v - 26 + 13\n\t\t\t}\n\t\t}\n\t\tfmt.Fprintf(conn, \"%s\\n\", rot13)\n\t}\n}\n\nfunc main() {\n\tln, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer ln.Close()\n\n\tfor {\n\t\tconn, err := ln.Accept()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\thandle(conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/19_DIY_http-server_request-line_headers/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n)\n\nfunc handleConn(conn net.Conn) {\n\tdefer conn.Close()\n\tscanner := bufio.NewScanner(conn)\n\tfor scanner.Scan() {\n\t\tfmt.Println(scanner.Text())\n\t}\n}\n\nfunc main() {\n\tserver, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\tdefer server.Close()\n\n\tfor {\n\t\tconn, err := server.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err.Error())\n\t\t}\n\t\tgo handleConn(conn)\n\t}\n}\n\n/*\nstart main.go (go run main.go) then ...\ngo to your browser and go to localhost:9000\n\nin the terminal on the server\ngo look at the request line & request headers\n*/\n"
  },
  {
    "path": "27_code-in-process/99_svcc/20_DIY_http-server_step-01/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n)\n\nfunc handleConn(conn net.Conn) {\n\tdefer conn.Close()\n\tscanner := bufio.NewScanner(conn)\n\ti := 0\n\tfor scanner.Scan() {\n\t\tln := scanner.Text()\n\t\tfmt.Println(ln)\n\n\t\tif i == 0 {\n\t\t\tmethod := strings.Fields(ln)[0]\n\t\t\tfmt.Println(\"WE PRINTED THIS - METHOD: \", method)\n\t\t} else {\n\n\t\t}\n\t\ti++\n\t}\n}\n\nfunc main() {\n\tserver, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\tdefer server.Close()\n\n\tfor {\n\t\tconn, err := server.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err.Error())\n\t\t}\n\t\tgo handleConn(conn)\n\t}\n}\n\n/*\nstart main.go (go run main.go) then ...\ngo to your browser and go to localhost:9000\n\nin the terminal on the server\ngo look at the request line & request headers\n*/\n"
  },
  {
    "path": "27_code-in-process/99_svcc/21_DIY_http-server_step-02/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n)\n\nfunc handleConn(conn net.Conn) {\n\tdefer conn.Close()\n\tscanner := bufio.NewScanner(conn)\n\ti := 0\n\tfor scanner.Scan() {\n\t\tln := scanner.Text()\n\t\tfmt.Println(ln)\n\n\t\tif i == 0 {\n\t\t\tmethod := strings.Fields(ln)[0]\n\t\t\tfmt.Println(\"WE PRINTED THIS - METHOD: \", method)\n\t\t} else {\n\t\t\t// in headers now\n\t\t\t// when line is empty, header is done\n\t\t\tif ln == \"\" {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\ti++\n\t}\n\n\t// response\n\tbody := \"hello world 2\"\n\n\tio.WriteString(conn, \"HTTP/1.1 200 OK\\r\\n\")\n\tfmt.Fprintf(conn, \"Content-Length: %d\\r\\n\", len(body))\n\tio.WriteString(conn, \"\\r\\n\")\n\tio.WriteString(conn, body)\n}\n\nfunc main() {\n\tserver, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\tdefer server.Close()\n\n\tfor {\n\t\tconn, err := server.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err.Error())\n\t\t}\n\t\tgo handleConn(conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/22_DIY_http-server_step-03/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n)\n\nfunc handleConn(conn net.Conn) {\n\tdefer conn.Close()\n\tscanner := bufio.NewScanner(conn)\n\ti := 0\n\tfor scanner.Scan() {\n\t\tln := scanner.Text()\n\t\tfmt.Println(ln)\n\n\t\tif i == 0 {\n\t\t\tmethod := strings.Fields(ln)[0]\n\t\t\tfmt.Println(\"WE PRINTED THIS - METHOD: \", method)\n\t\t} else {\n\t\t\t// in headers now\n\t\t\t// when line is empty, header is done\n\t\t\tif ln == \"\" {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\ti++\n\t}\n\n\t// response\n\tbody := `\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n</head>\n<body>\n\t<strong>Hello World</strong>\n</body>\n</html>\n\t`\n\n\tio.WriteString(conn, \"HTTP/1.1 200 OK\\r\\n\")\n\tfmt.Fprintf(conn, \"Content-Length: %d\\r\\n\", len(body))\n\tfmt.Fprintf(conn, \"Content-Type: text/plain; charset=utf-8\\r\\n\")\n\tio.WriteString(conn, \"\\r\\n\")\n\tio.WriteString(conn, body)\n}\n\nfunc main() {\n\tserver, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\tdefer server.Close()\n\n\tfor {\n\t\tconn, err := server.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err.Error())\n\t\t}\n\t\tgo handleConn(conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/23_DIY_http-server_step-04/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n)\n\nfunc handleConn(conn net.Conn) {\n\tdefer conn.Close()\n\tscanner := bufio.NewScanner(conn)\n\ti := 0\n\tfor scanner.Scan() {\n\t\tln := scanner.Text()\n\t\tfmt.Println(ln)\n\n\t\tif i == 0 {\n\t\t\tmethod := strings.Fields(ln)[0]\n\t\t\tfmt.Println(\"WE PRINTED THIS - METHOD: \", method)\n\t\t} else {\n\t\t\t// in headers now\n\t\t\t// when line is empty, header is done\n\t\t\tif ln == \"\" {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\ti++\n\t}\n\n\t// response\n\tbody := `\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n</head>\n<body>\n\t<strong>Hello World</strong>\n</body>\n</html>\n\t`\n\n\tio.WriteString(conn, \"HTTP/1.1 200 OK\\r\\n\")\n\tfmt.Fprintf(conn, \"Content-Length: %d\\r\\n\", len(body))\n\tfmt.Fprintf(conn, \"Content-Type: text/html; charset=utf-8\\r\\n\")\n\tio.WriteString(conn, \"\\r\\n\")\n\tio.WriteString(conn, body)\n}\n\nfunc main() {\n\tserver, err := net.Listen(\"tcp\", \":9000\")\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\tdefer server.Close()\n\n\tfor {\n\t\tconn, err := server.Accept()\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err.Error())\n\t\t}\n\t\tgo handleConn(conn)\n\t}\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/24_http-server_ServeMux/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc upTown(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, \"doggy doggy doggy\")\n}\n\nfunc youUp(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, \"catty catty catty\")\n}\n\nfunc main() {\n\n\tmux := http.NewServeMux()\n\tmux.HandleFunc(\"/\", upTown)\n\tmux.HandleFunc(\"/cat/\", youUp)\n\n\thttp.ListenAndServe(\":9000\", mux)\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/25_http-server_DefaultServeMux/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc upTown(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, \"doggy doggy doggy\")\n}\n\nfunc youUp(res http.ResponseWriter, req *http.Request) {\n\tio.WriteString(res, \"catty catty catty\")\n}\n\nfunc main() {\n\n\thttp.HandleFunc(\"/\", upTown)\n\thttp.HandleFunc(\"/cat/\", youUp)\n\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/26_serving-files_io-Copy/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc upTown(res http.ResponseWriter, req *http.Request) {\n\tres.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\tvar dogName string\n\tfs := strings.Split(req.URL.Path, \"/\")\n\tif len(fs) >= 2 {\n\t\tdogName = fs[1]\n\t}\n\t// the image doesn't serve\n\tio.WriteString(res, `\n\t<h1>Dog Name: `+dogName+`</h1><br>\n\t<img src=\"/toby.jpg\">\n\t`)\n}\n\nfunc dogPic(res http.ResponseWriter, req *http.Request) {\n\tf, err := os.Open(\"toby.jpg\")\n\tif err != nil {\n\t\thttp.Error(res, \"file not found\", 404)\n\t\treturn\n\t}\n\tdefer f.Close()\n\n\tio.Copy(res, f)\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", upTown)\n\thttp.HandleFunc(\"/toby.jpg\", dogPic)\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/27_serving-files_ServeContent/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc upTown(res http.ResponseWriter, req *http.Request) {\n\tres.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\tvar dogName string\n\tfs := strings.Split(req.URL.Path, \"/\")\n\tif len(fs) >= 2 {\n\t\tdogName = fs[1]\n\t}\n\t// the image doesn't serve\n\tio.WriteString(res, `\n\t<h1>Dog Name: `+dogName+`</h1><br>\n\t<img src=\"/toby.jpg\">\n\t`)\n}\n\nfunc dogPic(res http.ResponseWriter, req *http.Request) {\n\tf, err := os.Open(\"toby.jpg\")\n\tif err != nil {\n\t\thttp.Error(res, \"file not found\", 404)\n\t\treturn\n\t}\n\tdefer f.Close()\n\n\tfi, err := f.Stat()\n\tif err != nil {\n\t\thttp.Error(res, \"file not found\", 404)\n\t\treturn\n\t}\n\n\thttp.ServeContent(res, req, f.Name(), fi.ModTime(), f)\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", upTown)\n\thttp.HandleFunc(\"/toby.jpg\", dogPic)\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/28_serving-files_ServeFile/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc upTown(res http.ResponseWriter, req *http.Request) {\n\tres.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\tvar dogName string\n\tfs := strings.Split(req.URL.Path, \"/\")\n\tif len(fs) >= 2 {\n\t\tdogName = fs[1]\n\t}\n\t// the image doesn't serve\n\tio.WriteString(res, `\n\t<h1>Dog Name: `+dogName+`</h1><br>\n\t<img src=\"/toby.jpg\">\n\t`)\n}\n\nfunc dogPic(res http.ResponseWriter, req *http.Request) {\n\thttp.ServeFile(res, req, \"toby.jpg\")\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", upTown)\n\thttp.HandleFunc(\"/toby.jpg\", dogPic)\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/29_serving-files_FileServer/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc upTown(res http.ResponseWriter, req *http.Request) {\n\tres.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\tvar dogName string\n\tfs := strings.Split(req.URL.Path, \"/\")\n\tif len(fs) >= 3 {\n\t\tdogName = fs[2]\n\t}\n\t// the image doesn't serve\n\tio.WriteString(res, `\n\t<h1>Dog Name: `+dogName+`</h1><br>\n\t<img src=\"/toby.jpg\">\n\t`)\n}\n\nfunc main() {\n\t// FileServer returns a handler that serves HTTP requests\n\t// with the contents of the file system rooted at root.\n\thttp.Handle(\"/\", http.FileServer(http.Dir(\".\")))\n\thttp.HandleFunc(\"/dog/\", upTown)\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/30_serving-files_FileServer/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc upTown(res http.ResponseWriter, req *http.Request) {\n\tres.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\tvar dogName string\n\tfs := strings.Split(req.URL.Path, \"/\")\n\tif len(fs) >= 2 {\n\t\tdogName = fs[1]\n\t}\n\t// the image doesn't serve\n\tio.WriteString(res, `\n\t<h1>Dog Name: `+dogName+`</h1><br>\n\t<img src=\"/assets/toby.jpg\">\n\t`)\n}\n\nfunc main() {\n\thttp.Handle(\"/assets/\", http.StripPrefix(\"/assets\", http.FileServer(http.Dir(\"./assets\"))))\n\thttp.HandleFunc(\"/\", upTown)\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/31_serving-files_FileServer/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc upTown(res http.ResponseWriter, req *http.Request) {\n\tres.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\tvar dogName string\n\tfs := strings.Split(req.URL.Path, \"/\")\n\tif len(fs) >= 2 {\n\t\tdogName = fs[1]\n\t}\n\t// the image doesn't serve\n\tio.WriteString(res, `\n\t<h1>Dog Name: `+dogName+`</h1><br>\n\t<img src=\"/resources/toby.jpg\">\n\t`)\n}\n\nfunc main() {\n\thttp.Handle(\"/resources/\", http.StripPrefix(\"/resources\", http.FileServer(http.Dir(\"./assets\"))))\n\thttp.HandleFunc(\"/\", upTown)\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/32_static-FileServer/assets/images/home/imgres.html",
    "content": "<!DOCTYPE html><html itemscope itemtype=\"http://schema.org/SearchResultsPage\" prefix=\"og: http://ogp.me/ns/website#\"><head><meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\"><meta itemprop=\"image\" content=\"http://www.fresnocitycollege.edu/modules/showimage.aspx?imageid=463\"><meta itemprop=\"name\" content=\" Google Image Result for http://www.fresnocitycollege.edu/modules/showimage.aspx%3Fimageid%3D463\"><meta property=\"og:type\" content=\"website\"><meta property=\"og:image\" content=\"http://www.fresnocitycollege.edu/modules/showimage.aspx?imageid=463\"><meta property=\"og:title\" content=\" Google Image Result for http://www.fresnocitycollege.edu/modules/showimage.aspx%3Fimageid%3D463\"><title> Google Image Result for http://www.fresnocitycollege.edu/modules/showimage.aspx%3Fimageid%3D463</title><script>(function(){window.google={kEI:'P6DyVPi9IMzUoATG14L4Cg',kEXPI:'4011550,4011551,4011556,4011558,4011559,4014789,4020346,4020562,4020874,4023678,4023709,4026624,4027744,4027969,4028541,4028717,4028875,4029054,4029141,4029155,4029185,4029468,4029514,4029844,8300122,8500393,8500852,8501081,8501082,10200083,10200682',authuser:0,kSID:'P6DyVPi9IMzUoATG14L4Cg'};google.kHL='en';})();(function(){google.lc=[];google.li=0;google.getEI=function(a){for(var b;a&&(!a.getAttribute||!(b=a.getAttribute(\"eid\")));)a=a.parentNode;return b||google.kEI};google.getLEI=function(a){for(var b=null;a&&(!a.getAttribute||!(b=a.getAttribute(\"leid\")));)a=a.parentNode;return b};google.https=function(){return\"https:\"==window.location.protocol};google.ml=function(){};google.time=function(){return(new Date).getTime()};google.log=function(a,b,e,f,l){var d=new Image,h=google.lc,g=google.li,c=\"\",m=google.ls||\"\";d.onerror=d.onload=d.onabort=function(){delete h[g]};h[g]=d;if(!e&&-1==b.search(\"&ei=\")){var k=google.getEI(f),c=\"&ei=\"+k;-1==b.search(\"&lei=\")&&((f=google.getLEI(f))?c+=\"&lei=\"+f:k!=google.kEI&&(c+=\"&lei=\"+google.kEI))}a=e||\"/\"+(l||\"gen_204\")+\"?atyp=i&ct=\"+a+\"&cad=\"+b+c+m+\"&zx=\"+google.time();/^http:/i.test(a)&&google.https()?(google.ml(Error(\"a\"),!1,{src:a,glmm:1}),delete h[g]):(d.src=a,google.li=g+1)};google.y={};google.x=function(a,b){google.y[a.id]=[a,b];return!1};google.load=function(a,b,e){google.x({id:a+n++},function(){google.load(a,b,e)})};var n=0;})();google.kCSI={};</script><script></script><script>(function(){'use strict';var g=this,aa=function(a){var c=typeof a;if(\"object\"==c)if(a){if(a instanceof Array)return\"array\";if(a instanceof Object)return c;var b=Object.prototype.toString.call(a);if(\"[object Window]\"==b)return\"object\";if(\"[object Array]\"==b||\"number\"==typeof a.length&&\"undefined\"!=typeof a.splice&&\"undefined\"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable(\"splice\"))return\"array\";if(\"[object Function]\"==b||\"undefined\"!=typeof a.call&&\"undefined\"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable(\"call\"))return\"function\"}else return\"null\";else if(\"function\"==c&&\"undefined\"==typeof a.call)return\"object\";return c},ba=Date.now||function(){return+new Date};var h={};var ca=function(a,c){if(null===c)return!1;if(\"contains\"in a&&1==c.nodeType)return a.contains(c);if(\"compareDocumentPosition\"in a)return a==c||Boolean(a.compareDocumentPosition(c)&16);for(;c&&a!=c;)c=c.parentNode;return c==a};var da=function(a,c){return function(b){b||(b=window.event);return c.call(a,b)}},l=function(a){a=a.target||a.srcElement;!a.getAttribute&&a.parentNode&&(a=a.parentNode);return a},u=\"undefined\"!=typeof navigator&&/Macintosh/.test(navigator.userAgent),ea=\"undefined\"!=typeof navigator&&!/Opera/.test(navigator.userAgent)&&/WebKit/.test(navigator.userAgent),ga=function(a){var c=a.which||a.keyCode||a.key;ea&&3==c&&(c=13);if(13!=c&&32!=c)return!1;var b=l(a),d=(b.getAttribute(\"role\")||b.type||b.tagName).toUpperCase(),e;(e=\"keydown\"!=a.type)||(\"getAttribute\"in b?(e=(b.getAttribute(\"role\")||b.type||b.tagName).toUpperCase(),e=\"TEXT\"!=e&&\"TEXTAREA\"!=e&&\"PASSWORD\"!=e&&\"SEARCH\"!=e&&(\"COMBOBOX\"!=\ne||\"INPUT\"!=b.tagName.toUpperCase())&&!b.isContentEditable):e=!1,e=!e);if(e||a.ctrlKey||a.shiftKey||a.altKey||a.metaKey||\"INPUT\"==b.tagName.toUpperCase()&&b.type&&b.type.toUpperCase()in v&&32==c)return!1;if(a.originalTarget&&a.originalTarget!=b)return!0;(a=b.tagName in fa)||(a=b.getAttributeNode(\"tabindex\"),a=null!=a&&a.specified);if(!(a&&0<=b.tabIndex)||b.disabled)return!1;b=\"INPUT\"!=b.tagName.toUpperCase()||b.type;a=!(d in w)&&13==c;return(0==w[d]%c||a)&&!!b},fa={A:1,INPUT:1,TEXTAREA:1,SELECT:1,BUTTON:1},w={A:13,BUTTON:0,CHECKBOX:32,COMBOBOX:13,LINK:13,LISTBOX:13,MENU:0,MENUBAR:0,MENUITEM:0,MENUITEMCHECKBOX:0,MENUITEMRADIO:0,OPTION:13,RADIO:32,RADIOGROUP:32,RESET:0,SUBMIT:0,TAB:0,TABLIST:0,TREE:13,TREEITEM:13},v={CHECKBOX:1,OPTION:1,RADIO:1};var z=function(){this.o=this.i=null},B=function(a,c){var b=A;b.i=a;b.o=c;return b};z.prototype.k=function(){var a=this.i;this.i&&this.i!=this.o?this.i=this.i.__owner||this.i.parentNode:this.i=null;return a};var C=function(){this.p=[];this.i=0;this.o=null;this.s=!1};C.prototype.k=function(){if(this.s)return A.k();if(this.i!=this.p.length){var a=this.p[this.i];this.i++;a!=this.o&&a&&a.__owner&&(this.s=!0,B(a.__owner,this.o));return a}return null};var A=new z,G=new C;var H;n:{var I=g.navigator;if(I){var J=I.userAgent;if(J){H=J;break n}}H=\"\"}var K=function(a){return-1!=H.indexOf(a)};var L=function(){return K(\"Opera\")||K(\"OPR\")},M=function(){return K(\"Edge\")||K(\"Trident\")||K(\"MSIE\")},N=function(){return(K(\"Chrome\")||K(\"CriOS\"))&&!L()&&!M()};var ha=L(),O=M(),ia=K(\"Gecko\")&&!(-1!=H.toLowerCase().indexOf(\"webkit\")&&!K(\"Edge\"))&&!(K(\"Trident\")||K(\"MSIE\"))&&!K(\"Edge\"),ja=-1!=H.toLowerCase().indexOf(\"webkit\")&&!K(\"Edge\"),ka=function(){var a=H;if(ia)return/rv\\:([^\\);]+)(\\)|;)/.exec(a);if(O&&K(\"Edge\"))return/Edge\\/([\\d\\.]+)/.exec(a);if(O)return/\\b(?:MSIE|rv)[:]([^\\);]+)(\\)|;)/.exec(a);if(ja)return/WebKit\\/(\\S+)/.exec(a)};(function(){if(ha&&g.opera){var a=g.opera.version;return\"function\"==aa(a)?a():a}var a=\"\",c=ka();c&&(a=c?c[1]:\"\");return O&&!K(\"Edge\")&&(c=(c=g.document)?c.documentMode:void 0,c>parseFloat(a))?String(c):a})();!K(\"Android\")||N()||K(\"Firefox\")||L();N();var Q=function(){this.B=[];this.i=[];this.k=[];this.s={};this.o=null;this.p=[];P(this,\"_custom\")},la=\"undefined\"!=typeof navigator&&/iPhone|iPad|iPod/.test(navigator.userAgent),R=String.prototype.trim?function(a){return a.trim()}:function(a){return a.replace(/^\\s+/,\"\").replace(/\\s+$/,\"\")},ma=/\\s*;\\s*/,qa=function(a,c){return function(b){var d=c;if(\"_custom\"==d){d=b.detail;if(!d||!d._type)return;d=d._type}var e;var f=d;\"click\"==f&&(u&&b.metaKey||!u&&b.ctrlKey||2==b.which||null==b.which&&4==b.button||b.shiftKey)?f=\"clickmod\":ga(b)&&(f=\"clickkey\");var k=b.srcElement||b.target,d=S(f,b,k,\"\",null),m,q;b.path?(G.p=b.path,G.i=0,G.o=this,G.s=!1,q=G):q=B(k,this);for(var r;r=q.k();){m=e=r;r=f;var n=m.__jsaction;if(!n){var x=void 0,n=null;\"getAttribute\"in m&&(n=m.getAttribute(\"jsaction\"));if(x=\nn){n=h[x];if(!n){for(var n={},D=x.split(ma),E=0,oa=D?D.length:0;E<oa;E++){var t=D[E];if(t){var F=t.indexOf(\":\"),U=-1!=F,pa=U?R(t.substr(0,F)):\"click\",t=U?R(t.substr(F+1)):t;n[pa]=t}}h[x]=n}m.__jsaction=n}else n=na,m.__jsaction=n}\"clickkey\"==r?r=\"click\":\"click\"!=r||n.click||(r=\"clickonly\");m={v:r,action:n[r]||\"\",event:null,D:!1};d=S(m.v,m.event||b,k,m.action||\"\",e,d.timeStamp);if(m.D||m.action)break}if(m&&m.action){if(k=\"clickkey\"==f)k=l(b),k=(k.type||k.tagName).toUpperCase(),(k=32==(b.which||b.keyCode||\nb.key)&&\"CHECKBOX\"!=k)||(q=l(b),k=(q.getAttribute(\"role\")||q.tagName).toUpperCase(),q=q.type,k=\"BUTTON\"==k||!!q&&!(q.toUpperCase()in v));k&&(b.preventDefault?b.preventDefault():b.returnValue=!1);if(\"mouseenter\"==f||\"mouseleave\"==f)if(k=b.relatedTarget,!(\"mouseover\"==b.type&&\"mouseenter\"==f||\"mouseout\"==b.type&&\"mouseleave\"==f)||k&&(k===e||ca(e,k)))d.action=\"\",d.actionElement=null;else{var f={},p;for(p in b)\"function\"!==typeof b[p]&&\"srcElement\"!==p&&\"target\"!==p&&(f[p]=b[p]);f.type=\"mouseover\"==b.type?\"mouseenter\":\"mouseleave\";f.target=f.srcElement=e;f.bubbles=!1;d.event=f;d.targetElement=e}}else d.action=\"\",d.actionElement=null;e=d;a.o&&(p=S(e.eventType,e.event,e.targetElement,e.action,e.actionElement,e.timeStamp),\"clickonly\"==p.eventType&&(p.eventType=\"click\"),a.o(p,!0));if(e.actionElement)if(\"A\"!=e.actionElement.tagName||\"click\"!=e.eventType&&\"clickmod\"!=e.eventType||(b.preventDefault?b.preventDefault():b.returnValue=!1),a.o)a.o(e);else{var y;if((p=g.document)&&!p.createEvent&&p.createEventObject)try{y=\np.createEventObject(b)}catch(ua){y=b}else y=b;e.event=y;a.p.push(e)}}},S=function(a,c,b,d,e,f){return{eventType:a,event:c,targetElement:b,action:d,actionElement:e,timeStamp:f||ba()}},na={},ra=function(a,c){return function(b){var d=a,e=c,f=!1;\"mouseenter\"==d?d=\"mouseover\":\"mouseleave\"==d&&(d=\"mouseout\");if(b.addEventListener){if(\"focus\"==d||\"blur\"==d||\"error\"==d||\"load\"==d)f=!0;b.addEventListener(d,e,f)}else b.attachEvent&&(\"focus\"==d?d=\"focusin\":\"blur\"==d&&(d=\"focusout\"),e=da(b,e),b.attachEvent(\"on\"+d,e));return{v:d,w:e,C:f}}},P=function(a,c){if(!a.s.hasOwnProperty(c)){var b=qa(a,c),d=ra(c,b);a.s[c]=b;a.B.push(d);for(b=0;b<a.i.length;++b){var e=a.i[b];e.k.push(d.call(null,e.i))}\"click\"==c&&P(a,\"keydown\")}};Q.prototype.w=function(a){return this.s[a]};var Y=function(a){var c=T,b=new sa(a);n:{for(var d=0;d<c.i.length;d++)if(V(c.i[d],a)){a=!0;break n}a=!1}if(a)return c.k.push(b),b;W(c,b);c.i.push(b);X(c);return b},X=function(a){for(var c=a.k.concat(a.i),b=[],d=[],e=0;e<a.i.length;++e){var f=a.i[e];Z(f,c)?(b.push(f),ta(f)):d.push(f)}for(e=0;e<a.k.length;++e)f=a.k[e],Z(f,c)?b.push(f):(d.push(f),W(a,f));a.i=d;a.k=b},W=function(a,c){var b=c.i;la&&(b.style.cursor=\"pointer\");for(b=0;b<a.B.length;++b)c.k.push(a.B[b].call(null,c.i))},sa=function(a){this.i=a;this.k=[]},V=function(a,c){for(var b=a.i,d=c;b!=d&&d.parentNode;)d=d.parentNode;return b==d},Z=function(a,c){for(var b=0;b<c.length;++b)if(c[b].i!=a.i&&V(c[b],a.i))return!0;return!1},ta=function(a){for(var c=0;c<a.k.length;++c){var b=a.i,d=a.k[c];b.removeEventListener?b.removeEventListener(d.v,d.w,d.C):b.detachEvent&&b.detachEvent(\"on\"+d.v,d.w)}a.k=[]};var T=new Q;Y(window.document.documentElement);P(T,\"click\");P(T,\"focus\");P(T,\"focusin\");P(T,\"blur\");P(T,\"focusout\");P(T,\"error\");P(T,\"load\");P(T,\"change\");P(T,\"dblclick\");P(T,\"input\");P(T,\"keyup\");P(T,\"keydown\");P(T,\"keypress\");P(T,\"mousedown\");P(T,\"mouseenter\");P(T,\"mouseleave\");P(T,\"mouseout\");P(T,\"mouseover\");P(T,\"mouseup\");P(T,\"touchstart\");P(T,\"touchend\");P(T,\"touchcancel\");P(T,\"speech\");window.google.jsad=function(a){var c=T;c.o=a;c.p&&(0<c.p.length&&a(c.p),c.p=null)};window.google.jsaac=function(a){return Y(a)};window.google.jsarc=function(a){var c=T;ta(a);for(var b=!1,d=0;d<c.i.length;++d)if(c.i[d]===a){c.i.splice(d,1);b=!0;break}if(!b)for(d=0;d<c.k.length;++d)if(c.k[d]===a){c.k.splice(d,1);break}X(c)};}).call(window);</script></head><body><noscript><meta content=\"0;url=/imgres?tbnid=Neb7NEW2XN7WuM:&amp;tbnh=0&amp;tbnw=0&amp;imgurl=http://www.fresnocitycollege.edu/modules/showimage.aspx%253Fimageid%253D463&amp;imgrefurl=http://www.fresnocitycollege.edu/index.aspx%3Fpage%3D94&amp;h=394&amp;w=432&amp;tbm=isch&amp;gbv=1&amp;sei=P6DyVPi9IMzUoATG14L4Cg\" http-equiv=\"refresh\"><style>table,div,span,p{display:none}</style><div style=\"display:block\">Please click <a href=\"/imgres?tbnid=Neb7NEW2XN7WuM:&amp;tbnh=0&amp;tbnw=0&amp;imgurl=http://www.fresnocitycollege.edu/modules/showimage.aspx%253Fimageid%253D463&amp;imgrefurl=http://www.fresnocitycollege.edu/index.aspx%3Fpage%3D94&amp;h=394&amp;w=432&amp;tbm=isch&amp;gbv=1&amp;sei=P6DyVPi9IMzUoATG14L4Cg\">here</a> if you are not redirected within a few seconds.</div></noscript><body><div eid=\"P6DyVPi9IMzUoATG14L4Cg\" id=\"lgattr\"><div id=\"i3599\" data-ved=\"0CAQQjxw\"></div><div id=\"i3596\" data-ved=\"0CAUQjBw\"></div><div id=\"i3598\" data-ved=\"0CAYQjhw\"></div><div id=\"i3724\" data-ved=\"0CAcQjB0\"></div><div id=\"i3597\" data-ved=\"0CAgQjRw\"></div><div id=\"i3591\" data-ved=\"0CAkQhxw\"></div><div id=\"i3592\" data-ved=\"0CAoQiBw\"></div><div id=\"i5877\" data-ved=\"0CAsQ9S0\"></div></div><div><style>.irc_land,.irc_por,.irc_hcb{}.irc_por .irc_t{display:block}.irc_ifr{border:0;height:100%;width:100%}.irc_micol{height:100%;position:absolute;width:100%}.irc_pgb{margin:auto;position:absolute}.irc_pgb .progress-bar-thumb{background-color:#666;width:100%}.irc_por .irc_b{width:100%;}.irc_pdft{color:#aaa;font-size:16px}.irc_hd a{color:#7d7d7d}.irc_por ._r3{display:block;}._r3:before{color:#7d7d7d;content:\"-\";margin:0 5px}._r3:first-child:before{content:\"\";margin:0}._gec,._gec span{color:#7d7d7d;font-size:13px}.irc_sbc{display:inline-block}._ZR{text-decoration:none}.irc_hol{-webkit-tap-highlight-color:rgba(255,255,255,0.2)}#gsr a._ZR:active,._ZR:hover,._ZR:hover span{color:#d6d6d6;text-decoration:underline}.irc_fd{bottom:50%;background:rgba(51,51,51,.8);color:#fff;font-size:11px;line-height:100%;padding:3px 4px 5px;position:absolute;right:50%;text-decoration:none}.irc_but_dis{visibility:hidden}.irc_tdi{display:inline-block;margin-right:2px;margin-top:2px;overflow:hidden;vertical-align:top}.irc_tai{cursor:pointer;display:inline-block;overflow:hidden;position:relative;vertical-align:top;margin:8px 8px 2px 3px}.irc_tai:hover{outline:1px solid #ddd;outline-offset:1px}.irc_tai:active{outline:1px solid #fff}.irc_tai img{position:relative}.irc_rit{opacity:1;-webkit-transition:opacity .2s;transition:opacity .2s;}.irc_rimask{background-color:white}.irc_rih{color:#9f9f9f;font-size:13px}.irc_rist{cursor:default;outline:2px solid #bbb;outline-offset:1px}.irc_rist:hover{outline:2px solid #bbb;outline-offset:1px}.irc_rist img{opacity:.8}.irc_rismo{background-color:#000}.irc_rismo img{opacity:0.5}.irc_rismo span{color:#ddd;font-size:medium;left:10px;position:absolute;right:10px;text-align:center;text-shadow:0 0 .5em #000;top:22px;vertical-align:middle}.irc_rismo:hover img{opacity:0.6}.irc_rismo:hover span{color:#fff}.irc_rismol{display:none}.irc_por .irc_infosep{margin:20px 20px}.irc_por .irc_sep{background:#121212;box-shadow:0 1px #2A2A2A;display:block;height:1px;}.irc_bg{height:100%;left:0;overflow:hidden;width:100%;z-index:1001;position:fixed;top:0;}._KUc{position:fixed;width:100%;z-index:1001}#irc_bgl{background:#222;height:100%;position:absolute;top:0;width:100%}#irc_cc{display:inline-block;height:100%;position:relative;z-index:1}#_YTc{height:100%;overflow:hidden;position:relative}#irc_cb{cursor:pointer;padding:7px;position:absolute;right:10px;top:10px;z-index:2;height:30px;width:30px;background:url(data:image/gif;base64,R0lGODlhFAAUAJEAAE1NTf///////wAAACH5BAEHAAIALAAAAAAUABQAAAIzBISpK+YMm5Enpodw1HlCfnkKOIqU1VXk55goVb2hi7Y0q95lfG70uurNaqLgTviyyUoFADs=) no-repeat center center}.irc_hcb #irc_cb{display:none}#irc_cb:hover{opacity:.5}.irc_por .irc_ft{margin-top:20px}a.irc_fdbk{color:#7d7d7d;text-decoration:none}#irc_cc a.irc_fdbk:active{color:#d6d6d6}a.irc_fdbk:hover{color:#d6d6d6;text-decoration:underline}body{background:#222}.rg_meta{display:none}.g,body,html,.std,.c h2,h1{font:small arial,sans-serif}</style><style>.irc_land{}.irc_t{line-height:0;min-width:324px;position:relative;text-align:center;vertical-align:middle;width:66%}.irc_land .irc_t{display:inline-block}.irc_mutc,.irc_sscd{padding-top:20px}.irc_mutl{outline:0}.irc_mut{-webkit-box-shadow:0 5px 35px rgba(0,0,0,.65);box-shadow:0 5px 35px rgba(0,0,0,.65)}._Epb{-webkit-tap-highlight-color:rgba(255,255,255,0.2);text-decoration:none}.irc_pt:hover,._ZAd:hover{text-decoration:underline;color:#fff}.irc_b{min-width:425px;vertical-align:middle}.irc_land .irc_b{display:inline-block;width:33%}._Fcb{display:block;overflow:hidden;text-overflow:ellipsis}.irc_pt,._Hcb{color:#d6d6d6;font-size:22px}.irc_pt,._Hcb{white-space:nowrap}.irc_b>div{margin-left:20px;margin-right:20px}.irc_ho{color:#7d7d7d;margin-right:-2px;overflow:hidden;padding-right:2px;text-overflow:ellipsis;}.irc_hd{line-height:16px;font-size:13px;margin-top:-3px;margin-left:-3px;padding:3px 0 16px 3px}.irc_asc,.irc_asc a,.irc_asc a span{color:#888;overflow:hidden;padding-top:6px;text-overflow:ellipsis;white-space:normal}.irc_but{background-color:#454545;background-image:-webkit-gradient(linear,50% 0%,50% 100%,color-stop(0,#3e3e3e),color-stop(1,#333));background-image:-webkit-linear-gradient(top,#3e3e3e,#333);background-image:linear-gradient(top,#3e3e3e,#333);border:1px solid #141414;-webkit-border-radius:2px;border-radius:2px;-webkit-box-shadow:0 1px 0 rgba(255,255,255,.06),1px 1px 0 rgba(255,255,255,.03),-1px -1px 0 rgba(0,0,0,.02),inset 1px 1px 0 rgba(255,255,255,.05);box-shadow:0 1px 0 rgba(255,255,255,.06),1px 1px 0 rgba(255,255,255,.03),-1px -1px 0 rgba(0,0,0,.02),inset 1px 1px 0 rgba(255,255,255,.05);color:#aaa !important;cursor:pointer !important;display:inline-block;filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#303030',EndColorStr='#262626');font-size:11px;font-weight:bold;margin:0 5px;outline:0;text-align:center;text-decoration:none !important;text-shadow:0 -1px 0 rgba(0,0,0,.5);-webkit-user-select:none;user-select:none vertical-align:middle;white-space:normal;word-wrap:normal}.irc_but:active{border-color:#3d3d3d;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.3);box-shadow:inset 0 1px 2px rgba(0,0,0,.3)}.irc_but:hover{background-color:#3d3d3d;background-image:-webkit-gradient(linear,50% 0%,50% 100%,color-stop(0,#4e4e4e),color-stop(1,#474747));background-image:-webkit-linear-gradient(top,#4e4e4e,#474747);background-image:linear-gradient(top,#4e4e4e,#474747);border:1px solid #191919;-webkit-box-shadow:0 1px 0 rgba(255,255,255,.09),1px 1px 0 rgba(255,255,255,.05),-1px -1px 0 rgba(0,0,0,.02),inset 1px 1px 0 rgba(255,255,255,.05);box-shadow:0 1px 0 rgba(255,255,255,.09),1px 1px 0 rgba(255,255,255,.05),-1px -1px 0 rgba(0,0,0,.02),inset 1px 1px 0 rgba(255,255,255,.05);color:#bbb !important}.irc_but:focus{border-color:#414141;-webkit-box-shadow:0 1px 4px rgba(0,0,0,.6);box-shadow:0 1px 4px rgba(0,0,0,.6);color:#cfcfcf !important}._Ccb{border-spacing:0}._Ccb td{height:31px;padding:0}td:last-of-type .irc_but{margin:0}.irc_but_t{display:table-cell;padding:5px 0;vertical-align:middle}.irc_b .irc_but{display:inline-table;height:100%;margin:0;margin-right:10px;padding:0 8px}.irc_ris{margin-top:16px;width:364px;overflow:hidden}.irc_ris{height:198px}.irc_land .irc_infosep{border-bottom:1px solid #121212;box-shadow:0 1px #2A2A2A;margin:20px 9px}.irc_land .irc_sep{background:#121212;box-shadow: 1px 0 #2a2a2a;display:inline-block;margin:20px 0;vertical-align:middle;width:1px}.irc_c{display:inline-block;min-width:750px;position:absolute;vertical-align:top}.irc_por .irc_c{overflow-x:hidden}.irc_ft{bottom:10px;color:#666;font-size:11px;position:absolute}.irc_land .irc_ft{bottom:20px}</style><div class=\"_KUc irc_bg\" id=\"irc_bg\" style=\"display:none\"><div id=\"_YTc\"><a href=\"javascript:void(0)\" id=\"irc_cb\"></a><div id=\"irc_cc\"><div style=\"display:none\" class=\"irc_c\" jsaction=\"irc.cc\" data-ved=\"0CAwQ-z8\"><div class=\"irc_t\"><div class=\"irc_rric\"><div class=\"irc_pgb jfk-progressBar-blocking\"><div class=\"progress-bar-thumb\"></div></div><div class=\"irc_mic\"><div class=\"irc_pb\"><a class=\"irc_pbl\" jsaction=\"mousedown:irc.rl;keydown:irc.rlk\"><span class=\"irc_pbi\"></span></a></div><iframe src=\"/blank.html\" class=\"irc_ifr irc_mimg\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" scrolling=\"no\"></iframe><div class=\"irc_mutc\"><a class=\"irc_mutl\" jsaction=\"mousedown:irc.rl;keydown:irc.rlk\"><img class=\"irc_mut\"></a></div></div><div class=\"irc_fd\" style=\"display:none\"></div></div></div><div class=\"irc_sep\"></div><div class=\"irc_b\"><div><div class=\"_LAd\"><span class=\"_Hcb _Fcb\"><span class=\"irc_pdft\">[PDF] </span><a class=\"_Epb irc_tas\" jsaction=\"mousedown:irc.rl;keydown:irc.rlk\"><span class=\"irc_pt\"></span></a></span><div class=\"irc_hd\"><span class=\"_r3\"><a class=\"_ZR irc_hol\" jsaction=\"mousedown:irc.rl;keydown:irc.rlk\"><span class=\"irc_ho\"></span></a></span><span class=\"_r3 irc_msc\"><a class=\"_ZR irc_msl\" data-i=\"1\" jsaction=\"mousedown:irc.rl;keydown:irc.rlk\"><span class=\"irc_idim\"></span></a></span><span class=\"_r3 irc_sbc\"><a class=\"_ZR irc_sbl\" data-i=\"1\" jsaction=\"mousedown:irc.rl;keydown:irc.rlk\"><span>Search by image</span></a></span><div class=\"irc_asc\" style=\"display:none\"><span class=\"irc_su\"></span></div></div></div><div class=\"irc_butc\"><table class=\"_Ccb irc_but_r\" summary=\"\"><tr><td><a class=\"irc_vpl irc_but\" jsaction=\"mousedown:irc.rl;keydown:irc.rlk\"><span class=\"irc_but_t\">Visit page</span></a></td><td><a class=\"irc_fsl irc_but\" jsaction=\"mousedown:irc.rl;keydown:irc.rlk\"><span class=\"irc_but_t\">View image</span></a></td></tr></table><table class=\"_Ccb irc_but_pdfr\" summary=\"\"><tr><td><a class=\"irc_pdfl irc_but\" jsaction=\"mousedown:irc.rl;keydown:irc.rlk\"><span class=\"irc_but_t\">View PDF</span></a></td></tr></table></div><div class=\"irc_infosep\"></div><div class=\"irc_ris\"><div class=\"irc_rih\">Related images:</div><div class=\"irc_rit\" jsaction=\"irc.hric\"></div><span class=\"irc_risml\">View more</span></div></div></div><div class=\"irc_ft\"><span>Images may be subject to copyright.</span><span class=\"_r3\"><a href=\"javascript:void(0)\" class=\"irc_fdbk\" data-bucket=\"images\" jsaction=\"gf.sf\">Send feedback</a></span></div></div></div><div id=\"irc_bgl\"></div></div></div></div></body><div id=md class=rg_meta>{\"fn\":\"showimage.aspx\",\"id\":\"Neb7NEW2XN7WuM:\",\"is\":\"432\\u0026nbsp;\\u0026#215;\\u0026nbsp;394\",\"isu\":\"fresnocitycollege.edu\",\"ity\":\"aspx\",\"md\":\"/search?tbs=sbi:AMhZZiuGjQs9_16r-h07ZZTWkDSCBBwdzKZ7BBotTK38XxT2WBkSq2ufUZ01NJroxVEk3D2f5wglxcynRqi_16_1gTUqxw2s6V3zgr_1iqhp1sAEoxHWsoI_16IottSVeKBcWZu1DMfAd-4qfNALyX5lulozgRJ81YK-ybK6bLtMRo-3AA6745tKAb8f0XNNmn91OI6Vui5KFtofk1XziZf36NVJFSN5KJ1kas8_1fq8jFp0aW4eZiA2lT4x_1Jyw_1QGWg5RFbg9ygHhGpSPgxtWlF4z_1FHxmA_1n6E2z1fkF7dXRS9Wiltze4-2dXxk41D2EV4WVP9zuPbFm6pc\\u0026ei=4J7yVNyDA9ChoQSt_4KYCw\",\"msu\":\"/search?imgurl=http://www.fresnocitycollege.edu/modules/showimage.aspx%253Fimageid%253D463\\u0026imgrefurl=http://www.fresnocitycollege.edu/index.aspx%3Fpage%3D94\\u0026h=394\\u0026w=432\\u0026tbm=isch\\u0026tbs=simg:CAQSpwEJNeb7NEW2XN4akgELELCMpwgaiAEKOggCEhTaJIIg3CTyIt0kyyeIJPEalRSPFBogkZSJlTe4OjUFo6XfGkMc0l7YGbI3Gw0ltiqxv9nCP5EKSggDEhTZFNgU2xTeFN8U3BTXFPoU3RTgFBowDg9MQjQeH0jXwjtpC2NbwSqoPoPEkJXbL3Ill-_1wpVKO0aGje3yI7pB4AL9rKNhjDCFMFQNgWdyLfg\",\"oh\":394,\"os\":\"82KB\",\"ou\":\"http://www.fresnocitycollege.edu/modules/showimage.aspx?imageid=463\",\"ow\":432,\"pt\":\"Fresno City College : Social Sciences Division\",\"s\":\"Social Science Building\",\"si\":\"/search?imgurl=http://www.fresnocitycollege.edu/modules/showimage.aspx%253Fimageid%253D463\\u0026imgrefurl=http://www.fresnocitycollege.edu/index.aspx%3Fpage%3D94\\u0026h=394\\u0026w=432\\u0026tbm=isch\\u0026tbs=simg:CAESpwEJNeb7NEW2XN4akgELELCMpwgaiAEKOggCEhTaJIIg3CTyIt0kyyeIJPEalRSPFBogkZSJlTe4OjUFo6XfGkMc0l7YGbI3Gw0ltiqxv9nCP5EKSggDEhTZFNgU2xTeFN8U3BTXFPoU3RTgFBowDg9MQjQeH0jXwjtpC2NbwSqoPoPEkJXbL3Ill-_1wpVKO0aGje3yI7pB4AL9rKNhjDCFMFQNgWdyLfg\",\"th\":214,\"tu\":\"http://t3.gstatic.com/images?q=tbn:ANd9GcSkg2IF4dgWVsnXLGwTVauaXroIEZ8UiIQDd3yH3Hch2VAepo7FWg\",\"tw\":235}</div><div id=\"xjsd\"></div><div id=\"xjsi\" data-jiis=\"bp\"><script>(function(){function c(b){window.setTimeout(function(){var a=document.createElement(\"script\");a.src=b;document.getElementById(\"xjsd\").appendChild(a)},0)}google.dljp=function(b,a){google.xjsu=b;c(a)};google.dlj=c;})();(function(){window.google.xjsrm=[];})();if(google.y)google.y.first=[];if(!google.xjs){window._=window._||{};window._._DumpException=function(e){throw e};if(google.timers&&google.timers.load.t){google.timers.load.t.xjsls=new Date().getTime();}google.dljp('/xjs/_/js/k\\x3dxjs.il.en_US.I0qys4Iuq3c.O/m\\x3dcdos,ircl,jsa,d,csi/am\\x3dEJMB/rt\\x3dj/d\\x3d1/t\\x3dzcms/rs\\x3dACT90oFX7cbGBtlIhx1OTc5YiZCI_tB-9w','/xjs/_/js/k\\x3dxjs.il.en_US.I0qys4Iuq3c.O/m\\x3dcdos,ircl,jsa,d,csi/am\\x3dEJMB/rt\\x3dj/d\\x3d1/t\\x3dzcms/rs\\x3dACT90oFX7cbGBtlIhx1OTc5YiZCI_tB-9w');google.xjs=1;}google.pmc={\"cdos\":{\"bih\":705,\"biw\":1280,\"dpr\":\"1\"},\"gf\":{\"pid\":196,\"si\":true},\"ircl\":{\"rcc\":[\"AFQjCNHzYUeeU0o1hvHrjEILrmZ1JAjriw\\u0026ust=1425273279616369\",0,0,null,0,1,null,null,0,1,null,null,1,1,0,0,0,1,1,null,120,null,null,null,0,0,0,0,0,null,0,null,0,0,0,0,0,0,0,1,0.9,400,null,9,0,1,0,0,null,0,0]},\"jsa\":{},\"d\":{},\"csi\":{\"acsi\":true},\"10Kacw\":{},\"/1S6iw\":{},\"NpA8BQ\":{}};google.y.first.push(function(){if(google.med){google.med('init');google.initHistory();google.med('history');}});if(google.j&&google.j.en&&google.j.xi){window.setTimeout(google.j.xi,0);}\n</script></div></body><script></script></html>"
  },
  {
    "path": "27_code-in-process/99_svcc/32_static-FileServer/assets/stylesheets/main.css",
    "content": "/* http://meyerweb.com/eric/tools/css/reset/\n   v2.0 | 20110126\n   License: none (public domain)\n*/\nhtml, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header, hgroup,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n    margin: 0;\n    padding: 0;\n    border: 0;\n    font-size: 100%;\n    font: inherit;\n    vertical-align: baseline;\n}\n\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, hgroup, menu, nav, section {\n    display: block;\n}\nbody {\n    line-height: 1;\n}\nol, ul {\n    list-style: none;\n}\nblockquote, q {\n    quotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n    content: '';\n    content: none;\n}\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}\n\n/*\n=================================================\nCustom Styles\n=================================================\n*/\n\nbody {\n    background: #C0953D;\n    color: #888;\n    font: 300 16px/22px \"Lato\", \"Open Sana\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n}\n\n/*\n=================================================\nGrid\n=================================================\n*/\n\n*,\n*:before,\n*:after {\n    -webkit-box-sizing: border-box;\n    -moz-box-sizing: border-box;\n    box-sizing: border-box;\n}\n\n.container {\n    margin: 0 auto;\n    padding-left: 30px;\n    padding-right: 30px;\n    width:960px;\n}\n\n/*\n=================================================\nTypography\n=================================================\n*/\n\nh1, h3, h4, h5, p {\n    margin-bottom: 22px;\n}\n\nh1, h2, h3, h4 {\n    color: #20425D;\n}\n\nh1 {\n    font-size: 36px;\n    line-height: 44px;\n}\n\nh2 {\n    font-size: 24px;\n    line-height: 44px;\n}\n\nh3 {\n    font-size: 21px;\n}\n\nh4 {\n    font-size: 18px;\n}\n\nh5 {\n    color: #575652;\n    font-size: 14px;\n    font-weight: 400;\n    text-transform: uppercase;\n}\n\nstrong {\n    font-weight: 400;\n}\n\ncite,\nem {\n    font-style: italic;\n}\n\n/*\n==================================================\nLeads\n==================================================\n*/\n\n.lead {\n    text-align: center;\n}\n\n.lead p {\n    font-size: 21px;\n    line-height: 33px;\n}\n\n\n/*\n==================================================\nLinks\n==================================================\n*/\n\na {\n    color: #20425D;\n    text-decoration: none;\n}\n\na:hover {\n    color: #a9b2b9;\n}\n\np a {\n    border-bottom: 1px solid #dfe2e5;\n}\n\n.teaser a:hover h3 {\n    color: #a9b2b9;\n}\n\n.primary-header a,\n.primary-footer a {\n    color: #fff;\n}\n\n.primary-header a:hover,\n.primary-footer a:hover {\n    color:#20425D;\n}\n\n/*\n==================================================\nButtons\n==================================================\n*/\n\n.btn{\n    border-radius: 5px;\n    color: #fff;\n    cursor: pointer;\n    display: inline-block;\n    font-weight: 400;\n    margin: 0;\n    text-transform: uppercase;\n}\n\n.btn-alt {\n    border: 1px solid #fff;\n    padding: 20px 30px;\n}\n\n.btn-alt:hover {\n    background: #fff;\n    color: #F55837;\n}\n\n.btn-default {\n    border: 0;\n    background: 5D#2042;\n    padding: 11px 30px;\n    font-size: 14px;\n}\n.btn-default:hover {\n    background: #F55837;\n}\n\na.btn {\n    width: 300px;\n    border-radius: 5px;\n    background-color: lightgray;\n    text-transform: uppercase;\n    color: #20425D;\n    padding: 11px 30px;\n    margin-bottom: 1em;\n}\n\na.btn:hover {\n    color:#F55837;\n    background-color: lightgray;\n}\n\n/*\n===================================================\nHome\n===================================================\n*/\n\n.hero {\n    color: #fff;\n    line-height: 44px;\n    padding: 22px 80px 66px 80px;\n    text-align: center;\n}\n\n.hero h2 {\n    font-size: 36px;\n}\n.hero p {\n    font-size: 24px;\n    font-weight: 100;\n }\n\n.teaser img {\n    border-radius: 5px;\n    display: block;\n    margin-bottom: 22px;\n    max-width: 100%;\n}\n\n/*\n===================================================\nClearfix\n===================================================\n*/\n\n.group:before,\n.group:after {\n    content: \"\";\n    display: table;\n}\n\n.group:after {\n    clear: both;\n    *zoom: 1;\n}\n\n.group {\n    clear: both;\n    *zoom: 1;\n}\n\n/*\n===================================================\nRows\n===================================================\n*/\n\n.row,\n.row-alt {\n    min-width: 960px;\n}\n\n.row {\n    background: #fff;\n    padding: 66px 0 44px 0;\n}\n\n.row-alt {\n    background: #cbe2c1;\n    background: -webkit-linear-gradient(to right, #D2D0D1, #f6f1d3);\n    background: -moz-linear-gradient(to right, #D2D0D1, #f6f1d3);\n    background: linear-gradient(to right, #D2D0D1, #f6f1d3);\n    padding: 44px 0 22px 0;\n}\n\n\n/*\n===================================================\nPrimary Header\n===================================================\n*/\n\n.logo {\n    border-top: 4px solid #20425D;\n    float:left;\n    font-size: 48px;\n    font-weight: 100;\n    letter-spacing: .5px;\n    line-height: 44px;\n    padding: 40px 0 22px 0;\n    text-transform: uppercase;\n\n}\n\n.tagline {\n    margin: 66px 0 22px 0;\n    text-align: right;\n}\n\n.primary-nav {\n    font-size: 14px;\n    font-weight: 400;\n    letter-spacing: .5px;\n    text-transform: uppercase;\n}\n\n/*\n===================================================\nPrimary Footer\n===================================================\n*/\n\n.primary-footer small {\n    float: left;\n    font-weight: 400;\n}\n\n.primary-footer {\n    color: #20425D;\n    font-size: 14px;\n    padding-bottom: 44px;\n    padding-top: 44px;\n}\n\na.shay {\n    color:darkgrey;\n}\n\na:hover.shay {\n    color:#20425D;\n}\n\na.shay_light {\n    color:#ffffff;\n}\n\n\n/*\n===================================================\nReusable Layout\n===================================================\n*/\n\n.col-1-3 {\n    width: 33.33%;\n}\n\n.col-2-3 {\n    width: 66.66%;\n}\n\n.col-1-3,\n.col-2-3 {\n    display: inline-block;\n    vertical-align: top;\n}\n\n.grid,\n.col-2-3,\n.col-1-3 {\n    padding-left: 15px;\n    padding-right: 15px;\n}\n\n.container,\n.grid {\n    margin: 0 auto;\n    width: 960px;\n}\n\n.container {\n    padding-left: 30px;\n    padding-right: 30px;\n}\n\n/*\n===================================================\nNavigation\n===================================================\n*/\n\n.nav {\n    text-align: right;\n}\n\n.nav li {\n    display: inline-block;\n    margin: 0 10px;\n    vertical-align: top;\n}\n\n.nav li:last-child {\n    margin-right: 0;\n}\n\n\n/*\n===================================================\nSpeakers\n===================================================\n*/\n\n.speaker-info {\n    border: 1px solid #dfe2e5;\n    border-radius: 5px;\n    margin-top: 88px;\n    padding-bottom: 22px;\n    text-align: center;\n}\n\n.speaker {\n    margin-bottom: 44px;\n}\n\n.speaker-info img {\n    border-radius: 50%;\n    height: 130px;\n    margin: -66px 0 22px 0;\n    vertical-align: top;\n}\n\n/*\n  ========================================\n  Schedule\n  ========================================\n*/\n\ntable {\n    margin-bottom: 44px;\n    width: 100%;\n}\ntable:last-child {\n    margin-bottom: 0;\n}\n\nth,\ntd {\n    padding-bottom: 22px;\n    vertical-align: top;\n}\nth {\n    padding-right: 45px;\n    text-align: right;\n    width: 20%;\n}\ntd {\n    width: 40%;\n}\n\nthead {\n    line-height: 44px;\n}\nthead th {\n    color: #20425D;\n    font-size: 24px;\n}\ntbody th {\n    color: #a9b2b9;\n    font-size: 14px;\n    font-weight: 400;\n    padding-top: 22px;\n    text-transform: uppercase;\n}\n\ntbody td {\n    border-top: 1px solid #dfe2e5;\n    padding-top: 21px;\n}\ntbody td:first-of-type {\n    padding-right: 15px;\n}\ntbody td:last-of-type {\n    padding-left: 15px;\n}\ntbody td:only-of-type {\n    padding-left: 0;\n    padding-right: 0;\n}\n\ntable a {\n    color: #888;\n}\ntable h4 {\n    margin-bottom: 0;\n}\n\n.schedule-offset {\n    color: #a9b2b9;\n}\n\n/*\n  ========================================\n  Venue\n  ========================================\n*/\n\n.venue-theatre {\n    margin-bottom: 66px;\n}\n.venue-hotel {\n    margin-bottom: 22px;\n}\n\n.venue-map {\n    height: 264px;\n}\n\n/*\n  ========================================\n  Register\n  ========================================\n*/\n\n.why-attend {\n    list-style: square;\n    margin: 0 0 22px 30px;\n}\n\nform {\n    margin-bottom: 22px;\n}\ninput,\nselect,\ntextarea {\n    font: 300 16px/22px \"Lato\", \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n}\n\n.register-group label {\n    color: #20425D;\n    cursor: pointer;\n    font-weight: 400;\n}\n.register-group input,\n.register-group select,\n.register-group textarea {\n    border: 1px solid #c6c9cc;\n    border-radius: 5px;\n    color: #888;\n    display: block;\n    margin: 5px 0 27px 0;\n    padding: 5px 8px;\n}\n.register-group input,\n.register-group textarea {\n    width: 100%;\n}\n.register-group select {\n    height: 34px;\n    width: 60px;\n}\n.register-group textarea {\n    height: 78px;\n}\n\naside ul {\n    margin-top: 2.5em;\n}\n\n.register {\n    width: 500px;\n    margin: auto;\n}\n\n.flex {\n    display: flex;\n    flex-flow: row wrap;\n    justify-content: space-around;\n}\n\n\n\n"
  },
  {
    "path": "27_code-in-process/99_svcc/32_static-FileServer/button.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <meta charset=\"UTF-8\">\n    <title>My Button</title>\n</head>\n\n<style>\n\n    html, body, div, span, applet, object, iframe,\n    h1, h2, h3, h4, h5, h6, p, blockquote, pre,\n    a, abbr, acronym, address, big, cite, code,\n    del, dfn, em, img, ins, kbd, q, s, samp,\n    small, strike, strong, sub, sup, tt, var,\n    b, u, i, center,\n    dl, dt, dd, ol, ul, li,\n    fieldset, form, label, legend,\n    table, caption, tbody, tfoot, thead, tr, th, td,\n    article, aside, canvas, details, embed,\n    figure, figcaption, footer, header, hgroup,\n    menu, nav, output, ruby, section, summary,\n    time, mark, audio, video {\n        margin: 0;\n        padding: 0;\n        border: 0;\n        font-size: 100%;\n        font: inherit;\n        vertical-align: baseline;\n    }\n    body {\n        line-height: 22px;\n        font-family: \"Helvetica Neue\", Arial, Helvetica, sans-serif;\n    }\n\n    .btn {\n        width: 100px;\n        height: 100px;\n        /*padding: .5em;*/\n        background-color: darkslategray;\n        color: whitesmoke;\n        border:1px solid lightgray ;\n        height:22px;\n        /*line-height: 22px;*/\n        margin: auto;\n        border-radius: 5px;\n        /*text-align: center;*/\n\n    }\n\n    .btn:hover {\n\n        background-color: lightgray;\n        color:darkcyan;\n    }\n\n</style>\n<body>\n<button class=\"btn\">My Button</button>\n\n</body>\n</html>\n\n"
  },
  {
    "path": "27_code-in-process/99_svcc/32_static-FileServer/floats_in_practice.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <meta charset=\"UTF-8\">\n    <title>Floats in Practice</title>\n    <style>\n        header, section, aside, footer {\n            background-color: lightgray;\n            color: #666666;\n\n        }\n\n        .group:before,\n        .group:after {\n            content: \"\";\n            display: table;\n        }\n\n        .group:after {\n            clear: both;\n        }\n\n        .group {\n            clear: both;\n            *zoom: 1;\n        }\n\n        section {\n           float: left;\n            margin: 0 1.5%;\n            width: 63%;\n        }\n\n        aside {\n            float: right;\n            margin: 0 21.5%;\n            width: 30%;\n        }\n\n    </style>\n</head>\n\n<body>\n    <header>&lt;Header&gt;</header>\n    <div class=\"group\">\n    <section>&lt;Section&gt;</section>\n    <aside>&lt;Section&gt;</aside>\n    </div>\n    <footer>&lt;Footer&gt;</footer>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/99_svcc/32_static-FileServer/index.html",
    "content": "\n<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"utf-8\">\n    <title>Summer Web Development Bootcamp</title>\n    <link rel=\"stylesheet\" href=\"assets/stylesheets/main.css\">\n    <link rel=\"stylesheet\" href=\"http://fonts.googleapis.com/css?family=Lato:100,300,400\">\n    <meta name=\"description\" content=\"Summer 2015 Web Development Bootcamp\">\n    <meta name=\"keywords\" content=\"Web programming, web development, web bootcamp\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <link rel=\"shortcut icon\" href=\"assets/images/favicon.ico\">\n</head>\n\n<body>\n\n<!-- Header -->\n\n<header class=\"primary-header container group\">\n\n    <h1 class=\"logo\">\n        <a href=\"index.html\">Summer <br> Bootcamp</a>\n    </h1>\n\n    <h3 class=\"tagline\">May 25th &ndash;July 31st &mdash; Fresno, CA</h3>\n\n    <nav class=\"nav primary-nav\">\n        <ul>\n            <li><a href=\"index.html\">Home</a></li><!--\n          --><li><a href=\"speakers.html\">Speakers</a></li><!--\n          --><li><a href=\"schedule.html\">Schedule</a></li><!--\n          --><li><a href=\"venue.html\">Venue</a></li><!--\n          --><li><a href=\"register.html\">Register</a></li><!--\n          --><li><a href=\"sponsors.html\">Sponsors</a></li>\n        </ul>\n    </nav>\n\n</header>\n\n<!-- Hero -->\n\n<section class=\"hero container\">\n\n    <h2>Free Web Development Bootcamp</h2>\n\n    <p>Grow your knowledge in the latest Web Technologies. Join us, this\n        summer 2015, for the first ever Web Development Bootcamp\n        hosted at Fresno City College.</p>\n\n    <a class=\"btn btn-alt\" href=\"register.html\">Register Now</a>\n\n</section>\n\n<!-- Teasers -->\n\n<section class=\"row\">\n    <div class=\"grid\">\n\n        <!-- Speakers -->\n\n        <section class=\"teaser col-1-3\">\n            <h5>Speakers</h5>\n            <a href=\"speakers.html\">\n               <img src=\"assets/images/home/ray_villalobos.jpg\"\n                    alt=\"Professional Speaker\">\n               <h3>World-Class Trainers</h3>\n            </a>\n            <p>With five talented trainers, who are experts in their field,\n                you will learn some of the most in&ndash;demand skills in\n                the job market today.</p>\n        </section><!--\n\n        Schedule\n\n        --><section class=\"teaser col-1-3\">\n            <h5>Schedule</h5>\n            <a href=\"schedule.html\">\n               <img src=\"assets/images/home/dev_fest2.jpeg\" alt=\"schedule\">\n               <h3>50 Inspiring Days</h3>\n        </a>\n        <p>Fifty inspiring and action-packed days of\n            talks,\n            gatherings, learning and fun.</p>\n    </section><!--\n\n        Venue\n\n        --><section class=\"teaser col-1-3\">\n            <h5>Venue</h5>\n            <a href=\"venue.html\">\n               <img src=\"assets/images/home/library.jpeg\" alt=\"venue\">\n               <h3>Fresno City College</h3>\n        </a>\n        <p>The historical campus of Fresno City College will provide the perfect\n            conference venue.</p>\n    </section>\n\n    </div>\n</section>\n\n<!-- Footer -->\n\n<footer class=\"primary-footer container group\">\n\n    <small>&copy; Special thanks to <a href=\"http://learn.shayhowe.com/html-css/\" class=\"shay_light\"> Shay Howe </a>for the use of this template.</small>\n\n    <nav class=\"nav\">\n        <ul>\n            <li><a href=\"index.html\">Home</a></li><!--\n          --><li><a href=\"speakers.html\">Speakers</a></li><!--\n          --><li><a href=\"schedule.html\">Schedule</a></li><!--\n          --><li><a href=\"venue.html\">Venue</a></li><!--\n          --><li><a href=\"register.html\">Register</a></li>\n        </ul>\n    </nav>\n\n</footer>\n<div class=\"flex\">\n    <a href=\"http://doingwhatmatters.cccco.edu/\" target=\"_blank\"><img src=\"assets/images/DWM.png\" alt=\"logo of doing what matters for jobs and the economy\"></a>\n</div>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/99_svcc/32_static-FileServer/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n)\n\nfunc main() {\n\thttp.ListenAndServe(\":9000\", http.FileServer(http.Dir(\".\")))\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/32_static-FileServer/register.html",
    "content": "\n<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"utf-8\">\n    <title>Register - Styles Conference</title>\n    <link rel=\"stylesheet\" href=\"assets/stylesheets/main.css\">\n    <link rel=\"stylesheet\" href=\"http://fonts.googleapis.com/css?family=Lato:100,300,400\">\n    <meta name=\"description\" content=\"Summer 2015 Web Development Bootcamp\">\n    <meta name=\"keywords\" content=\"Web programming, web development, web bootcamp\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <link rel=\"shortcut icon\" href=\"assets/images/favicon.ico\">\n</head>\n\n<body>\n\n<!-- Header -->\n\n<header class=\"primary-header container group\">\n\n    <h1 class=\"logo\">\n        <a href=\"index.html\">Summer <br> Bootcamp</a>\n    </h1>\n\n    <h3 class=\"tagline\">May 25th &ndash;July 31st &mdash; Fresno, CA</h3>\n\n    <nav class=\"nav primary-nav\">\n        <ul>\n            <li><a href=\"index.html\">Home</a></li><!--\n          --><li><a href=\"speakers.html\">Speakers</a></li><!--\n          --><li><a href=\"schedule.html\">Schedule</a></li><!--\n          --><li><a href=\"venue.html\">Venue</a></li><!--\n          --><li><a href=\"register.html\">Register</a></li><!--\n          --><li><a href=\"sponsors.html\">Sponsors</a></li>\n        </ul>\n    </nav>\n\n</header>\n\n<!-- Lead -->\n\n<section class=\"row-alt\">\n    <div class=\"lead container\">\n\n        <h1>Register</h1>\n\n        <p>Thanks to our <a href=\"sponsors.html\">sponsors</a> we are able to offer\n            this exceptional opportunity absolutely free.\n            <br>\n            Please use the links below to register for the workshops you are\n            interested in attending.</p>\n\n    </div>\n</section>\n\n<section class=\"row\">\n    <div class=\"grid\">\n\n        <section class=\"col-2-3\">\n            <h2>REGISTRATION</h2>\n            <h5>Register for as many workshops as you are able to attend</h5>\n\n            <!--<p>There are 100 seats available for each workshop. If you are within the first 100 to register, you automatically have a seat. If you are after the first 100, you will be placed on the waitlist.</p>-->\n\n            <p>Please make sure to read the <a href=\"schedule.html#html5css3\">requirements and prerequisites</a> for each workshop.</p>\n\n            <p>You may attend this workshop if you are a teacher or are planning on becoming a teacher.\n                Current and future teachers, current and future substitute teachers, and\n                current and future adjunct faculty are all welcome.\n                The price: FREE!\n            </p>\n\n            <h4>Why Attend?</h4>\n\n            <ul class=\"why-attend\">\n                <li>Passionate and knowledgeable trainers, who are current in their field.</li>\n                <li>50 inspiring days of learning</li>\n                <li>Opportunity to network and mix with like&ndash;minded\n                    people in the field of Technology and Web Development</li>\n                <li>There could not be a better price point &ndash; FREE!</li>\n            </ul>\n        </section><!--\n\n    --><aside class=\"col-1-3\">\n        <ul>\n            <li><a class=\"btn\" btn-default href=\"https://docs.google.com/forms/d/1ME_vyqzJ4H_zmfgsklpJxM0GQyRF2YWPdoMdVQinWvc/viewform\" target=\"_blank\">HTML and CSS</a></li>\n            <li><a class=\"btn\" btn-default href=\"https://docs.google.com/forms/d/1il8rZj7eU5gk0ZzGKZBgQf371EjDwwIPBmeAE5AuKSs/viewform\" target=\"_blank\">Javascript</a></li>\n            <li><a class=\"btn\" btn-default href=\"https://docs.google.com/forms/d/1y_FM9u6imqzTe-BqiRFkcGHZ9Lp4XWfEFG9nnvdYJBE/viewform\" target=\"_blank\">Web Components</a></li>\n            <li><a class=\"btn\" btn-default href=\"https://docs.google.com/forms/d/1GOCcAR_b4bgFevWWziTHSof-gs3bZIwbmZ6gpsbVRR8/viewform\" target=\"_blank\">Polymer</a></li>\n            <li><a class=\"btn\" btn-default href=\"https://docs.google.com/forms/d/1flCighm9Wzw853_ZsWLgw2xuNFiEvvxSzzYgcXUvOKw/viewform\" target=\"_blank\">Go\n                Language and More</a></li>\n        </ul>\n    </aside>\n\n    </div>\n</section>\n\n<!-- Footer -->\n\n<footer class=\"primary-footer container group\">\n\n    <small>&copy; Special thanks to <a href=\"http://learn.shayhowe.com/html-css/\" class=\"shay_light\"> Shay Howe </a>for the use of this template.</small>\n\n    <nav class=\"nav\">\n        <ul>\n            <li><a href=\"index.html\">Home</a></li><!--\n          --><li><a href=\"speakers.html\">Speakers</a></li><!--\n          --><li><a href=\"schedule.html\">Schedule</a></li><!--\n          --><li><a href=\"venue.html\">Venue</a></li><!--\n          --><li><a href=\"register.html\">Register</a></li>\n        </ul>\n    </nav>\n\n</footer>\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/99_svcc/32_static-FileServer/schedule.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"utf-8\">\n    <title>Schedule - Styles Conference</title>\n    <link rel=\"stylesheet\" href=\"assets/stylesheets/main.css\">\n    <link rel=\"stylesheet\" href=\"http://fonts.googleapis.com/css?family=Lato:100,300,400\">\n    <meta name=\"description\" content=\"Summer 2015 Web Development Bootcamp\">\n    <meta name=\"keywords\" content=\"Web programming, web development, web bootcamp\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <link rel=\"shortcut icon\" href=\"assets/images/favicon.ico\">\n</head>\n\n<body>\n\n<!-- Header -->\n\n<header class=\"primary-header container group\">\n\n    <h1 class=\"logo\">\n        <a href=\"index.html\">Summer <br> Bootcamp</a>\n    </h1>\n\n    <h3 class=\"tagline\">May 25th &ndash;July 31st &mdash; Fresno, CA</h3>\n\n    <nav class=\"nav primary-nav\">\n        <ul>\n            <li><a href=\"index.html\">Home</a></li>\n            <!--\n                      -->\n            <li><a href=\"speakers.html\">Speakers</a></li>\n            <!--\n                      -->\n            <li><a href=\"schedule.html\">Schedule</a></li>\n            <!--\n                      -->\n            <li><a href=\"venue.html\">Venue</a></li>\n            <!--\n                      -->\n            <li><a href=\"register.html\">Register</a></li>\n            <!--\n                      -->\n            <li><a href=\"sponsors.html\">Sponsors</a></li>\n        </ul>\n    </nav>\n\n</header>\n\n<!-- Lead -->\n\n<section class=\"row-alt\">\n    <div class=\"lead container\">\n\n        <h1>Schedule</h1>\n\n        <p>Bootcamp runs May 25th - 31st July 2015 <br>\n            Monday - Friday from 7:45am - 5:00pm<br>\n            Lunch 12:00 - 1:00</p>\n\n        <ul>\n            <li><a href=\"#html5css3\">HTML5 / CSS3</a></li>\n            <p>May 25 - May 29</p>\n            <li><a href=\"#javascript\">JavaScript</a></li>\n            <p>June 1 - June 19</p>\n            <li><a href=\"#webcomponents\">Web Components</a></li>\n            <p>June 22 - June 26</p>\n            <li><a href=\"#polymer\">Polymer</a></li>\n            <p>June 29 - July 3</p>\n            <li><a href=\"#golang\">Go language, Google App Engine, Google Cloud Storage</a></li>\n            <p>July 6 - July 31</p>\n        </ul>\n    </div>\n</section>\n\n<!-- HTML -->\n\n<section class=\"row-alt\">\n    <div class=\"lead container\">\n\n        <h1 id=\"html5css3\">HTML5 / CSS3</h1>\n\n        <p>HTML5 & CSS3 combine to create the foundation of all websites.\n            HTML5 holds the content and CSS3 formats it.\n            Our bootcamp training will build upon the basics and cover the essentials of today's best-practices.\n            If you have never created a website before, you need to complete these two online trainings before coming\n            to our HTML5/CSS3 bootcamp:<br> <a href=\"http://www.codecademy.com/en/tracks/web\" target=\"_blank\">online\n                training #1</a>\n            <br> <a href=\"http://learn.shayhowe.com/html-css/building-your-first-web-page/\" target=\"_blank\">online\n                training #2</a>\n            <br> Some of the topics that will be covered at our bootcamp include: semantics, rich snippets & microdata,\n            emmet.io, performance\n            including page speed insights, responsive design, media queries, github, and flex-box. One of the most\n            valuable\n            aspects of our HTML5/CSS3 bootcamp will be spending 5 days together talking about HTML5 &\n            CSS3 best-practices: the contributions of everyone's knowledge and insight will allow us to learn\n            from each other. Our bootcamp will provide plenty of opportunities for \"hands-on\" practice.\n            See the full outline of the schedule here:\n            <a href=\"https://docs.google.com/document/d/1MFpG9epYXTDBWv2kv-JMtogFpmL3-BdiV3qZAFdlIyw/edit?usp=sharing\" target=\"_blank\">Week 01</a>\n        </p>\n    </div>\n</section>\n\n\n<!-- JAVASCRIPT -->\n\n<section class=\"row-alt\">\n    <div class=\"lead container\">\n\n        <h1 id=\"javascript\">JAVASCRIPT</h1>\n\n        <p>JavaScript provides functionality to websites.\n            HTML5 holds content, CSS3 formats it, and JavaScript allows us to manipulate it.\n            Our bootcamp training will build upon the basics and cover the essentials of today's best-practices.\n            If you have never created a website before, you need to complete these two online trainings before coming\n            to our JavaScript bootcamp:<br> <a href=\"http://www.codecademy.com/en/tracks/web\" target=\"_blank\">online\n                training #1</a>\n            <br> <a href=\"http://learn.shayhowe.com/html-css/building-your-first-web-page/\" target=\"_blank\">online\n                training #2</a>\n            <br>\n            If you have never used JavaScript before, you need to complete this online training before coming\n            to our JavaScript bootcamp:<br> <a href=\"http://www.codecademy.com/en/tracks/javascript\" target=\"_blank\">\n                JavaScript Online Training Prerequisite</a>\n            <br>\n            Some of the topics that will be covered at our JavaScript bootcamp include:\n            <a href=\"http://www.lynda.com/JavaScript-tutorials/JavaScript-Essential-Training/81266-2.html\" target=\"_blank\"> JavaScript Essentials, </a>\n            <a href=\"http://www.lynda.com/JavaScript-tutorials/JavaScript-Functions/148137-2.html\" target=\"_blank\"> Functions, </a>\n            <a href=\"http://www.lynda.com/HTML-tutorials/JavaScript-Enhancing-DOM/122462-2.html\" target=\"_blank\"> Enhancing the DOM, </a>\n            <a href=\"http://www.lynda.com/JavaScript-tutorials/JavaScript-Events/140780-2.html\" target=\"_blank\"> Events, </a>\n            <a href=\"http://www.lynda.com/JavaScript-tutorials/JavaScript-JSON/114901-2.html\" target=\"_blank\"> JavaScript and JSON, </a>\n            <a href=\"http://www.lynda.com/Developer-tutorials/JavaScript-and-AJAX/114900-2.html\" target=\"_blank\"> JavaScript and AJAX, </a>\n            and also if time permits\n            <a href=\"http://www.lynda.com/Web-Web-Design-tutorials/Web-Project-Workflows-Gulpjs-Git-Browserify/154416-2.html\" target=\"_blank\"> Web Project Workflows, </a>\n            <a href=\"http://www.lynda.com/Sublime-Text-tutorials/Up-Running-Sublime-Text-2/114325-2.html\" target=\"_blank\"> optimizing development on sublime, </a>\n            and\n            <a href=\"https://slack.com/\" target=\"_blank\">slack</a>.\n            Our bootcamp will provide plenty of opportunities for \"hands-on\" practice.\n            See the full outline of the schedule here:\n            <a href=\"https://docs.google.com/document/d/1zjeCcEeei8-dHMWFYL92G751sVxgQInxTkZR7pmOEas/edit?usp=sharing\" target=\"_blank\">Week 02, </a>\n            <a href=\"https://docs.google.com/document/d/1pm011AXcZ5jeLV0vPFUab0RpFJVm4MqXeaHM0eu2eGo/edit?usp=sharing\" target=\"_blank\">Week 03, </a>\n            <a href=\"https://docs.google.com/document/d/1fOrOA9hSzSGxCVutxDZ0v-im7MUG94TcewZB-ANJbcM/edit?usp=sharing\" target=\"_blank\">Week 04</a>\n        </p>\n    </div>\n</section>\n\n\n<!-- web components -->\n\n<section class=\"row-alt\">\n    <div class=\"lead container\">\n\n        <h1 id=\"webcomponents\">WEB COMPONENTS</h1>\n\n        <p>Web components usher in a new era of web development\n            based on encapsulated and interoperable custom elements that extend HTML itself.\n            HTML5 holds content, CSS3 formats it, JavaScript allows us to manipulate it, and web components allow us\n            to package all of our HTML5, CSS3, and JavaScript up into modular \"encapsulated\" components which can easily\n            be shared and re-used.\n            Our bootcamp training will start at the very beginning with web components.\n            If you have never created a website before, you need to complete these two online trainings before coming\n            to our web components bootcamp:<br> <a href=\"http://www.codecademy.com/en/tracks/web\" target=\"_blank\">online\n                training #1</a>\n            <br> <a href=\"http://learn.shayhowe.com/html-css/building-your-first-web-page/\" target=\"_blank\">online\n                training #2</a>\n            <br>\n            If you have never used JavaScript before, you need to complete this online training before coming\n            to our web components bootcamp:<br> <a href=\"http://www.codecademy.com/en/tracks/javascript\" target=\"_blank\">\n                JavaScript Online Training Prerequisite</a>\n            <br>\n            Some of the topics that will be covered at our web component bootcamp include: templates, custom elements,\n            shadow DOM, and HTML imports.\n            Our bootcamp will provide plenty of opportunities for \"hands-on\" practice.\n            See the full outline of the schedule here:\n            <a href=\"https://docs.google.com/document/d/18gncN4hBXqpuDt6fgfbW2oTUXX80Vi8DiqP_IZBZTOI/edit?usp=sharing\" target=\"_blank\">Week 05</a>\n        </p>\n    </div>\n</section>\n\n<!-- polymer -->\n\n<section class=\"row-alt\">\n    <div class=\"lead container\">\n\n        <h1 id=\"polymer\">Polymer</h1>\n\n        <p>Polymer is Google's implementation of web components.\n            Building upon web components, Polymer makes it easier and faster to create anything from a button to a\n            complete application across desktop, mobile, and beyond.\n\n            Our Polymer training will start at the very beginning with Google's Polymer.\n            If you have never created a website before, you need to complete these two online trainings before coming\n            to our Polymer bootcamp:<br> <a href=\"http://www.codecademy.com/en/tracks/web\" target=\"_blank\">online\n                training #1</a>\n            <br> <a href=\"http://learn.shayhowe.com/html-css/building-your-first-web-page/\" target=\"_blank\">online\n                training #2</a>\n            <br>\n            If you have never used JavaScript before, you need to complete this online training before coming\n            to our Polymer bootcamp:<br> <a href=\"http://www.codecademy.com/en/tracks/javascript\" target=\"_blank\">\n                JavaScript Online Training Prerequisite</a>\n            <br>\n            If you have never used web components before, you need to come to our web components bootcamp:\n            <br> <a href=\"#webcomponents\">\n            \"Web Components Bootcamp\" Prerequisite</a>\n            <br>\n            Some of the topics that will be covered at our Polymer bootcamp include: using Polymer to improve the\n            speed at which you create websites and to increase the quality of your websites.\n            Our bootcamp will provide plenty of opportunities for \"hands-on\" practice.\n            See the full outline of the schedule here:\n            <a href=\"https://docs.google.com/document/d/1fFKj85pwG4jQkVBTYqCixoBWofziIXfnx9wzYUu_Z9k/edit?usp=sharing\" target=\"_blank\">Week 06</a>\n        </p>\n    </div>\n</section>\n\n<!-- go, app engine, cloud -->\n\n<section class=\"row-alt\">\n    <div class=\"lead container\">\n\n        <h1 id=\"golang\">GO LANGUAGE (golang), GOOGLE APP ENGINE, GOOGLE CLOUD STORAGE</h1>\n\n        <p>Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.\n            Go provides the ability for \"server-side\" programming. Traditional choices for server-side languages have\n            included PHP, ASP, and JSP. Increasingly popular server-side programming languages include Ruby, Python, and\n            Node.js. While there are advantages and disadvantages to all languages, no server-side language is going\n            to be faster than \"Go.\" Couple the speed of Go with Google App Engine and Cloud Storage, and you are\n            now using the exact same architecture as Google. This means that your web apps are going to be incredibly\n            fast and will easily scale to millions of users. Go is an amazing choice for a server-side language\n            as it was developed by some of the same individuals who created the C programming language, one\n            of the most influential programming languages of all time. Robert Griesemer, Rob Pike, and Ken Thompson\n            created Go to be a modern language that easily uses multiple cores, easily implements concurrency,\n            easily works in distributed environments, and easily allows the programmer to write programs - it has a very\n            lean and user-friendly syntax! The four weeks we spend together learning Go, Google App Engine, and Google\n            Cloud Storage will not only be mind-blowing but also career-propelling and life-changing.\n            Our Go / App Engine / Cloud bootcamp will start at the very beginning with the Go language.\n            If you have never created a website before, you need to complete these two online trainings before coming\n            to our web component bootcamp:<br> <a href=\"http://www.codecademy.com/en/tracks/web\" target=\"_blank\">online\n                training #1</a>\n            <br> <a href=\"http://learn.shayhowe.com/html-css/building-your-first-web-page/\" target=\"_blank\">online\n                training #2</a>\n            <br>\n            If you have never used JavaScript before, you need to come to our JavaScript Bootcamp before coming\n            to our Go / App Engine / Cloud bootcamp:\n            <br>\n            <a href=\"#javascript\"\">\n            \"JavaScript Bootcamp\" Prerequisite</a>\n            <br>\n            Our bootcamp will provide plenty of opportunities for \"hands-on\" practice.\n            See the full outline of the schedule here:\n            <a href=\"https://docs.google.com/document/d/1bNpomv5AP6-plItcdW5WWJLrn3sCEMs2iv-XA648TBw/edit?usp=sharing\" target=\"_blank\">Week 07, </a>\n            <a href=\"https://docs.google.com/document/d/1_cmwZx2aGQut8KzEZ7miphKADQvc3VT6ZTzBYIhAWJ4/edit?usp=sharing\" target=\"_blank\">Week 08, </a>\n            <a href=\"https://docs.google.com/document/d/1IwXMXKQQR9Ip_27JBtrsExNH5FkyrI5BpbGxGySMSsU/edit?usp=sharing\" target=\"_blank\">Week 09, </a>\n            <a href=\"https://docs.google.com/document/d/1HioGAyPBS9MFqRYMcXqI1yxXGpIS9ZAl6c1qkrRwJSg/edit?usp=sharing\" target=\"_blank\">Week 10</a>\n        </p>\n    </div>\n</section>\n\n<!-- Footer -->\n\n<footer class=\"primary-footer container group\">\n\n    <small>&copy; Special thanks to <a href=\"http://learn.shayhowe.com/html-css/\" class=\"shay_light\"> Shay Howe </a>for\n        the use of this template.\n    </small>\n\n    <nav class=\"nav\">\n        <ul>\n            <li><a href=\"index.html\">Home</a></li>\n            <!--\n                      -->\n            <li><a href=\"speakers.html\">Speakers</a></li>\n            <!--\n                      -->\n            <li><a href=\"schedule.html\">Schedule</a></li>\n            <!--\n                      -->\n            <li><a href=\"venue.html\">Venue</a></li>\n            <!--\n                      -->\n            <li><a href=\"register.html\">Register</a></li>\n        </ul>\n    </nav>\n\n</footer>\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/99_svcc/32_static-FileServer/speakers.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"utf-8\">\n    <title>Trainers - Summer Bootcamp</title>\n    <link rel=\"stylesheet\" href=\"assets/stylesheets/main.css\">\n    <link rel=\"stylesheet\" href=\"http://fonts.googleapis.com/css?family=Lato:100,300,400\">\n    <meta name=\"description\" content=\"Summer 2015 Web Development Bootcamp\">\n    <meta name=\"keywords\" content=\"Web programming, web development, web bootcamp\">\n    <!--<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">-->\n    <!--<link rel=\"shortcut icon\" href=\"assets/images/favicon.ico\">-->\n</head>\n\n<body>\n\n<!-- Header -->\n\n<header class=\"primary-header container group\">\n\n    <h1 class=\"logo\">\n        <a href=\"index.html\">Summer <br> Bootcamp</a>\n    </h1>\n\n    <h3 class=\"tagline\">May 25th &ndash;July 31st &mdash; Fresno, CA</h3>\n\n    <nav class=\"nav primary-nav\">\n        <ul>\n            <li><a href=\"index.html\">Home</a></li>\n            <!--\n                      -->\n            <li><a href=\"speakers.html\">Speakers</a></li>\n            <!--\n                      -->\n            <li><a href=\"schedule.html\">Schedule</a></li>\n            <!--\n                      -->\n            <li><a href=\"venue.html\">Venue</a></li>\n            <!--\n                      -->\n            <li><a href=\"register.html\">Register</a></li>\n            <!--\n                      -->\n            <li><a href=\"sponsors.html\">Sponsors</a></li>\n        </ul>\n    </nav>\n\n</header>\n\n<!-- Lead -->\n\n<section class=\"row-alt\">\n    <div class=\"lead container\">\n\n        <h1>Speakers and Trainers</h1>\n\n        <p>We&#8217;re happy to welcome five outstanding trainers from around\n            the world who are not only passionate about what they do, but\n            are also experts in their field.\n        </p>\n\n    </div>\n</section>\n\n<!-- Main content -->\n\n<section class=\"row\">\n    <div class=\"grid\">\n\n        <!-- Ryan Bonhardt -->\n\n        <section class=\"speaker\" id=\"ryan-bonhardt\">\n\n            <div class=\"col-2-3\">\n\n                <h2>Ryan Bonhardt</h2>\n                <h5>HTML and CSS</h5>\n\n                <p>A strong believer in following his passion, Ryan Bonhardt is passionate about sharing his knowledge\n                    of HTML and CSS. He is also a great advocate of learning by doing, so be prepared to do\n                    and learn with Ryan this summer. </p>\n\n                <h5>About Ryan</h5>\n\n                <p>Ryan is the founder of <a href=\"http://www.makerbased.com/\" target=\"_blank\">Maker-Based Education</a>, where he\n                    strives to help schools teach real and relevant skills and to empower all teachers and students in\n                    today's world. He has\n                    run across the USA for Sarcoma cancer research, lived in 10 cities, been a white water river guide,\n                    surfed across Latin America, and advised multiple small businesses. His goal is to love what he does\n                    and learn something new every day.</p>\n\n            </div><aside class=\"col-1-3\">\n                <div class=\"speaker-info\">\n\n                    <img src=\"assets/images/speakers/ryan_bonhardt.jpeg\" alt=\"Adam Connor\">\n\n                    <ul>\n                        <li><a href=\"https://twitter.com/ryanbonhardt\" target=\"_blank\">@maker_based</a></li>\n                        <li><a href=\"http://www.ryanbonhardt.com/\" target=\"_blank\">ryanbonhardt.com</a></li>\n                    </ul>\n\n                </div>\n            </aside>\n\n        </section>\n\n\n        <!-- Ray Villallobos -->\n\n        <section class=\"speaker\" id=\"Ray-Villalobos\">\n\n            <div class=\"col-2-3\">\n\n                <h2>Ray Villalobos</h2>\n                <h5>Javascript Training</h5>\n\n                <p>With over 20 years experience developing and training,\n                    Ray Villalobos has what it takes to help you take your\n                    javascript skills to the next level. </p>\n\n                <h5>About Ray Villalobos</h5>\n\n                <p>Ray Villalobos is a full-time author and teacher at <a\n                        href=\"http://www.lynda.com/Ray-Villalobos/832401-1.html\" target=\"_blank\">Lynda.com</a> with over\n                    30 courses focusing on the\n                    front-end of the web including JavaScript, Responsive CSS, Sass, Compass, CoffeeScript and Workflows\n                    plus libraries and frameworks like Angular, Advanced Bootstrap, Gulp, Reveal, Grunt and others.\n\n                    He is also the author of the book, <a\n                            href=\"http://www.amazon.com/Exploring-Multimedia-Designers-Computer-Animation/dp/1418001031/ref=sr_1_1?ie=UTF8&qid=1425921731&sr=8-1&keywords=Exploring+Multimedia+for+Designers\"\n                            target=\"_blank\">Exploring Multimedia for Designers</a\n                            >. As the Director of Multimedia\n                    for Entravision Communications, he designed and developed a network of radio station and TV\n                    websites. As a Senior Producer for Tribune Interactive, he was responsible for designing\n                    <a href=\"http://www.orlandosentinel.com/\" target=\"_blank\">orlandosentinel.com</a> and for creating\n                    immersive interactive projects and Flash games for the Tribune\n                    network of websites. You can follow Ray <a href=\"https://twitter.com/planetoftheweb\"\n                                                               target=\"_blank\">@planetoftheweb</a> on Twitter or check\n                    out his blog at\n                    <a href=\"http://www.raybo.org/\" target=\"_blank\">http://raybo.org</a></p>\n\n            </div><aside class=\"col-1-3\">\n                <div class=\"speaker-info\">\n\n                    <img src=\"assets/images/speakers/ray_villalobos.jpeg\"\n                         alt=\"Ray Villalobos\">\n\n                    <ul>\n                        <li><a href=\"https://twitter.com/planetoftheweb\" target=\"_blank\">@planetoftheweb</a></li>\n                        <li><a href=\"http://www.raybo.org/\" target=\"_blank\">raybo.org</a></li>\n                    </ul>\n\n                </div>\n            </aside>\n\n        </section>\n\n\n        <!-- Andrew Rota -->\n\n        <section class=\"speaker\" id=\"andrew-rota\">\n\n            <div class=\"col-2-3\">\n\n                <h2>Andrew Rota</h2>\n                <h5>Web Components</h5>\n\n                <p>As the idea of web components is beginning to catch the\n                    attention of more and more developers, now is a good time to\n                    not only familiarize yourself with it's capabilities, but\n                    to add some useful tools to your toolset. Andrew Rota\n                    will be teaching web components at Fresno City College, this summer\n                    2015. </p>\n\n                <h5>About Andrew</h5>\n\n                <p>Andrew is a front­end software developer who specializes in building interactive HTML5 JavaScript web\n                    applications. He has experience writing modular and testable JavaScript, building cross-device\n                    responsive websites, and architecting service-­oriented web applications for clients in a variety of\n                    industries.</p>\n\n            </div><aside class=\"col-1-3\">\n                <div class=\"speaker-info\">\n\n                    <img src=\"assets/images/speakers/andrew_rota.jpeg\" alt=\"AJ Self\">\n\n                    <ul>\n                        <li><a href=\"https://twitter.com/andrewrota\" target=\"_blank\">@AndrewRota</a></li>\n                        <li><a href=\"https://www.linkedin.com/profile/in/andrewrota?goback=\" target=\"_blank\">Andrew@linkedin</a></li>\n                    </ul>\n\n                </div>\n            </aside>\n\n        </section>\n\n        <!-- Zeno Rocha -->\n\n        <section class=\"speaker\" id=\"zeno-rocha\">\n\n            <div class=\"col-2-3\">\n\n                <h2>Zeno Rocha</h2>\n                <h5>Polymer</h5>\n\n                <p>Boasted as the future of Web Development, Polymer makes it\n                    faster and easier to create web applications. Zeno Rocha is a Polymer rockstar and will be\n                    teaching us Polymer this summer at Fresno City College. </p>\n\n                <h5>About Zeno</h5>\n\n                <p>He is a co-founder of <a href=\"http://braziljs.org/\" target=\"_blank\">BrazilJS Foundation</a>, member at the <a\n                        href=\"https://developers.google.com/experts/people/zeno-rocha\">Google Developers Expert\n                    Program</a>, and a host on Zone of Front-enders. He also has a ton of activity on <a\n                        href=\"https://github.com/zenorocha\">github!</a> Author at <a\n                        href=\"http://www.smashingmagazine.com/2013/03/26/goodbye-zen-coding-hello-emmet/\">Smashing\n                    Magazine</a>, Zeno is always on the lookout for faster, more efficient development strategies.</p>\n\n            </div><aside class=\"col-1-3\">\n                <div class=\"speaker-info\">\n\n                    <img src=\"assets/images/speakers/zeno_rocha.jpeg\" alt=\"Zeno Rocha\">\n\n                    <ul>\n                        <li><a href=\"https://twitter.com/zenorocha\" target=\"_blank\">@zenorocha</a></li>\n                    </ul>\n\n                </div>\n            </aside>\n\n        </section>\n\n        <!-- Caleb Doxsey -->\n\n        <section class=\"speaker\" id=\"bermon-painter\">\n\n            <div class=\"col-2-3\">\n\n                <h2>Caleb Doxsey</h2>\n                <h5>Golang</h5>\n\n                <p>Do you want a website that is fast? Do you want a website that can scale to millions of individuals\n                    instantly? Use what Google uses for their infrastructure: Golang, Google App engine, and Google\n                    cloud storage.\n                    This set of tools is the best of the best. When you learn to use this architecture, you will be\n                    amazed\n                    at how quickly your websites run. Golang is a \"server side\" language that will allow you to add\n                    great\n                    functionality, at fast speeds, to your sites. Caleb Doxsey will be teaching us the power of this\n                    combination this summer.</p>\n\n                <h5>About Caleb</h5>\n\n                <p>Caleb is a software developer and a web applications developer,\n                    who is generous about sharing his knowledge through blogs,\n                    tutorials and presentations. He is the author of <a\n                            href=\"http://www.amazon.com/dp/1478355824/ref=as_sl_pd_tf_lc?tag=doxseynet-20&camp=14573&creative=327641&linkCode=as1&creativeASIN=1478355824&adid=1D8M6J8H13SV3MD7ETNA&&ref-refURL=http%3A%2F%2Fwww.doxsey.net%2F\">\"An\n                        Introduction\n                        to Programming in Go\"</a> and makes regular contributions on <a\n                            href=\"https://github.com/calebdoxsey\">Github.</a></p>\n\n            </div><aside class=\"col-1-3\">\n                <div class=\"speaker-info\">\n\n                    <img src=\"assets/images/speakers/caleb_doxsey.jpeg\" alt=\"Caleb Doxsey\">\n\n                    <ul>\n                        <li><a href=\"http://www.doxsey.net/\" target=\"_blank\">doxsey.net</a></li>\n                        <li><a href=\"https://github.com/calebdoxsey\" target=\"_blank\">Caleb@Github</a></li>\n                    </ul>\n\n                </div>\n            </aside>\n\n        </section>\n\n        </aside>\n\n        <!--</section>-->\n\n        <!-- Footer -->\n\n        <footer class=\"primary-footer container group\">\n\n            <small>&copy; Special thanks to <a href=\"http://learn.shayhowe.com/html-css/\" class=\"shay\" target=\"_blank\"> Shay Howe </a>for\n                the use of this template.\n            </small>\n\n            <nav class=\"nav\">\n                <ul>\n                    <li><a href=\"index.html\">Home</a></li>\n                    <!--\n                              -->\n                    <li><a href=\"speakers.html\">Speakers</a></li>\n                    <!--\n                              -->\n                    <li><a href=\"schedule.html\">Schedule</a></li>\n                    <!--\n                              -->\n                    <li><a href=\"venue.html\">Venue</a></li>\n                    <!--\n                              -->\n                    <li><a href=\"register.html\">Register</a></li>\n                </ul>\n            </nav>\n\n        </footer>\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/99_svcc/32_static-FileServer/sponsors.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"utf-8\">\n    <title>Schedule - Styles Conference</title>\n    <link rel=\"stylesheet\" href=\"assets/stylesheets/main.css\">\n    <link rel=\"stylesheet\" href=\"http://fonts.googleapis.com/css?family=Lato:100,300,400\">\n    <meta name=\"description\" content=\"Summer 2015 Web Development Bootcamp\">\n    <meta name=\"keywords\" content=\"Web programming, web development, web bootcamp\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <link rel=\"shortcut icon\" href=\"assets/images/favicon.ico\">\n</head>\n\n<body>\n\n<!-- Header -->\n\n<header class=\"primary-header container group\">\n\n    <h1 class=\"logo\">\n        <a href=\"index.html\">Summer <br> Bootcamp</a>\n    </h1>\n\n    <h3 class=\"tagline\">May 25th &ndash;July 31st &mdash; Fresno, CA</h3>\n\n    <nav class=\"nav primary-nav\">\n        <ul>\n            <li><a href=\"index.html\">Home</a></li><!--\n          --><li><a href=\"speakers.html\">Speakers</a></li><!--\n          --><li><a href=\"schedule.html\">Schedule</a></li><!--\n          --><li><a href=\"venue.html\">Venue</a></li><!--\n          --><li><a href=\"register.html\">Register</a></li><!--\n          --><li><a href=\"sponsors.html\">Sponsors</a></li>\n        </ul>\n    </nav>\n\n</header>\n\n<!-- Lead -->\n\n<section class=\"row-alt\">\n    <div class=\"lead container\">\n\n        <h1>Sponsors</h1>\n<p>A big thank you, to our sponsors!</p>\n<p>This outstanding training is provided by “<a href=\"http://ict-dm.net/\" target=\"_blank\">The Information Communications Technologies & Digital Media Sector Navigation Team</a>” which is part of the &quot;Economic & Workforce Development of California Community Colleges.&quot; Our goal is &quot;Doing what matters for jobs and the economy.&quot;</p>\n    <div class=\"flex\">\n        <img src=\"assets/images/fcc4.png\" alt=\"logo of fresno city college\">\n        <img src=\"assets/images/DWM.png\" alt=\"logo of doing what matters for jobs and the economy\">\n        <img src=\"assets/images/csuf.png\" alt=\"logo of CSU Fresno\">\n\n    </div>\n\n    </div>\n</section>\n\n\n<!-- Footer -->\n\n<footer class=\"primary-footer container group\">\n\n    <small>&copy; Special thanks to <a href=\"http://learn.shayhowe.com/html-css/\" class=\"shay_light\"> Shay Howe </a>for the use of this template.</small>\n\n    <nav class=\"nav\">\n        <ul>\n            <li><a href=\"index.html\">Home</a></li><!--\n          --><li><a href=\"speakers.html\">Speakers</a></li><!--\n          --><li><a href=\"schedule.html\">Schedule</a></li><!--\n          --><li><a href=\"venue.html\">Venue</a></li><!--\n          --><li><a href=\"register.html\">Register</a></li>\n        </ul>\n    </nav>\n\n</footer>\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/99_svcc/32_static-FileServer/venue.html",
    "content": "\n<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"utf-8\">\n    <title>Venue - Web Development Bootcamp</title>\n    <link rel=\"stylesheet\" href=\"assets/stylesheets/main.css\">\n    <link rel=\"stylesheet\" href=\"http://fonts.googleapis.com/css?family=Lato:100,300,400\">\n    <meta name=\"description\" content=\"Summer 2015 Web Development Bootcamp\">\n    <meta name=\"keywords\" content=\"Web programming, web development, web bootcamp\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <link rel=\"shortcut icon\" href=\"assets/images/favicon.ico\">\n</head>\n\n<body>\n\n\n<!-- Header -->\n\n<header class=\"primary-header container group\">\n\n    <h1 class=\"logo\">\n        <a href=\"index.html\">Summer <br> Bootcamp</a>\n    </h1>\n\n    <h3 class=\"tagline\">May 25th &ndash;July 31st &mdash; Fresno, CA</h3>\n\n    <nav class=\"nav primary-nav\">\n        <ul>\n            <li><a href=\"index.html\">Home</a></li><!--\n          --><li><a href=\"speakers.html\">Speakers</a></li><!--\n          --><li><a href=\"schedule.html\">Schedule</a></li><!--\n          --><li><a href=\"venue.html\">Venue</a></li><!--\n          --><li><a href=\"register.html\">Register</a></li><!--\n          --><li><a href=\"sponsors.html\">Sponsors</a></li>\n        </ul>\n    </nav>\n\n</header>\n\n<!-- Lead -->\n\n<section class=\"row-alt\">\n    <div class=\"lead container\">\n\n        <h1>Venue</h1>\n\n        <p>The Bootcamp will be held in the historic Old Administration Building at Fresno City College</p>\n\n    </div>\n</section>\n\n<!-- Main content -->\n\n<section class=\"row\">\n    <div class=\"grid\">\n\n        <!-- Chicago Theatre -->\n\n        <section class=\"venue-theatre\">\n\n            <div class=\"col-1-3\">\n                <h2>Fresno City College</h2>\n                <p>Old Administration Building, Room #114<br>1101 E. University Ave. <br> Fresno, CA 93741</p>\n                <p><a href=\"http://www.fresnocitycollege.edu/\">fresnocitycollege.edu</a> <br> (559) 442-4600</p>\n            </div><!--\n          --><iframe class=\"venue-map col-2-3\" src=\"https://www.google.com/maps/embed/v1/place?key=AIzaSyCQzULCnq-0AZ-6p4AglIQU3HSTIsXPq8g&q=Historic+Old+Administration+Bldg,+Fresno,+CA+93704&zoom=18&attribution_source=Google+Maps+Embed+API\n      &attribution_web_url=http://www.summerwebbootcamp.com/\"></iframe>\n\n\n        </section>\n\n        <div class=\"flex\">\n            <img src=\"assets/images/fcc3.png\" alt=\"logo of fresno city college\">\n        </div>\n\n<!-- Footer -->\n\n<footer class=\"primary-footer container group\">\n\n    <small>&copy; Special thanks to <a href=\"http://learn.shayhowe.com/html-css/\" class=\"shay\"> Shay Howe </a>for the use of this template.</small>\n\n    <nav class=\"nav\">\n        <ul>\n            <li><a href=\"index.html\">Home</a></li><!--\n          --><li><a href=\"speakers.html\">Speakers</a></li><!--\n          --><li><a href=\"schedule.html\">Schedule</a></li><!--\n          --><li><a href=\"venue.html\">Venue</a></li><!--\n          --><li><a href=\"register.html\">Register</a></li>\n        </ul>\n    </nav>\n\n</footer>\n\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/99_svcc/33_set-cookie/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n)\n\nfunc setCookie(res http.ResponseWriter, req *http.Request) {\n\thttp.SetCookie(res, &http.Cookie{\n\t\tName:  \"my-cookie\",\n\t\tValue: \"COOKIE MONSTER\",\n\t})\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", setCookie)\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/34_get-cookie/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n)\n\nfunc getCookie(res http.ResponseWriter, req *http.Request) {\n\tcookie, _ := req.Cookie(\"my-cookie\")\n\tfmt.Println(cookie)\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", getCookie)\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/35_favicon-bye-bye/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n)\n\nfunc getCookie(res http.ResponseWriter, req *http.Request) {\n\tcookie, _ := req.Cookie(\"my-cookie\")\n\tfmt.Println(cookie)\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", getCookie)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.ListenAndServe(\":9000\", nil)\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/36_sessions_cookie/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"net/http\"\n)\n\nfunc setCookie(res http.ResponseWriter, req *http.Request) {\n\tcookie, err := req.Cookie(\"session-id\")\n\t// if cookie is not set\n\tif err != nil {\n\t\tid, _ := uuid.NewV4()\n\t\tcookie = &http.Cookie{\n\t\t\tName:  \"session-id\",\n\t\t\tValue: id.String() + \" email=jon@email.com\" + \" JSON data\" + \" Whatever\",\n\t\t}\n\t\thttp.SetCookie(res, cookie)\n\t}\n\tfmt.Println(cookie)\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", setCookie)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.ListenAndServe(\":9000\", nil)\n}\n\n// go get uuid\n// https://github.com/nu7hatch/gouuid\n// NewV4\n"
  },
  {
    "path": "27_code-in-process/99_svcc/37_sessions_cookie_log-in-out/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/\", authenticate)\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.ListenAndServe(\":9000\", nil)\n}\n\nfunc authenticate(res http.ResponseWriter, req *http.Request) {\n\tcookie, err := req.Cookie(\"logged-in\")\n\t// no cookie\n\tif err == http.ErrNoCookie {\n\t\tcookie = &http.Cookie{\n\t\t\tName:  \"logged-in\",\n\t\t\tValue: \"0\",\n\t\t}\n\t}\n\n\t// check log in\n\tif req.Method == \"POST\" {\n\t\tpassword := req.FormValue(\"password\")\n\t\tif password == \"secret\" {\n\t\t\tcookie = &http.Cookie{\n\t\t\t\tName:  \"logged-in\",\n\t\t\t\tValue: \"1\",\n\t\t\t}\n\t\t}\n\t}\n\n\t// if logout, then logout\n\tif req.URL.Path == \"/logout\" {\n\t\tcookie = &http.Cookie{\n\t\t\tName:   \"logged-in\",\n\t\t\tValue:  \"0\",\n\t\t\tMaxAge: -1,\n\t\t}\n\t}\n\n\thttp.SetCookie(res, cookie)\n\tvar html string\n\n\t// not logged in\n\tif cookie.Value == strconv.Itoa(0) {\n\t\thtml = `\n\t\t\t<!DOCTYPE html>\n\t\t\t<html lang=\"en\">\n\t\t\t<head>\n\t\t\t\t<meta charset=\"UTF-8\">\n\t\t\t\t<title></title>\n\t\t\t</head>\n\t\t\t<body>\n\t\t\t<h1>LOG IN</h1>\n\t\t\t<form method=\"post\" action=\"http://localhost:9000/\">\n\t\t\t\t<h3>User name</h3>\n\t\t\t\t<input type=\"text\" name=\"userName\">\n\t\t\t\t<h3>Password</h3>\n\t\t\t\t<input type=\"text\" name=\"password\">\n\t\t\t\t<br>\n\t\t\t\t<input type=\"submit\">\n\t\t\t\t<input type=\"submit\" name=\"logout\" value=\"logout\">\n\t\t\t</form>\n\t\t\t</body>\n\t\t\t</html>`\n\t}\n\n\t// logged in\n\tif cookie.Value == strconv.Itoa(1) {\n\t\thtml = `\n\t\t\t<!DOCTYPE html>\n\t\t\t<html lang=\"en\">\n\t\t\t<head>\n\t\t\t\t<meta charset=\"UTF-8\">\n\t\t\t\t<title></title>\n\t\t\t</head>\n\t\t\t<body>\n\t\t\t<h1><a href=\"http://localhost:9000/logout\">LOG OUT</a></h1>\n\t\t\t</body>\n\t\t\t</html>`\n\t}\n\n\tio.WriteString(res, html)\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/38_HMAC/01/main.go",
    "content": "package main\n\nimport (\n\t\"crypto/hmac\"\n\t\"crypto/sha256\"\n\t\"fmt\"\n\t\"io\"\n)\n\nfunc main() {\n\tsessionID := \"1123456789\"\n\tfmt.Println(sessionID)\n\tcode := getCode(sessionID)\n\tfmt.Println(code)\n\t// we get the same code here b/c the string is unchanged\n\tcode = getCode(sessionID)\n\tfmt.Println(code)\n\t// we get a different code here b/c the string is unchanged\n\tcode = getCode(sessionID + \"some other stuff\")\n\tfmt.Println(code)\n\n}\n\nfunc getCode(data string) string {\n\th := hmac.New(sha256.New, []byte(\"this can be anything we want it to be it is our private key\"))\n\tio.WriteString(h, data)\n\treturn fmt.Sprintf(\"%x\", h.Sum(nil))\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/38_HMAC/02/main.go",
    "content": "package main\n\nimport (\n\t\"crypto/hmac\"\n\t\"crypto/sha256\"\n\t\"fmt\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"io\"\n)\n\nfunc main() {\n\tsessionID, _ := uuid.NewV4()\n\tfmt.Println(sessionID.String())\n\tcode := getCode(sessionID.String())\n\tfmt.Println(code)\n\t// we get the same code here b/c the string is unchanged\n\tcode = getCode(sessionID.String())\n\tfmt.Println(code)\n\t// we get a different code here b/c the string is unchanged\n\tcode = getCode(sessionID.String() + \"some other stuff\")\n\tfmt.Println(code)\n\n}\n\nfunc getCode(data string) string {\n\th := hmac.New(sha256.New, []byte(\"this can be anything we want it to be it is our private key\"))\n\tio.WriteString(h, data)\n\treturn fmt.Sprintf(\"%x\", h.Sum(nil))\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/38_HMAC/03/main.go",
    "content": "package main\n\nimport (\n\t\"crypto/hmac\"\n\t\"crypto/sha256\"\n\t\"fmt\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/\", home)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n\nfunc home(res http.ResponseWriter, req *http.Request) {\n\tcookie, err := req.Cookie(\"session-id\")\n\t// cookie is not set\n\tif err != nil {\n\t\tid, _ := uuid.NewV4()\n\t\tcode := getCode(id.String())\n\t\tval := code + \"|\" + id.String()\n\t\tcookie = &http.Cookie{\n\t\t\tName:  \"session-id\",\n\t\t\tValue: val,\n\t\t}\n\t}\n\n\tvalues := strings.Split(cookie.Value, \"|\")\n\tcode := getCode(values[1])\n\tcookieCode := values[0]\n\tfmt.Fprintln(res, code)\n\tfmt.Fprintln(res, cookieCode)\n\n\tif code != cookieCode {\n\t\tfmt.Fprintln(res, \"Cookie monsters says: someone's had their hands in my cookies!\")\n\t\tcookie = &http.Cookie{\n\t\t\tName:   \"session-id\",\n\t\t\tValue:  \"0\",\n\t\t\tMaxAge: -1,\n\t\t}\n\t}\n\n\thttp.SetCookie(res, cookie)\n}\n\nfunc getCode(data string) string {\n\th := hmac.New(sha256.New, []byte(\"ourkey\"))\n\tio.WriteString(h, data)\n\treturn fmt.Sprintf(\"%x\", h.Sum(nil))\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/39_AES-encrypt-decrypt/main.go",
    "content": "package main\n\nimport (\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"fmt\"\n)\n\nfunc main() {\n\t// The key argument should be the AES key,\n\t// either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.\n\tkey := \"opensesame123456\" // 16 bytes!\n\tblock, _ := aes.NewCipher([]byte(key))\n\tfmt.Printf(\"%d bytes NewCipher key with block size of %d bytes\\n\", len(key), block.BlockSize)\n\tstr := []byte(\"Hello World, and everyone else in the universe!\")\n\t// 16 bytes for AES-128, 24 bytes for AES-192, 32 bytes for AES-256\n\tciphertext := []byte(\"abcdef1234567890\")\n\tiv := ciphertext[:aes.BlockSize] // const BlockSize = 16\n\t// encrypt\n\tencrypter := cipher.NewCFBEncrypter(block, iv)\n\tencrypted := make([]byte, len(str))\n\tencrypter.XORKeyStream(encrypted, str)\n\tfmt.Printf(\"%s encrypted to %v\\n\", str, encrypted)\n\t// decrypt\n\tdecrypter := cipher.NewCFBDecrypter(block, iv) // simple!\n\tdecrypted := make([]byte, len(str))\n\tdecrypter.XORKeyStream(decrypted, encrypted)\n\tfmt.Printf(\"%v decrypt to %s\\n\", encrypted, decrypted)\n}\n\n// https://www.socketloop.com/tutorials/golang-how-to-encrypt-with-aes-crypto\n"
  },
  {
    "path": "27_code-in-process/99_svcc/40_sessions_GORILLA/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/gorilla/context\"\n\t\"github.com/gorilla/sessions\"\n\t\"io\"\n\t\"net/http\"\n)\n\nvar store = sessions.NewCookieStore([]byte(\"secret-password\"))\n\nfunc setSession(res http.ResponseWriter, req *http.Request) {\n\tsession, _ := store.Get(req, \"session\")\n\tif req.FormValue(\"email\") != \"\" {\n\t\tsession.Values[\"email\"] = req.FormValue(\"email\")\n\t}\n\tsession.Save(req, res)\n\n\tio.WriteString(res, `<!DOCTYPE html>\n<html>\n  <body>\n    <form method=\"POST\">\n    <p>`+fmt.Sprint(session.Values[\"email\"])+`</p>\n    <p>Enter Your Email:</p>\n      <input type=\"email\" name=\"email\">\n      <input type=\"submit\">\n    </form>\n  </body>\n</html>`)\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", setSession)\n\thttp.ListenAndServe(\":8080\", context.ClearHandler(http.DefaultServeMux))\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/41_sessions_GORILLA_log-in-out/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/gorilla/context\"\n\t\"github.com/gorilla/sessions\"\n\t\"io\"\n\t\"net/http\"\n)\n\nvar store = sessions.NewCookieStore([]byte(\"secret-password\"))\n\nfunc authenticate(res http.ResponseWriter, req *http.Request) {\n\tsession, _ := store.Get(req, \"session\")\n\n\t// check log in\n\tif req.Method == \"POST\" {\n\t\tpassword := req.FormValue(\"password\")\n\t\tif password == \"secret\" {\n\t\t\tsession.Values[\"loggedin\"] = \"true\"\n\t\t}\n\t}\n\n\t// if logout, then logout\n\tif req.URL.Path == \"/logout\" {\n\t\tsession.Values[\"loggedin\"] = \"false\"\n\t}\n\n\tsession.Save(req, res)\n\tvar html string\n\n\t// not logged in\n\tif session.Values[\"loggedin\"] == \"false\" ||\n\t\tsession.Values[\"loggedin\"] == nil {\n\t\thtml = `\n\t\t\t<!DOCTYPE html>\n\t\t\t<html lang=\"en\">\n\t\t\t<head>\n\t\t\t\t<meta charset=\"UTF-8\">\n\t\t\t\t<title></title>\n\t\t\t</head>\n\t\t\t<body>\n\t\t\t<h1>LOG IN</h1>\n\t\t\t<form method=\"post\" action=\"/\">\n\t\t\t\t<h3>User name</h3>\n\t\t\t\t<input type=\"text\" name=\"userName\" id=\"userName\">\n\t\t\t\t<h3>Password</h3>\n\t\t\t\t<input type=\"text\" name=\"password\" id=\"password\">\n\t\t\t\t<br>\n\t\t\t\t<input type=\"submit\">\n\t\t\t\t<input type=\"submit\" name=\"logout\" value=\"logout\">\n\t\t\t</form>\n\t\t\t</body>\n\t\t\t</html>`\n\t} else {\n\t\thtml = `\n\t\t\t<!DOCTYPE html>\n\t\t\t<html lang=\"en\">\n\t\t\t<head>\n\t\t\t\t<meta charset=\"UTF-8\">\n\t\t\t\t<title></title>\n\t\t\t</head>\n\t\t\t<body>\n\t\t\t<h1><a href=\"logout\">LOG OUT</a></h1>\n\t\t\t</body>\n\t\t\t</html>`\n\t}\n\n\tio.WriteString(res, html)\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", authenticate)\n\thttp.ListenAndServe(\":8080\", context.ClearHandler(http.DefaultServeMux))\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/42_JSON/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\nfunc main() {\n\tjsonData := `\n\t\t[\"one phrase\", \"another phrase\", \"four score\", \"monday night\"]\n\t\t`\n\tfmt.Printf(\"%T\\n\", jsonData)\n\n\tvar data []string\n\tjson.Unmarshal([]byte(jsonData), &data)\n\tfmt.Println(\"unmarshalled: \", data)\n\tfmt.Println(\"unmarshalled: \", data[1])\n\tfor i, v := range data {\n\t\tfmt.Println(\"unmarshalled: \", i, \" - \", v)\n\t}\n\n\tdata = append(data, \"One love\")\n\tbs, _ := json.Marshal(data)\n\tfmt.Println(\"marshalled: \", string(bs))\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/43_sessions_GORILLA_JSON/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/gorilla/context\"\n\t\"github.com/gorilla/sessions\"\n\t\"io\"\n\t\"net/http\"\n)\n\nvar store = sessions.NewCookieStore([]byte(\"secret-password\"))\n\nfunc authenticate(res http.ResponseWriter, req *http.Request) {\n\tsession, _ := store.Get(req, \"session\")\n\n\t// check log in\n\tif req.Method == \"POST\" &&\n\t\treq.FormValue(\"password\") != \"\" {\n\t\tpassword := req.FormValue(\"password\")\n\t\tif password == \"secret\" {\n\t\t\tsession.Values[\"loggedin\"] = \"true\"\n\t\t}\n\t}\n\n\t// add data\n\tif req.Method == \"POST\" &&\n\t\treq.FormValue(\"data\") != \"\" {\n\t\tvar data []string\n\t\tjsonData := session.Values[\"data\"]\n\t\tfmt.Printf(\"Type jsonData: %T\\n\", jsonData)\n\t\tif jsonData != nil {\n\t\t\tjson.Unmarshal([]byte(jsonData.(string)), &data)\n\t\t}\n\t\tdata = append(data, req.FormValue(\"data\"))\n\t\tbs, _ := json.Marshal(data)\n\t\tsession.Values[\"data\"] = string(bs)\n\t\tfmt.Println(\"cookie data: \", session.Values[\"data\"])\n\t}\n\n\t// if logout, then logout\n\tif req.URL.Path == \"/logout\" {\n\t\tsession.Values[\"loggedin\"] = \"false\"\n\t}\n\n\tvar html string\n\n\t// not logged in\n\tif session.Values[\"loggedin\"] == \"false\" ||\n\t\tsession.Values[\"loggedin\"] == nil {\n\t\thtml = `\n\t\t\t<!DOCTYPE html>\n\t\t\t<html lang=\"en\">\n\t\t\t<head>\n\t\t\t\t<meta charset=\"UTF-8\">\n\t\t\t\t<title></title>\n\t\t\t</head>\n\t\t\t<body>\n\t\t\t<h1>LOG IN</h1>\n\t\t\t<form method=\"post\" action=\"http://localhost:9000/\">\n\t\t\t\t<h3>User name</h3>\n\t\t\t\t<input type=\"text\" name=\"userName\" id=\"userName\">\n\t\t\t\t<h3>Password</h3>\n\t\t\t\t<input type=\"text\" name=\"password\" id=\"password\">\n\t\t\t\t<br>\n\t\t\t\t<input type=\"submit\">\n\t\t\t\t<input type=\"submit\" name=\"logout\" value=\"logout\">\n\t\t\t</form>\n\t\t\t</body>\n\t\t\t</html>`\n\t} else {\n\t\thtml = `\n\t\t\t<!DOCTYPE html>\n\t\t\t<html lang=\"en\">\n\t\t\t<head>\n\t\t\t\t<meta charset=\"UTF-8\">\n\t\t\t\t<title></title>\n\t\t\t</head>\n\t\t\t<body>\n\t\t\t<h1><a href=\"http://localhost:9000/logout\">LOG OUT</a></h1>\n\t\t\t\t\t\t<h1>ADD DATA</h1>\n\t\t\t<form method=\"post\" action=\"http://localhost:9000/\">\n\t\t\t\t<h3>Data</h3>\n\t\t\t\t<input type=\"text\" name=\"data\" id=\"data\">\n\t\t\t\t<br>\n\t\t\t\t<input type=\"submit\">\n\t\t\t\t<input type=\"submit\" name=\"logout\" value=\"logout\">\n\t\t\t</form> <p>` +\n\t\t\tfmt.Sprint(\"cookie data: \", session.Values[\"data\"]) +\n\t\t\t`</p>\n\t\t\t</body>\n\t\t\t</html>`\n\t}\n\n\tsession.Save(req, res)\n\tio.WriteString(res, html)\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", authenticate)\n\thttp.ListenAndServe(\":8080\", context.ClearHandler(http.DefaultServeMux))\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/44_file-paths/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\nfunc main() {\n\twd, _ := os.Getwd()\n\tfilename := \"01.jpg\"\n\tpath := filepath.Join(wd, \"assets\", \"imgs\", filename)\n\tfmt.Println(path)\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/45_sessions_GORILLA_photo-blog/assets/templates/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n</head>\n<body>\n<h1><a href=\"http://localhost:8080/logout\">LOG OUT</a></h1>\n<p><img src=\"/assets/imgs/01.jpg\"></p>\n<h1>ADD PHOTO</h1>\n<form method=\"POST\" action=\"http://localhost:8080/\" enctype=\"multipart/form-data\">\n    <input type=\"file\" name=\"data\" id=\"data\">\n    <input type=\"submit\">\n</form>\n<p>\n    {{range .}}\n    <img src=\"/assets/imgs/{{.}}\">\n    {{end}}\n</p>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/99_svcc/45_sessions_GORILLA_photo-blog/assets/templates/login.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title></title>\n</head>\n<body>\n<h1>LOG IN</h1>\n<form method=\"post\" action=\"http://localhost:8080/login\">\n    <h3>User name</h3>\n    <input type=\"text\" name=\"userName\" id=\"userName\">\n    <h3>Password</h3>\n    <input type=\"text\" name=\"password\" id=\"password\">\n    <br>\n    <input type=\"submit\">\n    <input type=\"submit\" name=\"logout\" value=\"logout\">\n</form>\n</body>\n</html>"
  },
  {
    "path": "27_code-in-process/99_svcc/45_sessions_GORILLA_photo-blog/main.go",
    "content": "package main\n\nimport (\n\t\"crypto/sha1\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/gorilla/context\"\n\t\"github.com/gorilla/sessions\"\n\t\"html/template\"\n\t\"io\"\n\t\"mime/multipart\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\nvar tpl *template.Template\nvar store = sessions.NewCookieStore([]byte(\"secret-password\"))\n\nfunc init() {\n\ttpl, _ = template.ParseGlob(\"assets/templates/*.html\")\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", index)\n\thttp.HandleFunc(\"/login\", login)\n\thttp.HandleFunc(\"/logout\", logout)\n\thttp.Handle(\"/assets/imgs/\", http.StripPrefix(\"/assets/imgs\", http.FileServer(http.Dir(\"./assets/imgs\"))))\n\thttp.Handle(\"/favicon.ico\", http.NotFoundHandler())\n\thttp.ListenAndServe(\":8080\", context.ClearHandler(http.DefaultServeMux))\n}\n\nfunc index(res http.ResponseWriter, req *http.Request) {\n\tsession, _ := store.Get(req, \"session\")\n\t// authenticate\n\tif session.Values[\"loggedin\"] == \"false\" || session.Values[\"loggedin\"] == nil {\n\t\thttp.Redirect(res, req, \"/login\", 302)\n\t\treturn\n\t}\n\t// upload photo\n\tsrc, hdr, err := req.FormFile(\"data\")\n\tif req.Method == \"POST\" && err == nil {\n\t\tuploadPhoto(src, hdr, session)\n\t}\n\t// save session\n\tsession.Save(req, res)\n\t// get photos\n\tdata := getPhotos(session)\n\t// execute template\n\ttpl.ExecuteTemplate(res, \"index.html\", data)\n}\n\nfunc logout(res http.ResponseWriter, req *http.Request) {\n\tsession, _ := store.Get(req, \"session\")\n\tsession.Values[\"loggedin\"] = \"false\"\n\tsession.Save(req, res)\n\thttp.Redirect(res, req, \"/login\", 302)\n}\n\nfunc login(res http.ResponseWriter, req *http.Request) {\n\tsession, _ := store.Get(req, \"session\")\n\tif req.Method == \"POST\" && req.FormValue(\"password\") == \"secret\" {\n\t\tsession.Values[\"loggedin\"] = \"true\"\n\t\tsession.Save(req, res)\n\t\thttp.Redirect(res, req, \"/\", 302)\n\t\treturn\n\t}\n\t// execute template\n\ttpl.ExecuteTemplate(res, \"login.html\", nil)\n}\n\nfunc uploadPhoto(src multipart.File, hdr *multipart.FileHeader, session *sessions.Session) {\n\tdefer src.Close()\n\tfName := getSha(src) + \".jpg\"\n\twd, _ := os.Getwd()\n\tpath := filepath.Join(wd, \"assets\", \"imgs\", fName)\n\tdst, _ := os.Create(path)\n\tdefer dst.Close()\n\tsrc.Seek(0, 0)\n\tio.Copy(dst, src)\n\taddPhoto(fName, session)\n}\n\nfunc getSha(src multipart.File) string {\n\th := sha1.New()\n\tio.Copy(h, src)\n\treturn fmt.Sprintf(\"%x\", h.Sum(nil))\n}\n\nfunc addPhoto(fName string, session *sessions.Session) {\n\tdata := getPhotos(session)\n\tdata = append(data, fName)\n\tbs, _ := json.Marshal(data)\n\tsession.Values[\"data\"] = string(bs)\n}\n\nfunc getPhotos(session *sessions.Session) []string {\n\tvar data []string\n\tjsonData := session.Values[\"data\"]\n\tif jsonData != nil {\n\t\tjson.Unmarshal([]byte(jsonData.(string)), &data)\n\t}\n\treturn data\n}\n"
  },
  {
    "path": "27_code-in-process/99_svcc/46_HTTPS-TLS/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc handler(w http.ResponseWriter, req *http.Request) {\n\tw.Header().Set(\"Content-Type\", \"text/plain\")\n\tw.Write([]byte(\"This is an example server.\\n\"))\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", handler)\n\tlog.Printf(\"About to listen on 10443. Go to https://127.0.0.1:10443/\")\n\n\tgo http.ListenAndServe(\":9999\", nil)\n\terr := http.ListenAndServeTLS(\":10443\", \"cert.pem\", \"key.pem\", nil)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n}\n\n/*\nfor a self-signed certificate:\n\ngo run $(go env GOROOT)/src/crypto/tls/generate_cert.go --host=somedomainname.com\n\neg\n\ngo run $(go env GOROOT)/src/crypto/tls/generate_cert.go --host=localhost\n*/\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "All material is licensed under the Apache License Version 2.0, January 2004\nhttp://www.apache.org/licenses/LICENSE-2.0 \n"
  },
  {
    "path": "README.md",
    "content": "# GolangTraining\nTraining for Golang (go language)\n"
  }
]