First try at adding Upstream Training material

Work in progress

Implements Blueprint: merge-upstream-university-training

Change-Id: I4d4c7f08d8c599178df2cbcf3969bc739ca6784c
This commit is contained in:
Stefano Maffulli 2014-06-18 12:10:04 -07:00
parent 035922110c
commit 6d66d0d550
7 changed files with 1561 additions and 0 deletions

View File

@ -0,0 +1,124 @@
OpenStack Release Cycle
=======================
OpenStack Upstream Training
---------------------------
<teacher name>
<date>
----
Planning : Design
=================
- Planning stage is at the start of a cycle
- take a step back
- focus on what we want to do for the next one
.. image:: ./_assets/01-01-release.png
----
Planning : Discuss
==================
- With our peers
- feedback and comments
- create the corresponding blueprint
- 4 weeks, Design Summit on the third week
.. image:: ./_assets/01-01-release.png
----
Planning : Target
=================
- file new blueprints
- set a target milestone
- when in the cycle they intend to complete it
- PTLs triage the submitted blueprints and sets Priority
.. image:: ./_assets/01-01-release.png
----
Implementation : Milestone
==========================
- pushed to our Gerrit review
- weeks before the milestone publication date.
- milestone-proposed branch
- feature-frozen
.. image:: ./_assets/01-01-release.png
----
Implementation : freezes
========================
- Feature proposal freeze
- String freeze
- Feature freeze
.. image:: ./_assets/01-01-release.png
----
Release Candidates
==================
- After the last milestone
- file bugs about everything you find
- prioritize bugs / bug triage
- write documentation
- fix as many bugs as you can
.. image:: ./_assets/01-01-release.png
----
Release candidate 1
===================
- Between the last milestone and the RC1
- stop adding features and concentrate on bugfixes
- Once all the release-critical bugs are fixed, we produce the first - - - release candidate for that project (RC1)
- used as-is as the final release
.. image:: ./_assets/01-01-release.png
----
Other release candidates
========================
- regressions and integration issues
- new release-critical bugs
- (RC2), with bugs targeted to it
- merged in the master branch first
- repeated as many times as necessary
.. image:: ./_assets/01-01-release.png
----
Release day
===========
- last published Release Candidate
- published collectively as the OpenStack release
.. image:: ./_assets/01-01-release.png
----
Exercise
========
Based on the Icehouse release schedule find the URL of a document or a patch that belongs to each of the steps.

View File

@ -0,0 +1,18 @@
Slides for Upstream Training
============================
The files are based on teaching material provided originally by Loic Dachary as ODP files. Converted to RST text in order to be converted by landslide in convenient html5 slides.
Documentation for landslide on https://github.com/adamzap/landslide
Install landslide
-----------------
Install the latest stable version of Landslide with a python package manager like pip:
$ pip install landslide
To build the presentations
--------------------------
$ landslide <presentation.rst>

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View File

