diff options
| author | Harald Welte <laforge@gnumonks.org> | 2018-04-11 21:52:49 +0200 | 
|---|---|---|
| committer | Harald Welte <laforge@gnumonks.org> | 2018-04-11 21:54:01 +0200 | 
| commit | 8fe4bb68050fab5d8fd95f8d926bc580cf6eb887 (patch) | |
| tree | 23891cf51a6f26653719ac7ddb5540d861999dcd /2018/osmodevcon2018-2017_retrospective/osmodevcon2018-2017_retrospective.html | |
| parent | 0e89fdc9fd9736d55ce462715b383637c39260c3 (diff) | |
osmodevcon: welcome, SD-E1, retrospective
Diffstat (limited to '2018/osmodevcon2018-2017_retrospective/osmodevcon2018-2017_retrospective.html')
| -rw-r--r-- | 2018/osmodevcon2018-2017_retrospective/osmodevcon2018-2017_retrospective.html | 4503 | 
1 files changed, 4503 insertions, 0 deletions
diff --git a/2018/osmodevcon2018-2017_retrospective/osmodevcon2018-2017_retrospective.html b/2018/osmodevcon2018-2017_retrospective/osmodevcon2018-2017_retrospective.html new file mode 100644 index 0000000..ac205c0 --- /dev/null +++ b/2018/osmodevcon2018-2017_retrospective/osmodevcon2018-2017_retrospective.html @@ -0,0 +1,4503 @@ +<?xml version="1.0" encoding="UTF-8"?>
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
 +<head>
 +<title>Year 2017 Osmocom retrospective</title>
 +<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
 +<meta name="copyright" content="Copyright © 2018 by Harald Welte (License: CC-BY-SA)" />
 +<meta name="generator" content="AsciiDoc 8.6.10" />
 +<style type="text/css">
 +/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
 +
 +/* Default font. */
 +body {
 +  font-family: Georgia,serif;
 +}
 +
 +/* Title font. */
 +h1, h2, h3, h4, h5, h6,
 +div.title, caption.title,
 +thead, p.table.header,
 +#toctitle,
 +#author, #revnumber, #revdate, #revremark,
 +#footer {
 +  font-family: Arial,Helvetica,sans-serif;
 +}
 +
 +body {
 +  margin: 1em 5% 1em 5%;
 +}
 +
 +a {
 +  color: blue;
 +  text-decoration: underline;
 +}
 +a:visited {
 +  color: fuchsia;
 +}
 +
 +em {
 +  font-style: italic;
 +  color: navy;
 +}
 +
 +strong {
 +  font-weight: bold;
 +  color: #083194;
 +}
 +
 +h1, h2, h3, h4, h5, h6 {
 +  color: #527bbd;
 +  margin-top: 1.2em;
 +  margin-bottom: 0.5em;
 +  line-height: 1.3;
 +}
 +
 +h1, h2, h3 {
 +  border-bottom: 2px solid silver;
 +}
 +h2 {
 +  padding-top: 0.5em;
 +}
 +h3 {
 +  float: left;
 +}
 +h3 + * {
 +  clear: left;
 +}
 +h5 {
 +  font-size: 1.0em;
 +}
 +
 +div.sectionbody {
 +  margin-left: 0;
 +}
 +
 +hr {
 +  border: 1px solid silver;
 +}
 +
 +p {
 +  margin-top: 0.5em;
 +  margin-bottom: 0.5em;
 +}
 +
 +ul, ol, li > p {
 +  margin-top: 0;
 +}
 +ul > li     { color: #aaa; }
 +ul > li > * { color: black; }
 +
 +.monospaced, code, pre {
 +  font-family: "Courier New", Courier, monospace;
 +  font-size: inherit;
 +  color: navy;
 +  padding: 0;
 +  margin: 0;
 +}
 +pre {
 +  white-space: pre-wrap;
 +}
 +
 +#author {
 +  color: #527bbd;
 +  font-weight: bold;
 +  font-size: 1.1em;
 +}
 +#email {
 +}
 +#revnumber, #revdate, #revremark {
 +}
 +
 +#footer {
 +  font-size: small;
 +  border-top: 2px solid silver;
 +  padding-top: 0.5em;
 +  margin-top: 4.0em;
 +}
 +#footer-text {
 +  float: left;
 +  padding-bottom: 0.5em;
 +}
 +#footer-badges {
 +  float: right;
 +  padding-bottom: 0.5em;
 +}
 +
 +#preamble {
 +  margin-top: 1.5em;
 +  margin-bottom: 1.5em;
 +}
 +div.imageblock, div.exampleblock, div.verseblock,
 +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
 +div.admonitionblock {
 +  margin-top: 1.0em;
 +  margin-bottom: 1.5em;
 +}
 +div.admonitionblock {
 +  margin-top: 2.0em;
 +  margin-bottom: 2.0em;
 +  margin-right: 10%;
 +  color: #606060;
 +}
 +
 +div.content { /* Block element content. */
 +  padding: 0;
 +}
 +
 +/* Block element titles. */
 +div.title, caption.title {
 +  color: #527bbd;
 +  font-weight: bold;
 +  text-align: left;
 +  margin-top: 1.0em;
 +  margin-bottom: 0.5em;
 +}
 +div.title + * {
 +  margin-top: 0;
 +}
 +
 +td div.title:first-child {
 +  margin-top: 0.0em;
 +}
 +div.content div.title:first-child {
 +  margin-top: 0.0em;
 +}
 +div.content + div.title {
 +  margin-top: 0.0em;
 +}
 +
 +div.sidebarblock > div.content {
 +  background: #ffffee;
 +  border: 1px solid #dddddd;
 +  border-left: 4px solid #f0f0f0;
 +  padding: 0.5em;
 +}
 +
 +div.listingblock > div.content {
 +  border: 1px solid #dddddd;
 +  border-left: 5px solid #f0f0f0;
 +  background: #f8f8f8;
 +  padding: 0.5em;
 +}
 +
 +div.quoteblock, div.verseblock {
 +  padding-left: 1.0em;
 +  margin-left: 1.0em;
 +  margin-right: 10%;
 +  border-left: 5px solid #f0f0f0;
 +  color: #888;
 +}
 +
 +div.quoteblock > div.attribution {
 +  padding-top: 0.5em;
 +  text-align: right;
 +}
 +
 +div.verseblock > pre.content {
 +  font-family: inherit;
 +  font-size: inherit;
 +}
 +div.verseblock > div.attribution {
 +  padding-top: 0.75em;
 +  text-align: left;
 +}
 +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
 +div.verseblock + div.attribution {
 +  text-align: left;
 +}
 +
 +div.admonitionblock .icon {
 +  vertical-align: top;
 +  font-size: 1.1em;
 +  font-weight: bold;
 +  text-decoration: underline;
 +  color: #527bbd;
 +  padding-right: 0.5em;
 +}
 +div.admonitionblock td.content {
 +  padding-left: 0.5em;
 +  border-left: 3px solid #dddddd;
 +}
 +
 +div.exampleblock > div.content {
 +  border-left: 3px solid #dddddd;
 +  padding-left: 0.5em;
 +}
 +
 +div.imageblock div.content { padding-left: 0; }
 +span.image img { border-style: none; vertical-align: text-bottom; }
 +a.image:visited { color: white; }
 +
 +dl {
 +  margin-top: 0.8em;
 +  margin-bottom: 0.8em;
 +}
 +dt {
 +  margin-top: 0.5em;
 +  margin-bottom: 0;
 +  font-style: normal;
 +  color: navy;
 +}
 +dd > *:first-child {
 +  margin-top: 0.1em;
 +}
 +
 +ul, ol {
 +    list-style-position: outside;
 +}
 +ol.arabic {
 +  list-style-type: decimal;
 +}
 +ol.loweralpha {
 +  list-style-type: lower-alpha;
 +}
 +ol.upperalpha {
 +  list-style-type: upper-alpha;
 +}
 +ol.lowerroman {
 +  list-style-type: lower-roman;
 +}
 +ol.upperroman {
 +  list-style-type: upper-roman;
 +}
 +
 +div.compact ul, div.compact ol,
 +div.compact p, div.compact p,
 +div.compact div, div.compact div {
 +  margin-top: 0.1em;
 +  margin-bottom: 0.1em;
 +}
 +
 +tfoot {
 +  font-weight: bold;
 +}
 +td > div.verse {
 +  white-space: pre;
 +}
 +
 +div.hdlist {
 +  margin-top: 0.8em;
 +  margin-bottom: 0.8em;
 +}
 +div.hdlist tr {
 +  padding-bottom: 15px;
 +}
 +dt.hdlist1.strong, td.hdlist1.strong {
 +  font-weight: bold;
 +}
 +td.hdlist1 {
 +  vertical-align: top;
 +  font-style: normal;
 +  padding-right: 0.8em;
 +  color: navy;
 +}
 +td.hdlist2 {
 +  vertical-align: top;
 +}
 +div.hdlist.compact tr {
 +  margin: 0;
 +  padding-bottom: 0;
 +}
 +
 +.comment {
 +  background: yellow;
 +}
 +
 +.footnote, .footnoteref {
 +  font-size: 0.8em;
 +}
 +
 +span.footnote, span.footnoteref {
 +  vertical-align: super;
 +}
 +
 +#footnotes {
 +  margin: 20px 0 20px 0;
 +  padding: 7px 0 0 0;
 +}
 +
 +#footnotes div.footnote {
 +  margin: 0 0 5px 0;
 +}
 +
 +#footnotes hr {
 +  border: none;
 +  border-top: 1px solid silver;
 +  height: 1px;
 +  text-align: left;
 +  margin-left: 0;
 +  width: 20%;
 +  min-width: 100px;
 +}
 +
 +div.colist td {
 +  padding-right: 0.5em;
 +  padding-bottom: 0.3em;
 +  vertical-align: top;
 +}
 +div.colist td img {
 +  margin-top: 0.3em;
 +}
 +
 +@media print {
 +  #footer-badges { display: none; }
 +}
 +
 +#toc {
 +  margin-bottom: 2.5em;
 +}
 +
 +#toctitle {
 +  color: #527bbd;
 +  font-size: 1.1em;
 +  font-weight: bold;
 +  margin-top: 1.0em;
 +  margin-bottom: 0.1em;
 +}
 +
 +div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
 +  margin-top: 0;
 +  margin-bottom: 0;
 +}
 +div.toclevel2 {
 +  margin-left: 2em;
 +  font-size: 0.9em;
 +}
 +div.toclevel3 {
 +  margin-left: 4em;
 +  font-size: 0.9em;
 +}
 +div.toclevel4 {
 +  margin-left: 6em;
 +  font-size: 0.9em;
 +}
 +
 +span.aqua { color: aqua; }
 +span.black { color: black; }
 +span.blue { color: blue; }
 +span.fuchsia { color: fuchsia; }
 +span.gray { color: gray; }
 +span.green { color: green; }
 +span.lime { color: lime; }
 +span.maroon { color: maroon; }
 +span.navy { color: navy; }
 +span.olive { color: olive; }
 +span.purple { color: purple; }
 +span.red { color: red; }
 +span.silver { color: silver; }
 +span.teal { color: teal; }
 +span.white { color: white; }
 +span.yellow { color: yellow; }
 +
 +span.aqua-background { background: aqua; }
 +span.black-background { background: black; }
 +span.blue-background { background: blue; }
 +span.fuchsia-background { background: fuchsia; }
 +span.gray-background { background: gray; }
 +span.green-background { background: green; }
 +span.lime-background { background: lime; }
 +span.maroon-background { background: maroon; }
 +span.navy-background { background: navy; }
 +span.olive-background { background: olive; }
 +span.purple-background { background: purple; }
 +span.red-background { background: red; }
 +span.silver-background { background: silver; }
 +span.teal-background { background: teal; }
 +span.white-background { background: white; }
 +span.yellow-background { background: yellow; }
 +
 +span.big { font-size: 2em; }
 +span.small { font-size: 0.6em; }
 +
 +span.underline { text-decoration: underline; }
 +span.overline { text-decoration: overline; }
 +span.line-through { text-decoration: line-through; }
 +
 +div.unbreakable { page-break-inside: avoid; }
 +
 +
 +/*
 + * xhtml11 specific
 + *
 + * */
 +
 +div.tableblock {
 +  margin-top: 1.0em;
 +  margin-bottom: 1.5em;
 +}
 +div.tableblock > table {
 +  border: 3px solid #527bbd;
 +}
 +thead, p.table.header {
 +  font-weight: bold;
 +  color: #527bbd;
 +}
 +p.table {
 +  margin-top: 0;
 +}
 +/* Because the table frame attribute is overriden by CSS in most browsers. */
 +div.tableblock > table[frame="void"] {
 +  border-style: none;
 +}
 +div.tableblock > table[frame="hsides"] {
 +  border-left-style: none;
 +  border-right-style: none;
 +}
 +div.tableblock > table[frame="vsides"] {
 +  border-top-style: none;
 +  border-bottom-style: none;
 +}
 +
 +
 +/*
 + * html5 specific
 + *
 + * */
 +
 +table.tableblock {
 +  margin-top: 1.0em;
 +  margin-bottom: 1.5em;
 +}
 +thead, p.tableblock.header {
 +  font-weight: bold;
 +  color: #527bbd;
 +}
 +p.tableblock {
 +  margin-top: 0;
 +}
 +table.tableblock {
 +  border-width: 3px;
 +  border-spacing: 0px;
 +  border-style: solid;
 +  border-color: #527bbd;
 +  border-collapse: collapse;
 +}
 +th.tableblock, td.tableblock {
 +  border-width: 1px;
 +  padding: 4px;
 +  border-style: solid;
 +  border-color: #527bbd;
 +}
 +
 +table.tableblock.frame-topbot {
 +  border-left-style: hidden;
 +  border-right-style: hidden;
 +}
 +table.tableblock.frame-sides {
 +  border-top-style: hidden;
 +  border-bottom-style: hidden;
 +}
 +table.tableblock.frame-none {
 +  border-style: hidden;
 +}
 +
 +th.tableblock.halign-left, td.tableblock.halign-left {
 +  text-align: left;
 +}
 +th.tableblock.halign-center, td.tableblock.halign-center {
 +  text-align: center;
 +}
 +th.tableblock.halign-right, td.tableblock.halign-right {
 +  text-align: right;
 +}
 +
 +th.tableblock.valign-top, td.tableblock.valign-top {
 +  vertical-align: top;
 +}
 +th.tableblock.valign-middle, td.tableblock.valign-middle {
 +  vertical-align: middle;
 +}
 +th.tableblock.valign-bottom, td.tableblock.valign-bottom {
 +  vertical-align: bottom;
 +}
 +
 +
 +/*
 + * manpage specific
 + *
 + * */
 +
 +body.manpage h1 {
 +  padding-top: 0.5em;
 +  padding-bottom: 0.5em;
 +  border-top: 2px solid silver;
 +  border-bottom: 2px solid silver;
 +}
 +body.manpage h2 {
 +  border-style: none;
 +}
 +body.manpage div.sectionbody {
 +  margin-left: 3em;
 +}
 +
 +@media print {
 +  body.manpage div#toc { display: none; }
 +}
 +/* slidy.css
 +
 +   Copyright (c) 2005-2010 W3C (MIT, ERCIM, Keio), All Rights Reserved.
 +   W3C liability, trademark, document use and software licensing
 +   rules apply, see:
 +
 +   http://www.w3.org/Consortium/Legal/copyright-documents
 +   http://www.w3.org/Consortium/Legal/copyright-software
 +*/
 +
 +/*
 +   SJR: 2010-09-29: Modified for AsciiDoc slidy backend.
 +   Mostly just commented out stuff that is handled by AsciiDoc's CSS files.
 +*/
 +
 +body
 +{
 +  margin: 0 0 0 0;
 +  padding: 0 0 0 0;
 +  width: 100%;
 +  height: 100%;
 +  color: black;
 +  background-color: white;
 +/*
 +  font-family: "Gill Sans MT", "Gill Sans", GillSans, sans-serif;
 +*/
 +  font-size: 14pt;
 +}
 +
 +div.toolbar {
 +  position: fixed; z-index: 200;
 +  top: auto; bottom: 0; left: 0; right: 0;
 +  height: 1.2em; text-align: right;
 +  padding-left: 1em;
 +  padding-right: 1em;
 +  font-size: 60%;
 +  color: red;
 +  background-color: rgb(240,240,240);
 +  border-top: solid 1px rgb(180,180,180);
 +}
 +
 +div.toolbar span.copyright {
 +  color: black;
 +  margin-left: 0.5em;
 +}
 +
 +div.initial_prompt {
 +  position: absolute;
 +  z-index: 1000;
 +  bottom: 1.2em;
 +  width: 90%;
 +  background-color: rgb(200,200,200);
 +  opacity: 0.35;
 +  background-color: rgb(200,200,200, 0.35);
 +  cursor: pointer;
 +}
 +
 +div.initial_prompt p.help {
 +  text-align: center;
 +}
 +
 +div.initial_prompt p.close {
 +  text-align: right;
 +  font-style: italic;
 +}
 +
 +div.slidy_toc {
 +  position: absolute;
 +  z-index: 300;
 +  width: 60%;
 +  max-width: 30em;
 +  height: 30em;
 +  overflow: auto;
 +  top: auto;
 +  right: auto;
 +  left: 4em;
 +  bottom: 4em;
 +  padding: 1em;
 +  background: rgb(240,240,240);
 +  border-style: solid;
 +  border-width: 2px;
 +  font-size: 60%;
 +}
 +
 +div.slidy_toc .toc_heading {
 +  text-align: center;
 +  width: 100%;
 +  margin: 0;
 +  margin-bottom: 1em;
 +  border-bottom-style: solid;
 +  border-bottom-color: rgb(180,180,180);
 +  border-bottom-width: 1px;
 +}
 +
 +div.slide {
 +  z-index: 20;
 +  margin: 0 0 0 0;
 +  padding-top: 0;
 +  padding-bottom: 0;
 +  padding-left: 20px;
 +  padding-right: 20px;
 +  border-width: 0;
 +  clear: both;
 +  top: 0;
 +  bottom: 0;
 +  left: 0;
 +  right: 0;
 +  line-height: 120%;
 +  background-color: transparent;
 +}
 +
 +div.background {
 +  display: none;
 +}
 +
 +div.handout {
 +  margin-left: 20px;
 +  margin-right: 20px;
 +}
 +
 +div.slide.titlepage {
 +  text-align: center;
 +}
 +
 +div.slide.titlepage.h1 {
 +  padding-top: 10%;
 +}
 +
 +div.slide h1 {
 +  padding-left: 0;
 +  padding-right: 20pt;
 +  padding-top: 4pt;
 +  padding-bottom: 4pt;
 +  margin-top: 0;
 +  margin-left: 0;
 +  margin-right: 60pt;
 +  margin-bottom: 0.5em;
 +  display: block;
 +  font-size: 160%;
 +  line-height: 1.2em;
 +  background: transparent;
 +}
 +
 +div.toc {
 +  position: absolute;
 +  top: auto;
 +  bottom: 4em;
 +  left: 4em;
 +  right: auto;
 +  width: 60%;
 +  max-width: 30em;
 +  height: 30em;
 +  border: solid thin black;
 +  padding: 1em;
 +  background: rgb(240,240,240);
 +  color: black;
 +  z-index: 300;
 +  overflow: auto;
 +  display: block;
 +  visibility: visible;
 +}
 +
 +div.toc-heading {
 +  width: 100%;
 +  border-bottom: solid 1px rgb(180,180,180);
 +  margin-bottom: 1em;
 +  text-align: center;
 +}
 +
 +/*
 +pre {
 + font-size: 80%;
 + font-weight: bold;
 + line-height: 120%;
 + padding-top: 0.2em;
 + padding-bottom: 0.2em;
 + padding-left: 1em;
 + padding-right: 1em;
 + border-style: solid;
 + border-left-width: 1em;
 + border-top-width: thin;
 + border-right-width: thin;
 + border-bottom-width: thin;
 + border-color: #95ABD0;
 + color: #00428C;
 + background-color: #E4E5E7;
 +}
 +*/
 +
 +/*
 +li pre { margin-left: 0; }
 +
 +blockquote { font-style: italic }
 +
 +img { background-color: transparent }
 +
 +p.copyright { font-size: smaller }
 +*/
 +
 +.center { text-align: center }
 +.footnote { font-size: smaller; margin-left: 2em; }
 +
 +/*
 +a img { border-width: 0; border-style: none }
 +*/
 +
 +a:visited { color: navy }
 +a:link { color: navy }
 +a:hover { color: red; text-decoration: underline }
 +a:active { color: red; text-decoration: underline }
 +
 +a {text-decoration: none}
 +.navbar a:link {color: white}
 +.navbar a:visited {color: yellow}
 +.navbar a:active {color: red}
 +.navbar a:hover {color: red}
 +
 +/*
 +ul { list-style-type: square; }
 +ul ul { list-style-type: disc; }
 +ul ul ul { list-style-type: circle; }
 +ul ul ul ul { list-style-type: disc; }
 +li { margin-left: 0.5em; margin-top: 0.5em; }
 +li li { font-size: 85%; font-style: italic }
 +li li li { font-size: 85%; font-style: normal }
 +*/
 +
 +div dt
 +{
 +  margin-left: 0;
 +  margin-top: 1em;
 +  margin-bottom: 0.5em;
 +  font-weight: bold;
 +}
 +div dd
 +{
 +  margin-left: 2em;
 +  margin-bottom: 0.5em;
 +}
 +
 +
 +/*
 +p,pre,ul,ol,blockquote,h2,h3,h4,h5,h6,dl,table {
 +  margin-left: 1em;
 +  margin-right: 1em;
 +}
 +*/
 +
 +p.subhead { font-weight: bold; margin-top: 2em; }
 +
 +.smaller { font-size: smaller }
 +.bigger { font-size: 130% }
 +
 +/*
 +td,th { padding: 0.2em }
 +*/
 +
 +ul {
 +  margin: 0.5em 1.5em 0.5em 1.5em;
 +  padding: 0;
 +}
 +
 +ol {
 +  margin: 0.5em 1.5em 0.5em 1.5em;
 +  padding: 0;
 +}
 +
 +ul { list-style-type: square; }
 +ul ul { list-style-type: disc; }
 +ul ul ul { list-style-type: circle; }
 +ul ul ul ul { list-style-type: disc; }
 +
 +/*
 +ul li {
 +  list-style: square;
 +  margin: 0.1em 0em 0.6em 0;
 +  padding: 0 0 0 0;
 +  line-height: 140%;
 +}
 +
 +ol li {
 +  margin: 0.1em 0em 0.6em 1.5em;
 +  padding: 0 0 0 0px;
 +  line-height: 140%;
 +  list-style-type: decimal;
 +}
 +
 +li ul li {
 +  font-size: 85%;
 +  font-style: italic;
 +  list-style-type: disc;
 +  background: transparent;
 +  padding: 0 0 0 0;
 +}
 +li li ul li {
 +  font-size: 85%;
 +  font-style: normal;
 +  list-style-type: circle;
 +  background: transparent;
 +  padding: 0 0 0 0;
 +}
 +li li li ul li {
 +  list-style-type: disc;
 +  background: transparent;
 +  padding: 0 0 0 0;
 +}
 +
 +li ol li {
 +  list-style-type: decimal;
 +}
 +
 +
 +li li ol li {
 +  list-style-type: decimal;
 +}
 +*/
 +
 +/*
 + setting class="outline" on ol or ul makes it behave as an
 + ouline list where blocklevel content in li elements is
 + hidden by default and can be expanded or collapsed with
 + mouse click. Set class="expand" on li to override default
 +*/
 +
 +ol.outline li:hover { cursor: pointer }
 +ol.outline li.nofold:hover { cursor: default }
 +
 +ul.outline li:hover { cursor: pointer }
 +ul.outline li.nofold:hover { cursor: default }
 +
 +ol.outline { list-style:decimal; }
 +ol.outline ol { list-style-type:lower-alpha }
 +
 +ol.outline li.nofold {
 +  padding: 0 0 0 20px;
 +  background: transparent url(../graphics/nofold-dim.gif) no-repeat 0px 0.5em;
 +}
 +ol.outline li.unfolded {
 +  padding: 0 0 0 20px;
 +  background: transparent url(../graphics/fold-dim.gif) no-repeat 0px 0.5em;
 +}
 +ol.outline li.folded {
 +  padding: 0 0 0 20px;
 +  background: transparent url(../graphics/unfold-dim.gif) no-repeat 0px 0.5em;
 +}
 +ol.outline li.unfolded:hover {
 +  padding: 0 0 0 20px;
 +  background: transparent url(../graphics/fold.gif) no-repeat 0px 0.5em;
 +}
 +ol.outline li.folded:hover {
 +  padding: 0 0 0 20px;
 +  background: transparent url(../graphics/unfold.gif) no-repeat 0px 0.5em;
 +}
 +
 +ul.outline li.nofold {
 +  padding: 0 0 0 20px;
 +  background: transparent url(../graphics/nofold-dim.gif) no-repeat 0px 0.5em;
 +}
 +ul.outline li.unfolded {
 +  padding: 0 0 0 20px;
 +  background: transparent url(../graphics/fold-dim.gif) no-repeat 0px 0.5em;
 +}
 +ul.outline li.folded {
 +  padding: 0 0 0 20px;
 +  background: transparent url(../graphics/unfold-dim.gif) no-repeat 0px 0.5em;
 +}
 +ul.outline li.unfolded:hover {
 +  padding: 0 0 0 20px;
 +  background: transparent url(../graphics/fold.gif) no-repeat 0px 0.5em;
 +}
 +ul.outline li.folded:hover {
 +  padding: 0 0 0 20px;
 +  background: transparent url(../graphics/unfold.gif) no-repeat 0px 0.5em;
 +}
 +
 +/* for slides with class "title" in table of contents */
 +a.titleslide { font-weight: bold; font-style: italic }
 +
 +/*
 + hide images for work around for save as bug
 + where browsers fail to save images used by CSS
 +*/
 +img.hidden { display: none; visibility: hidden }
 +div.initial_prompt { display: none; visibility: hidden }
 +
 +  div.slide {
 +     visibility: visible;
 +     position: inherit;
 +  }
 +  div.handout {
 +     border-top-style: solid;
 +     border-top-width: thin;
 +     border-top-color: black;
 +  }
 +
 +@media screen {
 +  .hidden { display: none; visibility: visible }
 +
 +  div.slide.hidden { display: block; visibility: visible }
 +  div.handout.hidden { display: block; visibility: visible }
 +  div.background { display: none; visibility: hidden }
 +  body.single_slide div.initial_prompt { display: block; visibility: visible }
 +  body.single_slide div.background { display: block; visibility: visible }
 +  body.single_slide div.background.hidden { display: none; visibility: hidden }
 +  body.single_slide .invisible { visibility: hidden }
 +  body.single_slide .hidden { display: none; visibility: hidden }
 +  body.single_slide div.slide { position: absolute }
 +  body.single_slide div.handout { display: none; visibility: hidden }
 +}
 +
 +@media print {
 +  .hidden { display: block; visibility: visible }
 +
 +/*
 +  div.slide pre { font-size: 60%; padding-left: 0.5em; }
 +*/
 +  div.toolbar { display: none; visibility: hidden; }
 +  div.slidy_toc { display: none; visibility: hidden; }
 +  div.background { display: none; visibility: hidden; }
 +  div.slide { page-break-before: always }
 +  /* :first-child isn't reliable for print media */
 +  div.slide.first-slide { page-break-before: avoid }
 +}
 +
 +
 +/* SJR: AsciiDoc slidy backend tweaks */
 +
 +ol, ul {
 +  margin: 0.8em 1.5em 0.8em 1.8em;
 +}
 +li > ul, li > ol {
 +  margin-top: 0.5em;
 +}
 +
 +.outline > li.folded,
 +.outline > li.unfolded {
 +  color: #527bbd;
 +}
 +ul > li{ color: #aaa; }
 +ul > li > *, ol > li > * { color: black; }
 +
 +li {
 +  margin-top: 0.5em;
 +  margin-bottom: 0.5em;
 +}
 +
 +
 +</style>
 +<script type="text/javascript">
 +/*<![CDATA[*/
 +/* slidy.js
 +
 +   Copyright (c) 2005-2010 W3C (MIT, ERCIM, Keio), All Rights Reserved.
 +   W3C liability, trademark, document use and software licensing
 +   rules apply, see:
 +
 +   http://www.w3.org/Consortium/Legal/copyright-documents
 +   http://www.w3.org/Consortium/Legal/copyright-software
 +*/
 +
 +// the slidy object implementation
 +var w3c_slidy = {
 +  // classify which kind of browser we're running under
 +  ns_pos: (typeof window.pageYOffset!='undefined'),
 +  khtml: ((navigator.userAgent).indexOf("KHTML") >= 0 ? true : false),
 +  opera: ((navigator.userAgent).indexOf("Opera") >= 0 ? true : false),
 +  ipad: ((navigator.userAgent).indexOf("iPad") >= 0 ? true : false),
 +  iphone: ((navigator.userAgent).indexOf("iPhone") >= 0 ? true : false),
 +  ie: (typeof document.all != "undefined" && !this.opera),
 +  ie6: (!this.ns_pos && navigator.userAgent.indexOf("MSIE 6") != -1),
 +  ie7: (!this.ns_pos && navigator.userAgent.indexOf("MSIE 7") != -1),
 +  ie8: (!this.ns_pos && navigator.userAgent.indexOf("MSIE 8") != -1),
 +  ie9: (!this.ns_pos && navigator.userAgent.indexOf("MSIE 9") != -1),
 +  keyboardless: (this.ipad || this.iphone),
 +
 +  // are we running as XHTML? (doesn't work on Opera)
 +  is_xhtml: /xml/.test(document.contentType),
 +
 +  slide_number: 0, // integer slide count: 0, 1, 2, ...
 +  slide_number_element: null, // element containing slide number
 +  slides: [], // set to array of slide div's
 +  notes: [], // set to array of handout div's
 +  backgrounds: [], // set to array of background div's
 +  toolbar: null, // element containing toolbar
 +  title: null, // document title
 +  last_shown: null, // last incrementally shown item
 +  eos: null,  // span element for end of slide indicator
 +  toc: null, // table of contents
 +  outline: null, // outline element with the focus
 +  selected_text_len: 0, // length of drag selection on document
 +  view_all: 0,  // 1 to view all slides + handouts
 +  want_toolbar: true,  // user preference to show/hide toolbar
 +  mouse_click_enabled: true, // enables left click for next slide
 +  scroll_hack: 0, // IE work around for position: fixed
 +  disable_slide_click: false,  // used by clicked anchors
 +
 +  lang: "en", // updated to language specified by html file
 +
 +  help_anchor: null, // used for keyboard focus hack in showToolbar()
 +  help_page: "http://www.w3.org/Talks/Tools/Slidy2/help/help.html",
 +  help_text: "Navigate with mouse click, space bar, Cursor Left/Right, " +
 +             "or Pg Up and Pg Dn. Use S and B to change font size.",
 +
 +  size_index: 0,
 +  size_adjustment: 0,
 +  sizes:  new Array("10pt", "12pt", "14pt", "16pt", "18pt", "20pt",
 +                    "22pt", "24pt", "26pt", "28pt", "30pt", "32pt"),
 +
 +  // needed for efficient resizing
 +  last_width: 0,
 +  last_height: 0,
 +
 +
 +  // Needed for cross browser support for relative width/height on
 +  // object elements. The work around is to save width/height attributes
 +  // and then to recompute absolute width/height dimensions on resizing
 +   objects: [],
 +
 +  // attach initialiation event handlers
 +  set_up: function () {
 +    var init = function() { w3c_slidy.init(); };
 +    if (typeof window.addEventListener != "undefined")
 +      window.addEventListener("load", init, false);
 +    else
 +      window.attachEvent("onload", init);
 +  },
 +
 +  hide_slides: function () {
 +    if (document.body && !w3c_slidy.initialized)
 +      document.body.style.visibility = "hidden";
 +    else
 +      setTimeout(w3c_slidy.hide_slides, 50);
 +  },
 +
 +  // hack to persuade IE to compute correct document height
 +  // as needed for simulating fixed positioning of toolbar
 +  ie_hack: function () {
 +    window.resizeBy(0,-1);
 +    window.resizeBy(0, 1);
 +  },
 +
 +  init: function () {
 +    //alert("slidy starting test 10");
 +    document.body.style.visibility = "visible";
 +    w3c_slidy_i18n.init();
 +    this.add_toolbar();
 +    this.wrap_implicit_slides();
 +    this.collect_slides();
 +    this.collect_notes();
 +    this.collect_backgrounds();
 +    this.objects = document.body.getElementsByTagName("object");
 +    this.patch_anchors();
 +    this.slide_number = this.find_slide_number(location.href);
 +    window.offscreenbuffering = true;
 +    this.size_adjustment = this.find_size_adjust();
 +    this.time_left = this.find_duration();
 +    this.hide_image_toolbar();  // suppress IE image toolbar popup
 +    this.init_outliner();  // activate fold/unfold support
 +    this.title = document.title;
 +
 +    // work around for opera bug
 +    this.is_xhtml = (document.body.tagName == "BODY" ? false : true);
 +
 +    if (this.slides.length > 0)
 +    {
 +      var slide = this.slides[this.slide_number];
 +
 +      if (this.slide_number > 0)
 +      {
 +        this.set_visibility_all_incremental("visible");
 +        this.last_shown = this.previous_incremental_item(null);
 +        this.set_eos_status(true);
 +      }
 +      else
 +      {
 +        this.last_shown = null;
 +        this.set_visibility_all_incremental("hidden");
 +        this.set_eos_status(!this.next_incremental_item(this.last_shown));
 +      }
 +
 +      this.set_location();
 +      this.add_class(this.slides[0], "first-slide");
 +      w3c_slidy.show_slide(slide);
 +    }
 +
 +    this.toc = this.table_of_contents();
 +
 +    this.add_initial_prompt();
 +
 +    // bind event handlers without interfering with custom page scripts
 +    // Tap events behave too weirdly to support clicks reliably on
 +    // iPhone and iPad, so exclude these from click handler
 +
 +    if (!this.keyboardless)
 +      this.add_listener(document.body, "click", this.mouse_button_click);
 +
 +    this.add_listener(document, "keydown", this.key_down);
 +    this.add_listener(document, "keypress", this.key_press);
 +    this.add_listener(window, "resize", this.resized);
 +    this.add_listener(window, "scroll", this.scrolled);
 +    this.add_listener(window, "unload", this.unloaded);
 +
 +    if (!document.body.onclick)
 +      document.body.onclick = function () { };
 +
 +    this.single_slide_view();
 +
 +    //this.set_location();
 +
 +    this.resized();
 +
 +    if (this.ie7)
 +      setTimeout(w3c_slidy.ie_hack, 100);
 +
 +    this.show_toolbar();
 +
 +    // for back button detection
 +    setInterval(function () { w3c_slidy.check_location(); }, 200);
 +    w3c_slidy.initialized = true;
 +  },
 +
 +  // create div element with links to each slide
 +  table_of_contents: function () {
 +    var toc = this.create_element("div");
 +    this.add_class(toc, "slidy_toc hidden");
 +    //toc.setAttribute("tabindex", "0");
 +
 +    var heading = this.create_element("div");
 +    this.add_class(heading, "toc-heading");
 +    heading.innerHTML = "Table of Contents".localize();
 +
 +    toc.appendChild(heading);
 +    var previous = null;
 +
 +    for (var i = 0; i < this.slides.length; ++i)
 +    {
 +      var title = this.has_class(this.slides[i], "title");
 +      var num = document.createTextNode((i + 1) + ". ");
 +
 +      toc.appendChild(num);
 +
 +      var a = this.create_element("a");
 +      a.setAttribute("href", "#(" + (i+1) + ")");
 +
 +      if (title)
 +        this.add_class(a, "titleslide");
 +
 +      var name = document.createTextNode(this.slide_name(i));
 +      a.appendChild(name);
 +      a.onclick = w3c_slidy.toc_click;
 +      a.onkeydown = w3c_slidy.toc_keydown;
 +      a.previous = previous;
 +
 +      if (previous)
 +        previous.next = a;
 +
 +      toc.appendChild(a);
 +
 +      if (i == 0)
 +        toc.first = a;
 +
 +      if (i < this.slides.length - 1)
 +      {
 +        var br = this.create_element("br");
 +        toc.appendChild(br);
 +      }
 +
 +      previous = a;
 +    }
 +
 +    toc.focus = function () {
 +      if (this.first)
 +        this.first.focus();
 +    }
 +
 +    toc.onmouseup = w3c_slidy.mouse_button_up;
 +
 +    toc.onclick = function (e) {
 +      e||(e=window.event);
 +
 +      if (w3c_slidy.selected_text_len <= 0)
 +         w3c_slidy.hide_table_of_contents();
 +
 +      w3c_slidy.stop_propagation(e);
 +
 +      if (e.cancel != undefined)
 +        e.cancel = true;
 +
 +      if (e.returnValue != undefined)
 +        e.returnValue = false;
 +
 +      return false;
 +    };
 +
 +    document.body.insertBefore(toc, document.body.firstChild);
 +    return toc;
 +  },
 +
 +  is_shown_toc: function () {
 +    return !w3c_slidy.has_class(w3c_slidy.toc, "hidden");
 +  },
 +
 +  show_table_of_contents: function () {
 +    w3c_slidy.remove_class(w3c_slidy.toc, "hidden");
 +    var toc = w3c_slidy.toc;
 +    toc.focus();
 +
 +    if (w3c_slidy.ie7 && w3c_slidy.slide_number == 0)
 +      setTimeout(w3c_slidy.ie_hack, 100);
 +  },
 +
 +  hide_table_of_contents: function () {
 +    w3c_slidy.add_class(w3c_slidy.toc, "hidden");
 +
 +    if (!w3c_slidy.opera)
 +      w3c_slidy.help_anchor.focus();
 +  },
 +
 +  toggle_table_of_contents: function () {
 +    if (w3c_slidy.is_shown_toc())
 +      w3c_slidy.hide_table_of_contents();
 +    else
 +      w3c_slidy.show_table_of_contents();
 +  },
 +
 +  // called on clicking toc entry
 +  toc_click: function (e) {
 +    if (!e)
 +      e = window.event;
 +
 +    var target = w3c_slidy.get_target(e);
 +
 +    if (target && target.nodeType == 1)
 +    {
 +      var uri = target.getAttribute("href");
 +
 +      if (uri)
 +      {
 +        //alert("going to " + uri);
 +        var slide = w3c_slidy.slides[w3c_slidy.slide_number];
 +        w3c_slidy.hide_slide(slide);
 +        w3c_slidy.slide_number = w3c_slidy.find_slide_number(uri);
 +        slide = w3c_slidy.slides[w3c_slidy.slide_number];
 +        w3c_slidy.last_shown = null;
 +        w3c_slidy.set_location();
 +        w3c_slidy.set_visibility_all_incremental("hidden");
 +        w3c_slidy.set_eos_status(!w3c_slidy.next_incremental_item(w3c_slidy.last_shown));
 +        w3c_slidy.show_slide(slide);
 +        //target.focus();
 +
 +        try
 +        {
 +          if (!w3c_slidy.opera)
 +            w3c_slidy.help_anchor.focus();
 +        }
 +        catch (e)
 +        {
 +        }
 +      }
 +    }
 +
 +    w3c_slidy.hide_table_of_contents(e);
 +    if (w3c_slidy.ie7) w3c_slidy.ie_hack();
 +    w3c_slidy.stop_propagation(e);
 +    return w3c_slidy.cancel(e);
 +  },
 +
 +  // called onkeydown for toc entry
 +  toc_keydown: function (event) {
 +    var key;
 +
 +    if (!event)
 +      var event = window.event;
 +
 +    // kludge around NS/IE differences
 +    if (window.event)
 +      key = window.event.keyCode;
 +    else if (event.which)
 +      key = event.which;
 +    else
 +      return true; // Yikes! unknown browser
 +
 +    // ignore event if key value is zero
 +    // as for alt on Opera and Konqueror
 +    if (!key)
 +      return true;
 +
 +    // check for concurrent control/command/alt key
 +    // but are these only present on mouse events?
 +
 +    if (event.ctrlKey || event.altKey)
 +      return true;
 +
 +    if (key == 13)
 +    {
 +      var uri = this.getAttribute("href");
 +
 +      if (uri)
 +      {
 +        //alert("going to " + uri);
 +       var slide = w3c_slidy.slides[w3c_slidy.slide_number];
 +        w3c_slidy.hide_slide(slide);
 +        w3c_slidy.slide_number = w3c_slidy.find_slide_number(uri);
 +        slide = w3c_slidy.slides[w3c_slidy.slide_number];
 +        w3c_slidy.last_shown = null;
 +        w3c_slidy.set_location();
 +        w3c_slidy.set_visibility_all_incremental("hidden");
 +        w3c_slidy.set_eos_status(!w3c_slidy.next_incremental_item(w3c_slidy.last_shown));
 +        w3c_slidy.show_slide(slide);
 +        //target.focus();
 +
 +        try
 +        {
 +          if (!w3c_slidy.opera)
 +            w3c_slidy.help_anchor.focus();
 +        }
 +        catch (e)
 +        {
 +        }
 +      }
 +
 +      w3c_slidy.hide_table_of_contents();
 +
 +      if (self.ie7)
 +       w3c_slidy.ie_hack();
 +
 +      return w3c_slidy.cancel(event);
 +    }
 +
 +    if (key == 40 && this.next)
 +    {
 +      this.next.focus();
 +      return w3c_slidy.cancel(event);
 +    }
 +
 +    if (key == 38 && this.previous)
 +    {
 +      this.previous.focus();
 +      return w3c_slidy.cancel(event);
 +    }
 +
 +    return true;
 +  },
 +
 +
 +  // ### OBSOLETE ###
 +  before_print: function () {
 +    this.show_all_slides();
 +    this.hide_toolbar();
 +    alert("before print");
 +  },
 +
 +  // ### OBSOLETE ###
 +  after_print: function () {
 +    if (!this.view_all)
 +    {
 +      this.single_slide_view();
 +      this.show_toolbar();
 +    }
 +    alert("after print");
 +  },
 +
 +  // ### OBSOLETE ###
 +  print_slides: function () {
 +    this.before_print();
 +    window.print();
 +    this.after_print();
 +  },
 +
 +  // ### OBSOLETE ?? ###
 +  toggle_view: function () {
 +    if (this.view_all)
 +    {
 +      this.single_slide_view();
 +      this.show_toolbar();
 +      this.view_all = 0;
 +    }
 +    else
 +    {
 +      this.show_all_slides();
 +      this.hide_toolbar();
 +      this.view_all = 1;
 +    }
 +  },
 +
 +  // prepare for printing  ### OBSOLETE ###
 +  show_all_slides: function () {
 +    this.remove_class(document.body, "single_slide");
 +    this.set_visibility_all_incremental("visible");
 +  },
 +
 +  // restore after printing  ### OBSOLETE ###
 +  single_slide_view: function () {
 +    this.add_class(document.body, "single_slide");
 +    this.set_visibility_all_incremental("visible");
 +    this.last_shown = this.previous_incremental_item(null);
 +  },
 +
 +  // suppress IE's image toolbar pop up
 +  hide_image_toolbar: function () {
 +    if (!this.ns_pos)
 +    {
 +      var images = document.getElementsByTagName("IMG");
 +
 +      for (var i = 0; i < images.length; ++i)
 +        images[i].setAttribute("galleryimg", "no");
 +    }
 +  },
 +
 +  unloaded: function (e) {
 +    //alert("unloaded");
 +  },
 +
 +  // Safari and Konqueror don't yet support getComputedStyle()
 +  // and they always reload page when location.href is updated
 +  is_KHTML: function () {
 +    var agent = navigator.userAgent;
 +    return (agent.indexOf("KHTML") >= 0 ? true : false);
 +  },
 +
 +  // find slide name from first h1 element
 +  // default to document title + slide number
 +  slide_name: function (index) {
 +    var name = null;
 +    var slide = this.slides[index];
 +
 +    var heading = this.find_heading(slide);
 +
 +    if (heading)
 +      name = this.extract_text(heading);
 +
 +    if (!name)
 +      name = this.title + "(" + (index + 1) + ")";
 +
 +    name.replace(/\&/g, "&");
 +    name.replace(/\</g, "<");
 +    name.replace(/\>/g, ">");
 +
 +    return name;
 +  },
 +
 +  // find first h1 element in DOM tree
 +  find_heading: function (node) {
 +    if (!node || node.nodeType != 1)
 +      return null;
 +
 +    if (node.nodeName == "H1" || node.nodeName == "h1")
 +      return node;
 +
 +    var child = node.firstChild;
 +
 +    while (child)
 +    {
 +      node = this.find_heading(child);
 +
 +      if (node)
 +        return node;
 +
 +      child = child.nextSibling;
 +    }
 +
 +    return null;
 +  },
 +
 +  // recursively extract text from DOM tree
 +  extract_text: function (node) {
 +    if (!node)
 +      return "";
 +
 +    // text nodes
 +    if (node.nodeType == 3)
 +      return node.nodeValue;
 +
 +    // elements
 +    if (node.nodeType == 1)
 +    {
 +      node = node.firstChild;
 +      var text = "";
 +
 +      while (node)
 +      {
 +        text = text + this.extract_text(node);
 +        node = node.nextSibling;
 +      }
 +
 +      return text;
 +    }
 +
 +    return "";
 +  },
 +
 +  // find copyright text from meta element
 +  find_copyright: function () {
 +    var name, content;
 +    var meta = document.getElementsByTagName("meta");
 +
 +    for (var i = 0; i < meta.length; ++i)
 +    {
 +      name = meta[i].getAttribute("name");
 +      content = meta[i].getAttribute("content");
 +
 +      if (name == "copyright")
 +        return content;
 +    }
 +
 +    return null;
 +  },
 +
 +  find_size_adjust: function () {
 +    var name, content, offset;
 +    var meta = document.getElementsByTagName("meta");
 +
 +    for (var i = 0; i < meta.length; ++i)
 +    {
 +      name = meta[i].getAttribute("name");
 +      content = meta[i].getAttribute("content");
 +
 +      if (name == "font-size-adjustment")
 +        return 1 * content;
 +    }
 +
 +    return 1;
 +  },
 +
 +  // <meta name="duration" content="20" />  for 20 minutes
 +  find_duration: function () {
 +    var name, content, offset;
 +    var meta = document.getElementsByTagName("meta");
 +
 +    for (var i = 0; i < meta.length; ++i)
 +    {
 +      name = meta[i].getAttribute("name");
 +      content = meta[i].getAttribute("content");
 +
 +      if (name == "duration")
 +        return 60000 * content;
 +    }
 +
 +    return null;
 +  },
 +
 +  replace_by_non_breaking_space: function (str) {
 +    for (var i = 0; i < str.length; ++i)
 +      str[i] = 160;
 +  },
 +
 +  // ### CHECK ME ### is use of "li" okay for text/html?
 +  // for XHTML do we also need to specify namespace?
 +  init_outliner: function () {
 +    var items = document.getElementsByTagName("li");
 +
 +    for (var i = 0; i < items.length; ++i)
 +    {
 +      var target = items[i];
 +
 +      if (!this.has_class(target.parentNode, "outline"))
 +        continue;
 +
 +      target.onclick = this.outline_click;
 +/* ### more work needed for IE6
 +      if (!this.ns_pos)
 +      {
 +        target.onmouseover = this.hover_outline;
 +        target.onmouseout = this.unhover_outline;
 +      }
 +*/
 +      if (this.foldable(target))
 +      {
 +        target.foldable = true;
 +        target.onfocus = function () {w3c_slidy.outline = this;};
 +        target.onblur = function () {w3c_slidy.outline = null;};
 +
 +        if (!target.getAttribute("tabindex"))
 +          target.setAttribute("tabindex", "0");
 +
 +        if (this.has_class(target, "expand"))
 +          this.unfold(target);
 +        else
 +          this.fold(target);
 +      }
 +      else
 +      {
 +        this.add_class(target, "nofold");
 +        target.visible = true;
 +        target.foldable = false;
 +      }
 +    }
 +  },
 +
 +  foldable: function (item) {
 +    if (!item || item.nodeType != 1)
 +      return false;
 +
 +    var node = item.firstChild;
 +
 +    while (node)
 +    {
 +      if (node.nodeType == 1 && this.is_block(node))
 +        return true;
 +
 +      node = node.nextSibling;
 +    }
 +
 +    return false;
 +  },
 +
 +  // ### CHECK ME ### switch to add/remove "hidden" class
 +  fold: function (item) {
 +    if (item)
 +    {
 +      this.remove_class(item, "unfolded");
 +      this.add_class(item, "folded");
 +    }
 +
 +    var node = item ? item.firstChild : null;
 +
 +    while (node)
 +    {
 +      if (node.nodeType == 1 && this.is_block(node)) // element
 +      {
 +         w3c_slidy.add_class(node, "hidden");
 +      }
 +
 +      node = node.nextSibling;
 +    }
 +
 +    item.visible = false;
 +  },
 +
 +  // ### CHECK ME ### switch to add/remove "hidden" class
 +  unfold: function (item) {
 +    if (item)
 +    {
 +      this.add_class(item, "unfolded");
 +      this.remove_class(item, "folded");
 +    }
 +
 +    var node = item ? item.firstChild : null;
 +
 +    while (node)
 +    {
 +      if (node.nodeType == 1 && this.is_block(node)) // element
 +      {
 +        w3c_slidy.remove_class(node, "hidden");
 +      }
 +
 +      node = node.nextSibling;
 +    }
 +
 +    item.visible = true;
 +  },
 +
 +  outline_click: function (e) {
 +    if (!e)
 +      e = window.event;
 +
 +    var rightclick = false;
 +    var target = w3c_slidy.get_target(e);
 +
 +    while (target && target.visible == undefined)
 +      target = target.parentNode;
 +
 +    if (!target)
 +      return true;
 +
 +    if (e.which)
 +      rightclick = (e.which == 3);
 +    else if (e.button)
 +      rightclick = (e.button == 2);
 +
 +    if (!rightclick && target.visible != undefined)
 +    {
 +      if (target.foldable)
 +      {
 +        if (target.visible)
 +          w3c_slidy.fold(target);
 +        else
 +          w3c_slidy.unfold(target);
 +      }
 +
 +      w3c_slidy.stop_propagation(e);
 +      e.cancel = true;
 +      e.returnValue = false;
 +    }
 +
 +    return false;
 +  },
 +
 +  add_initial_prompt: function () {
 +    var prompt = this.create_element("div");
 +    prompt.setAttribute("class", "initial_prompt");
 +
 +    var p1 = this.create_element("p");
 +    prompt.appendChild(p1);
 +    p1.setAttribute("class", "help");
 +
 +    if (this.keyboardless)
 +      p1.innerHTML = "Tap footer to move to next slide";
 +    else
 +      p1.innerHTML = "Space or Right Arrow to move to next " +
 +                     "slide, click help below for more details";
 +
 +    this.add_listener(prompt, "click", function (e) {
 +      document.body.removeChild(prompt);
 +      w3c_slidy.stop_propagation(e);
 +
 +      if (e.cancel != undefined)
 +        e.cancel = true;
 +
 +      if (e.returnValue != undefined)
 +        e.returnValue = false;
 +
 +      return false;
 +    });
 +
 +    document.body.appendChild(prompt);
 +    this.initial_prompt = prompt;
 +    setTimeout(function() {document.body.removeChild(prompt);}, 5000);
 +  },
 +
 +  add_toolbar: function () {
 +    var counter, page;
 +
 +     this.toolbar = this.create_element("div");
 +     this.toolbar.setAttribute("class", "toolbar");
 +
 +     // a reasonably behaved browser
 +     if (this.ns_pos || !this.ie6)
 +     {
 +       var right = this.create_element("div");
 +       right.setAttribute("style", "float: right; text-align: right");
 +
 +       counter = this.create_element("span")
 +       counter.innerHTML = "slide".localize() + " n/m";
 +       right.appendChild(counter);
 +       this.toolbar.appendChild(right);
 +
 +       var left = this.create_element("div");
 +       left.setAttribute("style", "text-align: left");
 +
 +       // global end of slide indicator
 +       this.eos = this.create_element("span");
 +       this.eos.innerHTML = "* ";
 +       left.appendChild(this.eos);
 +
 +       var help = this.create_element("a");
 +       help.setAttribute("href", this.help_page);
 +       help.setAttribute("title", this.help_text.localize());
 +       help.innerHTML = "help?".localize();
 +       left.appendChild(help);
 +       this.help_anchor = help;  // save for focus hack
 +
 +       var gap1 = document.createTextNode(" ");
 +       left.appendChild(gap1);
 +
 +       var contents = this.create_element("a");
 +       contents.setAttribute("href", "javascript:w3c_slidy.toggle_table_of_contents()");
 +       contents.setAttribute("title", "table of contents".localize());
 +       contents.innerHTML = "contents?".localize();
 +       left.appendChild(contents);
 +
 +       var gap2 = document.createTextNode(" ");
 +       left.appendChild(gap2);
 +
 +       var copyright = this.find_copyright();
 +
 +       if (copyright)
 +       {
 +         var span = this.create_element("span");
 +         span.className = "copyright";
 +         span.innerHTML = copyright;
 +         left.appendChild(span);
 +       }
 +
 +       this.toolbar.setAttribute("tabindex", "0");
 +       this.toolbar.appendChild(left);
 +     }
 +     else // IE6 so need to work around its poor CSS support
 +     {
 +       this.toolbar.style.position = (this.ie7 ? "fixed" : "absolute");
 +       this.toolbar.style.zIndex = "200";
 +       this.toolbar.style.width = "99.9%";
 +       this.toolbar.style.height = "1.2em";
 +       this.toolbar.style.top = "auto";
 +       this.toolbar.style.bottom = "0";
 +       this.toolbar.style.left = "0";
 +       this.toolbar.style.right = "0";
 +       this.toolbar.style.textAlign = "left";
 +       this.toolbar.style.fontSize = "60%";
 +       this.toolbar.style.color = "red";
 +       this.toolbar.borderWidth = 0;
 +       this.toolbar.className = "toolbar";
 +       this.toolbar.style.background = "rgb(240,240,240)";
 +
 +       // would like to have help text left aligned
 +       // and page counter right aligned, floating
 +       // div's don't work, so instead use nested
 +       // absolutely positioned div's.
 +
 +       var sp = this.create_element("span");
 +       sp.innerHTML = "  * ";
 +       this.toolbar.appendChild(sp);
 +       this.eos = sp;  // end of slide indicator
 +
 +       var help = this.create_element("a");
 +       help.setAttribute("href", this.help_page);
 +       help.setAttribute("title", this.help_text.localize());
 +       help.innerHTML = "help?".localize();
 +       this.toolbar.appendChild(help);
 +       this.help_anchor = help;  // save for focus hack
 +
 +       var gap1 = document.createTextNode(" ");
 +       this.toolbar.appendChild(gap1);
 +
 +       var contents = this.create_element("a");
 +       contents.setAttribute("href", "javascript:toggleTableOfContents()");
 +       contents.setAttribute("title", "table of contents".localize());
 +       contents.innerHTML = "contents?".localize();
 +       this.toolbar.appendChild(contents);
 +
 +       var gap2 = document.createTextNode(" ");
 +       this.toolbar.appendChild(gap2);
 +
 +       var copyright = this.find_copyright();
 +
 +       if (copyright)
 +       {
 +         var span = this.create_element("span");
 +         span.innerHTML = copyright;
 +         span.style.color = "black";
 +         span.style.marginLeft = "0.5em";
 +         this.toolbar.appendChild(span);
 +       }
 +
 +       counter = this.create_element("div")
 +       counter.style.position = "absolute";
 +       counter.style.width = "auto"; //"20%";
 +       counter.style.height = "1.2em";
 +       counter.style.top = "auto";
 +       counter.style.bottom = 0;
 +       counter.style.right = "0";
 +       counter.style.textAlign = "right";
 +       counter.style.color = "red";
 +       counter.style.background = "rgb(240,240,240)";
 +
 +       counter.innerHTML = "slide".localize() + " n/m";
 +       this.toolbar.appendChild(counter);
 +     }
 +
 +     // ensure that click isn't passed through to the page
 +     this.toolbar.onclick =
 +         function (e) {
 +           if (!e)
 +             e = window.event;
 +
 +           var target = e.target;
 +
 +           if (!target && e.srcElement)
 +             target = e.srcElement;
 +
 +           // work around Safari bug
 +           if (target && target.nodeType == 3)
 +             target = target.parentNode;
 +
 +           w3c_slidy.stop_propagation(e);
 +
 +           if (target && target.nodeName.toLowerCase() != "a")
 +             w3c_slidy.mouse_button_click(e);
 +         };
 +
 +     this.slide_number_element = counter;
 +     this.set_eos_status(false);
 +     document.body.appendChild(this.toolbar);
 +  },
 +
 +  // wysiwyg editors make it hard to use div elements
 +  // e.g. amaya loses the div when you copy and paste
 +  // this function wraps div elements around implicit
 +  // slides which start with an h1 element and continue
 +  // up to the next heading or div element
 +  wrap_implicit_slides: function () {
 +    var i, heading, node, next, div;
 +    var headings = document.getElementsByTagName("h1");
 +
 +    if (!headings)
 +      return;
 +
 +    for (i = 0; i < headings.length; ++i)
 +    {
 +      heading = headings[i];
 +
 +      if (heading.parentNode != document.body)
 +        continue;
 +
 +      node = heading.nextSibling;
 +
 +      div = document.createElement("div");
 +      this.add_class(div, "slide");
 +      document.body.replaceChild(div, heading);
 +      div.appendChild(heading);
 +
 +      while (node)
 +      {
 +        if (node.nodeType == 1 &&    // an element
 +             (node.nodeName == "H1" ||
 +              node.nodeName == "h1" ||
 +              node.nodeName == "DIV" ||
 +              node.nodeName == "div"))
 +          break;
 +
 +        next = node.nextSibling;
 +        node = document.body.removeChild(node);
 +        div.appendChild(node);
 +        node = next;
 +      }
 +    }
 +  },
 +
 +// return new array of all slides
 +  collect_slides: function () {
 +    var slides = new Array();
 +    var divs = document.body.getElementsByTagName("div");
 +
 +    for (var i = 0; i < divs.length; ++i)
 +    {
 +      div = divs.item(i);
 +
 +      if (this.has_class(div, "slide"))
 +      {
 +        // add slide to collection
 +        slides[slides.length] = div;
 +
 +        // hide each slide as it is found
 +        this.add_class(div, "hidden");
 +
 +        // add dummy <br/> at end for scrolling hack
 +        var node1 = document.createElement("br");
 +        div.appendChild(node1);
 +        var node2 = document.createElement("br");
 +        div.appendChild(node2);
 +      }
 +      else if (this.has_class(div, "background"))
 +      {  // work around for Firefox SVG reload bug
 +        // which otherwise replaces 1st SVG graphic with 2nd
 +        div.style.display = "block";
 +      }
 +    }
 +
 +    this.slides = slides;
 +  },
 +
 +  // return new array of all <div class="handout">
 +  collect_notes: function () {
 +    var notes = new Array();
 +    var divs = document.body.getElementsByTagName("div");
 +
 +    for (var i = 0; i < divs.length; ++i)
 +    {
 +      div = divs.item(i);
 +
 +      if (this.has_class(div, "handout"))
 +      {
 +        // add note to collection
 +        notes[notes.length] = div;
 +
 +        // and hide it
 +        this.add_class(div, "hidden");
 +      }
 +    }
 +
 +    this.notes = notes;
 +  },
 +
 +  // return new array of all <div class="background">
 +  // including named backgrounds e.g. class="background titlepage"
 +  collect_backgrounds: function () {
 +    var backgrounds = new Array();
 +    var divs = document.body.getElementsByTagName("div");
 +
 +    for (var i = 0; i < divs.length; ++i)
 +    {
 +      div = divs.item(i);
 +
 +      if (this.has_class(div, "background"))
 +      {
 +        // add background to collection
 +        backgrounds[backgrounds.length] = div;
 +
 +        // and hide it
 +        this.add_class(div, "hidden");
 +      }
 +    }
 +
 +    this.backgrounds = backgrounds;
 +  },
 +
 +  // set click handlers on all anchors
 +  patch_anchors: function () {
 +    var self = w3c_slidy;
 +    var handler = function (event) {
 +      // compare this.href with location.href
 +      // for link to another slide in this doc
 +
 +      if (self.page_address(this.href) == self.page_address(location.href))
 +      {
 +        // yes, so find new slide number
 +        var newslidenum = self.find_slide_number(this.href);
 +
 +        if (newslidenum != self.slide_number)
 +        {
 +          var slide = self.slides[self.slide_number];
 +          self.hide_slide(slide);
 +          self.slide_number = newslidenum;
 +          slide = self.slides[self.slide_number];
 +          self.show_slide(slide);
 +          self.set_location();
 +        }
 +      }
 +      else if (this.target == null)
 +        location.href = this.href;
 +
 +      this.blur();
 +      self.disable_slide_click = true;
 +    };
 +
 +    var anchors = document.body.getElementsByTagName("a");
 +
 +    for (var i = 0; i < anchors.length; ++i)
 +    {
 +      if (window.addEventListener)
 +        anchors[i].addEventListener("click", handler, false);
 +      else
 +        anchors[i].attachEvent("onclick", handler);
 +    }
 +  },
 +
 +  // ### CHECK ME ### see which functions are invoked via setTimeout
 +  // either directly or indirectly for use of w3c_slidy vs this
 +  show_slide_number: function () {
 +    var timer = w3c_slidy.get_timer();
 +    w3c_slidy.slide_number_element.innerHTML = timer + "slide".localize() + " " +
 +           (w3c_slidy.slide_number + 1) + "/" + w3c_slidy.slides.length;
 +  },
 +
 +  // every 200mS check if the location has been changed as a
 +  // result of the user activating the Back button/menu item
 +  // doesn't work for Opera < 9.5
 +  check_location: function () {
 +    var hash = location.hash;
 +
 +    if (w3c_slidy.slide_number > 0 && (hash == "" || hash == "#"))
 +      w3c_slidy.goto_slide(0);
 +    else if (hash.length > 2 && hash != "#("+(w3c_slidy.slide_number+1)+")")
 +    {
 +      var num = parseInt(location.hash.substr(2));
 +
 +      if (!isNaN(num))
 +        w3c_slidy.goto_slide(num-1);
 +    }
 +
 +    if (w3c_slidy.time_left && w3c_slidy.slide_number > 0)
 +    {
 +      w3c_slidy.show_slide_number();
 +
 +      if (w3c_slidy.time_left > 0)
 +        w3c_slidy.time_left -= 200;
 +    }
 +  },
 +
 +  get_timer: function () {
 +    var timer = "";
 +    if (w3c_slidy.time_left)
 +    {
 +      var mins, secs;
 +      secs = Math.floor(w3c_slidy.time_left/1000);
 +      mins = Math.floor(secs / 60);
 +      secs = secs % 60;
 +      timer = (mins ? mins+"m" : "") + secs + "s ";
 +    }
 +
 +    return timer;
 +  },
 +
 +  // this doesn't push location onto history stack for IE
 +  // for which a hidden iframe hack is needed: load page into
 +  // the iframe with script that set's parent's location.hash
 +  // but that won't work for standalone use unless we can
 +  // create the page dynamically via a javascript: URL
 +  set_location: function () {
 +     var uri = w3c_slidy.page_address(location.href);
 +     var hash = "#(" + (w3c_slidy.slide_number+1) + ")";
 +
 +     if (w3c_slidy.slide_number >= 0)
 +       uri = uri + hash;
 +
 +     if (w3c_slidy.ie && !w3c_slidy.ie8)
 +       w3c_slidy.push_hash(hash);
 +
 +     if (uri != location.href) // && !khtml
 +        location.href = uri;
 +
 +     if (this.khtml)
 +        hash = "(" + (w3c_slidy.slide_number+1) + ")";
 +
 +     if (!this.ie && location.hash != hash && location.hash != "")
 +       location.hash = hash;
 +
 +     document.title = w3c_slidy.title + " (" + (w3c_slidy.slide_number+1) + ")";
 +     w3c_slidy.show_slide_number();
 +  },
 +
 +  page_address: function (uri) {
 +    var i = uri.indexOf("#");
 +
 +    if (i < 0)
 +      i = uri.indexOf("%23");
 +
 +    // check if anchor is entire page
 +
 +    if (i < 0)
 +      return uri;  // yes
 +
 +    return uri.substr(0, i);
 +  },
 +
 +  // only used for IE6 and IE7
 +  on_frame_loaded: function (hash) {
 +    location.hash = hash;
 +    var uri = w3c_slidy.page_address(location.href);
 +    location.href = uri + hash;
 +  },
 +
 +  // history hack with thanks to Bertrand Le Roy
 +  push_hash: function (hash) {
 +    if (hash == "") hash = "#(1)";
 +      window.location.hash = hash;
 +
 +    var doc = document.getElementById("historyFrame").contentWindow.document;
 +    doc.open("javascript:'<html></html>'");
 +    // PWL modified this string literal to break the close script tag
 +    // which otherwise gets parsed when incorporated
 +    doc.write("<html><head><script type=\"text/javascript\">window.parent.w3c_slidy.on_frame_loaded('"+
 +      (hash) + "');</" + "script></head><body>hello mum</body></html>");
 +    doc.close();
 +    },
 +
 +  // find current slide based upon location
 +  // first find target anchor and then look
 +  // for associated div element enclosing it
 +  // finally map that to slide number
 +  find_slide_number: function (uri) {
 +    // first get anchor from page location
 +
 +    var i = uri.indexOf("#");
 +
 +    // check if anchor is entire page
 +    if (i < 0)
 +      return 0;  // yes
 +
 +    var anchor = unescape(uri.substr(i+1));
 +
 +    // now use anchor as XML ID to find target
 +    var target = document.getElementById(anchor);
 +
 +    if (!target)
 +    {
 +      // does anchor look like "(2)" for slide 2 ??
 +      // where first slide is (1)
 +      var re = /\((\d)+\)/;
 +
 +      if (anchor.match(re))
 +      {
 +        var num = parseInt(anchor.substring(1, anchor.length-1));
 +
 +        if (num > this.slides.length)
 +          num = 1;
 +
 +        if (--num < 0)
 +          num = 0;
 +
 +        return num;
 +      }
 +
 +      // accept [2] for backwards compatibility
 +      re = /\[(\d)+\]/;
 +
 +      if (anchor.match(re))
 +      {
 +         var num = parseInt(anchor.substring(1, anchor.length-1));
 +
 +         if (num > this.slides.length)
 +            num = 1;
 +
 +         if (--num < 0)
 +            num = 0;
 +
 +         return num;
 +      }
 +
 +      // oh dear unknown anchor
 +      return 0;
 +    }
 +
 +    // search for enclosing slide
 +
 +    while (true)
 +    {
 +      // browser coerces html elements to uppercase!
 +      if (target.nodeName.toLowerCase() == "div" &&
 +            this.has_class(target, "slide"))
 +      {
 +        // found the slide element
 +        break;
 +      }
 +
 +      // otherwise try parent element if any
 +
 +      target = target.parentNode;
 +
 +      if (!target)
 +      {
 +        return 0;   // no luck!
 +      }
 +    };
 +
 +    for (i = 0; i < slides.length; ++i)
 +    {
 +      if (slides[i] == target)
 +        return i;  // success
 +    }
 +
 +    // oh dear still no luck
 +    return 0;
 +  },
 +
 +  previous_slide: function (incremental) {
 +    if (!w3c_slidy.view_all)
 +    {
 +      var slide;
 +
 +      if ((incremental || w3c_slidy.slide_number == 0) && w3c_slidy.last_shown != null)
 +      {
 +        w3c_slidy.last_shown = w3c_slidy.hide_previous_item(w3c_slidy.last_shown);
 +        w3c_slidy.set_eos_status(false);
 +      }
 +      else if (w3c_slidy.slide_number > 0)
 +      {
 +        slide = w3c_slidy.slides[w3c_slidy.slide_number];
 +        w3c_slidy.hide_slide(slide);
 +
 +        w3c_slidy.slide_number = w3c_slidy.slide_number - 1;
 +        slide = w3c_slidy.slides[w3c_slidy.slide_number];
 +        w3c_slidy.set_visibility_all_incremental("visible");
 +        w3c_slidy.last_shown = w3c_slidy.previous_incremental_item(null);
 +        w3c_slidy.set_eos_status(true);
 +        w3c_slidy.show_slide(slide);
 +      }
 +
 +      w3c_slidy.set_location();
 +
 +      if (!w3c_slidy.ns_pos)
 +        w3c_slidy.refresh_toolbar(200);
 +    }
 +  },
 +
 +  next_slide: function (incremental) {
 +    if (!w3c_slidy.view_all)
 +    {
 +      var slide, last = w3c_slidy.last_shown;
 +
 +      if (incremental || w3c_slidy.slide_number == w3c_slidy.slides.length - 1)
 +         w3c_slidy.last_shown = w3c_slidy.reveal_next_item(w3c_slidy.last_shown);
 +
 +      if ((!incremental || w3c_slidy.last_shown == null) &&
 +             w3c_slidy.slide_number < w3c_slidy.slides.length - 1)
 +      {
 +         slide = w3c_slidy.slides[w3c_slidy.slide_number];
 +         w3c_slidy.hide_slide(slide);
 +
 +         w3c_slidy.slide_number = w3c_slidy.slide_number + 1;
 +         slide = w3c_slidy.slides[w3c_slidy.slide_number];
 +         w3c_slidy.last_shown = null;
 +         w3c_slidy.set_visibility_all_incremental("hidden");
 +         w3c_slidy.show_slide(slide);
 +      }
 +      else if (!w3c_slidy.last_shown)
 +      {
 +         if (last && incremental)
 +           w3c_slidy.last_shown = last;
 +      }
 +
 +      w3c_slidy.set_location();
 +
 +      w3c_slidy.set_eos_status(!w3c_slidy.next_incremental_item(w3c_slidy.last_shown));
 +
 +      if (!w3c_slidy.ns_pos)
 +         w3c_slidy.refresh_toolbar(200);
 +     }
 +  },
 +
 +  // to first slide with nothing revealed
 +  // i.e. state at start of presentation
 +  first_slide: function () {
 +     if (!w3c_slidy.view_all)
 +     {
 +       var slide;
 +
 +       if (w3c_slidy.slide_number != 0)
 +       {
 +         slide = w3c_slidy.slides[w3c_slidy.slide_number];
 +         w3c_slidy.hide_slide(slide);
 +
 +         w3c_slidy.slide_number = 0;
 +         slide = w3c_slidy.slides[w3c_slidy.slide_number];
 +         w3c_slidy.last_shown = null;
 +         w3c_slidy.set_visibility_all_incremental("hidden");
 +         w3c_slidy.show_slide(slide);
 +       }
 +
 +       w3c_slidy.set_eos_status(
 +         !w3c_slidy.next_incremental_item(w3c_slidy.last_shown));
 +       w3c_slidy.set_location();
 +     }
 +  },
 +
 +  // goto last slide with everything revealed
 +  // i.e. state at end of presentation
 +  last_slide: function () {
 +    if (!w3c_slidy.view_all)
 +    {
 +      var slide;
 +
 +      w3c_slidy.last_shown = null; //revealNextItem(lastShown);
 +
 +      if (w3c_slidy.last_shown == null &&
 +          w3c_slidy.slide_number < w3c_slidy.slides.length - 1)
 +      {
 +         slide = w3c_slidy.slides[w3c_slidy.slide_number];
 +         w3c_slidy.hide_slide(slide);
 +         w3c_slidy.slide_number = w3c_slidy.slides.length - 1;
 +         slide = w3c_slidy.slides[w3c_slidy.slide_number];
 +         w3c_slidy.set_visibility_all_incremental("visible");
 +         w3c_slidy.last_shown = w3c_slidy.previous_incremental_item(null);
 +
 +         w3c_slidy.show_slide(slide);
 +      }
 +      else
 +      {
 +         w3c_slidy.set_visibility_all_incremental("visible");
 +         w3c_slidy.last_shown = w3c_slidy.previous_incremental_item(null);
 +      }
 +
 +      w3c_slidy.set_eos_status(true);
 +      w3c_slidy.set_location();
 +    }
 +  },
 +
 +
 +  // ### check this and consider add/remove class
 +  set_eos_status: function (state) {
 +    if (this.eos)
 +      this.eos.style.color = (state ? "rgb(240,240,240)" : "red");
 +  },
 +
 +  // first slide is 0
 +  goto_slide: function (num) {
 +    //alert("going to slide " + (num+1));
 +    var slide = w3c_slidy.slides[w3c_slidy.slide_number];
 +    w3c_slidy.hide_slide(slide);
 +    w3c_slidy.slide_number = num;
 +    slide = w3c_slidy.slides[w3c_slidy.slide_number];
 +    w3c_slidy.last_shown = null;
 +    w3c_slidy.set_visibility_all_incremental("hidden");
 +    w3c_slidy.set_eos_status(!w3c_slidy.next_incremental_item(w3c_slidy.last_shown));
 +    document.title = w3c_slidy.title + " (" + (w3c_slidy.slide_number+1) + ")";
 +    w3c_slidy.show_slide(slide);
 +    w3c_slidy.show_slide_number();
 +  },
 +
 +
 +  show_slide: function (slide) {
 +    this.sync_background(slide);
 +    window.scrollTo(0,0);
 +    this.remove_class(slide, "hidden");
 +  },
 +
 +  hide_slide: function (slide) {
 +    this.add_class(slide, "hidden");
 +  },
 +
 +  // show just the backgrounds pertinent to this slide
 +  // when slide background-color is transparent
 +  // this should now work with rgba color values
 +  sync_background: function (slide) {
 +    var background;
 +    var bgColor;
 +
 +    if (slide.currentStyle)
 +      bgColor = slide.currentStyle["backgroundColor"];
 +    else if (document.defaultView)
 +    {
 +      var styles = document.defaultView.getComputedStyle(slide,null);
 +
 +      if (styles)
 +        bgColor = styles.getPropertyValue("background-color");
 +      else // broken implementation probably due Safari or Konqueror
 +      {
 +        //alert("defective implementation of getComputedStyle()");
 +        bgColor = "transparent";
 +      }
 +    }
 +    else
 +      bgColor == "transparent";
 +
 +    if (bgColor == "transparent" ||
 +        bgColor.indexOf("rgba") >= 0 ||
 +        bgColor.indexOf("opacity") >= 0)
 +    {
 +      var slideClass = this.get_class_list(slide);
 +
 +      for (var i = 0; i < this.backgrounds.length; i++)
 +      {
 +        background = this.backgrounds[i];
 +
 +        var bgClass = this.get_class_list(background);
 +
 +        if (this.matching_background(slideClass, bgClass))
 +          this.remove_class(background, "hidden");
 +        else
 +          this.add_class(background, "hidden");
 +      }
 +    }
 +    else // forcibly hide all backgrounds
 +      this.hide_backgrounds();
 +  },
 +
 +  hide_backgrounds: function () {
 +    for (var i = 0; i < this.backgrounds.length; i++)
 +    {
 +      background = this.backgrounds[i];
 +      this.add_class(background, "hidden");
 +    }
 +  },
 +
 +  // compare classes for slide and background
 +  matching_background: function (slideClass, bgClass) {
 +    var i, count, pattern, result;
 +
 +    // define pattern as regular expression
 +    pattern = /\w+/g;
 +
 +    // check background class names
 +    result = bgClass.match(pattern);
 +
 +    for (i = count = 0; i < result.length; i++)
 +    {
 +      if (result[i] == "hidden")
 +        continue;
 +
 +      if (result[i] == "background")
 +	continue;
 +
 +      ++count;
 +    }
 +
 +    if (count == 0)  // default match
 +      return true;
 +
 +    // check for matches and place result in array
 +    result = slideClass.match(pattern);
 +
 +    // now check if desired name is present for background
 +    for (i = count = 0; i < result.length; i++)
 +    {
 +      if (result[i] == "hidden")
 +        continue;
 +
 +      if (this.has_token(bgClass, result[i]))
 +        return true;
 +    }
 +
 +    return false;
 +  },
 +
 +  resized: function () {
 +     var width = 0;
 +
 +     if ( typeof( window.innerWidth ) == 'number' )
 +       width = window.innerWidth;  // Non IE browser
 +     else if (document.documentElement && document.documentElement.clientWidth)
 +       width = document.documentElement.clientWidth;  // IE6
 +     else if (document.body && document.body.clientWidth)
 +       width = document.body.clientWidth; // IE4
 +
 +     var height = 0;
 +
 +     if ( typeof( window.innerHeight ) == 'number' )
 +       height = window.innerHeight;  // Non IE browser
 +     else if (document.documentElement && document.documentElement.clientHeight)
 +       height = document.documentElement.clientHeight;  // IE6
 +     else if (document.body && document.body.clientHeight)
 +       height = document.body.clientHeight; // IE4
 +
 +     if (height && (width/height > 1.05*1024/768))
 +     {
 +       width = height * 1024.0/768;
 +     }
 +
 +     // IE fires onresize even when only font size is changed!
 +     // so we do a check to avoid blocking < and > actions
 +     if (width != w3c_slidy.last_width || height != w3c_slidy.last_height)
 +     {
 +       if (width >= 1100)
 +         w3c_slidy.size_index = 5;    // 4
 +       else if (width >= 1000)
 +         w3c_slidy.size_index = 4;    // 3
 +       else if (width >= 800)
 +         w3c_slidy.size_index = 3;    // 2
 +       else if (width >= 600)
 +         w3c_slidy.size_index = 2;    // 1
 +       else if (width)
 +         w3c_slidy.size_index = 0;
 +
 +       // add in font size adjustment from meta element e.g.
 +       // <meta name="font-size-adjustment" content="-2" />
 +       // useful when slides have too much content ;-)
 +
 +       if (0 <= w3c_slidy.size_index + w3c_slidy.size_adjustment &&
 +             w3c_slidy.size_index + w3c_slidy.size_adjustment < w3c_slidy.sizes.length)
 +         w3c_slidy.size_index = w3c_slidy.size_index + w3c_slidy.size_adjustment;
 +
 +       // enables cross browser use of relative width/height
 +       // on object elements for use with SVG and Flash media
 +       w3c_slidy.adjust_object_dimensions(width, height);
 +
 +       if (document.body.style.fontSize != w3c_slidy.sizes[w3c_slidy.size_index])
 +       {
 +         document.body.style.fontSize = w3c_slidy.sizes[w3c_slidy.size_index];
 +       }
 +
 +       w3c_slidy.last_width = width;
 +       w3c_slidy.last_height = height;
 +
 +       // force reflow to work around Mozilla bug
 +       if (w3c_slidy.ns_pos)
 +       {
 +         var slide = w3c_slidy.slides[w3c_slidy.slide_number];
 +         w3c_slidy.hide_slide(slide);
 +         w3c_slidy.show_slide(slide);
 +       }
 +
 +       // force correct positioning of toolbar
 +       w3c_slidy.refresh_toolbar(200);
 +     }
 +  },
 +
 +  scrolled: function () {
 +    if (w3c_slidy.toolbar && !w3c_slidy.ns_pos && !w3c_slidy.ie7)
 +    {
 +      w3c_slidy.hack_offset = w3c_slidy.scroll_x_offset();
 +      // hide toolbar
 +      w3c_slidy.toolbar.style.display = "none";
 +
 +      // make it reappear later
 +      if (w3c_slidy.scrollhack == 0 && !w3c_slidy.view_all)
 +      {
 +        setTimeout(function () {w3c_slidy.show_toolbar(); }, 1000);
 +        w3c_slidy.scrollhack = 1;
 +      }
 +    }
 +  },
 +
 +  hide_toolbar: function () {
 +    w3c_slidy.add_class(w3c_slidy.toolbar, "hidden");
 +    window.focus();
 +  },
 +
 +  // used to ensure IE refreshes toolbar in correct position
 +  refresh_toolbar: function (interval) {
 +    if (!w3c_slidy.ns_pos && !w3c_slidy.ie7)
 +    {
 +      w3c_slidy.hide_toolbar();
 +      setTimeout(function () {w3c_slidy.show_toolbar(); }, interval);
 +    }
 +  },
 +
 +  // restores toolbar after short delay
 +  show_toolbar: function () {
 +    if (w3c_slidy.want_toolbar)
 +    {
 +      w3c_slidy.toolbar.style.display = "block";
 +
 +      if (!w3c_slidy.ns_pos)
 +      {
 +        // adjust position to allow for scrolling
 +        var xoffset = w3c_slidy.scroll_x_offset();
 +        w3c_slidy.toolbar.style.left = xoffset;
 +        w3c_slidy.toolbar.style.right = xoffset;
 +
 +        // determine vertical scroll offset
 +        //var yoffset = scrollYOffset();
 +
 +        // bottom is doc height - window height - scroll offset
 +        //var bottom = documentHeight() - lastHeight - yoffset
 +
 +        //if (yoffset > 0 || documentHeight() > lastHeight)
 +        //   bottom += 16;  // allow for height of scrollbar
 +
 +        w3c_slidy.toolbar.style.bottom = 0; //bottom;
 +      }
 +
 +      w3c_slidy.remove_class(w3c_slidy.toolbar, "hidden");
 +    }
 +
 +    w3c_slidy.scrollhack = 0;
 +
 +
 +    // set the keyboard focus to the help link on the
 +    // toolbar to ensure that document has the focus
 +    // IE doesn't always work with window.focus()
 +    // and this hack has benefit of Enter for help
 +
 +    try
 +    {
 +      if (!w3c_slidy.opera)
 +        w3c_slidy.help_anchor.focus();
 +    }
 +    catch (e)
 +    {
 +    }
 +  },
 +
 +// invoked via F key
 +  toggle_toolbar: function () {
 +    if (!w3c_slidy.view_all)
 +    {
 +      if (w3c_slidy.has_class(w3c_slidy.toolbar, "hidden"))
 +      {
 +        w3c_slidy.remove_class(w3c_slidy.toolbar, "hidden")
 +        w3c_slidy.want_toolbar = 1;
 +      }
 +      else
 +      {
 +        w3c_slidy.add_class(w3c_slidy.toolbar, "hidden")
 +        w3c_slidy.want_toolbar = 0;
 +      }
 +    }
 +  },
 +
 +  scroll_x_offset: function () {
 +    if (window.pageXOffset)
 +      return self.pageXOffset;
 +
 +    if (document.documentElement &&
 +             document.documentElement.scrollLeft)
 +      return document.documentElement.scrollLeft;
 +
 +    if (document.body)
 +      return document.body.scrollLeft;
 +
 +    return 0;
 +  },
 +
 +  scroll_y_offset: function () {
 +    if (window.pageYOffset)
 +      return self.pageYOffset;
 +
 +    if (document.documentElement &&
 +             document.documentElement.scrollTop)
 +      return document.documentElement.scrollTop;
 +
 +    if (document.body)
 +      return document.body.scrollTop;
 +
 +    return 0;
 +  },
 +
 +  // looking for a way to determine height of slide content
 +  // the slide itself is set to the height of the window
 +  optimize_font_size: function () {
 +    var slide = w3c_slidy.slides[w3c_slidy.slide_number];
 +
 +    //var dh = documentHeight(); //getDocHeight(document);
 +    var dh = slide.scrollHeight;
 +    var wh = getWindowHeight();
 +    var u = 100 * dh / wh;
 +
 +    alert("window utilization = " + u + "% (doc "
 +      + dh + " win " + wh + ")");
 +  },
 +
 +  // from document object
 +  get_doc_height: function (doc) {
 +    if (!doc)
 +      doc = document;
 +
 +    if (doc && doc.body && doc.body.offsetHeight)
 +      return doc.body.offsetHeight;  // ns/gecko syntax
 +
 +    if (doc && doc.body && doc.body.scrollHeight)
 +      return doc.body.scrollHeight;
 +
 +    alert("couldn't determine document height");
 +  },
 +
 +  get_window_height: function () {
 +    if ( typeof( window.innerHeight ) == 'number' )
 +      return window.innerHeight;  // Non IE browser
 +
 +    if (document.documentElement && document.documentElement.clientHeight)
 +      return document.documentElement.clientHeight;  // IE6
 +
 +    if (document.body && document.body.clientHeight)
 +      return document.body.clientHeight; // IE4
 +  },
 +
 +  document_height: function () {
 +    var sh, oh;
 +
 +    sh = document.body.scrollHeight;
 +    oh = document.body.offsetHeight;
 +
 +    if (sh && oh)
 +    {
 +      return (sh > oh ? sh : oh);
 +    }
 +
 +    // no idea!
 +    return 0;
 +  },
 +
 +  smaller: function () {
 +    if (w3c_slidy.size_index > 0)
 +    {
 +      --w3c_slidy.size_index;
 +    }
 +
 +    w3c_slidy.toolbar.style.display = "none";
 +    document.body.style.fontSize = w3c_slidy.sizes[w3c_slidy.size_index];
 +    var slide = w3c_slidy.slides[w3c_slidy.slide_number];
 +    w3c_slidy.hide_slide(slide);
 +    w3c_slidy.show_slide(slide);
 +    setTimeout(function () {w3c_slidy.show_toolbar(); }, 50);
 +  },
 +
 +  bigger: function () {
 +    if (w3c_slidy.size_index < w3c_slidy.sizes.length - 1)
 +    {
 +      ++w3c_slidy.size_index;
 +    }
 +
 +    w3c_slidy.toolbar.style.display = "none";
 +    document.body.style.fontSize = w3c_slidy.sizes[w3c_slidy.size_index];
 +    var slide = w3c_slidy.slides[w3c_slidy.slide_number];
 +    w3c_slidy.hide_slide(slide);
 +    w3c_slidy.show_slide(slide);
 +    setTimeout(function () {w3c_slidy.show_toolbar(); }, 50);
 +  },
 +
 +  // enables cross browser use of relative width/height
 +  // on object elements for use with SVG and Flash media
 +  // with thanks to Ivan Herman for the suggestion
 +  adjust_object_dimensions: function (width, height) {
 +    for( var i = 0; i < w3c_slidy.objects.length; i++ )
 +    {
 +      var obj = this.objects[i];
 +      var mimeType = obj.getAttribute("type");
 +
 +      if (mimeType == "image/svg+xml" || mimeType == "application/x-shockwave-flash")
 +      {
 +        if ( !obj.initialWidth )
 +          obj.initialWidth = obj.getAttribute("width");
 +
 +        if ( !obj.initialHeight )
 +          obj.initialHeight = obj.getAttribute("height");
 +
 +        if ( obj.initialWidth && obj.initialWidth.charAt(obj.initialWidth.length-1) == "%" )
 +        {
 +          var w = parseInt(obj.initialWidth.slice(0, obj.initialWidth.length-1));
 +          var newW = width * (w/100.0);
 +          obj.setAttribute("width",newW);
 +        }
 +
 +        if ( obj.initialHeight &&
 +             obj.initialHeight.charAt(obj.initialHeight.length-1) == "%" )
 +        {
 +          var h = parseInt(obj.initialHeight.slice(0, obj.initialHeight.length-1));
 +          var newH = height * (h/100.0);
 +          obj.setAttribute("height", newH);
 +        }
 +      }
 +    }
 +  },
 +
 +  // needed for Opera to inhibit default behavior
 +  // since Opera delivers keyPress even if keyDown
 +  // was cancelled
 +  key_press: function (event) {
 +    if (!event)
 +      event = window.event;
 +
 +    if (!w3c_slidy.key_wanted)
 +      return w3c_slidy.cancel(event);
 +
 +    return true;
 +  },
 +
 +  //  See e.g. http://www.quirksmode.org/js/events/keys.html for keycodes
 +  key_down: function (event) {
 +    var key;
 +
 +    w3c_slidy.key_wanted = true;
 +
 +    if (!event)
 +      event = window.event;
 +
 +    // kludge around NS/IE differences
 +    if (window.event)
 +      key = window.event.keyCode;
 +    else if (event.which)
 +      key = event.which;
 +    else
 +      return true; // Yikes! unknown browser
 +
 +    // ignore event if key value is zero
 +    // as for alt on Opera and Konqueror
 +    if (!key)
 +       return true;
 +
 +    // check for concurrent control/command/alt key
 +    // but are these only present on mouse events?
 +
 +    if (event.ctrlKey || event.altKey || event.metaKey)
 +       return true;
 +
 +    // dismiss table of contents if visible
 +    if (w3c_slidy.is_shown_toc() && key != 9 && key != 16 && key != 38 && key != 40)
 +    {
 +      w3c_slidy.hide_table_of_contents();
 +
 +      if (key == 27 || key == 84 || key == 67)
 +        return w3c_slidy.cancel(event);
 +    }
 +
 +    if (key == 34) // Page Down
 +    {
 +      if (w3c_slidy.view_all)
 +        return true;
 +
 +      w3c_slidy.next_slide(false);
 +      return w3c_slidy.cancel(event);
 +    }
 +    else if (key == 33) // Page Up
 +    {
 +      if (w3c_slidy.view_all)
 +        return true;
 +
 +      w3c_slidy.previous_slide(false);
 +      return w3c_slidy.cancel(event);
 +    }
 +    else if (key == 32) // space bar
 +    {
 +      w3c_slidy.next_slide(true);
 +      return w3c_slidy.cancel(event);
 +    }
 +    else if (key == 37) // Left arrow
 +    {
 +      w3c_slidy.previous_slide(!event.shiftKey);
 +      return w3c_slidy.cancel(event);
 +    }
 +    else if (key == 36) // Home
 +    {
 +      w3c_slidy.first_slide();
 +      return w3c_slidy.cancel(event);
 +    }
 +    else if (key == 35) // End
 +    {
 +      w3c_slidy.last_slide();
 +      return w3c_slidy.cancel(event);
 +    }
 +    else if (key == 39) // Right arrow
 +    {
 +      w3c_slidy.next_slide(!event.shiftKey);
 +      return w3c_slidy.cancel(event);
 +    }
 +    else if (key == 13) // Enter
 +    {
 +      if (w3c_slidy.outline)
 +      {
 +        if (w3c_slidy.outline.visible)
 +          w3c_slidy.fold(w3c_slidy.outline);
 +        else
 +          w3c_slidy.unfold(w3c_slidy.outline);
 +
 +       return w3c_slidy.cancel(event);
 +      }
 +    }
 +    else if (key == 188)  // < for smaller fonts
 +    {
 +      w3c_slidy.smaller();
 +      return w3c_slidy.cancel(event);
 +    }
 +    else if (key == 190)  // > for larger fonts
 +    {
 +      w3c_slidy.bigger();
 +      return w3c_slidy.cancel(event);
 +    }
 +    else if (key == 189 || key == 109)  // - for smaller fonts
 +    {
 +      w3c_slidy.smaller();
 +      return w3c_slidy.cancel(event);
 +    }
 +    else if (key == 187 || key == 191 || key == 107)  // = +  for larger fonts
 +    {
 +      w3c_slidy.bigger();
 +      return w3c_slidy.cancel(event);
 +    }
 +    else if (key == 83)  // S for smaller fonts
 +    {
 +      w3c_slidy.smaller();
 +      return w3c_slidy.cancel(event);
 +    }
 +    else if (key == 66)  // B for larger fonts
 +    {
 +      w3c_slidy.bigger();
 +      return w3c_slidy.cancel(event);
 +    }
 +    else if (key == 90)  // Z for last slide
 +    {
 +      w3c_slidy.last_slide();
 +      return w3c_slidy.cancel(event);
 +    }
 +    else if (key == 70)  // F for toggle toolbar
 +    {
 +      w3c_slidy.toggle_toolbar();
 +      return w3c_slidy.cancel(event);
 +    }
 +    else if (key == 65)  // A for toggle view single/all slides
 +    {
 +      w3c_slidy.toggle_view();
 +      return w3c_slidy.cancel(event);
 +    }
 +    else if (key == 75)  // toggle action of left click for next page
 +    {
 +      w3c_slidy.mouse_click_enabled = !w3c_slidy.mouse_click_enabled;
 +      var alert_msg = (w3c_slidy.mouse_click_enabled ?
 +                "enabled" : "disabled") +  " mouse click advance";
 +
 +      alert(alert_msg.localize());
 +      return w3c_slidy.cancel(event);
 +    }
 +    else if (key == 84 || key == 67)  // T or C for table of contents
 +    {
 +      if (w3c_slidy.toc)
 +        w3c_slidy.toggle_table_of_contents();
 +
 +      return w3c_slidy.cancel(event);
 +    }
 +    else if (key == 72) // H for help
 +    {
 +      window.location = w3c_slidy.help_page;
 +      return w3c_slidy.cancel(event);
 +    }
 +    //else alert("key code is "+ key);
 +
 +    return true;
 +  },
 +
 +  // safe for both text/html and application/xhtml+xml
 +  create_element: function (name) {
 +    if (this.xhtml && (typeof document.createElementNS != 'undefined'))
 +      return document.createElementNS("http://www.w3.org/1999/xhtml", name)
 +
 +    return document.createElement(name);
 +  },
 +
 +  get_element_style: function (elem, IEStyleProp, CSSStyleProp) {
 +    if (elem.currentStyle)
 +    {
 +      return elem.currentStyle[IEStyleProp];
 +    }
 +    else if (window.getComputedStyle)
 +    {
 +      var compStyle = window.getComputedStyle(elem, "");
 +      return compStyle.getPropertyValue(CSSStyleProp);
 +    }
 +    return "";
 +  },
 +
 +  // the string str is a whitespace separated list of tokens
 +  // test if str contains a particular token, e.g. "slide"
 +  has_token: function (str, token) {
 +    if (str)
 +    {
 +      // define pattern as regular expression
 +      var pattern = /\w+/g;
 +
 +      // check for matches
 +      // place result in array
 +      var result = str.match(pattern);
 +
 +      // now check if desired token is present
 +      for (var i = 0; i < result.length; i++)
 +      {
 +        if (result[i] == token)
 +          return true;
 +      }
 +    }
 +
 +    return false;
 +  },
 +
 +  get_class_list: function (element) {
 +    if (typeof element.className != 'undefined')
 +      return element.className;
 +
 +    return element.getAttribute("class");
 +  },
 +
 +  has_class: function (element, name) {
 +    if (element.nodeType != 1)
 +      return false;
 +
 +    var regexp = new RegExp("(^| )" + name + "\W*");
 +
 +    if (typeof element.className != 'undefined')
 +      return regexp.test(element.className);
 +
 +    return regexp.test(element.getAttribute("class"));
 +  },
 +
 +  remove_class: function (element, name) {
 +    var regexp = new RegExp("(^| )" + name + "\W*");
 +    var clsval = "";
 +
 +    if (typeof element.className != 'undefined')
 +    {
 +      clsval = element.className;
 +
 +      if (clsval)
 +      {
 +        clsval = clsval.replace(regexp, "");
 +        element.className = clsval;
 +      }
 +    }
 +    else
 +    {
 +      clsval = element.getAttribute("class");
 +
 +      if (clsval)
 +      {
 +        clsval = clsval.replace(regexp, "");
 +        element.setAttribute("class", clsval);
 +      }
 +    }
 +  },
 +
 +  add_class: function (element, name) {
 +    if (!this.has_class(element, name))
 +    {
 +      if (typeof element.className != 'undefined')
 +        element.className += " " + name;
 +      else
 +      {
 +        var clsval = element.getAttribute("class");
 +        clsval = clsval ? clsval + " " + name : name;
 +        element.setAttribute("class", clsval);
 +      }
 +    }
 +  },
 +
 +  // HTML elements that can be used with class="incremental"
 +  // note that you can also put the class on containers like
 +  // up, ol, dl, and div to make their contents appear
 +  // incrementally. Upper case is used since this is what
 +  // browsers report for HTML node names (text/html).
 +  incremental_elements: null,
 +  okay_for_incremental: function (name) {
 +    if (!this.incremental_elements)
 +    {
 +      var inclist = new Array();
 +      inclist["p"] = true;
 +      inclist["pre"] = true;
 +      inclist["li"] = true;
 +      inclist["blockquote"] = true;
 +      inclist["dt"] = true;
 +      inclist["dd"] = true;
 +      inclist["h2"] = true;
 +      inclist["h3"] = true;
 +      inclist["h4"] = true;
 +      inclist["h5"] = true;
 +      inclist["h6"] = true;
 +      inclist["span"] = true;
 +      inclist["address"] = true;
 +      inclist["table"] = true;
 +      inclist["tr"] = true;
 +      inclist["th"] = true;
 +      inclist["td"] = true;
 +      inclist["img"] = true;
 +      inclist["object"] = true;
 +      this.incremental_elements = inclist;
 +    }
 +    return this.incremental_elements[name.toLowerCase()];
 +  },
 +
 +  next_incremental_item: function (node) {
 +    var br = this.is_xhtml ? "br" : "BR";
 +    var slide = w3c_slidy.slides[w3c_slidy.slide_number];
 +
 +    for (;;)
 +    {
 +      node = w3c_slidy.next_node(slide, node);
 +
 +      if (node == null || node.parentNode == null)
 +        break;
 +
 +      if (node.nodeType == 1)  // ELEMENT
 +      {
 +        if (node.nodeName == br)
 +          continue;
 +
 +        if (w3c_slidy.has_class(node, "incremental")
 +             && w3c_slidy.okay_for_incremental(node.nodeName))
 +          return node;
 +
 +        if (w3c_slidy.has_class(node.parentNode, "incremental")
 +             && !w3c_slidy.has_class(node, "non-incremental"))
 +          return node;
 +      }
 +    }
 +
 +    return node;
 +  },
 +
 +  previous_incremental_item: function (node) {
 +    var br = this.is_xhtml ? "br" : "BR";
 +    var slide = w3c_slidy.slides[w3c_slidy.slide_number];
 +
 +    for (;;)
 +    {
 +      node = w3c_slidy.previous_node(slide, node);
 +
 +      if (node == null || node.parentNode == null)
 +        break;
 +
 +      if (node.nodeType == 1)
 +      {
 +        if (node.nodeName == br)
 +          continue;
 +
 +        if (w3c_slidy.has_class(node, "incremental")
 +             && w3c_slidy.okay_for_incremental(node.nodeName))
 +          return node;
 +
 +        if (w3c_slidy.has_class(node.parentNode, "incremental")
 +             && !w3c_slidy.has_class(node, "non-incremental"))
 +          return node;
 +      }
 +    }
 +
 +    return node;
 +  },
 +
 +  // set visibility for all elements on current slide with
 +  // a parent element with attribute class="incremental"
 +  set_visibility_all_incremental: function (value) {
 +    var node = this.next_incremental_item(null);
 +
 +    if (value == "hidden")
 +    {
 +      while (node)
 +      {
 +        w3c_slidy.add_class(node, "invisible");
 +        node = w3c_slidy.next_incremental_item(node);
 +      }
 +    }
 +    else // value == "visible"
 +    {
 +      while (node)
 +      {
 +        w3c_slidy.remove_class(node, "invisible");
 +        node = w3c_slidy.next_incremental_item(node);
 +      }
 +    }
 +  },
 +
 +  // reveal the next hidden item on the slide
 +  // node is null or the node that was last revealed
 +  reveal_next_item: function (node) {
 +    node = w3c_slidy.next_incremental_item(node);
 +
 +    if (node && node.nodeType == 1)  // an element
 +      w3c_slidy.remove_class(node, "invisible");
 +
 +    return node;
 +  },
 +
 +  // exact inverse of revealNextItem(node)
 +  hide_previous_item: function (node) {
 +    if (node && node.nodeType == 1)  // an element
 +      w3c_slidy.add_class(node, "invisible");
 +
 +    return this.previous_incremental_item(node);
 +  },
 +
 +  // left to right traversal of root's content
 +  next_node: function (root, node) {
 +    if (node == null)
 +      return root.firstChild;
 +
 +    if (node.firstChild)
 +      return node.firstChild;
 +
 +    if (node.nextSibling)
 +      return node.nextSibling;
 +
 +    for (;;)
 +    {
 +      node = node.parentNode;
 +
 +      if (!node || node == root)
 +        break;
 +
 +      if (node && node.nextSibling)
 +        return node.nextSibling;
 +    }
 +
 +    return null;
 +  },
 +
 +  // right to left traversal of root's content
 +  previous_node: function (root, node) {
 +    if (node == null)
 +    {
 +      node = root.lastChild;
 +
 +      if (node)
 +      {
 +        while (node.lastChild)
 +          node = node.lastChild;
 +      }
 +
 +      return node;
 +    }
 +
 +    if (node.previousSibling)
 +    {
 +      node = node.previousSibling;
 +
 +      while (node.lastChild)
 +        node = node.lastChild;
 +
 +      return node;
 +    }
 +
 +    if (node.parentNode != root)
 +      return node.parentNode;
 +
 +    return null;
 +  },
 +
 +  previous_sibling_element: function (el) {
 +    el = el.previousSibling;
 +
 +    while (el && el.nodeType != 1)
 +      el = el.previousSibling;
 +
 +    return el;
 +  },
 +
 +  next_sibling_element: function (el) {
 +    el = el.nextSibling;
 +
 +    while (el && el.nodeType != 1)
 +      el = el.nextSibling;
 +
 +    return el;
 +  },
 +
 +  first_child_element: function (el) {
 +    var node;
 +
 +    for (node = el.firstChild; node; node = node.nextSibling)
 +    {
 +      if (node.nodeType == 1)
 +        break;
 +    }
 +
 +    return node;
 +  },
 +
 +  first_tag: function (element, tag) {
 +    var node;
 +
 +    if (!this.is_xhtml)
 +      tag = tag.toUpperCase();
 +
 +    for (node = element.firstChild; node; node = node.nextSibling)
 +    {
 +      if (node.nodeType == 1 && node.nodeName == tag)
 +        break;
 +    }
 +
 +    return node;
 +  },
 +
 +  hide_selection: function () {
 +    if (window.getSelection) // Firefox, Chromium, Safari, Opera
 +    {
 +      var selection = window.getSelection();
 +
 +      if (selection.rangeCount > 0)
 +      {
 +        var range = selection.getRangeAt(0);
 +        range.collapse (false);
 +      }
 +    }
 +    else // Internet Explorer
 +    {
 +      var textRange = document.selection.createRange ();
 +      textRange.collapse (false);
 +    }
 +  },
 +
 +  get_selected_text: function () {
 +    try
 +    {
 +      if (window.getSelection)
 +        return window.getSelection().toString();
 +
 +      if (document.getSelection)
 +        return document.getSelection().toString();
 +
 +      if (document.selection)
 +        return document.selection.createRange().text;
 +    }
 +    catch (e)
 +    {
 +    }
 +
 +    return "";
 +  },
 +
 +  // make note of length of selected text
 +  // as this evaluates to zero in click event
 +  mouse_button_up: function (e) {
 +    w3c_slidy.selected_text_len = w3c_slidy.get_selected_text().length;
 +  },
 +
 +  // right mouse button click is reserved for context menus
 +  // it is more reliable to detect rightclick than leftclick
 +  mouse_button_click: function (e) {
 +    var rightclick = false;
 +    var leftclick = false;
 +    var middleclick = false;
 +    var target;
 +
 +    if (!e)
 +      var e = window.event;
 +
 +    if (e.target)
 +      target = e.target;
 +    else if (e.srcElement)
 +      target = e.srcElement;
 +
 +    // work around Safari bug
 +    if (target.nodeType == 3)
 +      target = target.parentNode;
 +
 +    if (e.which) // all browsers except IE
 +    {
 +      leftclick = (e.which == 1);
 +      middleclick = (e.which == 2);
 +      rightclick = (e.which == 3);
 +    }
 +    else if (e.button)
 +    {
 +      // Konqueror gives 1 for left, 4 for middle
 +      // IE6 gives 0 for left and not 1 as I expected
 +
 +      if (e.button == 4)
 +        middleclick = true;
 +
 +      // all browsers agree on 2 for right button
 +      rightclick = (e.button == 2);
 +    }
 +    else leftclick = true;
 +/*
 +    alert("you clicked over a " + target.nodeName + " element\n" +
 +    "w3c_slidy.mouse_click_enabled = " + w3c_slidy.mouse_click_enabled + "\n" +
 +    "leftclick = " + leftclick + "\n" +
 +    "selected text length = " + w3c_slidy.selected_text_len);
 +    //alert("selected text length = " + w3c_slidy.selected_text_len);
 +*/
 +    if (w3c_slidy.selected_text_len > 0)
 +    {
 +      w3c_slidy.stop_propagation(e);
 +      e.cancel = true;
 +      e.returnValue = false;
 +      return false;
 +    }
 +
 +    // dismiss table of contents
 +    w3c_slidy.hide_table_of_contents();
 +
 +    // check if target is something that probably want's clicks
 +    // e.g. a, embed, object, input, textarea, select, option
 +    var tag = target.nodeName.toLowerCase();
 +
 +    if (w3c_slidy.mouse_click_enabled && leftclick &&
 +        tag != "a" &&
 +        tag != "embed" &&
 +        tag != "object" &&
 +        tag != "video" &&
 +        tag != "input" &&
 +        tag != "textarea" &&
 +        tag != "select" &&
 +        tag != "option" &&
 +        !target.onclick)
 +    {
 +      w3c_slidy.next_slide(true);
 +      w3c_slidy.stop_propagation(e);
 +      e.cancel = true;
 +      e.returnValue = false;
 +      return false;
 +    }
 +  },
 +
 +  get_key: function (e)
 +  {
 +    var key;
 +
 +    // kludge around NS/IE differences
 +    if (typeof window.event != "undefined")
 +      key = window.event.keyCode;
 +    else if (e.which)
 +      key = e.which;
 +
 +    return key;
 +  },
 +
 +  get_target: function (e) {
 +    var target;
 +
 +    if (!e)
 +      e = window.event;
 +
 +    if (e.target)
 +      target = e.target;
 +    else if (e.srcElement)
 +      target = e.srcElement;
 +
 +    if (target.nodeType != 1)
 +      target = target.parentNode;
 +
 +    return target;
 +  },
 +
 +  // does display property provide correct defaults?
 +  is_block: function (elem) {
 +    var tag = elem.nodeName.toLowerCase();
 +
 +    return tag == "ol" || tag == "ul" || tag == "p" ||
 +           tag == "li" || tag == "table" || tag == "pre" ||
 +           tag == "h1" || tag == "h2" || tag == "h3" ||
 +           tag == "h4" || tag == "h5" || tag == "h6" ||
 +           tag == "blockquote" || tag == "address";
 +  },
 +
 +  add_listener: function (element, event, handler) {
 +    if (window.addEventListener)
 +      element.addEventListener(event, handler, false);
 +    else
 +      element.attachEvent("on"+event, handler);
 +  },
 +
 +  // used to prevent event propagation from field controls
 +  stop_propagation: function (event) {
 +    event = event ? event : window.event;
 +    event.cancelBubble = true;  // for IE
 +
 +    if (event.stopPropagation)
 +      event.stopPropagation();
 +
 +    return true;
 +  },
 +
 +  cancel: function (event) {
 +    if (event)
 +    {
 +       event.cancel = true;
 +       event.returnValue = false;
 +
 +      if (event.preventDefault)
 +        event.preventDefault();
 +    }
 +
 +    w3c_slidy.key_wanted = false;
 +    return false;
 +  }
 +};
 +
 +// for each language define an associative array
 +// and also the help text which is longer
 +
 +var w3c_slidy_i18n = {
 +  strings_es: {
 +    "slide":"pág.",
 +    "help?":"Ayuda",
 +    "contents?":"Índice",
 +    "table of contents":"tabla de contenidos",
 +    "Table of Contents":"Tabla de Contenidos",
 +    "restart presentation":"Reiniciar presentación",
 +    "restart?":"Inicio"
 +  },
 +  help_es:
 +    "Utilice el ratón, barra espaciadora, teclas Izda/Dcha, " +
 +    "o Re pág y Av pág. Use S y B para cambiar el tamaño de fuente.",
 +
 +  strings_ca: {
 +    "slide":"pàg..",
 +    "help?":"Ajuda",
 +    "contents?":"Índex",
 +    "table of contents":"taula de continguts",
 +    "Table of Contents":"Taula de Continguts",
 +    "restart presentation":"Reiniciar presentació",
 +    "restart?":"Inici"
 +  },
 +  help_ca:
 +    "Utilitzi el ratolí, barra espaiadora, tecles Esq./Dta. " +
 +    "o Re pàg y Av pàg. Usi S i B per canviar grandària de font.",
 +
 +  strings_cs: {
 +    "slide":"snímek",
 +    "help?":"nápověda",
 +    "contents?":"obsah",
 +    "table of contents":"obsah prezentace",
 +    "Table of Contents":"Obsah prezentace",
 +    "restart presentation":"znovu spustit prezentaci",
 +    "restart?":"restart"
 +  },
 +  help_cs:
 +    "Prezentaci můžete procházet pomocí kliknutí myši, mezerníku, " +
 +    "šipek vlevo a vpravo nebo kláves PageUp a PageDown. Písmo se " +
 +    "dá zvětšit a zmenšit pomocí kláves B a S.",
 +
 +  strings_nl: {
 +    "slide":"pagina",
 +    "help?":"Help?",
 +    "contents?":"Inhoud?",
 +    "table of contents":"inhoudsopgave",
 +    "Table of Contents":"Inhoudsopgave",
 +    "restart presentation":"herstart presentatie",
 +    "restart?":"Herstart?"
 +  },
 +  help_nl:
 +     "Navigeer d.m.v. het muis, spatiebar, Links/Rechts toetsen, " +
 +     "of PgUp en PgDn. Gebruik S en B om de karaktergrootte te veranderen.",
 +
 +  strings_de: {
 +    "slide":"Seite",
 +    "help?":"Hilfe",
 +    "contents?":"Übersicht",
 +    "table of contents":"Inhaltsverzeichnis",
 +    "Table of Contents":"Inhaltsverzeichnis",
 +    "restart presentation":"Präsentation neu starten",
 +    "restart?":"Neustart"
 +  },
 +  help_de:
 +    "Benutzen Sie die Maus, Leerschlag, die Cursortasten links/rechts oder " +
 +    "Page up/Page Down zum Wechseln der Seiten und S und B für die Schriftgrösse.",
 +
 +  strings_pl: {
 +    "slide":"slajd",
 +    "help?":"pomoc?",
 +    "contents?":"spis treści?",
 +    "table of contents":"spis treści",
 +    "Table of Contents":"Spis Treści",
 +    "restart presentation":"Restartuj prezentację",
 +    "restart?":"restart?"
 +  },
 +  help_pl:
 +    "Zmieniaj slajdy klikając myszą, naciskając spację, strzałki lewo/prawo" +
 +    "lub PgUp / PgDn. Użyj klawiszy S i B, aby zmienić rozmiar czczionki.",
 +
 +  strings_fr: {
 +    "slide":"page",
 +    "help?":"Aide",
 +    "contents?":"Index",
 +    "table of contents":"table des matières",
 +    "Table of Contents":"Table des matières",
 +    "restart presentation":"Recommencer l'exposé",
 +    "restart?":"Début"
 +  },
 +  help_fr:
 +    "Naviguez avec la souris, la barre d'espace, les flèches " +
 +    "gauche/droite ou les touches Pg Up, Pg Dn. Utilisez " +
 +    "les touches S et B pour modifier la taille de la police.",
 +
 +  strings_hu: {
 +    "slide":"oldal",
 +    "help?":"segítség",
 +    "contents?":"tartalom",
 +    "table of contents":"tartalomjegyzék",
 +    "Table of Contents":"Tartalomjegyzék",
 +    "restart presentation":"bemutató újraindítása",
 +    "restart?":"újraindítás"
 +  },
 +  help_hu:
 +    "Az oldalak közti lépkedéshez kattintson az egérrel, vagy " +
 +    "használja a szóköz, a bal, vagy a jobb nyíl, illetve a Page Down, " +
 +    "Page Up billentyűket. Az S és a B billentyűkkel változtathatja " +
 +    "a szöveg méretét.",
 +
 +  strings_it: {
 +    "slide":"pag.",
 +    "help?":"Aiuto",
 +    "contents?":"Indice",
 +    "table of contents":"indice",
 +    "Table of Contents":"Indice",
 +    "restart presentation":"Ricominciare la presentazione",
 +    "restart?":"Inizio"
 +  },
 +  help_it:
 +    "Navigare con mouse, barra spazio, frecce sinistra/destra o " +
 +    "PgUp e PgDn. Usare S e B per cambiare la dimensione dei caratteri.",
 +
 +  strings_el: {
 +    "slide":"σελίδα",
 +    "help?":"βοήθεια;",
 +    "contents?":"περιεχόμενα;",
 +    "table of contents":"πίνακας περιεχομένων",
 +    "Table of Contents":"Πίνακας Περιεχομένων",
 +    "restart presentation":"επανεκκίνηση παρουσίασης",
 +    "restart?":"επανεκκίνηση;"
 +  },
 +  help_el:
 +    "Πλοηγηθείτε με το κλίκ του ποντικιού, το space, τα βέλη αριστερά/δεξιά, " +
 +    "ή Page Up και Page Down. Χρησιμοποιήστε τα πλήκτρα S και B για να αλλάξετε " +
 +    "το μέγεθος της γραμματοσειράς.",
 +
 +  strings_ja: {
 +    "slide":"スライド",
 +    "help?":"ヘルプ",
 +    "contents?":"目次",
 +    "table of contents":"目次を表示",
 +    "Table of Contents":"目次",
 +    "restart presentation":"最初から再生",
 +    "restart?":"最初から"
 +  },
 +  help_ja:
 +     "マウス左クリック ・ スペース ・ 左右キー " +
 +     "または Page Up ・ Page Downで操作, S ・ Bでフォントサイズ変更",
 +
 +  strings_zh: {
 +    "slide":"幻灯片",
 +    "help?":"帮助?",
 +    "contents?":"内容?",
 +    "table of contents":"目录",
 +    "Table of Contents":"目录",
 +    "restart presentation":"重新启动展示",
 +    "restart?":"重新启动?"
 +  },
 +  help_zh:
 +    "用鼠标点击, 空格条, 左右箭头, Pg Up 和 Pg Dn 导航. " +
 +    "用 S, B 改变字体大小.",
 +
 +  strings_ru: {
 +    "slide":"слайд",
 +    "help?":"помощь?",
 +    "contents?":"содержание?",
 +    "table of contents":"оглавление",
 +    "Table of Contents":"Оглавление",
 +    "restart presentation":"перезапустить презентацию",
 +    "restart?":"перезапуск?"
 +  },
 +  help_ru:
 +    "Перемещайтесь кликая мышкой, используя клавишу пробел, стрелки" +
 +    "влево/вправо или Pg Up и Pg Dn. Клавиши S и B меняют размер шрифта.",
 +
 +  strings_sv: {
 +    "slide":"sida",
 +    "help?":"hjälp",
 +    "contents?":"innehåll",
 +    "table of contents":"innehållsförteckning",
 +    "Table of Contents":"Innehållsförteckning",
 +    "restart presentation":"visa presentationen från början",
 +    "restart?":"börja om"
 +  },
 +  help_sv:
 +    "Bläddra med ett klick med vänstra musknappen, mellanslagstangenten, " +
 +    "vänster- och högerpiltangenterna eller tangenterna Pg Up, Pg Dn. " +
 +    "Använd tangenterna S och B för att ändra textens storlek.",
 +
 +// each such language array is declared in the localize array
 +// which is set on string prototype and used as in "foo".localize();
 +  localize: {
 +    "es":this.strings_es,
 +    "ca":this.strings_ca,
 +    "cs":this.strings_cs,
 +    "nl":this.strings_nl,
 +    "de":this.strings_de,
 +    "pl":this.strings_pl,
 +    "fr":this.strings_fr,
 +    "hu":this.strings_hu,
 +    "it":this.strings_it,
 +    "el":this.strings_el,
 +    "jp":this.strings_ja,
 +    "zh":this.strings_zh,
 +    "ru":this.strings_ru,
 +    "sv":this.strings_sv
 +  },
 +
 +  init: function () {
 +    var i18n = w3c_slidy_i18n;
 +    var help_text = w3c_slidy.help_text;
 +    i18n.strings_es[help_text] = i18n.help_es;
 +    i18n.strings_ca[help_text] = i18n.help_ca;
 +    i18n.strings_cs[help_text] = i18n.help_cs;
 +    i18n.strings_nl[help_text] = i18n.help_nl;
 +    i18n.strings_de[help_text] = i18n.help_de;
 +    i18n.strings_pl[help_text] = i18n.help_pl;
 +    i18n.strings_fr[help_text] = i18n.help_fr;
 +    i18n.strings_hu[help_text] = i18n.help_hu;
 +    i18n.strings_it[help_text] = i18n.help_it;
 +    i18n.strings_el[help_text] = i18n.help_el;
 +    i18n.strings_ja[help_text] = i18n.help_ja;
 +    i18n.strings_zh[help_text] = i18n.help_zh;
 +    i18n.strings_ru[help_text] = i18n.help_ru;
 +    i18n.strings_sv[help_text] = i18n.help_sv;
 +
 +    w3c_slidy.lang = document.body.parentNode.getAttribute("lang");
 +
 +    if (!w3c_slidy.lang)
 +      w3c_slidy.lang = document.body.parentNode.getAttribute("xml:lang");
 +
 +    if (!w3c_slidy.lang)
 +      w3c_slidy.lang = "en";
 +
 +    // add localize method to all strings
 +    // for use as in "contents".localize()
 +   String.prototype.localize = function() {
 +     if (this == "")
 +       return this;
 +
 +     // try full language code, e.g. en-US
 +     var s, lookup = w3c_slidy_i18n.localize[w3c_slidy.lang];
 +
 +     if (lookup)
 +     {
 +       s = lookup[this];
 +
 +       if (s)
 +        return s;
 +     }
 +
 +     // strip country code suffix, e.g.
 +     // try en if undefined for en-US
 +     var lg = w3c_slidy.lang.split("-");
 +
 +     if (lg.length > 1)
 +     {
 +       lookup = w3c_slidy_i18n.localize[lg[0]];
 +
 +       if (lookup)
 +       {
 +         s = lookup[this];
 +
 +         if (s)
 +          return s;
 +       }
 +     }
 +
 +     // otherwise string as is
 +     return this;
 +   };
 +  }
 +};
 +
 +// hack for back button behavior
 +if (w3c_slidy.ie6 || w3c_slidy.ie7)
 +{
 +  document.write("<iframe id='historyFrame' " +
 +  "src='javascript:\"<html"+"></"+"html>\"' " +
 +  "height='1' width='1' " +
 +  "style='position:absolute;left:-800px'></iframe>");
 +}
 +
 +// attach event listeners for initialization
 +w3c_slidy.set_up();
 +
 +// hide the slides as soon as body element is available
 +// to reduce annoying screen mess before the onload event
 +setTimeout(w3c_slidy.hide_slides, 50);
 +
 +/*]]>*/
 +</script>
 +</head>
 +<body class="article" style="max-width:45em">
 +<div id="header" class="slide">
 +<h1>Year 2017 Osmocom retrospective</h1>
 +<span id="author">Harald Welte <laforge@gnumonks.org></span><br />
 +</div>
 +<div class="sect1 slide">
 +<h1 id="_2017_a_year_of_change">2017 - a year of change</h1>
 +<div class="sectionbody" style="max-width:45em">
 +<div class="paragraph"><p>Osmocom CNI (Cellular Network Infrastructure) has changed a lot:</p></div>
 +<ul class="">
 +<li>
 +<span>
 +software changes
 +</span>
 +</li>
 +<li>
 +<span>
 +team / developer changes
 +</span>
 +</li>
 +<li>
 +<span>
 +sysmocom company focus changes
 +</span>
 +</li>
 +</ul>
 +</div>
 +</div>
 +<div class="sect1 slide">
 +<h1 id="_2017_cni_software_changes">2017 - CNI Software changes</h1>
 +<div class="sectionbody" style="max-width:45em">
 +<ul class="">
 +<li>
 +<span>
 +OsmoBSC migration from SCCPlite to 3GPP AoIP
 +</span>
 +</li>
 +<li>
 +<span>
 +OsmoMGW as integral part of both BSC and MSC
 +</span>
 +</li>
 +<li>
 +<span>
 +NITB split into separate MSC, HLR, BSC
 +</span>
 +</li>
 +<li>
 +<span>
 +3G (IuCS, IuPS) goes mainline
 +</span>
 +</li>
 +</ul>
 +</div>
 +</div>
 +<div class="sect1 slide">
 +<h1 id="_2016_2017_2018_team_changes">2016/2017/2018 - Team changes</h1>
 +<div class="sectionbody" style="max-width:45em">
 +<ul class="">
 +<li>
 +<span>
 +Q1 2016: Jacob Erlbeck leaves sysmocom
 +</span>
 +<ul class="">
 +<li>
 +<span>
 +unfortunately a complete loss to Osmocom, particularly OsmoPCU
 +</span>
 +</li>
 +</ul>
 +</li>
 +<li>
 +<span>
 +2017: Holger Freyther leaves sysmocom
 +</span>
 +<ul class="">
 +<li>
 +<span>
 +unfortunately also shift of focus away from Osmocom :(
 +</span>
 +</li>
 +<li>
 +<span>
 +immense loss to the project in terms of skill and capacity
 +</span>
 +</li>
 +</ul>
 +</li>
 +<li>
 +<span>
 +Q1 2018: Max Suraev leaves sysmocom
 +</span>
 +<ul class="">
 +<li>
 +<span>
 +another loss of lots of Osmocom knowledge
 +</span>
 +</li>
 +</ul>
 +</li>
 +</ul>
 +</div>
 +</div>
 +<div class="sect1 slide">
 +<h1 id="_sysmocom_changes">sysmocom changes</h1>
 +<div class="sectionbody" style="max-width:45em">
 +<ul class="">
 +<li>
 +<span>
 +we used to have to do lots of non-Osmocom work to cross-subsidize Osmocom
 +</span>
 +<ul class="">
 +<li>
 +<span>
 +big distraction of resources in 2014/2015, now gone
 +</span>
 +</li>
 +</ul>
 +</li>
 +<li>
 +<span>
 +we used to cross-subsidize Osmocom development by hardware sales
 +</span>
 +<ul class="">
 +<li>
 +<span>
 +not happening as much anymore
 +</span>
 +</li>
 +</ul>
 +</li>
 +<li>
 +<span>
 +we now work almost 100% on Osmocom
 +</span>
 +<ul class="">
 +<li>
 +<span>
 +R&D projects, support contracts and grants
 +</span>
 +</li>
 +</ul>
 +</li>
 +</ul>
 +</div>
 +</div>
 +<div class="sect1 slide">
 +<h1 id="_split_nitb_aftermath_the_good_parts">split NITB aftermath (the good parts)</h1>
 +<div class="sectionbody" style="max-width:45em">
 +<ul class="">
 +<li>
 +<span>
 +biggest architectural change since we started in 2008
 +</span>
 +</li>
 +<li>
 +<span>
 +lots of good reasons and design improvements
 +</span>
 +<ul class="">
 +<li>
 +<span>
 +finite state machines with proper timeouts / clean-up
 +</span>
 +</li>
 +<li>
 +<span>
 +proper 3GPP AoIP with interoperability tesing
 +</span>
 +</li>
 +<li>
 +<span>
 +no synchronous HLR database access
 +</span>
 +</li>
 +<li>
 +<span>
 +HLR access from OsmoMSC and OsmoSGSN
 +</span>
 +</li>
 +<li>
 +<span>
 +2G/3G authentication over GERAN and UTRAN
 +</span>
 +</li>
 +</ul>
 +</li>
 +</ul>
 +</div>
 +</div>
 +<div class="sect1 slide">
 +<h1 id="_split_nitb_aftermath_the_bad_parts">split NITB aftermath (the bad parts)</h1>
 +<div class="sectionbody" style="max-width:45em">
 +<ul class=" incremental">
 +<li>
 +<span>
 +never-ending list of breakage
 +</span>
 +<ul class="">
 +<li>
 +<span>
 +actual regressions of things that used to work before
 +</span>
 +</li>
 +<li>
 +<span>
 +things that were <em>known omissions</em> during the restructuring
 +</span>
 +</li>
 +</ul>
 +</li>
 +<li>
 +<span>
 +some commercial users stuck with SCCPlite and thus old @osmo-bsc-sccplite@
 +</span>
 +<ul class="">
 +<li>
 +<span>
 +almost none of the new features or bug fixes there
 +</span>
 +</li>
 +<li>
 +<span>
 +no automatic testing
 +</span>
 +</li>
 +<li>
 +<span>
 +back-ports time-consuming
 +</span>
 +</li>
 +</ul>
 +</li>
 +</ul>
 +</div>
 +</div>
 +<div class="sect1 slide">
 +<h1 id="_split_nitb_aftermath_lessons_learned">split NITB aftermath (lessons learned)</h1>
 +<div class="sectionbody" style="max-width:45em">
 +<ul class="">
 +<li>
 +<span>
 +overall complexity of Osomcoom cellular is quite stunning now
 +</span>
 +</li>
 +<li>
 +<span>
 +absence of proper functional testing has caused massive fall-out
 +</span>
 +</li>
 +<li>
 +<span>
 +the split architecture allows for betteer testing of smaller parts of the system
 +</span>
 +</li>
 +<li>
 +<span>
 +my personal main focus of the last 5+ months:
 +</span>
 +<ul class=" incremental">
 +<li>
 +<span>
 +testing, testing, testing, testing
 +</span>
 +</li>
 +<li>
 +<span>
 +testing, testing, testing, testing
 +</span>
 +</li>
 +<li>
 +<span>
 +some more testing
 +</span>
 +</li>
 +<li>
 +<span>
 +even more testing
 +</span>
 +</li>
 +</ul>
 +</li>
 +</ul>
 +</div>
 +</div>
 +<div class="sect1 slide">
 +<h1 id="_osmocom_cni_testing_1_2">Osmocom CNI testing (1/2)</h1>
 +<div class="sectionbody" style="max-width:45em">
 +<ul class=" incremental">
 +<li>
 +<span>
 +unit test (autotest, like we always had)
 +</span>
 +<ul class="">
 +<li>
 +<span>
 +test individual functions / APIs of libraries / programs
 +</span>
 +</li>
 +<li>
 +<span>
 +executed during "make check" and hence before any patch can get merged
 +</span>
 +</li>
 +</ul>
 +</li>
 +<li>
 +<span>
 +automatized functional tests in TTCN-3
 +</span>
 +<ul class="">
 +<li>
 +<span>
 +test <em>external</em> visible behavior on interfaces such as Abis, A, GSUP, GTP, MNCC, PCUIF, CTRL, VTY, …
 +</span>
 +</li>
 +<li>
 +<span>
 +executed nightly by Jenkins (could be more frequently)
 +</span>
 +</li>
 +</ul>
 +</li>
 +</ul>
 +</div>
 +</div>
 +<div class="sect1 slide">
 +<h1 id="_osmocom_cni_testing_2_2">Osmocom CNI testing (2/2)</h1>
 +<div class="sectionbody" style="max-width:45em">
 +<ul class=" incremental">
 +<li>
 +<span>
 +osmo-gsm-tester
 +</span>
 +<ul class="">
 +<li>
 +<span>
 +tests entire Osmoocom network with BTS/BSC/MSC/HLR/PCU/SGSN/GGSN/…
 +</span>
 +</li>
 +<li>
 +<span>
 +uses real BTS + MS hardware (over coaxial cable)
 +</span>
 +</li>
 +<li>
 +<span>
 +automatic execution multiple times per day
 +</span>
 +</li>
 +</ul>
 +</li>
 +<li>
 +<span>
 +interop tests
 +</span>
 +<ul class="">
 +<li>
 +<span>
 +against NG40 RAN + CN simulator from NG4% (A / Gb / Iu level)
 +</span>
 +</li>
 +<li>
 +<span>
 +not fully automatized yet
 +</span>
 +</li>
 +</ul>
 +</li>
 +</ul>
 +</div>
 +</div>
 +<div class="sect1 slide">
 +<h1 id="_osmocom_project_health_cni">Osmocom project health (CNI)</h1>
 +<div class="sectionbody" style="max-width:45em">
 +<ul class=" incremental">
 +<li>
 +<span>
 +lots of funded developments, <strong>but</strong>
 +</span>
 +<ul class="">
 +<li>
 +<span>
 +primarily <em>enterprise features</em> required by professional users
 +</span>
 +</li>
 +</ul>
 +</li>
 +<li>
 +<span>
 +dominance of sysmocom is problematic
 +</span>
 +<ul class="">
 +<li>
 +<span>
 +sustainable FOSS has no single point of failure!
 +</span>
 +</li>
 +</ul>
 +</li>
 +<li>
 +<span>
 +we need more contributions from third parties
 +</span>
 +<ul class="">
 +<li>
 +<span>
 +particularly those that benefit commercially from Osmocom
 +</span>
 +</li>
 +</ul>
 +</li>
 +</ul>
 +</div>
 +</div>
 +<div class="sect1 slide">
 +<h1 id="_osmocom_project_health_other_projects">Osmocom project health (other projects)</h1>
 +<div class="sectionbody" style="max-width:45em">
 +<ul class=" incremental">
 +<li>
 +<span>
 +OsmocomTETRA dead since 2012, occasional small fixes
 +</span>
 +</li>
 +<li>
 +<span>
 +No OsmocomBB ports to other PHY/chip yet
 +</span>
 +</li>
 +<li>
 +<span>
 +OsmocomDECT completely dead
 +</span>
 +</li>
 +<li>
 +<span>
 +Erlang core network projects dead
 +</span>
 +</li>
 +<li>
 +<span>
 +Smalltalk projects dead (AFAICT)
 +</span>
 +</li>
 +<li>
 +<span>
 +SIMtrace dead for years, about to be resurrected
 +</span>
 +</li>
 +</ul>
 +</div>
 +</div>
 +<div class="sect1 slide">
 +<h1 id="_osmocom_project_health_other_projects_2">Osmocom project health (other projects)</h1>
 +<div class="sectionbody" style="max-width:45em">
 +<ul class=" incremental">
 +<li>
 +<span>
 +gr-osmosdr very low commit ratio
 +</span>
 +</li>
 +<li>
 +<span>
 +rtl-sdr no commits in 2015-2017
 +</span>
 +</li>
 +<li>
 +<span>
 +but it’s not that bad… (see next slide)
 +</span>
 +</li>
 +</ul>
 +</div>
 +</div>
 +<div class="sect1 slide">
 +<h1 id="_osmocom_project_health_other_projects_3">Osmocom project health (other projects)</h1>
 +<div class="sectionbody" style="max-width:45em">
 +<ul class=" incremental">
 +<li>
 +<span>
 +gr-gsm, fake_trx and trxcon a welcome change in OsmocomBB
 +</span>
 +</li>
 +<li>
 +<span>
 +osmocom-analog (jolly to the rescue)
 +</span>
 +</li>
 +<li>
 +<span>
 +osmo-fl2k (soon! now! this year!)
 +</span>
 +</li>
 +</ul>
 +</div>
 +</div>
 +<div class="sect1 slide">
 +<h1 id="_osmocom_status_cni">Osmocom status (CNI)</h1>
 +<div class="sectionbody" style="max-width:45em">
 +<ul class=" incremental">
 +<li>
 +<span>
 +CS RAN (BTS, BSC) is quite strong/complete these days
 +</span>
 +<ul class="">
 +<li>
 +<span>
 +ready to be used with 3rd party CN
 +</span>
 +</li>
 +</ul>
 +</li>
 +<li>
 +<span>
 +PS RAN (PCU) suffers from lack of attention
 +</span>
 +<ul class="">
 +<li>
 +<span>
 +lack of automatic testsuite with decent coverage
 +</span>
 +</li>
 +<li>
 +<span>
 +lack of uplink multi-slot any many EGPRS features
 +</span>
 +</li>
 +</ul>
 +</li>
 +<li>
 +<span>
 +CS CN (MSC, HLR)
 +</span>
 +<ul class="">
 +<li>
 +<span>
 +in halthy state, but lack of TCAP/MAP interface limits us to non-roaming networks
 +</span>
 +</li>
 +</ul>
 +</li>
 +<li>
 +<span>
 +PS CN (SGSN, GGSN)
 +</span>
 +<ul class="">
 +<li>
 +<span>
 +in good health, now with IPv6 supoprt and kernel GTP acceleration
 +</span>
 +</li>
 +</ul>
 +</li>
 +</ul>
 +</div>
 +</div>
 +<div class="sect1 slide">
 +<h1 id="_osmocom_outlook_cni">Osmocom outlook (CNI)</h1>
 +<div class="sectionbody" style="max-width:45em">
 +<ul class="">
 +<li>
 +<span>
 +2G still in demand by lots of use cases (rural, maritime, …)
 +</span>
 +<ul class="">
 +<li>
 +<span>
 +if we had TCAP/MAP interface, many more deployments possible
 +</span>
 +</li>
 +</ul>
 +</li>
 +<li>
 +<span>
 +3G has some users but lack of FOSS RNC limits us to femtocells
 +</span>
 +</li>
 +<li>
 +<span>
 +4G is deployed in parallel to 2G in many scenarios
 +</span>
 +<ul class="">
 +<li>
 +<span>
 +Osmocom 2G stack needs 2G-4G integration (SGs, DIAMETER)
 +</span>
 +</li>
 +<li>
 +<span>
 +Osmocom needs to contribute  to FOSS 4G projects (nextepc, srsLTE)
 +</span>
 +</li>
 +</ul>
 +</li>
 +<li>
 +<span>
 +irony: Now that it’s possible to do properly funded Osmocom development, we have less people involved than in the early days :(
 +</span>
 +</li>
 +</ul>
 +<div class="paragraph"><p>If we don’t manage to focus on 4G soon, interest in 2G will diminish soon</p></div>
 +</div>
 +</div>
 +<div class="sect1 slide">
 +<h1 id="_osmocom_outlook_other_projects">Osmocom outlook (other projects)</h1>
 +<div class="sectionbody" style="max-width:45em">
 +<ul class="">
 +<li>
 +<span>
 +activity of original/traditional Osmocom developers decreased
 +</span>
 +</li>
 +<li>
 +<span>
 +without attracting more developers, a lot of projects will remain dormant and/or never realize their potential
 +</span>
 +</li>
 +<li>
 +<span>
 +I’d love to work on TETRA, DMR or other mobile communications technology
 +</span>
 +<ul class="">
 +<li>
 +<span>
 +but lack of developers and contributors even for 2G makes me stuck in 2G CNI land :(
 +</span>
 +</li>
 +</ul>
 +</li>
 +</ul>
 +</div>
 +</div>
 +<div class="sect1 slide">
 +<h1 id="_personal_request">Personal Request</h1>
 +<div class="sectionbody" style="max-width:45em">
 +<ul class="">
 +<li>
 +<span>
 +Osmocom needs you!
 +</span>
 +</li>
 +<li>
 +<span>
 +we’ve lost too many friends already
 +</span>
 +</li>
 +<li>
 +<span>
 +please don’t leave Osmocom; please don’t leave me
 +</span>
 +</li>
 +</ul>
 +</div>
 +</div>
 +<div class="sect1 slide">
 +<h1 id="_further_reading">Further Reading</h1>
 +<div class="sectionbody" style="max-width:45em">
 +<div class="paragraph"><p>See my detailed 2017 review:
 +* <a href="http://osmocom.org/news/84">http://osmocom.org/news/84</a></p></div>
 +</div>
 +</div>
 +<div class="sect1 slide">
 +<h1 id="_eof">EOF</h1>
 +<div class="sectionbody" style="max-width:45em">
 +<div class="paragraph"><p>End of File</p></div>
 +</div>
 +</div>
 +</body>
 +</html>
  | 
