whatcanGOwrong

This commit is contained in:
2024-09-19 21:38:24 -04:00
commit d0ae4d841d
17908 changed files with 4096831 additions and 0 deletions
@@ -0,0 +1,218 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"html/template"
"io"
"io/fs"
"log"
"net"
"net/http"
"os"
"path/filepath"
"sort"
"strings"
"golang.org/x/tools/present"
)
func init() {
http.HandleFunc("/", dirHandler)
}
// dirHandler serves a directory listing for the requested path, rooted at *contentPath.
func dirHandler(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/favicon.ico" {
http.NotFound(w, r)
return
}
name := filepath.Join(*contentPath, r.URL.Path)
if isDoc(name) {
err := renderDoc(w, name)
if err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
}
return
}
if isDir, err := dirList(w, name); err != nil {
addr, _, e := net.SplitHostPort(r.RemoteAddr)
if e != nil {
addr = r.RemoteAddr
}
log.Printf("request from %s: %s", addr, err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
} else if isDir {
return
}
http.FileServer(http.Dir(*contentPath)).ServeHTTP(w, r)
}
func isDoc(path string) bool {
_, ok := contentTemplate[filepath.Ext(path)]
return ok
}
var (
// dirListTemplate holds the front page template.
dirListTemplate *template.Template
// contentTemplate maps the presentable file extensions to the
// template to be executed.
contentTemplate map[string]*template.Template
)
func initTemplates(fsys fs.FS) error {
// Locate the template file.
actionTmpl := "templates/action.tmpl"
contentTemplate = make(map[string]*template.Template)
for ext, contentTmpl := range map[string]string{
".slide": "slides.tmpl",
".article": "article.tmpl",
} {
contentTmpl = "templates/" + contentTmpl
// Read and parse the input.
tmpl := present.Template()
tmpl = tmpl.Funcs(template.FuncMap{"playable": playable})
if _, err := tmpl.ParseFS(fsys, actionTmpl, contentTmpl); err != nil {
return err
}
contentTemplate[ext] = tmpl
}
var err error
dirListTemplate, err = template.ParseFS(fsys, "templates/dir.tmpl")
return err
}
// renderDoc reads the present file, gets its template representation,
// and executes the template, sending output to w.
func renderDoc(w io.Writer, docFile string) error {
// Read the input and build the doc structure.
doc, err := parse(docFile, 0)
if err != nil {
return err
}
// Find which template should be executed.
tmpl := contentTemplate[filepath.Ext(docFile)]
// Execute the template.
return doc.Render(w, tmpl)
}
func parse(name string, mode present.ParseMode) (*present.Doc, error) {
f, err := os.Open(name)
if err != nil {
return nil, err
}
defer f.Close()
return present.Parse(f, name, mode)
}
// dirList scans the given path and writes a directory listing to w.
// It parses the first part of each .slide file it encounters to display the
// presentation title in the listing.
// If the given path is not a directory, it returns (isDir == false, err == nil)
// and writes nothing to w.
func dirList(w io.Writer, name string) (isDir bool, err error) {
f, err := os.Open(name)
if err != nil {
return false, err
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
return false, err
}
if isDir = fi.IsDir(); !isDir {
return false, nil
}
fis, err := f.Readdir(0)
if err != nil {
return false, err
}
strippedPath := strings.TrimPrefix(name, filepath.Clean(*contentPath))
strippedPath = strings.TrimPrefix(strippedPath, "/")
d := &dirListData{Path: strippedPath}
for _, fi := range fis {
// skip the golang.org directory
if name == "." && fi.Name() == "golang.org" {
continue
}
e := dirEntry{
Name: fi.Name(),
Path: filepath.ToSlash(filepath.Join(strippedPath, fi.Name())),
}
if fi.IsDir() && showDir(e.Name) {
d.Dirs = append(d.Dirs, e)
continue
}
if isDoc(e.Name) {
fn := filepath.ToSlash(filepath.Join(name, fi.Name()))
if p, err := parse(fn, present.TitlesOnly); err != nil {
log.Printf("parse(%q, present.TitlesOnly): %v", fn, err)
} else {
e.Title = p.Title
}
switch filepath.Ext(e.Path) {
case ".article":
d.Articles = append(d.Articles, e)
case ".slide":
d.Slides = append(d.Slides, e)
}
} else if showFile(e.Name) {
d.Other = append(d.Other, e)
}
}
if d.Path == "." {
d.Path = ""
}
sort.Sort(d.Dirs)
sort.Sort(d.Slides)
sort.Sort(d.Articles)
sort.Sort(d.Other)
return true, dirListTemplate.Execute(w, d)
}
// showFile reports whether the given file should be displayed in the list.
func showFile(n string) bool {
switch filepath.Ext(n) {
case ".pdf":
case ".html":
case ".go":
default:
return isDoc(n)
}
return true
}
// showDir reports whether the given directory should be displayed in the list.
func showDir(n string) bool {
if len(n) > 0 && (n[0] == '.' || n[0] == '_') || n == "present" {
return false
}
return true
}
type dirListData struct {
Path string
Dirs, Slides, Articles, Other dirEntrySlice
}
type dirEntry struct {
Name, Path, Title string
}
type dirEntrySlice []dirEntry
func (s dirEntrySlice) Len() int { return len(s) }
func (s dirEntrySlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s dirEntrySlice) Less(i, j int) bool { return s[i].Name < s[j].Name }
@@ -0,0 +1,50 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Present displays slide presentations and articles. It runs a web server that
presents slide and article files from the current directory.
It may be run as a stand-alone command or an App Engine app.
To use with App Engine, copy the files in the tools/cmd/present directory to the
root of your application and create an app.yaml file similar to this:
runtime: go111
handlers:
- url: /favicon.ico
static_files: static/favicon.ico
upload: static/favicon.ico
- url: /static
static_dir: static
- url: /.*
script: auto
# nobuild_files is a regexp that identifies which files to not build. It
# is useful for embedding static assets like code snippets and preventing
# them from producing build errors for your project.
nobuild_files: [path regexp for talk materials]
When running on App Engine, content will be served from the ./content/
subdirectory.
Present then can be tested in a local App Engine environment with
GAE_ENV=standard go run .
And deployed using
gcloud app deploy
Input files are named foo.extension, where "extension" defines the format of
the generated output. The supported formats are:
.slide // HTML5 slide presentation
.article // article format, such as a blog post
The present file format is documented by the present package:
https://pkg.go.dev/golang.org/x/tools/present
*/
package main
@@ -0,0 +1,151 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"embed"
"flag"
"fmt"
"io/fs"
"log"
"net"
"net/http"
"net/url"
"os"
"strings"
"golang.org/x/tools/present"
)
var (
httpAddr = flag.String("http", "127.0.0.1:3999", "HTTP service address (e.g., '127.0.0.1:3999')")
originHost = flag.String("orighost", "", "host component of web origin URL (e.g., 'localhost')")
basePath = flag.String("base", "", "base path for slide template and static resources")
contentPath = flag.String("content", ".", "base path for presentation content")
usePlayground = flag.Bool("use_playground", false, "run code snippets using play.golang.org; if false, run them locally and deliver results by WebSocket transport")
)
//go:embed static templates
var embedFS embed.FS
func main() {
flag.BoolVar(&present.PlayEnabled, "play", true, "enable playground (permit execution of arbitrary user code)")
flag.BoolVar(&present.NotesEnabled, "notes", false, "enable presenter notes (press 'N' from the browser to display them)")
flag.Parse()
if os.Getenv("GAE_ENV") == "standard" {
log.Print("Configuring for App Engine Standard")
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
*httpAddr = fmt.Sprintf("0.0.0.0:%s", port)
pwd, err := os.Getwd()
if err != nil {
log.Fatalf("Couldn't get pwd: %v\n", err)
}
*basePath = pwd
*usePlayground = true
*contentPath = "./content/"
}
var fsys fs.FS = embedFS
if *basePath != "" {
fsys = os.DirFS(*basePath)
}
err := initTemplates(fsys)
if err != nil {
log.Fatalf("Failed to parse templates: %v", err)
}
ln, err := net.Listen("tcp", *httpAddr)
if err != nil {
log.Fatal(err)
}
defer ln.Close()
_, port, err := net.SplitHostPort(ln.Addr().String())
if err != nil {
log.Fatal(err)
}
origin := &url.URL{Scheme: "http"}
if *originHost != "" {
if strings.HasPrefix(*originHost, "https://") {
*originHost = strings.TrimPrefix(*originHost, "https://")
origin.Scheme = "https"
}
*originHost = strings.TrimPrefix(*originHost, "http://")
origin.Host = net.JoinHostPort(*originHost, port)
} else if ln.Addr().(*net.TCPAddr).IP.IsUnspecified() {
name, _ := os.Hostname()
origin.Host = net.JoinHostPort(name, port)
} else {
reqHost, reqPort, err := net.SplitHostPort(*httpAddr)
if err != nil {
log.Fatal(err)
}
if reqPort == "0" {
origin.Host = net.JoinHostPort(reqHost, port)
} else {
origin.Host = *httpAddr
}
}
initPlayground(fsys, origin)
http.Handle("/static/", http.FileServer(http.FS(fsys)))
if !ln.Addr().(*net.TCPAddr).IP.IsLoopback() &&
present.PlayEnabled && !*usePlayground {
log.Print(localhostWarning)
}
log.Printf("Open your web browser and visit %s", origin.String())
if present.NotesEnabled {
log.Println("Notes are enabled, press 'N' from the browser to display them.")
}
log.Fatal(http.Serve(ln, nil))
}
func environ(vars ...string) []string {
env := os.Environ()
for _, r := range vars {
k := strings.SplitAfter(r, "=")[0]
var found bool
for i, v := range env {
if strings.HasPrefix(v, k) {
env[i] = r
found = true
}
}
if !found {
env = append(env, r)
}
}
return env
}
const basePathMessage = `
By default, gopresent locates the slide template files and associated
static content by looking for a %q package
in your Go workspaces (GOPATH).
You may use the -base flag to specify an alternate location.
`
const localhostWarning = `
WARNING! WARNING! WARNING!
The present server appears to be listening on an address that is not localhost
and is configured to run code snippets locally. Anyone with access to this address
and port will have access to this machine as the user running present.
To avoid this message, listen on localhost, run with -play=false, or run with
-play_socket=false.
If you don't understand this message, hit Control-C to terminate this process.
WARNING! WARNING! WARNING!
`
@@ -0,0 +1,71 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"bytes"
"fmt"
"io/fs"
"net/http"
"net/url"
"time"
"golang.org/x/tools/playground/socket"
"golang.org/x/tools/present"
// This will register a handler at /compile that will proxy to the
// respective endpoints at play.golang.org. This allows the frontend to call
// these endpoints without needing cross-origin request sharing (CORS).
// Note that this is imported regardless of whether the endpoints are used or
// not (in the case of a local socket connection, they are not called).
_ "golang.org/x/tools/playground"
)
var scripts = []string{"jquery.js", "jquery-ui.js", "playground.js", "play.js"}
// playScript registers an HTTP handler at /play.js that serves all the
// scripts specified by the variable above, and appends a line that
// initializes the playground with the specified transport.
func playScript(fsys fs.FS, transport string) {
modTime := time.Now()
var buf bytes.Buffer
for _, p := range scripts {
b, err := fs.ReadFile(fsys, "static/"+p)
if err != nil {
panic(err)
}
buf.Write(b)
}
fmt.Fprintf(&buf, "\ninitPlayground(new %v());\n", transport)
b := buf.Bytes()
http.HandleFunc("/play.js", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-type", "application/javascript")
http.ServeContent(w, r, "", modTime, bytes.NewReader(b))
})
}
func initPlayground(fsys fs.FS, origin *url.URL) {
if !present.PlayEnabled {
return
}
if *usePlayground {
playScript(fsys, "HTTPTransport")
return
}
playScript(fsys, "SocketTransport")
http.Handle("/socket", socket.NewHandler(origin))
}
func playable(c present.Code) bool {
play := present.PlayEnabled && c.Play
// Restrict playable files to only Go source files when using play.golang.org,
// since there is no method to execute shell scripts there.
if *usePlayground {
return play && c.Ext == ".go"
}
return play
}
@@ -0,0 +1,183 @@
body {
margin: 0;
font-family: Helvetica, Arial, sans-serif;
font-size: 16px;
}
pre,
code {
font-family: Menlo, monospace;
font-size: 14px;
}
pre {
line-height: 18px;
margin: 0;
padding: 0;
}
a {
color: #375eab;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
p,
ul,
ol {
margin: 20px;
}
h1,
h2,
h3,
h4 {
margin: 20px 0;
padding: 0;
color: #375eab;
font-weight: bold;
}
h1 {
font-size: 18px;
padding: 2px 5px;
}
h2 {
font-size: 16px;
}
h3 {
font-size: 16px;
}
h3,
h4 {
margin: 20px 5px;
}
h4 {
font-size: 16px;
}
div#heading {
margin: 0 0 10px 0;
padding: 21px 0;
font-size: 20px;
font-weight: bold;
}
div#heading .author {
padding-top: 10px;
font-size: 14px;
font-weight: normal;
}
div#topbar {
}
body {
text-align: center;
}
div#page {
width: 100%;
}
div#page > .container,
div#topbar > .container {
text-align: left;
margin-left: auto;
margin-right: auto;
padding: 0 20px;
width: 900px;
}
div#page.wide > .container,
div#topbar.wide > .container {
width: auto;
}
div#footer {
text-align: center;
color: #666;
font-size: 14px;
margin: 40px 0;
}
.author p {
margin: 0;
padding: 0 20px;
}
div.code,
div.output {
margin: 0;
}
pre {
margin: 20px 20px 20px 40px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}
div.output pre {
padding: 10px;
}
pre {
background: white;
}
div.output pre {
background: black;
}
div.output .stdout pre {
color: #e6e6e6;
}
div.output .stderr pre {
color: rgb(244, 74, 63);
}
div.output .system pre {
color: rgb(255, 209, 77);
}
.buttons {
margin-left: 20px;
}
div.output .buttons {
margin-left: 0;
margin-bottom: 10px;
}
#toc {
float: right;
margin: 0px 10px;
padding: 10px;
border: 1px solid #e5ecf9;
background-color: #eee;
box-shadow: 3px 3px 2px #888888;
max-width: 33%;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}
#tochead {
font-weight: bold;
font-variant: small-caps;
font-size: 100%;
text-align: center;
padding-bottom: 5px;
}
#toc ul,
#toc a {
list-style-type: none;
padding-left: 0px;
color: black;
margin: 0px;
}
ul.toc-inner a {
padding-left: 10px !important;
}
@media print {
.no-print,
.no-print * {
display: none !important;
}
}
@@ -0,0 +1,186 @@
/* copied from $GOROOT/doc/style.css */
body {
margin: 0;
font-family: Helvetica, Arial, sans-serif;
font-size: 16px;
}
pre,
code {
font-family: Menlo, monospace;
font-size: 14px;
}
pre {
line-height: 18px;
}
pre .comment {
color: #375eab;
}
pre .highlight,
pre .highlight-comment,
pre .selection-highlight,
pre .selection-highlight-comment {
background: #ffff00;
}
pre .selection,
pre .selection-comment {
background: #ff9632;
}
pre .ln {
color: #999;
}
body {
color: #222;
}
a,
.exampleHeading .text {
color: #375eab;
text-decoration: none;
}
a:hover,
.exampleHeading .text:hover {
text-decoration: underline;
}
p,
pre,
ul,
ol {
margin: 20px;
}
pre {
background: #e9e9e9;
padding: 10px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}
h1,
h2,
h3,
h4,
.rootHeading {
margin: 20px 0;
padding: 0;
color: #375eab;
font-weight: bold;
}
h1 {
font-size: 24px;
}
h2 {
font-size: 20px;
background: #e0ebf5;
padding: 2px 5px;
}
h3 {
font-size: 20px;
}
h3,
h4 {
margin: 20px 5px;
}
h4 {
font-size: 16px;
}
dl {
margin: 20px;
}
dd {
margin: 2px 20px;
}
dl,
dd {
font-size: 14px;
}
div#nav table td {
vertical-align: top;
}
div#heading {
float: left;
margin: 0 0 10px 0;
padding: 21px 0;
font-size: 20px;
font-weight: normal;
}
div#heading a {
color: #222;
text-decoration: none;
}
div#topbar {
background: #e0ebf5;
height: 64px;
}
body {
text-align: center;
}
div#page,
div#topbar > .container {
clear: both;
text-align: left;
margin-left: auto;
margin-right: auto;
padding: 0 20px;
width: 900px;
}
div#page.wide,
div#topbar > .wide {
width: auto;
}
div#plusone {
float: right;
}
div#footer {
color: #666;
font-size: 14px;
margin: 40px 0;
}
div#menu > a,
div#menu > input {
padding: 10px;
text-decoration: none;
font-size: 16px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}
div#menu > a,
div#menu > input {
border: 1px solid #375eab;
}
div#menu > a {
color: white;
background: #375eab;
}
div#menu {
float: right;
min-width: 590px;
padding: 10px 0;
text-align: right;
}
div#menu > a {
margin-right: 5px;
margin-bottom: 10px;
padding: 10px;
}
div#menu > input {
position: relative;
top: 1px;
width: 60px;
background: white;
color: #222;
}
div#menu > input.inactive {
color: #999;
}
@@ -0,0 +1,41 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// copied from $GOROOT/doc/godocs.js
function bindEvent(el, e, fn) {
if (el.addEventListener) {
el.addEventListener(e, fn, false);
} else if (el.attachEvent) {
el.attachEvent('on' + e, fn);
}
}
function godocs_bindSearchEvents() {
var search = document.getElementById('search');
if (!search) {
// no search box (index disabled)
return;
}
function clearInactive() {
if (search.className == 'inactive') {
search.value = '';
search.className = '';
}
}
function restoreInactive() {
if (search.value !== '') {
return;
}
if (search.type != 'search') {
search.value = search.getAttribute('placeholder');
}
search.className = 'inactive';
}
restoreInactive();
bindEvent(search, 'focus', clearInactive);
bindEvent(search, 'blur', restoreInactive);
}
bindEvent(window, 'load', godocs_bindSearchEvents);
Binary file not shown.