@ -0,0 +1,182 @@
<!DOCTYPE html>
<!--
Copyright 2010 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Original slides: Marcin Wichary (mwichary@google.com)
Modifications: Ernest Delgado (ernestd@google.com)
Alex Russell (slightlyoff@chromium.org)
landslide modifications: Adam Zapletal (adamzap@gmail.com)
Nicolas Perriault (nperriault@gmail.com)
-->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>{{ head_title }}</title>
<!-- Styles -->
{% if embed %}
<style type="text/css" media="print">
{{ css.print.contents }}
</style>
<style type="text/css" media="screen, projection">
{{ css.screen.contents }}
</style>
{% else %}
<link rel="stylesheet" media="print" href="{{ css.print.path_url }}">
<link rel="stylesheet" media="screen, projection" href="{{ css.screen.path_url }}">
{% endif %}
{% for css in user_css %}
{% if embed %}
<style type="text/css" media="screen, projection">
{{ css.contents }}
</style>
{% else %}
<link rel="stylesheet" href="{{ css.path_url }}">
{% endif %}
{% endfor %}
<!-- /Styles -->
<!-- Javascripts -->
{% if embed %}
<script>
{{ js.contents }}
</script>
{% else %}
<script type="text/javascript" src="{{ js.path_url }}"></script>
{% endif %}
{% for js in user_js %}
{% if embed %}
<script>
{{ js.contents }}
</script>
{% else %}
<script type="text/javascript" src="{{ js.path_url }}"></script>
{% endif %}
{% endfor %}
<!-- /Javascripts -->
</head>
<body>
<div id="blank"></div>
<div class="presentation">
<div id="current_presenter_notes">
<div id="presenter_note"></div>
</div>
<div class="slides">
{% for slide in slides %}
<!-- slide source: {% if slide.source %}{{ slide.source.rel_path }}{% endif %} -->
<div class="slide-wrapper">
<div class="slide{% if slide.classes %}{% for class in slide.classes %} {{ class }}{% endfor %}{% endif %}">
<div class="inner">
{% if slide.header %}
<header>{{ slide.header }}</header>
{% endif %}
{% if slide.content %}
<section>{{ slide.content }}</section>
{% endif %}
</div>
<div class="presenter_notes">
<header><h1>Presenter Notes</h1></header>
<section>
{% if slide.presenter_notes %}
{{ slide.presenter_notes }}
{% endif %}
</section>
</div>
<footer>
{% if slide.source %}
<aside class="source">
Source: <a href="{{ slide.source.rel_path }}">{{ slide.source.rel_path }}</a>
</aside>
{% endif %}
<aside class="page_number">
{{ slide.number }}/{{ num_slides }}
</aside>
</footer>
</div>
</div>
{% endfor %}
</div>
</div>
{% if toc %}
<div id="toc" class="sidebar hidden">
<h2>Table of Contents</h2>
<table>
<caption>Table of Contents</caption>
{% for section in toc %}
<tr id="toc-row-{{ section.number }}">
<th><a href="#slide{{ section.number }}">{{ section.title }}</a></th>
<td><a href="#slide{{ section.number }}">{{ section.number }}</a></td>
</tr>
{% if section.sub %}
{% for subsection in section.sub %}
<tr id="toc-row-{{ subsection.number }}" class="sub">
<th><a href="#slide{{ subsection.number }}">{{ subsection.title }}</a></th>
<td><a href="#slide{{ subsection.number }}">{{ subsection.number }}</a></td>
</tr>
{% endfor %}
{% endif %}
{% endfor %}
</table>
</div>
{% endif %}
<div id="help" class="sidebar hidden">
<h2>Help</h2>
<table>
<caption>Help</caption>
<tr>
<th>Table of Contents</th>
<td>t</td>
</tr>
<tr>
<th>Exposé</th>
<td>ESC</td>
</tr>
<tr>
<th>Full screen slides</th>
<td>e</td>
</tr>
<tr>
<th>Presenter View</th>
<td>p</td>
</tr>
<tr>
<th>Source Files</th>
<td>s</td>
</tr>
<tr>
<th>Slide Numbers</th>
<td>n</td>
</tr>
<tr>
<th>Toggle screen blanking</th>
<td>b</td>
</tr>
<tr>
<th>Show/hide slide context</th>
<td>c</td>
</tr>
<tr>
<th>Notes</th>
<td>2</td>
</tr>
<tr>
<th>Help</th>
<td>h</td>
</tr>
</table>
</div>
<script>main()</script>
</body>
</html>

View File

@ -0,0 +1,94 @@
* {
margin: 0;
padding: 0;
}
@page {
size: landscape;
}
body {
font: 100% "Lucida Grande", "Trebuchet MS", Verdana, sans-serif;
padding: 0;
margin: 0;
}
div.slide {
min-width: 800px;
min-height: 600px;
padding: 1em;
overflow: hidden;
page-break-after: always;
border: 1px solid black;
border-radius: 20px;
}
div.slide div.inner {
width: 800px;
height: 600px;
margin: auto;
display: table-cell;
}
h1 {
font-size: 2.4em;
}
h2 {
font-size: 1.4em;
}
h3 {
margin: 1em 0;
}
ul {
margin: 0;
padding: 0;
}
p, li, pre {
margin: 1em 0;
}
li {
margin-left: 2em;
}
a {
color: #000000;
}
pre, code {
max-width: 800px;
background: #eee;
font-family: Monaco, monospace;
font-size: 90%;
}
pre {
padding: .2em .5em;
overflow: hidden;
border-radius: .8em;
}
code {
padding: 0 .2em;
}
.slide header:only-child h1 {
line-height: 180%;
text-align: center;
display: table-cell;
vertical-align: middle;
height: 600px;
width: 800px;
font-size: 48px;
margin-top:100px;
margin-bottom:100px;
}
#toc, #help, .slide aside, .slide footer, .slide .notes,
.presenter_notes, #current_presenter_notes, #presenter_note {
display: none;
}

View File

@ -0,0 +1,563 @@
body {
font: 14px "Lucida Grande", "Trebuchet MS", Verdana, sans-serif;
background: #778;
padding: 0;
margin: 0;
overflow: hidden;
}
div.presentation {
position: absolute;
width: 100%;
display: table-cell;
vertical-align: middle;
height: 100%;
background: inherit;
}
div.presentation > h1 {
display: none;
}
div.slides, body.expose div.slides.nocontext {
width: 100%;
height: 100%;
left: 0;
top: 0;
position: absolute;
display: block;
}
div.slides.nocontext {
width: 900px;
margin: 0 auto;
overflow: hidden;
position: relative;
left: auto;
top: auto;
}
div.slide {
display: inline;
position: absolute;
overflow: hidden;
width: 900px;
height: 700px;
margin-top: -350px;
margin-left: -400px;
left: 50%;
top: 50%;
background: -webkit-gradient(linear, left bottom, left top, from(#bbd), to(#fff));
background-color: #eee;
background: -moz-linear-gradient(bottom, #bbd, #fff);
-webkit-transition: margin 0.25s ease-in-out;
-moz-transition: margin 0.25s ease-in-out;
-o-transition: margin 0.25s ease-in-out;
border-top-left-radius: 20px;
-moz-border-radius-topleft: 20px;
-webkit-border-top-left-radius: 20px;
border-top-right-radius: 20px;
-moz-border-radius-topright: 20px;
-webkit-border-top-right-radius: 20px;
border-bottom-right-radius: 20px;
-moz-border-radius-bottomright: 20px;
-webkit-border-bottom-right-radius: 20px;
border-bottom-left-radius: 20px;
-moz-border-radius-bottomleft: 20px;
-webkit-border-bottom-left-radius: 20px;
}
/* Expose */
body.expose div.slides {
float: left;
position: relative;
overflow: auto;
margin-bottom: 10px;
}
body.expose div.slide {
display: block;
float: left;
position: relative;
left: auto !important;
top: auto !important;
margin: 10px !important;
-webkit-transition: none;
-moz-transition: none;
-o-transition: none;
-moz-transform: scale(.33, .33);
-moz-transform-origin: 0 0;
-webkit-transform: scale(.33, .33);
-webkit-transform-origin: 0 0;
-o-transform: scale(.33, .33);
-o-transform-origin: 0 0;
-webkit-transition: none;
-moz-transition: none;
-o-transition: none;
cursor: pointer;
}
body.expose div.slide:hover {
background: -webkit-gradient(linear, left bottom, left top, from(#bdd), to(#fff));
background-color: #eee;
background: -moz-linear-gradient(bottom, #bdd, #fff);
}
body.expose .slide-wrapper {
float: left;
position: relative;
margin: .5%;
width: 300px;
height: 233px;
}
body.expose .slide footer {
}
body.expose .slide .inner {
}
body.expose .slide.far-past,
body.expose .slide.past,
body.expose .slide.future,
body.expose .slide.far-future {
margin-left: 0;
}
body.expose .slide.current {
background: -webkit-gradient(linear, left bottom, left top, from(#ddb), to(#fff));
background-color: #eee;
background: -moz-linear-gradient(bottom, #ddb, #fff);
border: 16px solid #fff;
-moz-transform: scale(.315, .315);
-moz-transform-origin: 0 0;
-webkit-transform: scale(.315, .315);
-webkit-transform-origin: 0 0;
-o-transform: scale(.315, .315);
-o-transform-origin: 0 0;
}
/* Presenter Mode */
body.presenter_view div.slide {
display: inline;
position: absolute;
overflow: hidden;
-moz-transform: scale(.5, .5);
-moz-transform-origin: 0 0;
-webkit-transform: scale(.5, .5);
-webkit-transform-origin: 0 0;
-o-transform: scale(.5, .5);
-o-transform-origin: 0 0;
margin-top: -300px;
}
body.presenter_view .slide.far-past {
display: block;
margin-left: -1500px;
}
body.presenter_view .slide.past {
display: block;
margin-left: -975px;
}
body.presenter_view .slide.current {
display: block;
margin-left: -475px;
border: 8px solid maroon;
z-index: 2;
}
body.presenter_view .slide.future {
display: block;
margin-left: 25px;
z-index: 1;
}
body.presenter_view .slide.far-future {
display: block;
margin-left: 525px;
}
body.presenter_view div#current_presenter_notes {
visibility: visible;
display: block;
position: absolute;
overflow: auto;
vertical-align: middle;
left: 50%;
top: 50%;
margin-left: -475px;
margin-top: 100px;
z-index: 2;
width: 950px;
border-style: solid;
height: 30%;
background-color: silver;
}
body.presenter_view div#current_presenter_notes section {
font-family: "Lucida Grande", "Trebuchet MS", Verdana, sans-serif;
color: black;
text-shadow: rgba(0, 0, 0, 0.2) 0 2px 5px;
display: block;
overflow: visible;
position: relative;
background-color: #fffeff;
height: 120px;
margin-right: 30px;
margin-top: 60px;
margin-left: 30px;
padding-right: 10px;
padding-left: 10px;
padding-top: 10px;
}
body.presenter_view div#current_presenter_notes section p {
margin: 0;
}
body.presenter_view div#current_presenter_notes h1 {
font-size: 50%;
display: block;
}
div#current_presenter_notes {
display: none;
}
div.slide div.presenter_notes, div.slides div.presenter_notes {
display: none;
}
/* Slide styles */
div.slide p {
font-size: 20px;
}
.slide.far-past {
display: block;
margin-left: -2400px;
}
.slide.past {
display: block;
margin-left: -1400px;
}
.slide.current {
display: block;
margin-left: -450px;
}
.slide.future {
display: block;
margin-left: 500px;
}
.slide.far-future {
display: block;
margin-left: 1500px;
}
body.three-d div.slides {
-webkit-transform: translateX(50px) scale(0.8) rotateY(10deg);
-moz-transform: translateX(50px) scale(0.8) rotateY(10deg);
-o-transform: translateX(50px) scale(0.8) rotateY(10deg);
}
/* Content */
header:not(:only-child) {
font-family: "Lucida Grande", "Trebuchet MS", Verdana, sans-serif;
font-weight: normal;
font-size: 50px;
letter-spacing: -.05em;
color: black;
text-shadow: rgba(0, 0, 0, 0.2) 0 2px 5px;
position: absolute;
left: 30px;
top: 25px;
margin: 0;
padding: 0;
}
header h1, header h2, header h3, header h4, header h5, header h6 {
display: inline;
font-size: 100%;
font-weight: normal;
padding: 0;
margin: 0;
}
header h2:first-child {
margin-top: 0;
}
section, .slide header:only-child h1 {
font-family: "Lucida Grande", "Trebuchet MS", Verdana, sans-serif;
color: #3f3f3f;
text-shadow: rgba(0, 0, 0, 0.2) 0 2px 5px;
margin-left: 30px;
margin-right: 30px;
margin-top: 100px;
display: block;
overflow: hidden;
}
img { display: block; margin: auto; }
section img.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
section img.align-right {
display: block;
margin-left: auto;
margin-right: 0;
}
section img.align-left {
display: block;
margin-right: auto;
margin-left: 0;
}
a {
color: inherit;
display: inline-block;
text-decoration: none;
line-height: 110%;
border-bottom: 2px solid #3f3f3f;
}
pre, code, tt {
font-family: Monaco, Consolas, 'Bitstream Vera Sans Mono', 'Lucida Console', FreeMono, Courier, monospace;
}
pre, .gist .gist-file .gist-data {
font-size: 18px;
max-height: 485px;
padding-top: 0.25em !important;
padding-right: 0.5em !important;
padding-left: 0.5em !important;
overflow: auto;
}
/* render a nice scrollbar in overflowed pre area's */
::-webkit-scrollbar {
height: 8px;
width: 8px;
}
::-webkit-scrollbar-thumb {
background: -webkit-gradient(linear, left bottom, left top, from(#777), to(#bbd));
-webkit-border-radius: 1ex;
}
::-webkit-scrollbar-corner {
background: #dedede;
}
blockquote {
border-left: solid 8px #778;
padding: .1ex 1ex;
font-style: italic;
}
li {
padding: 10px 0;
font-size: 20px;
}
li pre { margin-left: 0em; }
.slide header:only-child h1 {
line-height: 180%;
text-align: center;
display: table-cell;
vertical-align: middle;
height: 700px;
width: 900px;
font-size: 50px;
margin-top:100px;
margin-bottom:100px;
}
.sidebar {
clear: both;
background: -webkit-gradient(linear, top right, bottom right, from(#dde), to(#fff));
-webkit-transition: margin 0.25s ease-in-out;
background-color: #eee;
background: -moz-linear-gradient(right, #dde, #fff);
border-right: 5px solid #ccd;
z-index: 9999999;
height: 100%;
overflow: hidden;
top: 0;
position: absolute;
display: block;
margin: 0;
margin-left: -400px;
padding: 10px 16px;
overflow: auto;
-webkit-transition: margin 0.2s ease-in-out;
-moz-transition: margin 0.2s ease-in-out;
-o-transition: margin 0.2s ease-in-out;
}
.sidebar h2 {
text-shadow: rgba(0, 0, 0, 0.2) 0 2px 5px;
margin: 0 0 16px;
padding: 0;
}
.sidebar table {
width: 100%;
margin: 0;
padding: 0;
border-collapse: collapse;
}
.sidebar table caption {
display: none;
}
.sidebar tr {
margin: 2px 0;
border-bottom: 1px solid #ccc;
}
.sidebar th {
text-align: left;
font-weight: normal;
max-width: 300px;
overflow: hidden;
}
.sidebar tr.sub th {
text-indent: 20px;
}
.sidebar td {
text-align: right;
min-width: 20px;
}
.sidebar a {
display: block;
text-decoration: none;
border-bottom: none;
padding: 4px 0;
}
.sidebar tr.active {
background: #ff0;
}
aside {
display: none;
}
aside.source {
position: absolute;
bottom: 6px;
left: 10px;
text-indent: 10px;
}
aside.page_number {
position: absolute;
bottom: 6px;
right: 10px;
text-indent: 10px;
}
.notes {
display: none;
padding: 10px;
background: #ccc;
border-radius: 10px;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
}
div.slide p.notes {
font-size: 90%;
}
/* Pygments default theme */
.hll { background-color: #ffffcc }
.c { color: #408080; font-style: italic } /* Comment */
.err { border: 1px solid #FF0000 } /* Error */
.k { color: #008000; font-weight: bold } /* Keyword */
.o { color: #666666 } /* Operator */
.cm { color: #408080; font-style: italic } /* Comment.Multiline */
.cp { color: #BC7A00 } /* Comment.Preproc */
.c1 { color: #408080; font-style: italic } /* Comment.Single */
.cs { color: #408080; font-style: italic } /* Comment.Special */
.gd { color: #A00000 } /* Generic.Deleted */
.ge { font-style: italic } /* Generic.Emph */
.gr { color: #FF0000 } /* Generic.Error */
.gh { color: #000080; font-weight: bold } /* Generic.Heading */
.gi { color: #00A000 } /* Generic.Inserted */
.go { color: #808080 } /* Generic.Output */
.gp { color: #000080; font-weight: bold } /* Generic.Prompt */
.gs { font-weight: bold } /* Generic.Strong */
.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.gt { color: #0040D0 } /* Generic.Traceback */
.kc { color: #008000; font-weight: bold } /* Keyword.Constant */
.kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
.kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
.kp { color: #008000 } /* Keyword.Pseudo */
.kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
.kt { color: #B00040 } /* Keyword.Type */
.m { color: #666666 } /* Literal.Number */
.s { color: #BA2121 } /* Literal.String */
.na { color: #7D9029 } /* Name.Attribute */
.nb { color: #008000 } /* Name.Builtin */
.nc { color: #0000FF; font-weight: bold } /* Name.Class */
.no { color: #880000 } /* Name.Constant */
.nd { color: #AA22FF } /* Name.Decorator */
.ni { color: #999999; font-weight: bold } /* Name.Entity */
.ne { color: #D2413A; font-weight: bold } /* Name.Exception */
.nf { color: #0000FF } /* Name.Function */
.nl { color: #A0A000 } /* Name.Label */
.nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
.nt { color: #008000; font-weight: bold } /* Name.Tag */
.nv { color: #19177C } /* Name.Variable */
.ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
.w { color: #bbbbbb } /* Text.Whitespace */
.mf { color: #666666 } /* Literal.Number.Float */
.mh { color: #666666 } /* Literal.Number.Hex */
.mi { color: #666666 } /* Literal.Number.Integer */
.mo { color: #666666 } /* Literal.Number.Oct */
.sb { color: #BA2121 } /* Literal.String.Backtick */
.sc { color: #BA2121 } /* Literal.String.Char */
.sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
.s2 { color: #BA2121 } /* Literal.String.Double */
.se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
.sh { color: #BA2121 } /* Literal.String.Heredoc */
.si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
.sx { color: #008000 } /* Literal.String.Other */
.sr { color: #BB6688 } /* Literal.String.Regex */
.s1 { color: #BA2121 } /* Literal.String.Single */
.ss { color: #19177C } /* Literal.String.Symbol */
.bp { color: #008000 } /* Name.Builtin.Pseudo */
.vc { color: #19177C } /* Name.Variable.Class */
.vg { color: #19177C } /* Name.Variable.Global */
.vi { color: #19177C } /* Name.Variable.Instance */
.il { color: #666666 } /* Literal.Number.Integer.Long */
.lineno { padding-right: 10px } /* A few space after linenos */
#blank {
position: absolute;
top: 0;
left: 0;
background-color: black;
width: 100%;
height: 100%;
z-index: 64;
display: none;
}

View File

@ -0,0 +1,580 @@
function main() {
// Since we don't have the fallback of attachEvent and
// other IE only stuff we won't try to run JS for IE.
// It will run though when using Google Chrome Frame
if (document.all) { return; }
var currentSlideNo;
var notesOn = false;
var expanded = false;
var hiddenContext = false;
var blanked = false;
var slides = document.getElementsByClassName('slide');
var touchStartX = 0;
var spaces = /\s+/, a1 = [''];
var tocOpened = false;
var helpOpened = false;
var overviewActive = false;
var modifierKeyDown = false;
var scale = 1;
var showingPresenterView = false;
var presenterViewWin = null;
var isPresenterView = false;
var str2array = function(s) {
if (typeof s == 'string' || s instanceof String) {
if (s.indexOf(' ') < 0) {
a1[0] = s;
return a1;
} else {
return s.split(spaces);
}
}
return s;
};
var trim = function(str) {
return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
};
var addClass = function(node, classStr) {
classStr = str2array(classStr);
var cls = ' ' + node.className + ' ';
for (var i = 0, len = classStr.length, c; i < len; ++i) {
c = classStr[i];
if (c && cls.indexOf(' ' + c + ' ') < 0) {
cls += c + ' ';
}
}
node.className = trim(cls);
};
var removeClass = function(node, classStr) {
var cls;
if (!node) {
throw 'no node provided';
}
if (classStr !== undefined) {
classStr = str2array(classStr);
cls = ' ' + node.className + ' ';
for (var i = 0, len = classStr.length; i < len; ++i) {
cls = cls.replace(' ' + classStr[i] + ' ', ' ');
}
cls = trim(cls);
} else {
cls = '';
}
if (node.className != cls) {
node.className = cls;
}
};
var getSlideEl = function(slideNo) {
if (slideNo > 0) {
return slides[slideNo - 1];
} else {
return null;
}
};
var getSlideTitle = function(slideNo) {
var el = getSlideEl(slideNo);
if (el) {
var headers = el.getElementsByTagName('header');
if (headers.length > 0) {
return el.getElementsByTagName('header')[0].innerText;
}
}
return null;
};
var getSlidePresenterNote = function(slideNo) {
var el = getSlideEl(slideNo);
if (el) {
var n = el.getElementsByClassName('presenter_notes');
if (n.length > 0) {
return n[0];
}
}
return null;
};
var changeSlideElClass = function(slideNo, className) {
var el = getSlideEl(slideNo);
if (el) {
removeClass(el, 'far-past past current future far-future');
addClass(el, className);
}
};
var updateSlideClasses = function(updateOther) {
window.location.hash = (isPresenterView ? "presenter" : "slide") + currentSlideNo;
for (var i=1; i<currentSlideNo-1; i++) {
changeSlideElClass(i, 'far-past');
}
changeSlideElClass(currentSlideNo - 1, 'past');
changeSlideElClass(currentSlideNo, 'current');
changeSlideElClass(currentSlideNo + 1, 'future');
for (i=currentSlideNo+2; i<slides.length+1; i++) {
changeSlideElClass(i, 'far-future');
}
highlightCurrentTocLink();
processContext();
document.getElementsByTagName('title')[0].innerText = getSlideTitle(currentSlideNo);
updatePresenterNotes();
if (updateOther) { updateOtherPage(); }
};
var updatePresenterNotes = function() {
if (!isPresenterView) { return; }
var existingNote = document.getElementById('current_presenter_notes');
var currentNote = getSlidePresenterNote(currentSlideNo).cloneNode(true);
currentNote.setAttribute('id', 'presenter_note');
existingNote.replaceChild(currentNote, document.getElementById('presenter_note'));
};
var highlightCurrentTocLink = function() {
var toc = document.getElementById('toc');
if (toc) {
var tocRows = toc.getElementsByTagName('tr');
for (var i=0; i<tocRows.length; i++) {
removeClass(tocRows.item(i), 'active');
}
var currentTocRow = document.getElementById('toc-row-' + currentSlideNo);
if (currentTocRow) {
addClass(currentTocRow, 'active');
}
}
};
var updateOtherPage = function() {
if (!showingPresenterView) { return; }
var w = isPresenterView ? window.opener : presenterViewWin;
w.postMessage('slide#' + currentSlideNo, '*');
};
var nextSlide = function() {
if (currentSlideNo < slides.length) {
currentSlideNo++;
}
updateSlideClasses(true);
};
var prevSlide = function() {
if (currentSlideNo > 1) {
currentSlideNo--;
}
updateSlideClasses(true);
};
var showNotes = function() {
var notes = getSlideEl(currentSlideNo).getElementsByClassName('notes');
for (var i = 0, len = notes.length; i < len; i++) {
notes.item(i).style.display = (notesOn) ? 'none':'block';
}
notesOn = !notesOn;
};
var showSlideNumbers = function() {
var asides = document.getElementsByClassName('page_number');
var hidden = asides[0].style.display != 'block';
for (var i = 0; i < asides.length; i++) {
asides.item(i).style.display = hidden ? 'block' : 'none';
}
};
var showSlideSources = function() {
var asides = document.getElementsByClassName('source');
var hidden = asides[0].style.display != 'block';
for (var i = 0; i < asides.length; i++) {
asides.item(i).style.display = hidden ? 'block' : 'none';
}
};
var showToc = function() {
if (helpOpened) {
showHelp();
}
var toc = document.getElementById('toc');
if (toc) {
toc.style.marginLeft = tocOpened ? '-' + (toc.clientWidth + 20) + 'px' : '0px';
tocOpened = !tocOpened;
}
updateOverview();
};
var showHelp = function() {
if (tocOpened) {
showToc();
}
var help = document.getElementById('help');
if (help) {
help.style.marginLeft = helpOpened ? '-' + (help.clientWidth + 20) + 'px' : '0px';
helpOpened = !helpOpened;
}
};
var showPresenterView = function() {
if (isPresenterView) { return; }
if (showingPresenterView) {
presenterViewWin.close();
presenterViewWin = null;
showingPresenterView = false;
} else {
presenterViewWin = open(window.location.pathname + "#presenter" + currentSlideNo, 'presenter_notes',
'directories=no,location=no,toolbar=no,menubar=no,copyhistory=no');
showingPresenterView = true;
}
};
var switch3D = function() {
if (document.body.className.indexOf('three-d') == -1) {
document.getElementsByClassName('presentation')[0].style.webkitPerspective = '1000px';
document.body.className += ' three-d';
} else {
window.setTimeout('document.getElementsByClassName(\'presentation\')[0].style.webkitPerspective = \'0\';', 2000);
document.body.className = document.body.className.replace(/three-d/, '');
}
};
var toggleOverview = function() {
if (!overviewActive) {
addClass(document.body, 'expose');
overviewActive = true;
setScale(1);
} else {
removeClass(document.body, 'expose');
overviewActive = false;
if (expanded) {
setScale(scale); // restore scale
}
}
processContext();
updateOverview();
};
var updateOverview = function() {
try {
var presentation = document.getElementsByClassName('presentation')[0];
} catch (e) {
return;
}
if (isPresenterView) {
var action = overviewActive ? removeClass : addClass;
action(document.body, 'presenter_view');
}
var toc = document.getElementById('toc');
if (!toc) {
return;
}
if (!tocOpened || !overviewActive) {
presentation.style.marginLeft = '0px';
presentation.style.width = '100%';
} else {
presentation.style.marginLeft = toc.clientWidth + 'px';
presentation.style.width = (presentation.clientWidth - toc.clientWidth) + 'px';
}
};
var computeScale = function() {
var cSlide = document.getElementsByClassName('current')[0];
var sx = cSlide.clientWidth / window.innerWidth;
var sy = cSlide.clientHeight / window.innerHeight;
return 1 / Math.max(sx, sy);
};
var setScale = function(scale) {
var presentation = document.getElementsByClassName('slides')[0];
var transform = 'scale(' + scale + ')';
presentation.style.MozTransform = transform;
presentation.style.WebkitTransform = transform;
presentation.style.OTransform = transform;
presentation.style.msTransform = transform;
presentation.style.transform = transform;
};
var expandSlides = function() {
if (overviewActive) {
return;
}
if (expanded) {
setScale(1);
expanded = false;
} else {
scale = computeScale();
setScale(scale);
expanded = true;
}
};
var showContext = function() {
try {
var presentation = document.getElementsByClassName('slides')[0];
removeClass(presentation, 'nocontext');
} catch (e) {}
};
var hideContext = function() {
try {
var presentation = document.getElementsByClassName('slides')[0];
addClass(presentation, 'nocontext');
} catch (e) {}
};
var processContext = function() {
if (hiddenContext) {
hideContext();
} else {
showContext();
}
};
var toggleContext = function() {
hiddenContext = !hiddenContext;
processContext();
};
var toggleBlank = function() {
blank_elem = document.getElementById('blank');
blank_elem.style.display = blanked ? 'none' : 'block';
blanked = !blanked;
};
var isModifierKey = function(keyCode) {
switch (keyCode) {
case 16: // shift
case 17: // ctrl
case 18: // alt
case 91: // command
return true;
break;
default:
return false;
break;
}
};
var checkModifierKeyUp = function(event) {
if (isModifierKey(event.keyCode)) {
modifierKeyDown = false;
}
};
var checkModifierKeyDown = function(event) {
if (isModifierKey(event.keyCode)) {
modifierKeyDown = true;
}
};
var handleBodyKeyDown = function(event) {
switch (event.keyCode) {
case 13: // Enter
if (overviewActive) {
toggleOverview();
}
break;
case 27: // ESC
toggleOverview();
break;
case 37: // left arrow
case 33: // page up
event.preventDefault();
prevSlide();
break;
case 39: // right arrow
case 32: // space
case 34: // page down
event.preventDefault();
nextSlide();
break;
case 50: // 2
if (!modifierKeyDown) {
showNotes();
}
break;
case 51: // 3
if (!modifierKeyDown && !overviewActive) {
switch3D();
}
break;
case 190: // .
case 48: // 0
case 66: // b
if (!modifierKeyDown && !overviewActive) {
toggleBlank();
}
break;
case 67: // c
if (!modifierKeyDown && !overviewActive) {
toggleContext();
}
break;
case 69: // e
if (!modifierKeyDown && !overviewActive) {
expandSlides();
}
break;
case 72: // h
showHelp();
break;
case 78: // n
if (!modifierKeyDown && !overviewActive) {
showSlideNumbers();
}
break;
case 80: // p
if (!modifierKeyDown && !overviewActive) {
showPresenterView();
}
break;
case 83: // s
if (!modifierKeyDown && !overviewActive) {
showSlideSources();
}
break;
case 84: // t
showToc();
break;
}
};
var handleWheel = function(event) {
if (tocOpened || helpOpened || overviewActive) {
return;
}
var delta = 0;
if (!event) {
event = window.event;
}
if (event.wheelDelta) {
delta = event.wheelDelta/120;
if (window.opera) delta = -delta;
} else if (event.detail) {
delta = -event.detail/3;
}
if (delta && delta <0) {
nextSlide();
} else if (delta) {
prevSlide();
}
};
var addSlideClickListeners = function() {
for (var i=0; i < slides.length; i++) {
var slide = slides.item(i);
slide.num = i + 1;
slide.addEventListener('click', function(e) {
if (overviewActive) {
currentSlideNo = this.num;
toggleOverview();
updateSlideClasses(true);
e.preventDefault();
}
return false;
}, true);
}
};
var addRemoteWindowControls = function() {
window.addEventListener("message", function(e) {
if (e.data.indexOf("slide#") != -1) {
currentSlideNo = Number(e.data.replace('slide#', ''));
updateSlideClasses(false);
}
}, false);
};
var addTouchListeners = function() {
document.addEventListener('touchstart', function(e) {
touchStartX = e.touches[0].pageX;
}, false);
document.addEventListener('touchend', function(e) {
var pixelsMoved = touchStartX - e.changedTouches[0].pageX;
var SWIPE_SIZE = 150;
if (pixelsMoved > SWIPE_SIZE) {
nextSlide();
}
else if (pixelsMoved < -SWIPE_SIZE) {
prevSlide();
}
}, false);
};
var addTocLinksListeners = function() {
var toc = document.getElementById('toc');
if (toc) {
var tocLinks = toc.getElementsByTagName('a');
for (var i=0; i < tocLinks.length; i++) {
tocLinks.item(i).addEventListener('click', function(e) {
currentSlideNo = Number(this.attributes['href'].value.replace('#slide', ''));
updateSlideClasses(true);
e.preventDefault();
}, true);
}
}
};
// initialize
(function() {
if (window.location.hash == "") {
currentSlideNo = 1;
} else if (window.location.hash.indexOf("#presenter") != -1) {
currentSlideNo = Number(window.location.hash.replace('#presenter', ''));
isPresenterView = true;
showingPresenterView = true;
presenterViewWin = window;
addClass(document.body, 'presenter_view');
} else {
currentSlideNo = Number(window.location.hash.replace('#slide', ''));
}
document.addEventListener('keyup', checkModifierKeyUp, false);
document.addEventListener('keydown', handleBodyKeyDown, false);
document.addEventListener('keydown', checkModifierKeyDown, false);
document.addEventListener('DOMMouseScroll', handleWheel, false);
window.onmousewheel = document.onmousewheel = handleWheel;
window.onresize = expandSlides;
for (var i = 0, el; el = slides[i]; i++) {
addClass(el, 'slide far-future');
}
updateSlideClasses(false);
// add support for finger events (filter it by property detection?)
addTouchListeners();
addTocLinksListeners();
addSlideClickListeners();
addRemoteWindowControls();
})();
}