After

Width:  |  Height:  |  Size: 785 B

File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,32 @@
p {
margin: 10px;
}
#presenter-slides {
display: block;
margin-top: -10px;
margin-left: -17px;
position: fixed;
border: 0;
width: 146%;
height: 750px;
transform: scale(0.7, 0.7);
transform-origin: top left;
-moz-transform: scale(0.7);
-moz-transform-origin: top left;
-o-transform: scale(0.7);
-o-transform-origin: top left;
-webkit-transform: scale(0.7);
-webkit-transform-origin: top left;
}
#presenter-notes {
margin-top: -180px;
font-family: 'Open Sans', Arial, sans-serif;
height: 30%;
width: 100%;
overflow: scroll;
position: fixed;
top: 706px;
}
@@ -0,0 +1,175 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Store child window object which will display slides with notes
var notesWindow = null;
var isParentWindow = window.parent == window;
// When parent window closes, clear storage and close child window
if (isParentWindow) {
window.onbeforeunload = function() {
localStorage.clear();
if (notesWindow) notesWindow.close();
};
}
function toggleNotesWindow() {
if (!isParentWindow) return;
if (notesWindow) {
notesWindow.close();
notesWindow = null;
return;
}
initNotes();
}
// Create a unique key for the local storage so we don't mix the
// destSlide of different presentations. For golang.org/issue/24688.
function destSlideKey() {
var key = '';
if (notesWindow) {
var slides = notesWindow.document.getElementById('presenter-slides');
key = slides.src.split('#')[0];
} else {
key = window.location.href.split('#')[0];
}
return 'destSlide:' + key;
}
function initNotes() {
notesWindow = window.open('', '', 'width=1000,height=700');
var w = notesWindow;
var slidesUrl = window.location.href;
// Hack to apply css. Requires existing html on notesWindow.
w.document.write("<div style='display:none;'></div>");
w.document.title = window.document.title;
var slides = w.document.createElement('iframe');
slides.id = 'presenter-slides';
slides.src = slidesUrl;
w.document.body.appendChild(slides);
var curSlide = parseInt(localStorage.getItem(destSlideKey()), 10);
var formattedNotes = '';
var section = sections[curSlide - 1];
// curSlide is 0 when initialized from the first page of slides.
// Check if section is valid before retrieving Notes.
if (section) {
formattedNotes = formatNotes(section.Notes);
} else if (curSlide == 0) {
formattedNotes = formatNotes(titleNotes);
}
// setTimeout needed for Firefox
setTimeout(function() {
slides.focus();
}, 100);
var notes = w.document.createElement('div');
notes.id = 'presenter-notes';
notes.innerHTML = formattedNotes;
w.document.body.appendChild(notes);
w.document.close();
function addPresenterNotesStyle() {
var el = w.document.createElement('link');
el.rel = 'stylesheet';
el.type = 'text/css';
el.href = PERMANENT_URL_PREFIX + 'notes.css';
w.document.body.appendChild(el);
w.document.querySelector('head').appendChild(el);
}
addPresenterNotesStyle();
// Add listener on notesWindow to update notes when triggered from
// parent window
w.addEventListener('storage', updateNotes, false);
}
function formatNotes(notes) {
var formattedNotes = '';
if (notes) {
for (var i = 0; i < notes.length; i++) {
formattedNotes = formattedNotes + '<p>' + notes[i] + '</p>';
}
}
return formattedNotes;
}
function updateNotes() {
// When triggered from parent window, notesWindow is null
// The storage event listener on notesWindow will update notes
if (!notesWindow) return;
var destSlide = parseInt(localStorage.getItem(destSlideKey()), 10);
var section = sections[destSlide - 1];
var el = notesWindow.document.getElementById('presenter-notes');
if (!el) return;
if (section && section.Notes) {
el.innerHTML = formatNotes(section.Notes);
} else if (destSlide == 0) {
el.innerHTML = formatNotes(titleNotes);
} else {
el.innerHTML = '';
}
}
/* Playground syncing */
// When presenter notes are enabled, playground click handlers are
// stored here to sync click events on the correct playground
var playgroundHandlers = { onRun: [], onKill: [], onClose: [] };
function updatePlay(e) {
var i = localStorage.getItem('play-index');
switch (e.key) {
case 'play-index':
return;
case 'play-action':
// Sync 'run', 'kill', 'close' actions
var action = localStorage.getItem('play-action');
playgroundHandlers[action][i](e);
return;
case 'play-code':
// Sync code editing
var play = document.querySelectorAll('div.playground')[i];
play.innerHTML = localStorage.getItem('play-code');
return;
case 'output-style':
// Sync resizing of playground output
var out = document.querySelectorAll('.output')[i];
out.style = localStorage.getItem('output-style');
return;
}
}
// Reset 'run', 'kill', 'close' storage items when synced
// so that successive actions can be synced correctly
function updatePlayStorage(action, index, e) {
localStorage.setItem('play-index', index);
if (localStorage.getItem('play-action') === action) {
// We're the receiving window, and the message has been received
localStorage.removeItem('play-action');
} else {
// We're the triggering window, send the message
localStorage.setItem('play-action', action);
}
if (action === 'onRun') {
if (localStorage.getItem('play-shiftKey') === 'true') {
localStorage.removeItem('play-shiftKey');
} else if (e.shiftKey) {
localStorage.setItem('play-shiftKey', e.shiftKey);
}
}
}
@@ -0,0 +1,114 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
function initPlayground(transport) {
'use strict';
function text(node) {
var s = '';
for (var i = 0; i < node.childNodes.length; i++) {
var n = node.childNodes[i];
if (n.nodeType === 1) {
if (n.tagName === 'BUTTON') continue;
if (n.tagName === 'SPAN' && n.className === 'number') continue;
if (n.tagName === 'DIV' || n.tagName === 'BR' || n.tagName === 'PRE') {
s += '\n';
}
s += text(n);
continue;
}
if (n.nodeType === 3) {
s += n.nodeValue;
}
}
return s.replace('\xA0', ' '); // replace non-breaking spaces
}
// When presenter notes are enabled, the index passed
// here will identify the playground to be synced
function init(code, index) {
var output = document.createElement('div');
var outpre = document.createElement('pre');
var running;
if ($ && $(output).resizable) {
$(output).resizable({
handles: 'n,w,nw',
minHeight: 27,
minWidth: 135,
maxHeight: 608,
maxWidth: 990,
});
}
function onKill() {
if (running) running.Kill();
if (window.notesEnabled) updatePlayStorage('onKill', index);
}
function onRun(e) {
var sk = e.shiftKey || localStorage.getItem('play-shiftKey') === 'true';
if (running) running.Kill();
output.style.display = 'block';
outpre.textContent = '';
run1.style.display = 'none';
var options = { Race: sk };
running = transport.Run(text(code), PlaygroundOutput(outpre), options);
if (window.notesEnabled) updatePlayStorage('onRun', index, e);
}
function onClose() {
if (running) running.Kill();
output.style.display = 'none';
run1.style.display = 'inline-block';
if (window.notesEnabled) updatePlayStorage('onClose', index);
}
if (window.notesEnabled) {
playgroundHandlers.onRun.push(onRun);
playgroundHandlers.onClose.push(onClose);
playgroundHandlers.onKill.push(onKill);
}
var run1 = document.createElement('button');
run1.textContent = 'Run';
run1.className = 'run';
run1.addEventListener('click', onRun, false);
var run2 = document.createElement('button');
run2.className = 'run';
run2.textContent = 'Run';
run2.addEventListener('click', onRun, false);
var kill = document.createElement('button');
kill.className = 'kill';
kill.textContent = 'Kill';
kill.addEventListener('click', onKill, false);
var close = document.createElement('button');
close.className = 'close';
close.textContent = 'Close';
close.addEventListener('click', onClose, false);
var button = document.createElement('div');
button.classList.add('buttons');
button.appendChild(run1);
// Hack to simulate insertAfter
code.parentNode.insertBefore(button, code.nextSibling);
var buttons = document.createElement('div');
buttons.classList.add('buttons');
buttons.appendChild(run2);
buttons.appendChild(kill);
buttons.appendChild(close);
output.classList.add('output');
output.appendChild(buttons);
output.appendChild(outpre);
output.style.display = 'none';
code.parentNode.insertBefore(output, button.nextSibling);
}
var play = document.querySelectorAll('div.playground');
for (var i = 0; i < play.length; i++) {
init(play[i], i);
}
}
@@ -0,0 +1,593 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
In the absence of any formal way to specify interfaces in JavaScript,
here's a skeleton implementation of a playground transport.
function Transport() {
// Set up any transport state (eg, make a websocket connection).
return {
Run: function(body, output, options) {
// Compile and run the program 'body' with 'options'.
// Call the 'output' callback to display program output.
return {
Kill: function() {
// Kill the running program.
}
};
}
};
}
// The output callback is called multiple times, and each time it is
// passed an object of this form.
var write = {
Kind: 'string', // 'start', 'stdout', 'stderr', 'end'
Body: 'string' // content of write or end status message
}
// The first call must be of Kind 'start' with no body.
// Subsequent calls may be of Kind 'stdout' or 'stderr'
// and must have a non-null Body string.
// The final call should be of Kind 'end' with an optional
// Body string, signifying a failure ("killed", for example).
// The output callback must be of this form.
// See PlaygroundOutput (below) for an implementation.
function outputCallback(write) {
}
*/
// HTTPTransport is the default transport.
// enableVet enables running vet if a program was compiled and ran successfully.
// If vet returned any errors, display them before the output of a program.
function HTTPTransport(enableVet) {
'use strict';
function playback(output, data) {
// Backwards compatibility: default values do not affect the output.
var events = data.Events || [];
var errors = data.Errors || '';
var status = data.Status || 0;
var isTest = data.IsTest || false;
var testsFailed = data.TestsFailed || 0;
var timeout;
output({ Kind: 'start' });
function next() {
if (!events || events.length === 0) {
if (isTest) {
if (testsFailed > 0) {
output({
Kind: 'system',
Body:
'\n' +
testsFailed +
' test' +
(testsFailed > 1 ? 's' : '') +
' failed.',
});
} else {
output({ Kind: 'system', Body: '\nAll tests passed.' });
}
} else {
if (status > 0) {
output({ Kind: 'end', Body: 'status ' + status + '.' });
} else {
if (errors !== '') {
// errors are displayed only in the case of timeout.
output({ Kind: 'end', Body: errors + '.' });
} else {
output({ Kind: 'end' });
}
}
}
return;
}
var e = events.shift();
if (e.Delay === 0) {
output({ Kind: e.Kind, Body: e.Message });
next();
return;
}
timeout = setTimeout(function() {
output({ Kind: e.Kind, Body: e.Message });
next();
}, e.Delay / 1000000);
}
next();
return {
Stop: function() {
clearTimeout(timeout);
},
};
}
function error(output, msg) {
output({ Kind: 'start' });
output({ Kind: 'stderr', Body: msg });
output({ Kind: 'end' });
}
function buildFailed(output, msg) {
output({ Kind: 'start' });
output({ Kind: 'stderr', Body: msg });
output({ Kind: 'system', Body: '\nGo build failed.' });
}
var seq = 0;
return {
Run: function(body, output, options) {
seq++;
var cur = seq;
var playing;
$.ajax('/compile', {
type: 'POST',
data: { version: 2, body: body, withVet: enableVet },
dataType: 'json',
success: function(data) {
if (seq != cur) return;
if (!data) return;
if (playing != null) playing.Stop();
if (data.Errors) {
if (data.Errors === 'process took too long') {
// Playback the output that was captured before the timeout.
playing = playback(output, data);
} else {
buildFailed(output, data.Errors);
}
return;
}
if (!data.Events) {
data.Events = [];
}
if (data.VetErrors) {
// Inject errors from the vet as the first events in the output.
data.Events.unshift({
Message: 'Go vet exited.\n\n',
Kind: 'system',
Delay: 0,
});
data.Events.unshift({
Message: data.VetErrors,
Kind: 'stderr',
Delay: 0,
});
}
if (!enableVet || data.VetOK || data.VetErrors) {
playing = playback(output, data);
return;
}
// In case the server support doesn't support
// compile+vet in same request signaled by the
// 'withVet' parameter above, also try the old way.
// TODO: remove this when it falls out of use.
// It is 2019-05-13 now.
$.ajax('/vet', {
data: { body: body },
type: 'POST',
dataType: 'json',
success: function(dataVet) {
if (dataVet.Errors) {
// inject errors from the vet as the first events in the output
data.Events.unshift({
Message: 'Go vet exited.\n\n',
Kind: 'system',
Delay: 0,
});
data.Events.unshift({
Message: dataVet.Errors,
Kind: 'stderr',
Delay: 0,
});
}
playing = playback(output, data);
},
error: function() {
playing = playback(output, data);
},
});
},
error: function() {
error(output, 'Error communicating with remote server.');
},
});
return {
Kill: function() {
if (playing != null) playing.Stop();
output({ Kind: 'end', Body: 'killed' });
},
};
},
};
}
function SocketTransport() {
'use strict';
var id = 0;
var outputs = {};
var started = {};
var websocket;
if (window.location.protocol == 'http:') {
websocket = new WebSocket('ws://' + window.location.host + '/socket');
} else if (window.location.protocol == 'https:') {
websocket = new WebSocket('wss://' + window.location.host + '/socket');
}
websocket.onclose = function() {
console.log('websocket connection closed');
};
websocket.onmessage = function(e) {
var m = JSON.parse(e.data);
var output = outputs[m.Id];
if (output === null) return;
if (!started[m.Id]) {
output({ Kind: 'start' });
started[m.Id] = true;
}
output({ Kind: m.Kind, Body: m.Body });
};
function send(m) {
websocket.send(JSON.stringify(m));
}
return {
Run: function(body, output, options) {
var thisID = id + '';
id++;
outputs[thisID] = output;
send({ Id: thisID, Kind: 'run', Body: body, Options: options });
return {
Kill: function() {
send({ Id: thisID, Kind: 'kill' });
},
};
},
};
}
function PlaygroundOutput(el) {
'use strict';
return function(write) {
if (write.Kind == 'start') {
el.innerHTML = '';
return;
}
var cl = 'system';
if (write.Kind == 'stdout' || write.Kind == 'stderr') cl = write.Kind;
var m = write.Body;
if (write.Kind == 'end') {
m = '\nProgram exited' + (m ? ': ' + m : '.');
}
if (m.indexOf('IMAGE:') === 0) {
// TODO(adg): buffer all writes before creating image
var url = 'data:image/png;base64,' + m.substr(6);
var img = document.createElement('img');
img.src = url;
el.appendChild(img);
return;
}
// ^L clears the screen.
var s = m.split('\x0c');
if (s.length > 1) {
el.innerHTML = '';
m = s.pop();
}
m = m.replace(/&/g, '&amp;');
m = m.replace(/</g, '&lt;');
m = m.replace(/>/g, '&gt;');
var needScroll = el.scrollTop + el.offsetHeight == el.scrollHeight;
var span = document.createElement('span');
span.className = cl;
span.innerHTML = m;
el.appendChild(span);
if (needScroll) el.scrollTop = el.scrollHeight - el.offsetHeight;
};
}
(function() {
function lineHighlight(error) {
var regex = /prog.go:([0-9]+)/g;
var r = regex.exec(error);
while (r) {
$('.lines div')
.eq(r[1] - 1)
.addClass('lineerror');
r = regex.exec(error);
}
}
function highlightOutput(wrappedOutput) {
return function(write) {
if (write.Body) lineHighlight(write.Body);
wrappedOutput(write);
};
}
function lineClear() {
$('.lineerror').removeClass('lineerror');
}
// opts is an object with these keys
// codeEl - code editor element
// outputEl - program output element
// runEl - run button element
// fmtEl - fmt button element (optional)
// fmtImportEl - fmt "imports" checkbox element (optional)
// shareEl - share button element (optional)
// shareURLEl - share URL text input element (optional)
// shareRedirect - base URL to redirect to on share (optional)
// toysEl - toys select element (optional)
// enableHistory - enable using HTML5 history API (optional)
// transport - playground transport to use (default is HTTPTransport)
// enableShortcuts - whether to enable shortcuts (Ctrl+S/Cmd+S to save) (default is false)
// enableVet - enable running vet and displaying its errors
function playground(opts) {
var code = $(opts.codeEl);
var transport = opts['transport'] || new HTTPTransport(opts['enableVet']);
var running;
// autoindent helpers.
function insertTabs(n) {
// find the selection start and end
var start = code[0].selectionStart;
var end = code[0].selectionEnd;
// split the textarea content into two, and insert n tabs
var v = code[0].value;
var u = v.substr(0, start);
for (var i = 0; i < n; i++) {
u += '\t';
}
u += v.substr(end);
// set revised content
code[0].value = u;
// reset caret position after inserted tabs
code[0].selectionStart = start + n;
code[0].selectionEnd = start + n;
}
function autoindent(el) {
var curpos = el.selectionStart;
var tabs = 0;
while (curpos > 0) {
curpos--;
if (el.value[curpos] == '\t') {
tabs++;
} else if (tabs > 0 || el.value[curpos] == '\n') {
break;
}
}
setTimeout(function() {
insertTabs(tabs);
}, 1);
}
// NOTE(cbro): e is a jQuery event, not a DOM event.
function handleSaveShortcut(e) {
if (e.isDefaultPrevented()) return false;
if (!e.metaKey && !e.ctrlKey) return false;
if (e.key != 'S' && e.key != 's') return false;
e.preventDefault();
// Share and save
share(function(url) {
window.location.href = url + '.go?download=true';
});
return true;
}
function keyHandler(e) {
if (opts.enableShortcuts && handleSaveShortcut(e)) return;
if (e.keyCode == 9 && !e.ctrlKey) {
// tab (but not ctrl-tab)
insertTabs(1);
e.preventDefault();
return false;
}
if (e.keyCode == 13) {
// enter
if (e.shiftKey) {
// +shift
run();
e.preventDefault();
return false;
}
if (e.ctrlKey) {
// +control
fmt();
e.preventDefault();
} else {
autoindent(e.target);
}
}
return true;
}
code.unbind('keydown').bind('keydown', keyHandler);
var outdiv = $(opts.outputEl).empty();
var output = $('<pre/>').appendTo(outdiv);
function body() {
return $(opts.codeEl).val();
}
function setBody(text) {
$(opts.codeEl).val(text);
}
function origin(href) {
return ('' + href)
.split('/')
.slice(0, 3)
.join('/');
}
var pushedEmpty = window.location.pathname == '/';
function inputChanged() {
if (pushedEmpty) {
return;
}
pushedEmpty = true;
$(opts.shareURLEl).hide();
window.history.pushState(null, '', '/');
}
function popState(e) {
if (e === null) {
return;
}
if (e && e.state && e.state.code) {
setBody(e.state.code);
}
}
var rewriteHistory = false;
if (
window.history &&
window.history.pushState &&
window.addEventListener &&
opts.enableHistory
) {
rewriteHistory = true;
code[0].addEventListener('input', inputChanged);
window.addEventListener('popstate', popState);
}
function setError(error) {
if (running) running.Kill();
lineClear();
lineHighlight(error);
output
.empty()
.addClass('error')
.text(error);
}
function loading() {
lineClear();
if (running) running.Kill();
output.removeClass('error').text('Waiting for remote server...');
}
function run() {
loading();
running = transport.Run(
body(),
highlightOutput(PlaygroundOutput(output[0]))
);
}
function fmt() {
loading();
var data = { body: body() };
if ($(opts.fmtImportEl).is(':checked')) {
data['imports'] = 'true';
}
$.ajax('/fmt', {
data: data,
type: 'POST',
dataType: 'json',
success: function(data) {
if (data.Error) {
setError(data.Error);
} else {
setBody(data.Body);
setError('');
}
},
});
}
var shareURL; // jQuery element to show the shared URL.
var sharing = false; // true if there is a pending request.
var shareCallbacks = [];
function share(opt_callback) {
if (opt_callback) shareCallbacks.push(opt_callback);
if (sharing) return;
sharing = true;
var sharingData = body();
$.ajax('https://play.golang.org/share', {
processData: false,
data: sharingData,
type: 'POST',
contentType: 'text/plain; charset=utf-8',
complete: function(xhr) {
sharing = false;
if (xhr.status != 200) {
alert('Server error; try again.');
return;
}
if (opts.shareRedirect) {
window.location = opts.shareRedirect + xhr.responseText;
}
var path = '/p/' + xhr.responseText;
var url = origin(window.location) + path;
for (var i = 0; i < shareCallbacks.length; i++) {
shareCallbacks[i](url);
}
shareCallbacks = [];
if (shareURL) {
shareURL
.show()
.val(url)
.focus()
.select();
if (rewriteHistory) {
var historyData = { code: sharingData };
window.history.pushState(historyData, '', path);
pushedEmpty = false;
}
}
},
});
}
$(opts.runEl).click(run);
$(opts.fmtEl).click(fmt);
if (
opts.shareEl !== null &&
(opts.shareURLEl !== null || opts.shareRedirect !== null)
) {
if (opts.shareURLEl) {
shareURL = $(opts.shareURLEl).hide();
}
$(opts.shareEl).click(function() {
share();
});
}
if (opts.toysEl !== null) {
$(opts.toysEl).bind('change', function() {
var toy = $(this).val();
$.ajax('/doc/play/' + toy, {
processData: false,
type: 'GET',
complete: function(xhr) {
if (xhr.status != 200) {
alert('Server error; try again.');
return;
}
setBody(xhr.responseText);
},
});
});
}
}
window.playground = playground;
})();
@@ -0,0 +1,635 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
var PERMANENT_URL_PREFIX = '/static/';
var SLIDE_CLASSES = ['far-past', 'past', 'current', 'next', 'far-next'];
var PM_TOUCH_SENSITIVITY = 15;
var curSlide;
/* ---------------------------------------------------------------------- */
/* classList polyfill by Eli Grey
* (http://purl.eligrey.com/github/classList.js/blob/master/classList.js) */
if (
typeof document !== 'undefined' &&
!('classList' in document.createElement('a'))
) {
(function(view) {
var classListProp = 'classList',
protoProp = 'prototype',
elemCtrProto = (view.HTMLElement || view.Element)[protoProp],
objCtr = Object;
(strTrim =
String[protoProp].trim ||
function() {
return this.replace(/^\s+|\s+$/g, '');
}),
(arrIndexOf =
Array[protoProp].indexOf ||
function(item) {
for (var i = 0, len = this.length; i < len; i++) {
if (i in this && this[i] === item) {
return i;
}
}
return -1;
}),
// Vendors: please allow content code to instantiate DOMExceptions
(DOMEx = function(type, message) {
this.name = type;
this.code = DOMException[type];
this.message = message;
}),
(checkTokenAndGetIndex = function(classList, token) {
if (token === '') {
throw new DOMEx(
'SYNTAX_ERR',
'An invalid or illegal string was specified'
);
}
if (/\s/.test(token)) {
throw new DOMEx(
'INVALID_CHARACTER_ERR',
'String contains an invalid character'
);
}
return arrIndexOf.call(classList, token);
}),
(ClassList = function(elem) {
var trimmedClasses = strTrim.call(elem.className),
classes = trimmedClasses ? trimmedClasses.split(/\s+/) : [];
for (var i = 0, len = classes.length; i < len; i++) {
this.push(classes[i]);
}
this._updateClassName = function() {
elem.className = this.toString();
};
}),
(classListProto = ClassList[protoProp] = []),
(classListGetter = function() {
return new ClassList(this);
});
// Most DOMException implementations don't allow calling DOMException's toString()
// on non-DOMExceptions. Error's toString() is sufficient here.
DOMEx[protoProp] = Error[protoProp];
classListProto.item = function(i) {
return this[i] || null;
};
classListProto.contains = function(token) {
token += '';
return checkTokenAndGetIndex(this, token) !== -1;
};
classListProto.add = function(token) {
token += '';
if (checkTokenAndGetIndex(this, token) === -1) {
this.push(token);
this._updateClassName();
}
};
classListProto.remove = function(token) {
token += '';
var index = checkTokenAndGetIndex(this, token);
if (index !== -1) {
this.splice(index, 1);
this._updateClassName();
}
};
classListProto.toggle = function(token) {
token += '';
if (checkTokenAndGetIndex(this, token) === -1) {
this.add(token);
} else {
this.remove(token);
}
};
classListProto.toString = function() {
return this.join(' ');
};
if (objCtr.defineProperty) {
var classListPropDesc = {
get: classListGetter,
enumerable: true,
configurable: true,
};
try {
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
} catch (ex) {
// IE 8 doesn't support enumerable:true
if (ex.number === -0x7ff5ec54) {
classListPropDesc.enumerable = false;
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
}
}
} else if (objCtr[protoProp].__defineGetter__) {
elemCtrProto.__defineGetter__(classListProp, classListGetter);
}
})(self);
}
/* ---------------------------------------------------------------------- */
/* Slide movement */
function hideHelpText() {
document.getElementById('help').style.display = 'none';
}
function getSlideEl(no) {
if (no < 0 || no >= slideEls.length) {
return null;
} else {
return slideEls[no];
}
}
function updateSlideClass(slideNo, className) {
var el = getSlideEl(slideNo);
if (!el) {
return;
}
if (className) {
el.classList.add(className);
}
for (var i in SLIDE_CLASSES) {
if (className != SLIDE_CLASSES[i]) {
el.classList.remove(SLIDE_CLASSES[i]);
}
}
}
function updateSlides() {
if (window.trackPageview) window.trackPageview();
for (var i = 0; i < slideEls.length; i++) {
switch (i) {
case curSlide - 2:
updateSlideClass(i, 'far-past');
break;
case curSlide - 1:
updateSlideClass(i, 'past');
break;
case curSlide:
updateSlideClass(i, 'current');
break;
case curSlide + 1:
updateSlideClass(i, 'next');
break;
case curSlide + 2:
updateSlideClass(i, 'far-next');
break;
default:
updateSlideClass(i);
break;
}
}
triggerLeaveEvent(curSlide - 1);
triggerEnterEvent(curSlide);
window.setTimeout(function() {
// Hide after the slide
disableSlideFrames(curSlide - 2);
}, 301);
enableSlideFrames(curSlide - 1);
enableSlideFrames(curSlide + 2);
updateHash();
}
function prevSlide() {
hideHelpText();
if (curSlide > 0) {
curSlide--;
updateSlides();
}
if (notesEnabled) localStorage.setItem(destSlideKey(), curSlide);
}
function nextSlide() {
hideHelpText();
if (curSlide < slideEls.length - 1) {
curSlide++;
updateSlides();
}
if (notesEnabled) localStorage.setItem(destSlideKey(), curSlide);
}
/* Slide events */
function triggerEnterEvent(no) {
var el = getSlideEl(no);
if (!el) {
return;
}
var onEnter = el.getAttribute('onslideenter');
if (onEnter) {
new Function(onEnter).call(el);
}
var evt = document.createEvent('Event');
evt.initEvent('slideenter', true, true);
evt.slideNumber = no + 1; // Make it readable
el.dispatchEvent(evt);
}
function triggerLeaveEvent(no) {
var el = getSlideEl(no);
if (!el) {
return;
}
var onLeave = el.getAttribute('onslideleave');
if (onLeave) {
new Function(onLeave).call(el);
}
var evt = document.createEvent('Event');
evt.initEvent('slideleave', true, true);
evt.slideNumber = no + 1; // Make it readable
el.dispatchEvent(evt);
}
/* Touch events */
function handleTouchStart(event) {
if (event.touches.length == 1) {
touchDX = 0;
touchDY = 0;
touchStartX = event.touches[0].pageX;
touchStartY = event.touches[0].pageY;
document.body.addEventListener('touchmove', handleTouchMove, true);
document.body.addEventListener('touchend', handleTouchEnd, true);
}
}
function handleTouchMove(event) {
if (event.touches.length > 1) {
cancelTouch();
} else {
touchDX = event.touches[0].pageX - touchStartX;
touchDY = event.touches[0].pageY - touchStartY;
event.preventDefault();
}
}
function handleTouchEnd(event) {
var dx = Math.abs(touchDX);
var dy = Math.abs(touchDY);
if (dx > PM_TOUCH_SENSITIVITY && dy < (dx * 2) / 3) {
if (touchDX > 0) {
prevSlide();
} else {
nextSlide();
}
}
cancelTouch();
}
function cancelTouch() {
document.body.removeEventListener('touchmove', handleTouchMove, true);
document.body.removeEventListener('touchend', handleTouchEnd, true);
}
/* Preloading frames */
function disableSlideFrames(no) {
var el = getSlideEl(no);
if (!el) {
return;
}
var frames = el.getElementsByTagName('iframe');
for (var i = 0, frame; (frame = frames[i]); i++) {
disableFrame(frame);
}
}
function enableSlideFrames(no) {
var el = getSlideEl(no);
if (!el) {
return;
}
var frames = el.getElementsByTagName('iframe');
for (var i = 0, frame; (frame = frames[i]); i++) {
enableFrame(frame);
}
}
function disableFrame(frame) {
frame.src = 'about:blank';
}
function enableFrame(frame) {
var src = frame._src;
if (frame.src != src && src != 'about:blank') {
frame.src = src;
}
}
function setupFrames() {
var frames = document.querySelectorAll('iframe');
for (var i = 0, frame; (frame = frames[i]); i++) {
frame._src = frame.src;
disableFrame(frame);
}
enableSlideFrames(curSlide);
enableSlideFrames(curSlide + 1);
enableSlideFrames(curSlide + 2);
}
function setupInteraction() {
/* Clicking and tapping */
var el = document.createElement('div');
el.className = 'slide-area';
el.id = 'prev-slide-area';
el.addEventListener('click', prevSlide, false);
document.querySelector('section.slides').appendChild(el);
var el = document.createElement('div');
el.className = 'slide-area';
el.id = 'next-slide-area';
el.addEventListener('click', nextSlide, false);
document.querySelector('section.slides').appendChild(el);
/* Swiping */
document.body.addEventListener('touchstart', handleTouchStart, false);
}
/* Hash functions */
function getCurSlideFromHash() {
var slideNo = parseInt(location.hash.substr(1));
if (slideNo) {
curSlide = slideNo - 1;
} else {
curSlide = 0;
}
}
function updateHash() {
location.replace('#' + (curSlide + 1));
}
/* Event listeners */
function handleBodyKeyDown(event) {
// If we're in a code element, only handle pgup/down.
var inCode = event.target.classList.contains('code');
switch (event.keyCode) {
case 78: // 'N' opens presenter notes window
if (!inCode && notesEnabled) toggleNotesWindow();
break;
case 72: // 'H' hides the help text
case 27: // escape key
if (!inCode) hideHelpText();
break;
case 39: // right arrow
case 13: // Enter
case 32: // space
if (inCode) break;
case 34: // PgDn
nextSlide();
event.preventDefault();
break;
case 37: // left arrow
case 8: // Backspace
if (inCode) break;
case 33: // PgUp
prevSlide();
event.preventDefault();
break;
case 40: // down arrow
if (inCode) break;
nextSlide();
event.preventDefault();
break;
case 38: // up arrow
if (inCode) break;
prevSlide();
event.preventDefault();
break;
}
}
function scaleSmallViewports() {
var el = document.querySelector('section.slides');
var transform = '';
var sWidthPx = 1250;
var sHeightPx = 750;
var sAspectRatio = sWidthPx / sHeightPx;
var wAspectRatio = window.innerWidth / window.innerHeight;
if (wAspectRatio <= sAspectRatio && window.innerWidth < sWidthPx) {
transform = 'scale(' + window.innerWidth / sWidthPx + ')';
} else if (window.innerHeight < sHeightPx) {
transform = 'scale(' + window.innerHeight / sHeightPx + ')';
}
el.style.transform = transform;
}
function addEventListeners() {
document.addEventListener('keydown', handleBodyKeyDown, false);
var resizeTimeout;
window.addEventListener('resize', function() {
// throttle resize events
window.clearTimeout(resizeTimeout);
resizeTimeout = window.setTimeout(function() {
resizeTimeout = null;
scaleSmallViewports();
}, 50);
});
// Force reset transform property of section.slides when printing page.
// Use both onbeforeprint and matchMedia for compatibility with different browsers.
var beforePrint = function() {
var el = document.querySelector('section.slides');
el.style.transform = '';
};
window.onbeforeprint = beforePrint;
if (window.matchMedia) {
var mediaQueryList = window.matchMedia('print');
mediaQueryList.addListener(function(mql) {
if (mql.matches) beforePrint();
});
}
}
/* Initialization */
function addFontStyle() {
var el = document.createElement('link');
el.rel = 'stylesheet';
el.type = 'text/css';
el.href =
'//fonts.googleapis.com/css?family=' +
'Open+Sans:regular,semibold,italic,italicsemibold|Droid+Sans+Mono';
document.body.appendChild(el);
}
function addGeneralStyle() {
var el = document.createElement('link');
el.rel = 'stylesheet';
el.type = 'text/css';
el.href = PERMANENT_URL_PREFIX + 'styles.css';
document.body.appendChild(el);
var el = document.createElement('meta');
el.name = 'viewport';
el.content = 'width=device-width,height=device-height,initial-scale=1';
document.querySelector('head').appendChild(el);
var el = document.createElement('meta');
el.name = 'apple-mobile-web-app-capable';
el.content = 'yes';
document.querySelector('head').appendChild(el);
scaleSmallViewports();
}
function handleDomLoaded() {
slideEls = document.querySelectorAll('section.slides > article');
setupFrames();
addFontStyle();
addGeneralStyle();
addEventListeners();
updateSlides();
setupInteraction();
if (
window.location.hostname == 'localhost' ||
window.location.hostname == '127.0.0.1' ||
window.location.hostname == '::1'
) {
hideHelpText();
}
document.body.classList.add('loaded');
setupNotesSync();
}
function initialize() {
getCurSlideFromHash();
if (window['_DEBUG']) {
PERMANENT_URL_PREFIX = '../';
}
if (window['_DCL']) {
handleDomLoaded();
} else {
document.addEventListener('DOMContentLoaded', handleDomLoaded, false);
}
}
// If ?debug exists then load the script relative instead of absolute
if (!window['_DEBUG'] && document.location.href.indexOf('?debug') !== -1) {
document.addEventListener(
'DOMContentLoaded',
function() {
// Avoid missing the DomContentLoaded event
window['_DCL'] = true;
},
false
);
window['_DEBUG'] = true;
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = '../slides.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(script, s);
// Remove this script
s.parentNode.removeChild(s);
} else {
initialize();
}
/* Synchronize windows when notes are enabled */
function setupNotesSync() {
if (!notesEnabled) return;
function setupPlayResizeSync() {
var out = document.getElementsByClassName('output');
for (var i = 0; i < out.length; i++) {
$(out[i]).bind('resize', function(event) {
if ($(event.target).hasClass('ui-resizable')) {
localStorage.setItem('play-index', i);
localStorage.setItem('output-style', out[i].style.cssText);
}
});
}
}
function setupPlayCodeSync() {
var play = document.querySelectorAll('div.playground');
for (var i = 0; i < play.length; i++) {
play[i].addEventListener('input', inputHandler, false);
function inputHandler(e) {
localStorage.setItem('play-index', i);
localStorage.setItem('play-code', e.target.innerHTML);
}
}
}
setupPlayCodeSync();
setupPlayResizeSync();
localStorage.setItem(destSlideKey(), curSlide);
window.addEventListener('storage', updateOtherWindow, false);
}
// An update to local storage is caught only by the other window
// The triggering window does not handle any sync actions
function updateOtherWindow(e) {
// Ignore remove storage events which are not meant to update the other window
var isRemoveStorageEvent = !e.newValue;
if (isRemoveStorageEvent) return;
var destSlide = localStorage.getItem(destSlideKey());
while (destSlide > curSlide) {
nextSlide();
}
while (destSlide < curSlide) {
prevSlide();
}
updatePlay(e);
updateNotes();
}
@@ -0,0 +1,558 @@
@media screen {
/* Framework */
html {
height: 100%;
}
body {
margin: 0;
padding: 0;
display: block !important;
height: 100%;
height: 100vh;
overflow: hidden;
background: rgb(215, 215, 215);
background: -o-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190));
background: -moz-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190));
background: -webkit-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190));
background: -webkit-gradient(
radial,
50% 50%,
0,
50% 50%,
500,
from(rgb(240, 240, 240)),
to(rgb(190, 190, 190))
);
-webkit-font-smoothing: antialiased;
}
.slides {
width: 100%;
height: 100%;
left: 0;
top: 0;
position: absolute;
-webkit-transform: translate3d(0, 0, 0);
}
.slides > article {
display: block;
position: absolute;
overflow: hidden;
width: 900px;
height: 700px;
left: 50%;
top: 50%;
margin-left: -450px;
margin-top: -350px;
padding: 40px 60px;
box-sizing: border-box;
-o-box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
border-radius: 10px;
-o-border-radius: 10px;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
background-color: white;
border: 1px solid rgba(0, 0, 0, 0.3);
transition: transform 0.3s ease-out;
-o-transition: -o-transform 0.3s ease-out;
-moz-transition: -moz-transform 0.3s ease-out;
-webkit-transition: -webkit-transform 0.3s ease-out;
}
.slides.layout-widescreen > article {
margin-left: -550px;
width: 1100px;
}
.slides.layout-faux-widescreen > article {
margin-left: -550px;
width: 1100px;
padding: 40px 160px;
}
.slides.layout-widescreen > article:not(.nobackground):not(.biglogo),
.slides.layout-faux-widescreen > article:not(.nobackground):not(.biglogo) {
background-position-x: 0, 840px;
}
/* Clickable/tappable areas */
.slide-area {
z-index: 1000;
position: absolute;
left: 0;
top: 0;
width: 150px;
height: 700px;
left: 50%;
top: 50%;
cursor: pointer;
margin-top: -350px;
tap-highlight-color: transparent;
-o-tap-highlight-color: transparent;
-moz-tap-highlight-color: transparent;
-webkit-tap-highlight-color: transparent;
}
#prev-slide-area {
margin-left: -550px;
}
#next-slide-area {
margin-left: 400px;
}
.slides.layout-widescreen #prev-slide-area,
.slides.layout-faux-widescreen #prev-slide-area {
margin-left: -650px;
}
.slides.layout-widescreen #next-slide-area,
.slides.layout-faux-widescreen #next-slide-area {
margin-left: 500px;
}
/* Slides */
.slides > article {
display: none;
}
.slides > article.far-past {
display: block;
transform: translate(-2040px);
-o-transform: translate(-2040px);
-moz-transform: translate(-2040px);
-webkit-transform: translate3d(-2040px, 0, 0);
}
.slides > article.past {
display: block;
transform: translate(-1020px);
-o-transform: translate(-1020px);
-moz-transform: translate(-1020px);
-webkit-transform: translate3d(-1020px, 0, 0);
}
.slides > article.current {
display: block;
transform: translate(0);
-o-transform: translate(0);
-moz-transform: translate(0);
-webkit-transform: translate3d(0, 0, 0);
}
.slides > article.next {
display: block;
transform: translate(1020px);
-o-transform: translate(1020px);
-moz-transform: translate(1020px);
-webkit-transform: translate3d(1020px, 0, 0);
}
.slides > article.far-next {
display: block;
transform: translate(2040px);
-o-transform: translate(2040px);
-moz-transform: translate(2040px);
-webkit-transform: translate3d(2040px, 0, 0);
}
.slides.layout-widescreen > article.far-past,
.slides.layout-faux-widescreen > article.far-past {
display: block;
transform: translate(-2260px);
-o-transform: translate(-2260px);
-moz-transform: translate(-2260px);
-webkit-transform: translate3d(-2260px, 0, 0);
}
.slides.layout-widescreen > article.past,
.slides.layout-faux-widescreen > article.past {
display: block;
transform: translate(-1130px);
-o-transform: translate(-1130px);
-moz-transform: translate(-1130px);
-webkit-transform: translate3d(-1130px, 0, 0);
}
.slides.layout-widescreen > article.current,
.slides.layout-faux-widescreen > article.current {
display: block;
transform: translate(0);
-o-transform: translate(0);
-moz-transform: translate(0);
-webkit-transform: translate3d(0, 0, 0);
}
.slides.layout-widescreen > article.next,
.slides.layout-faux-widescreen > article.next {
display: block;
transform: translate(1130px);
-o-transform: translate(1130px);
-moz-transform: translate(1130px);
-webkit-transform: translate3d(1130px, 0, 0);
}
.slides.layout-widescreen > article.far-next,
.slides.layout-faux-widescreen > article.far-next {
display: block;
transform: translate(2260px);
-o-transform: translate(2260px);
-moz-transform: translate(2260px);
-webkit-transform: translate3d(2260px, 0, 0);
}
}
@media print {
/* Set page layout */
@page {
size: A4 landscape;
}
body {
display: block !important;
}
.slides > article {
display: block;
position: relative;
page-break-inside: never;
page-break-after: always;
overflow: hidden;
}
h2 {
position: static !important;
margin-top: 400px !important;
margin-bottom: 100px !important;
}
pre {
background: rgb(240, 240, 240);
}
/* Add explicit links */
a:link:after,
a:visited:after {
content: ' (' attr(href) ') ';
font-size: 50%;
}
#help {
display: none;
visibility: hidden;
}
}
/* Styles for slides */
.slides > article {
font-family: 'Open Sans', Arial, sans-serif;
color: black;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
font-size: 26px;
line-height: 36px;
letter-spacing: -1px;
}
b {
font-weight: 600;
}
a {
color: rgb(0, 102, 204);
text-decoration: none;
}
a:visited {
color: rgba(0, 102, 204, 0.75);
}
a:hover {
color: black;
}
p {
margin: 0;
padding: 0;
margin-top: 20px;
}
p:first-child {
margin-top: 0;
}
h1 {
font-size: 60px;
line-height: 60px;
padding: 0;
margin: 0;
margin-top: 200px;
margin-bottom: 5px;
padding-right: 40px;
font-weight: 600;
letter-spacing: -3px;
color: rgb(51, 51, 51);
}
h2 {
font-size: 45px;
line-height: 45px;
position: absolute;
bottom: 150px;
padding: 0;
margin: 0;
padding-right: 40px;
font-weight: 600;
letter-spacing: -2px;
color: rgb(51, 51, 51);
}
h3 {
font-size: 30px;
line-height: 36px;
padding: 0;
margin: 0;
padding-right: 40px;
font-weight: 600;
letter-spacing: -1px;
color: rgb(51, 51, 51);
}
ul {
margin: 0;
padding: 0;
margin-top: 20px;
margin-left: 1.5em;
}
li {
padding: 0;
margin: 0 0 0.5em 0;
}
div.code, div.output {
margin: 0;
padding: 0;
}
pre {
padding: 5px 10px;
margin-top: 20px;
margin-bottom: 20px;
overflow: hidden;
background: rgb(240, 240, 240);
border: 1px solid rgb(224, 224, 224);
font-family: 'Droid Sans Mono', 'Courier New', monospace;
font-size: 18px;
line-height: 24px;
letter-spacing: -1px;
color: black;
}
pre.numbers span:before {
content: attr(num);
margin-right: 1em;
display: inline-block;
}
code {
font-size: 95%;
font-family: 'Droid Sans Mono', 'Courier New', monospace;
color: black;
}
pre code {
font-size: 100%;
}
article > .image,
article > .video {
text-align: center;
margin-top: 40px;
}
article.background {
background-size: contain;
background-repeat: round;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 40px;
}
th {
font-weight: 600;
text-align: left;
}
td,
th {
border: 1px solid rgb(224, 224, 224);
padding: 5px 10px;
vertical-align: top;
}
p.link {
margin-left: 20px;
}
.pagenumber {
color: #8c8c8c;
font-size: 75%;
position: absolute;
bottom: 0px;
right: 10px;
}
/* Code */
pre {
outline: 0px solid transparent;
}
div.playground {
position: relative;
}
div.output {
position: absolute;
left: 50%;
top: 50%;
right: 40px;
bottom: 40px;
background: #202020;
padding: 5px 10px;
z-index: 2;
border-radius: 10px;
-o-border-radius: 10px;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
}
div.output pre {
margin: 0;
padding: 0;
background: none;
border: none;
width: 100%;
height: 100%;
overflow: auto;
}
div.output .stdout,
div.output pre {
color: #e6e6e6;
}
div.output .stderr,
div.output .error {
color: rgb(255, 200, 200);
}
div.output .system,
div.output .exit {
color: rgb(255, 230, 120);
}
.buttons {
position: relative;
float: right;
top: -60px;
right: 10px;
}
div.output .buttons {
position: absolute;
float: none;
top: auto;
right: 5px;
bottom: 5px;
}
/* Presenter details */
.presenter {
margin-top: 20px;
}
.presenter p,
.presenter .link {
margin: 0;
font-size: 28px;
line-height: 1.2em;
}
/* Output resize details */
.ui-resizable-handle {
position: absolute;
}
.ui-resizable-n {
cursor: n-resize;
height: 7px;
width: 100%;
top: -5px;
left: 0;
}
.ui-resizable-w {
cursor: w-resize;
width: 7px;
left: -5px;
top: 0;
height: 100%;
}
.ui-resizable-nw {
cursor: nw-resize;
width: 9px;
height: 9px;
left: -5px;
top: -5px;
}
iframe {
border: none;
}
figcaption {
color: #666;
text-align: center;
font-size: 0.75em;
}
#help {
font-family: 'Open Sans', Arial, sans-serif;
text-align: center;
color: white;
background: #000;
opacity: 0.5;
position: fixed;
bottom: 25px;
left: 50px;
right: 50px;
padding: 20px;
border-radius: 10px;
-o-border-radius: 10px;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
}
@@ -0,0 +1,62 @@
{/*
This is the action template.
It determines how the formatting actions are rendered.
*/}
{{define "section"}}
<h{{len .Number}} id="TOC_{{.FormattedNumber}}">{{.FormattedNumber}} {{.Title}}</h{{len .Number}}>
{{range .Elem}}{{elem $.Template .}}{{end}}
{{end}}
{{define "list"}}
<ul>
{{range .Bullet}}
<li>{{style .}}</li>
{{end}}
</ul>
{{end}}
{{define "text"}}
{{if .Pre}}
<div class="code"><pre>{{range .Lines}}{{.}}{{end}}</pre></div>
{{else}}
<p>
{{range $i, $l := .Lines}}{{if $i}}{{template "newline"}}
{{end}}{{style $l}}{{end}}
</p>
{{end}}
{{end}}
{{define "code"}}
<div class="code{{if playable .}} playground{{end}}" {{if .Edit}}contenteditable="true" spellcheck="false"{{end}}>{{.Text}}</div>
{{end}}
{{define "image"}}
<div class="image">
<img src="{{.URL}}"{{with .Height}} height="{{.}}"{{end}}{{with .Width}} width="{{.}}"{{end}}>
</div>
{{end}}
{{define "video"}}
<div class="video">
<video {{with .Height}} height="{{.}}"{{end}}{{with .Width}} width="{{.}}"{{end}} controls>
<source src="{{.URL}}" type="{{.SourceType}}">
</video>
</div>
{{end}}
{{define "background"}}
<div class="background">
<img src="{{.URL}}">
</div>
{{end}}
{{define "iframe"}}
<iframe src="{{.URL}}"{{with .Height}} height="{{.}}"{{end}}{{with .Width}} width="{{.}}"{{end}}></iframe>
{{end}}
{{define "link"}}<p class="link"><a href="{{.URL}}" target="_blank">{{style .Label}}</a></p>{{end}}
{{define "html"}}{{.HTML}}{{end}}
{{define "caption"}}<figcaption>{{style .Text}}</figcaption>{{end}}
@@ -0,0 +1,98 @@
{/* This is the article template. It defines how articles are formatted. */}
{{define "root"}}
<!DOCTYPE html>
<html>
<head>
<title>{{.Title}}</title>
<link type="text/css" rel="stylesheet" href="/static/article.css">
<meta charset='utf-8'>
<script>
// Initialize Google Analytics tracking code on production site only.
if (window["location"] && window["location"]["hostname"] == "talks.golang.org") {
var _gaq = _gaq || [];
_gaq.push(["_setAccount", "UA-11222381-6"]);
_gaq.push(["b._setAccount", "UA-49880327-6"]);
window.trackPageview = function() {
_gaq.push(["_trackPageview", location.pathname+location.hash]);
_gaq.push(["b._trackPageview", location.pathname+location.hash]);
};
window.trackPageview();
window.trackEvent = function(category, action, opt_label, opt_value, opt_noninteraction) {
_gaq.push(["_trackEvent", category, action, opt_label, opt_value, opt_noninteraction]);
_gaq.push(["b._trackEvent", category, action, opt_label, opt_value, opt_noninteraction]);
};
}
</script>
</head>
<body>
<div id="topbar" class="wide">
<div class="container">
<div id="heading">{{.Title}}
{{with .Subtitle}}{{.}}{{end}}
{{if .Authors}}
{{range .Authors}}
<div class="author">
{{range .Elem}}{{elem $.Template .}}{{end}}
</div>
{{end}}
{{end}}
</div>
</div>
</div>
<div id="page" class="wide">
<div class="container">
{{with .Sections}}
<div id="toc" class="no-print">
<div id="tochead">Contents</div>
{{template "TOC" .}}
</div>
{{end}}
{{range .Sections}}
{{elem $.Template .}}
{{end}}{{/* of Section block */}}
</div>
</div>
{{if .PlayEnabled}}
<script src='/play.js'></script>
{{end}}
<script>
(function() {
// Load Google Analytics tracking code on production site only.
if (window["location"] && window["location"]["hostname"] == "talks.golang.org") {
var ga = document.createElement("script"); ga.type = "text/javascript"; ga.async = true;
ga.src = ("https:" == document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js";
var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(ga, s);
}
})();
</script>
</body>
</html>
{{end}}
{{define "TOC"}}
<ul class="toc-outer">
{{range .}}
<li><a href="#TOC_{{.FormattedNumber}}">{{.Title}}</a></li>
{{with .Sections}}{{template "TOC-Inner" .}}{{end}}
{{end}}
</ul>
{{end}}
{{define "TOC-Inner"}}
<ul class="toc-inner">
{{range .}}
<li><a href="#TOC_{{.FormattedNumber}}">{{.Title}}</a></li>
{{with .Sections}}{{template "TOC-Inner" .}}{{end}}
{{end}}
</ul>
{{end}}
{{define "newline"}}
{{/* No automatic line break. Paragraphs are free-form. */}}
{{end}}
@@ -0,0 +1,108 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Talks - The Go Programming Language</title>
<link type="text/css" rel="stylesheet" href="/static/dir.css">
<script src="/static/dir.js"></script>
<script>
// Initialize Google Analytics tracking code on production site only.
if (window["location"] && window["location"]["hostname"] == "talks.golang.org") {
var _gaq = _gaq || [];
_gaq.push(["_setAccount", "UA-11222381-6"]);
_gaq.push(["b._setAccount", "UA-49880327-6"]);
window.trackPageview = function() {
_gaq.push(["_trackPageview", location.pathname+location.hash]);
_gaq.push(["b._trackPageview", location.pathname+location.hash]);
};
window.trackPageview();
window.trackEvent = function(category, action, opt_label, opt_value, opt_noninteraction) {
_gaq.push(["_trackEvent", category, action, opt_label, opt_value, opt_noninteraction]);
_gaq.push(["b._trackEvent", category, action, opt_label, opt_value, opt_noninteraction]);
};
}
</script>
</head>
<body>
<div id="topbar"><div class="container">
<form method="GET" action="//golang.org/search">
<div id="menu">
<a href="http://golang.org/doc/">Documents</a>
<a href="http://golang.org/ref">References</a>
<a href="http://golang.org/pkg/">Packages</a>
<a href="http://golang.org/project/">The Project</a>
<a href="http://golang.org/help/">Help</a>
<input type="text" id="search" name="q" class="inactive" value="Search">
</div>
<div id="heading"><a href="/">The Go Programming Language</a></div>
</form>
</div></div>
<div id="page">
<h1>Go talks</h1>
{{with .Path}}<h2>{{.}}</h2>{{end}}
{{with .Articles}}
<h4>Articles:</h4>
<dl>
{{range .}}
<dd><a href="/{{.Path}}">{{.Name}}</a>: {{.Title}}</dd>
{{end}}
</dl>
{{end}}
{{with .Slides}}
<h4>Slide decks:</h4>
<dl>
{{range .}}
<dd><a href="/{{.Path}}">{{.Name}}</a>: {{.Title}}</dd>
{{end}}
</dl>
{{end}}
{{with .Other}}
<h4>Files:</h4>
<dl>
{{range .}}
<dd><a href="/{{.Path}}">{{.Name}}</a></dd>
{{end}}
</dl>
{{end}}
{{with .Dirs}}
<h4>Sub-directories:</h4>
<dl>
{{range .}}
<dd><a href="/{{.Path}}">{{.Name}}</a></dd>
{{end}}
</dl>
{{end}}
</div>
<div id="footer">
Except as <a href="https://developers.google.com/site-policies#restrictions">noted</a>,
the content of this page is licensed under the
Creative Commons Attribution 3.0 License,
and code is licensed under a <a href="http://golang.org/LICENSE">BSD license</a>.<br>
<a href="http://golang.org/doc/tos.html">Terms of Service</a> |
<a href="http://www.google.com/intl/en/policies/privacy/">Privacy Policy</a>
</div>
<script>
(function() {
// Load Google Analytics tracking code on production site only.
if (window["location"] && window["location"]["hostname"] == "talks.golang.org") {
var ga = document.createElement("script"); ga.type = "text/javascript"; ga.async = true;
ga.src = ("https:" == document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js";
var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(ga, s);
}
})();
</script>
</body>
</html>
@@ -0,0 +1,107 @@
{/* This is the slide template. It defines how presentations are formatted. */}
{{define "root"}}
<!DOCTYPE html>
<html>
<head>
<title>{{.Title}}</title>
<meta charset='utf-8'>
<script>
var notesEnabled = {{.NotesEnabled}};
</script>
<script src='/static/slides.js'></script>
{{if .NotesEnabled}}
<script>
var sections = {{.Sections}};
var titleNotes = {{.TitleNotes}}
</script>
<script src='/static/notes.js'></script>
{{end}}
<script>
// Initialize Google Analytics tracking code on production site only.
if (window["location"] && window["location"]["hostname"] == "talks.golang.org") {
var _gaq = _gaq || [];
_gaq.push(["_setAccount", "UA-11222381-6"]);
_gaq.push(["b._setAccount", "UA-49880327-6"]);
window.trackPageview = function() {
_gaq.push(["_trackPageview", location.pathname+location.hash]);
_gaq.push(["b._trackPageview", location.pathname+location.hash]);
};
window.trackPageview();
window.trackEvent = function(category, action, opt_label, opt_value, opt_noninteraction) {
_gaq.push(["_trackEvent", category, action, opt_label, opt_value, opt_noninteraction]);
_gaq.push(["b._trackEvent", category, action, opt_label, opt_value, opt_noninteraction]);
};
}
</script>
</head>
<body style='display: none'>
<section class='slides layout-widescreen'>
<article>
<h1>{{.Title}}</h1>
{{with .Subtitle}}<h3>{{.}}</h3>{{end}}
{{if not .Time.IsZero}}<h3>{{.Time.Format "2 January 2006"}}</h3>{{end}}
{{range .Authors}}
<div class="presenter">
{{range .TextElem}}{{elem $.Template .}}{{end}}
</div>
{{end}}
</article>
{{range $i, $s := .Sections}}
<!-- start of slide {{$s.Number}} -->
<article {{$s.HTMLAttributes}}>
{{if $s.Elem}}
<h3>{{$s.Title}}</h3>
{{range $s.Elem}}{{elem $.Template .}}{{end}}
{{else}}
<h2>{{$s.Title}}</h2>
{{end}}
<span class="pagenumber">{{pagenum $s 1}}</span>
</article>
<!-- end of slide {{$s.Number}} -->
{{end}}{{/* of Slide block */}}
<article>
<h3>Thank you</h3>
{{range .Authors}}
<div class="presenter">
{{range .Elem}}{{elem $.Template .}}{{end}}
</div>
{{end}}
</article>
</section>
<div id="help">
Use the left and right arrow keys or click the left and right
edges of the page to navigate between slides.<br>
(Press 'H' or navigate to hide this message.)
</div>
{{if .PlayEnabled}}
<script src='/play.js'></script>
{{end}}
<script>
(function() {
// Load Google Analytics tracking code on production site only.
if (window["location"] && window["location"]["hostname"] == "talks.golang.org") {
var ga = document.createElement("script"); ga.type = "text/javascript"; ga.async = true;
ga.src = ("https:" == document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js";
var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(ga, s);
}
})();
</script>
</body>
</html>
{{end}}
{{define "newline"}}
<br>
{{end}}