blob: e37271bf1254e2e6a684ea2ffa9f724ab2403095 [file] [log] [blame]
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui" /><title>What is the ASF?</title><meta name="description" content="A short 30 minute introduction talk about what Apache Community Development is" /><meta name="keywords" content="ComDev, Community Development" /><meta name="author" content="Your Name" /><link rel="stylesheet" href="reveal.js-3.9.2/css/reset.css" /><link rel="stylesheet" href="reveal.js-3.9.2/css/reveal.css" /><link href="css/c3.min.css" rel="stylesheet" /><script src="js/d3.min.js" charset="utf-8"></script><script src="js/c3.min.js"></script><link rel="stylesheet" href="reveal.js-3.9.2/css/theme/apache.css" id="theme" /><!--This CSS is generated by the Asciidoctor reveal.js converter to further integrate AsciiDoc's existing semantic with reveal.js--><style type="text/css">.reveal div.right {
float: right
}
/* source blocks */
.reveal .listingblock.stretch > .content {
height: 100%
}
.reveal .listingblock.stretch > .content > pre {
height: 100%
}
.reveal .listingblock.stretch > .content > pre > code {
height: 100%;
max-height: 100%
}
/* auto-animate feature */
/* hide the scrollbar when auto-animating source blocks */
.reveal pre[data-auto-animate-target] {
overflow: hidden;
}
.reveal pre[data-auto-animate-target] code {
overflow: hidden;
}
/* add a min width to avoid horizontal shift on line numbers */
code.hljs .hljs-ln-line.hljs-ln-n {
min-width: 1.25em;
}
/* tables */
table {
border-collapse: collapse;
border-spacing: 0
}
table {
margin-bottom: 1.25em;
border: solid 1px #dedede
}
table thead tr th, table thead tr td, table tfoot tr th, table tfoot tr td {
padding: .5em .625em .625em;
font-size: inherit;
text-align: left
}
table tr th, table tr td {
padding: .5625em .625em;
font-size: inherit
}
table thead tr th, table tfoot tr th, table tbody tr td, table tr td, table tfoot tr td {
display: table-cell;
line-height: 1.6
}
td.tableblock > .content {
margin-bottom: 1.25em
}
td.tableblock > .content > :last-child {
margin-bottom: -1.25em
}
table.tableblock, th.tableblock, td.tableblock {
border: 0 solid #dedede
}
table.grid-all > thead > tr > .tableblock, table.grid-all > tbody > tr > .tableblock {
border-width: 0 1px 1px 0
}
table.grid-all > tfoot > tr > .tableblock {
border-width: 1px 1px 0 0
}
table.grid-cols > * > tr > .tableblock {
border-width: 0 1px 0 0
}
table.grid-rows > thead > tr > .tableblock, table.grid-rows > tbody > tr > .tableblock {
border-width: 0 0 1px
}
table.grid-rows > tfoot > tr > .tableblock {
border-width: 1px 0 0
}
table.grid-all > * > tr > .tableblock:last-child, table.grid-cols > * > tr > .tableblock:last-child {
border-right-width: 0
}
table.grid-all > tbody > tr:last-child > .tableblock, table.grid-all > thead:last-child > tr > .tableblock, table.grid-rows > tbody > tr:last-child > .tableblock, table.grid-rows > thead:last-child > tr > .tableblock {
border-bottom-width: 0
}
table.frame-all {
border-width: 1px
}
table.frame-sides {
border-width: 0 1px
}
table.frame-topbot, table.frame-ends {
border-width: 1px 0
}
.reveal table th.halign-left, .reveal table td.halign-left {
text-align: left
}
.reveal table th.halign-right, .reveal table td.halign-right {
text-align: right
}
.reveal table th.halign-center, .reveal table td.halign-center {
text-align: center
}
.reveal table th.valign-top, .reveal table td.valign-top {
vertical-align: top
}
.reveal table th.valign-bottom, .reveal table td.valign-bottom {
vertical-align: bottom
}
.reveal table th.valign-middle, .reveal table td.valign-middle {
vertical-align: middle
}
table thead th, table tfoot th {
font-weight: bold
}
tbody tr th {
display: table-cell;
line-height: 1.6
}
tbody tr th, tbody tr th p, tfoot tr th, tfoot tr th p {
font-weight: bold
}
thead {
display: table-header-group
}
.reveal table.grid-none th, .reveal table.grid-none td {
border-bottom: 0 !important
}
/* kbd macro */
kbd {
font-family: "Droid Sans Mono", "DejaVu Sans Mono", monospace;
display: inline-block;
color: rgba(0, 0, 0, .8);
font-size: .65em;
line-height: 1.45;
background: #f7f7f7;
border: 1px solid #ccc;
-webkit-border-radius: 3px;
border-radius: 3px;
-webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, .2), 0 0 0 .1em white inset;
box-shadow: 0 1px 0 rgba(0, 0, 0, .2), 0 0 0 .1em #fff inset;
margin: 0 .15em;
padding: .2em .5em;
vertical-align: middle;
position: relative;
top: -.1em;
white-space: nowrap
}
.keyseq kbd:first-child {
margin-left: 0
}
.keyseq kbd:last-child {
margin-right: 0
}
/* callouts */
.conum[data-value] {
display: inline-block;
color: #fff !important;
background: rgba(0, 0, 0, .8);
-webkit-border-radius: 50%;
border-radius: 50%;
text-align: center;
font-size: .75em;
width: 1.67em;
height: 1.67em;
line-height: 1.67em;
font-family: "Open Sans", "DejaVu Sans", sans-serif;
font-style: normal;
font-weight: bold
}
.conum[data-value] * {
color: #fff !important
}
.conum[data-value] + b {
display: none
}
.conum[data-value]:after {
content: attr(data-value)
}
pre .conum[data-value] {
position: relative;
top: -.125em
}
b.conum * {
color: inherit !important
}
.conum:not([data-value]):empty {
display: none
}
/* Callout list */
.hdlist > table, .colist > table {
border: 0;
background: none
}
.hdlist > table > tbody > tr, .colist > table > tbody > tr {
background: none
}
td.hdlist1, td.hdlist2 {
vertical-align: top;
padding: 0 .625em
}
td.hdlist1 {
font-weight: bold;
padding-bottom: 1.25em
}
/* Disabled from Asciidoctor CSS because it caused callout list to go under the
* source listing when .stretch is applied (see #335)
* .literalblock+.colist,.listingblock+.colist{margin-top:-.5em} */
.colist td:not([class]):first-child {
padding: .4em .75em 0;
line-height: 1;
vertical-align: top
}
.colist td:not([class]):first-child img {
max-width: none
}
.colist td:not([class]):last-child {
padding: .25em 0
}
/* Override Asciidoctor CSS that causes issues with reveal.js features */
.reveal .hljs table {
border: 0
}
/* Callout list rows would have a bottom border with some reveal.js themes (see #335) */
.reveal .colist > table th, .reveal .colist > table td {
border-bottom: 0
}
/* Fixes line height with Highlight.js source listing when linenums enabled (see #331) */
.reveal .hljs table thead tr th, .reveal .hljs table tfoot tr th, .reveal .hljs table tbody tr td, .reveal .hljs table tr td, .reveal .hljs table tfoot tr td {
line-height: inherit
}
/* Columns layout */
.columns .slide-content {
display: flex;
}
.columns.wrap .slide-content {
flex-wrap: wrap;
}
.columns.is-vcentered .slide-content {
align-items: center;
}
.columns .slide-content > .column {
display: block;
flex-basis: 0;
flex-grow: 1;
flex-shrink: 1;
}
.columns .slide-content > .column > * {
padding: .75rem;
}
/* See #353 */
.columns.wrap .slide-content > .column {
flex-basis: auto;
}
.columns .slide-content > .column.is-full {
flex: none;
width: 100%;
}
.columns .slide-content > .column.is-four-fifths {
flex: none;
width: 80%;
}
.columns .slide-content > .column.is-three-quarters {
flex: none;
width: 75%;
}
.columns .slide-content > .column.is-two-thirds {
flex: none;
width: 66.6666%;
}
.columns .slide-content > .column.is-three-fifths {
flex: none;
width: 60%;
}
.columns .slide-content > .column.is-half {
flex: none;
width: 50%;
}
.columns .slide-content > .column.is-two-fifths {
flex: none;
width: 40%;
}
.columns .slide-content > .column.is-one-third {
flex: none;
width: 33.3333%;
}
.columns .slide-content > .column.is-one-quarter {
flex: none;
width: 25%;
}
.columns .slide-content > .column.is-one-fifth {
flex: none;
width: 20%;
}
.columns .slide-content > .column.has-text-left {
text-align: left;
}
.columns .slide-content > .column.has-text-justified {
text-align: justify;
}
.columns .slide-content > .column.has-text-right {
text-align: right;
}
.columns .slide-content > .column.has-text-left {
text-align: left;
}
.columns .slide-content > .column.has-text-justified {
text-align: justify;
}
.columns .slide-content > .column.has-text-right {
text-align: right;
}
.text-left {
text-align: left !important
}
.text-right {
text-align: right !important
}
.text-center {
text-align: center !important
}
.text-justify {
text-align: justify !important
}
.footnotes {
border-top: 1px solid rgba(0, 0, 0, 0.2);
padding: 0.5em 0 0 0;
font-size: 0.65em;
margin-top: 4em;
}
.byline {
font-size:.8em
}
ul.byline {
list-style-type: none;
}
ul.byline li + li {
margin-top: 0.25em;
}
</style><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css" /><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/v4-shims.min.css" /><!--Printing and PDF exports--><script>var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match( /print-pdf/gi ) ? "reveal.js-3.9.2/css/print/pdf.css" : "reveal.js-3.9.2/css/print/paper.css";
document.getElementsByTagName( 'head' )[0].appendChild( link );</script></head><body><div class="header"><div class="left"></div><div class="right"></div></div><div class="reveal"><div class="slides"><section id="what-is-the-asf"><h2>What is the ASF?</h2><div class="slide-content"><div class="imageblock"><img src="images/ApacheLogo.png" alt="ApacheLogo" /></div></div></section>
<section id="who-am-i"><h2>Who am I?</h2><div class="slide-content"><div class="paragraph"><p>Your Name<br />
Your role<br />
Your email<br /></p></div>
<aside class="notes"><div class="paragraph"><p>Please add your own details here</p></div></aside></div></section>
<section id="what-am-i-going-to-cover"><h2>What am I going to cover?</h2><div class="slide-content"><div class="imageblock"><img src="images/asf_logo.png" alt="asf logo" /></div>
<div class="ulist"><ul><li><p>What is the ASF?</p></li><li><p>How is an ASF project structured?</p></li><li><p>How is the ASF structured?</p></li><li><p>How does all of this work?</p></li></ul></div></div></section>
<section id="what-is-the-asf-2"><h2>What is the ASF?</h2><div class="slide-content"><div class="ulist"><ul><li><p>ASF = The Apache Software Foundation</p></li><li><p><strong>US 501(c)3 charity</strong> (Non-profit charity)</p></li><li><p>Community of volunteers</p></li><li><p>Virtual, world-wide organisation</p></li><li><p>Provides organisational, legal and financial support for a large number of open-source projects</p></li></ul></div></div></section>
<section id="the-apache-group"><h2>The Apache Group</h2><div class="slide-content"><div class="imageblock" style="text-align: center; float: right"><img src="images/apache_8.png" alt="250" width="250" /></div>
<div class="ulist"><ul><li><p>Before there was the ASF, there was the "Apache Group"</p></li><li><p>Informal corporate structure</p></li><li><p>8 members</p></li><li><p>Formed in Feb. 1995</p></li><li><p>Continued the work on the NCSA httpd</p></li><li><p>Chose a very promiscuous license</p></li></ul></div></div></section>
<section id="growth"><h2>Growth</h2><div class="slide-content"><table class="tableblock frame-all grid-all" style="width:100%"><colgroup><col style="width:50%" /><col style="width:50%" /></colgroup><tbody><tr><td class="tableblock halign-left valign-top"><p class="tableblock">Then (1999)</p></td><td class="tableblock halign-left valign-top"><p class="tableblock">Now (03.2023)</p></td></tr><tr><td class="tableblock halign-left valign-middle"><div><div class="ulist"><ul><li><p>21 Members</p></li><li><p>2 Projects</p></li><li><p>All servers and services donated</p></li></ul></div></div></td><td class="tableblock halign-left valign-middle"><div><div class="ulist"><ul><li><p>743 Members</p></li><li><p>362 Projects (Managed by 207 PMCs)</p></li><li><p>8833 Committers</p></li><li><p>Cloud infrastructure</p></li></ul></div></div></td></tr></table>
<aside class="notes"><div class="ulist"><ul><li><p>ICLA: Individual Contributor License Agreement</p></li><li><p>CCLA: Corporate Contributor License Agreement</p></li><li><p>31 Incubator Podlings</p></li><li><p>5 Special Committees: Infrastructure, Travel Assistance, Security Team, Legal Affairs and Brand Management</p></li></ul></div></aside></div></section>
<section id="number-of-projects-over-time"><h2>Number of projects over time</h2><div class="slide-content"><div class="imageblock"><img src="images/project-number-over-time.png" alt="project number over time" /></div></div></section>
<section id="commits-over-time"><h2>Commits over time</h2><div class="slide-content"><div class="imageblock"><img src="images/commits-over-time.png" alt="commits over time" /></div></div></section>
<section id="language-distribution"><h2>Language distribution</h2><div class="slide-content"><div class="imageblock"><img src="images/language-distribution.png" alt="language distribution" /></div></div></section>
<section id="project-categories"><h2>Project categories</h2><div class="slide-content"><div class="imageblock"><img src="images/project-categories.png" alt="project categories" /></div></div></section>
<section id="the-mission"><h2>The mission</h2><div class="slide-content"><div class="ulist"><ul><li><p><strong>Provide software for the public good</strong></p></li><li><p>Protect the trademark: <strong>Apache</strong> and her software products against misuse by other organisations</p></li><li><p>Provide the technical and legal infrastructure for open-source development</p></li><li><p>Provide all means to protect every volunteer from persecution as long as this persecution is aimed at a project of the foundation</p></li></ul></div>
<aside class="notes"><div class="ulist"><ul><li><p>legal infrastructure = Apache license, ICLA, CCLA, &#8230;&#8203;</p></li><li><p>legal umbrella: If someone initiates legal action against an Apache committer for things related to the ASF, the ASF takes the place of the accused.</p></li></ul></div></aside></div></section>
<section id="the-vision"><h2>The vision</h2><div class="slide-content"><div class="paragraph"><p>The Apache Software Foundation provides support for the Apache community of open-source software projects. The Apache projects are characterized by a <strong>collaborative</strong>, <strong>consensus based</strong> development process, an <strong>open</strong> and pragmatic software license, and a desire to create <strong>high quality</strong> software that leads the way in its field. We consider ourselves not simply a group of projects sharing a server, but rather a <strong>community of developers and users</strong>.</p></div></div></section>
<section id="projects"><h2>Projects</h2><div class="slide-content"><div class="ulist"><ul><li><p>Heart of the ASF are the <strong>projects</strong></p></li><li><p>Also named "Top Level Project" (TLP)</p></li><li><p>ASF provides services:</p><div class="ulist"><ul><li><p>Mailinglists, code-repositories (SVN, Git, &#8230;&#8203;)</p></li><li><p>Bug &amp; Issue trackers (Jira, &#8230;&#8203;), Wiki (Confluence, &#8230;&#8203;)</p></li><li><p>CI Server (Jenkins, &#8230;&#8203;), Webservers for project websites</p></li><li><p>&#8230;&#8203;</p></li></ul></div></li></ul></div>
<aside class="notes"><div class="ulist"><ul><li><p>Currently, there is a trend to use GitHub Issues, GitHub Discussions, GitHub Actions (CI)</p></li><li><p>The ASF provides tooling to integrate these</p></li></ul></div></aside></div></section>
<section id="structure-of-a-project"><h2>Structure of a project</h2><div class="slide-content"><div class="imageblock"><img src="images/project-structure.png" alt="project structure" /></div>
<aside class="notes"><div class="ulist"><ul><li><p>Contributors: People who have contributed anything to a project</p></li><li><p>Users: Almost every phone, tv, has at least some Apache software in it</p></li></ul></div></aside></div></section>
<section id="lifecycle-of-a-project"><h2>Lifecycle of a project</h2><div class="slide-content"><div class="imageblock"><img src="images/project-lifecycle.png" alt="project lifecycle" /></div>
<aside class="notes"><div class="ulist"><ul><li><p>Projects don&#8217;t start at Apache</p></li><li><p>Projects can also leave any time</p><div class="ulist"><ul><li><p>Might need to re-brand</p></li></ul></div></li></ul></div></aside></div></section>
<section id="how-is-the-asf-structured"><h2>How is the ASF structured?</h2><div class="slide-content"><div class="ulist"><ul><li><p><strong>Member</strong> based - only individuals can join (no companies)</p></li><li><p>Members nominate and elect new members</p></li><li><p>Members elect <strong>board</strong> (9 <strong>directors</strong>)</p></li><li><p>Annual members meeting via IRC</p></li><li><p>Monthly board meeting</p></li><li><p>Every project elects a <strong>Chair</strong> as interface to the board</p></li></ul></div>
<aside class="notes"><div class="ulist"><ul><li><p>Projects don&#8217;t start at Apache</p></li><li><p>Projects can also leave any time</p><div class="ulist"><ul><li><p>Might need to re-brand</p></li></ul></div></li></ul></div></aside></div></section>
<section id="structure-of-the-asf"><h2>Structure of the ASF</h2><div class="slide-content"><div class="imageblock"><img src="images/asf-structure.png" alt="asf structure" /></div></div></section>
<section id="how-does-this-all-work"><h2>How does this all work?</h2><div class="slide-content"><div class="ulist"><ul><li><p>The Apache Way</p><div class="ulist"><ul><li><p>A method to develop software</p></li><li><p>A method to run communities</p></li><li><p>A method to run an organisation</p></li></ul></div></li></ul></div></div></section>
<section id="on-which-principles-is-it-based"><h2>On which principles is it based?</h2><div class="slide-content"><div class="ulist"><ul><li><p>Meritocracy: Advancement through action &amp; commitment</p></li><li><p>Transparency: Nothing happens in secret</p></li><li><p>Community: Together we are strong</p></li></ul></div></div></section>
<section id="ways-to-be-committed"><h2>Ways to be committed</h2><div class="slide-content"><div class="ulist"><ul><li><p>Documentation, Tutorials, Examples</p></li><li><p>Talks (at conferences &amp; meetups)</p></li><li><p>User groups</p></li><li><p>Helping others (On mailing lists)</p></li><li><p>Filing bug reports</p></li><li><p>Testing and helping fix bugs &amp; issues</p></li><li><p>Bugfixes</p></li><li><p>New features</p></li><li><p>Mentoring, involvement in the foundation itself</p></li></ul></div></div></section>
<section id="path-of-merit"><h2>Path of merit</h2><div class="slide-content"><div class="imageblock"><img src="images/merit-path.png" alt="merit path" /></div></div></section>
<section id="if-it-didnt-happen-on-the-list-it-didnt-happen"><h2>If it didn&#8217;t happen on the list, it didn&#8217;t happen</h2><div class="slide-content"><div class="ulist"><ul><li><p>If something isn&#8217;t documented on any of the mailing lists, it didn&#8217;t happen</p><div class="ulist"><ul><li><p>Every discussion and decision needs to be documented</p></li></ul></div></li><li><p>All discussions should happen in the public</p></li><li><p>Off-list discussions can happen, but important information needs to be forwarded to the mailing list</p></li><li><p>Others are need to be able to participate</p></li></ul></div>
<aside class="notes"><div class="ulist"><ul><li><p>Discussions on meetups or at conferences</p></li><li><p>Many things (like votes) require 72 hour periods</p></li><li><p>Private lists: Discussing security issues, voting on new committers and PMC members</p></li></ul></div></aside></div></section>
<section id="community-over-code"><h2>Community over Code</h2><div class="slide-content"><div class="ulist"><ul><li><p>We&#8217;re (all) volunteers, life happens and our availability and our interests change</p></li><li><p>A vital community encourages new community members</p></li><li><p>It&#8217;s normal, that members (temporarily) leave the community</p></li><li><p><strong>Poisonous people</strong> scare others and must be fought</p></li><li><p>Result of a healthy community &#8594; better code, long-lasting projects</p></li></ul></div></div></section>
<section id="consensus-based-decisions"><h2>Consensus-based decisions</h2><div class="slide-content"><div class="ulist"><ul><li><p>PMC members have <strong>binding votes</strong></p></li><li><p>Non-PMC members have <strong>non-binding votes</strong></p></li><li><p>Formally only binding votes count</p></li><li><p><strong>But</strong> non-binding votes usually are still respected</p></li><li><p>Something is considered decided if:</p><div class="ulist"><ul><li><p>At least 3 binding votes</p></li><li><p>More <code>+1</code> as <code>-1</code> votes</p></li></ul></div></li></ul></div>
<aside class="notes"><div class="ulist"><ul><li><p>Valid votes are <code>+1</code> (pro), <code>0</code>, <code>-1</code> (contra)</p></li><li><p><code>-1</code> votes should be constructive</p></li></ul></div></aside></div></section>
<section id="collaborative-development"><h2>Collaborative development</h2><div class="slide-content"><div class="ulist"><ul><li><p>Code should be developed in community with others</p><div class="ulist"><ul><li><p>Large code-drops are bad</p></li></ul></div></li><li><p>Development should happen on-line (Git/SVN, Email, &#8230;&#8203;)</p></li><li><p>Votes ensure that at least 3 developers are still active</p></li><li><p>In order to allow anyone to participate, votes usually last at least 72 hours</p></li><li><p>Discussions and votes happen only on the mailing-list</p></li></ul></div>
<aside class="notes"><div class="ulist"><ul><li><p>72h = at least one working day, no matter where on earth you live</p></li></ul></div></aside></div></section>
<section id="the-result"><h2>The result</h2><div class="slide-content"><div class="ulist"><ul><li><p>Vendor neutrality</p></li><li><p>Diversity</p></li><li><p>Trust</p></li><li><p>Safety</p></li><li><p>Security</p></li></ul></div></div></section>
<section id="how-can-companies-help"><h2>How can companies help?</h2><div class="slide-content"><div class="ulist"><ul><li><p>Companies can allow their employees to contribute during working hours</p></li><li><p>Companies can directly support the ASF financially (Sponsoring)</p></li><li><p>Companies can donate code, so everyone can profit from it</p></li><li><p>Companies can&#8217;t directly fund development in projects</p></li><li><p>Companies can donate funds towards projects (Targeted donations)</p></li></ul></div>
<aside class="notes"><div class="ulist"><ul><li><p>Targeted donations: Licenses, Hardware costs, Membership fees, &#8230;&#8203;</p></li></ul></div></aside></div></section></div></div><div class="footer"><div class="left"></div><div class="right"></div></div><script src="reveal.js-3.9.2/js/reveal.js"></script><script>Array.prototype.slice.call(document.querySelectorAll('.slides section')).forEach(function(slide) {
if (slide.getAttribute('data-background-color')) return;
// user needs to explicitly say he wants CSS color to override otherwise we might break custom css or theme (#226)
if (!(slide.classList.contains('canvas') || slide.classList.contains('background'))) return;
var bgColor = getComputedStyle(slide).backgroundColor;
if (bgColor !== 'rgba(0, 0, 0, 0)' && bgColor !== 'transparent') {
slide.setAttribute('data-background-color', bgColor);
slide.style.backgroundColor = 'transparent';
}
});
// More info about config & dependencies:
// - https://github.com/hakimel/reveal.js#configuration
// - https://github.com/hakimel/reveal.js#dependencies
Reveal.initialize({
// Display presentation control arrows
controls: true,
// Help the user learn the controls by providing hints, for example by
// bouncing the down arrow when they first encounter a vertical slide
controlsTutorial: true,
// Determines where controls appear, "edges" or "bottom-right"
controlsLayout: 'bottom-right',
// Visibility rule for backwards navigation arrows; "faded", "hidden"
// or "visible"
controlsBackArrows: 'faded',
// Display a presentation progress bar
progress: true,
// Display the page number of the current slide
slideNumber: 'true',
// Control which views the slide number displays on
showSlideNumber: 'all',
// Add the current slide number to the URL hash so that reloading the
// page/copying the URL will return you to the same slide
hash: false,
// Push each slide change to the browser history. Implies `hash: true`
history: true,
// Enable keyboard shortcuts for navigation
keyboard: true,
// Enable the slide overview mode
overview: true,
// Disables the default reveal.js slide layout so that you can use custom CSS layout
disableLayout: false,
// Vertical centering of slides
center: false,
// Enables touch navigation on devices with touch input
touch: true,
// Loop the presentation
loop: false,
// Change the presentation direction to be RTL
rtl: false,
// See https://github.com/hakimel/reveal.js/#navigation-mode
navigationMode: 'default',
// Randomizes the order of slides each time the presentation loads
shuffle: false,
// Turns fragments on and off globally
fragments: true,
// Flags whether to include the current fragment in the URL,
// so that reloading brings you to the same fragment position
fragmentInURL: false,
// Flags if the presentation is running in an embedded mode,
// i.e. contained within a limited portion of the screen
embedded: false,
// Flags if we should show a help overlay when the questionmark
// key is pressed
help: true,
// Flags if speaker notes should be visible to all viewers
showNotes: false,
// Global override for autolaying embedded media (video/audio/iframe)
// - null: Media will only autoplay if data-autoplay is present
// - true: All media will autoplay, regardless of individual setting
// - false: No media will autoplay, regardless of individual setting
autoPlayMedia: null,
// Global override for preloading lazy-loaded iframes
// - null: Iframes with data-src AND data-preload will be loaded when within
// the viewDistance, iframes with only data-src will be loaded when visible
// - true: All iframes with data-src will be loaded when within the viewDistance
// - false: All iframes with data-src will be loaded only when visible
preloadIframes: null,
// Number of milliseconds between automatically proceeding to the
// next slide, disabled when set to 0, this value can be overwritten
// by using a data-autoslide attribute on your slides
autoSlide: 0,
// Stop auto-sliding after user input
autoSlideStoppable: true,
// Use this method for navigation when auto-sliding
autoSlideMethod: Reveal.navigateNext,
// Specify the average time in seconds that you think you will spend
// presenting each slide. This is used to show a pacing timer in the
// speaker view
defaultTiming: 120,
// Specify the total time in seconds that is available to
// present. If this is set to a nonzero value, the pacing
// timer will work out the time available for each slide,
// instead of using the defaultTiming value
totalTime: 0,
// Specify the minimum amount of time you want to allot to
// each slide, if using the totalTime calculation method. If
// the automated time allocation causes slide pacing to fall
// below this threshold, then you will see an alert in the
// speaker notes window
minimumTimePerSlide: 0,
// Enable slide navigation via mouse wheel
mouseWheel: false,
// Hide cursor if inactive
hideInactiveCursor: true,
// Time before the cursor is hidden (in ms)
hideCursorTime: 5000,
// Hides the address bar on mobile devices
hideAddressBar: true,
// Opens links in an iframe preview overlay
// Add `data-preview-link` and `data-preview-link="false"` to customise each link
// individually
previewLinks: false,
// Transition style (e.g., none, fade, slide, convex, concave, zoom)
transition: 'linear',
// Transition speed (e.g., default, fast, slow)
transitionSpeed: 'default',
// Transition style for full page slide backgrounds (e.g., none, fade, slide, convex, concave, zoom)
backgroundTransition: 'fade',
// Number of slides away from the current that are visible
viewDistance: 3,
// Number of slides away from the current that are visible on mobile
// devices. It is advisable to set this to a lower number than
// viewDistance in order to save resources.
mobileViewDistance: 3,
// Parallax background image (e.g., "'https://s3.amazonaws.com/hakim-static/reveal-js/reveal-parallax-1.jpg'")
parallaxBackgroundImage: '',
// Parallax background size in CSS syntax (e.g., "2100px 900px")
parallaxBackgroundSize: '',
// Number of pixels to move the parallax background per slide
// - Calculated automatically unless specified
// - Set to 0 to disable movement along an axis
parallaxBackgroundHorizontal: null,
parallaxBackgroundVertical: null,
// The display mode that will be used to show slides
display: 'block',
// The "normal" size of the presentation, aspect ratio will be preserved
// when the presentation is scaled to fit different resolutions. Can be
// specified using percentage units.
width: 960,
height: 700,
// Factor of the display size that should remain empty around the content
margin: 0.1,
// Bounds for smallest/largest possible scale to apply to content
minScale: 0.2,
maxScale: 1.5,
// PDF Export Options
// Put each fragment on a separate page
pdfSeparateFragments: true,
// For slides that do not fit on a page, max number of pages
pdfMaxPagesPerSlide: 1,
// Optional libraries used to extend on reveal.js
dependencies: [
{ src: 'reveal.js-3.9.2/plugin/zoom/zoom.js', async: true, callback: function () { Reveal.registerPlugin(RevealZoom) } },
{ src: 'reveal.js-3.9.2/plugin/notes/notes.js', async: true, callback: function () { Reveal.registerPlugin(RevealNotes) } }
],
});</script><script>var dom = {};
dom.slides = document.querySelector('.reveal .slides');
function getRemainingHeight(element, slideElement, height) {
height = height || 0;
if (element) {
var newHeight, oldHeight = element.style.height;
// Change the .stretch element height to 0 in order find the height of all
// the other elements
element.style.height = '0px';
// In Overview mode, the parent (.slide) height is set of 700px.
// Restore it temporarily to its natural height.
slideElement.style.height = 'auto';
newHeight = height - slideElement.offsetHeight;
// Restore the old height, just in case
element.style.height = oldHeight + 'px';
// Clear the parent (.slide) height. .removeProperty works in IE9+
slideElement.style.removeProperty('height');
return newHeight;
}
return height;
}
function layoutSlideContents(width, height) {
// Handle sizing of elements with the 'stretch' class
toArray(dom.slides.querySelectorAll('section .stretch')).forEach(function (element) {
// Determine how much vertical space we can use
var limit = 5; // hard limit
var parent = element.parentNode;
while (parent.nodeName !== 'SECTION' && limit > 0) {
parent = parent.parentNode;
limit--;
}
if (limit === 0) {
// unable to find parent, aborting!
return;
}
var remainingHeight = getRemainingHeight(element, parent, height);
// Consider the aspect ratio of media elements
if (/(img|video)/gi.test(element.nodeName)) {
var nw = element.naturalWidth || element.videoWidth, nh = element.naturalHeight || element.videoHeight;
var es = Math.min(width / nw, remainingHeight / nh);
element.style.width = (nw * es) + 'px';
element.style.height = (nh * es) + 'px';
} else {
element.style.width = width + 'px';
element.style.height = remainingHeight + 'px';
}
});
}
function toArray(o) {
return Array.prototype.slice.call(o);
}
Reveal.addEventListener('slidechanged', function () {
layoutSlideContents(960, 700)
});
Reveal.addEventListener('ready', function () {
layoutSlideContents(960, 700)
});
Reveal.addEventListener('resize', function () {
layoutSlideContents(960, 700)
});</script><link rel="stylesheet" href="reveal.js-3.9.2/plugin/highlight/monokai.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.3/highlight.min.js"></script>
<script>
/* highlightjs-line-numbers.js 2.6.0 | (C) 2018 Yauheni Pakala | MIT License | github.com/wcoder/highlightjs-line-numbers.js */
/* Edited by Hakim for reveal.js; removed async timeout */
!function(n,e){"use strict";function t(){var n=e.createElement("style");n.type="text/css",n.innerHTML=g(".{0}{border-collapse:collapse}.{0} td{padding:0}.{1}:before{content:attr({2})}",[v,L,b]),e.getElementsByTagName("head")[0].appendChild(n)}function r(t){"interactive"===e.readyState||"complete"===e.readyState?i(t):n.addEventListener("DOMContentLoaded",function(){i(t)})}function i(t){try{var r=e.querySelectorAll("code.hljs,code.nohighlight");for(var i in r)r.hasOwnProperty(i)&&l(r[i],t)}catch(o){n.console.error("LineNumbers error: ",o)}}function l(n,e){"object"==typeof n&&f(function(){n.innerHTML=s(n,e)})}function o(n,e){if("string"==typeof n){var t=document.createElement("code");return t.innerHTML=n,s(t,e)}}function s(n,e){e=e||{singleLine:!1};var t=e.singleLine?0:1;return c(n),a(n.innerHTML,t)}function a(n,e){var t=u(n);if(""===t[t.length-1].trim()&&t.pop(),t.length>e){for(var r="",i=0,l=t.length;i<l;i++)r+=g('<tr><td class="{0}"><div class="{1} {2}" {3}="{5}"></div></td><td class="{4}"><div class="{1}">{6}</div></td></tr>',[j,m,L,b,p,i+1,t[i].length>0?t[i]:" "]);return g('<table class="{0}">{1}</table>',[v,r])}return n}function c(n){var e=n.childNodes;for(var t in e)if(e.hasOwnProperty(t)){var r=e[t];h(r.textContent)>0&&(r.childNodes.length>0?c(r):d(r.parentNode))}}function d(n){var e=n.className;if(/hljs-/.test(e)){for(var t=u(n.innerHTML),r=0,i="";r<t.length;r++){var l=t[r].length>0?t[r]:" ";i+=g('<span class="{0}">{1}</span>\n',[e,l])}n.innerHTML=i.trim()}}function u(n){return 0===n.length?[]:n.split(y)}function h(n){return(n.trim().match(y)||[]).length}function f(e){e()}function g(n,e){return n.replace(/{(\d+)}/g,function(n,t){return e[t]?e[t]:n})}var v="hljs-ln",m="hljs-ln-line",p="hljs-ln-code",j="hljs-ln-numbers",L="hljs-ln-n",b="data-line-number",y=/\r\n|\r|\n/g;n.hljs?(n.hljs.initLineNumbersOnLoad=r,n.hljs.lineNumbersBlock=l,n.hljs.lineNumbersValue=o,t()):n.console.error("highlight.js not detected!")}(window,document);
/**
* This reveal.js plugin is wrapper around the highlight.js
* syntax highlighting library.
*/
(function( root, factory ) {
if (typeof define === 'function' && define.amd) {
root.RevealHighlight = factory();
} else if( typeof exports === 'object' ) {
module.exports = factory();
} else {
// Browser globals (root is window)
root.RevealHighlight = factory();
}
}( this, function() {
// Function to perform a better "data-trim" on code snippets
// Will slice an indentation amount on each line of the snippet (amount based on the line having the lowest indentation length)
function betterTrim(snippetEl) {
// Helper functions
function trimLeft(val) {
// Adapted from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim#Polyfill
return val.replace(/^[\s\uFEFF\xA0]+/g, '');
}
function trimLineBreaks(input) {
var lines = input.split('\n');
// Trim line-breaks from the beginning
for (var i = 0; i < lines.length; i++) {
if (lines[i].trim() === '') {
lines.splice(i--, 1);
} else break;
}
// Trim line-breaks from the end
for (var i = lines.length-1; i >= 0; i--) {
if (lines[i].trim() === '') {
lines.splice(i, 1);
} else break;
}
return lines.join('\n');
}
// Main function for betterTrim()
return (function(snippetEl) {
var content = trimLineBreaks(snippetEl.innerHTML);
var lines = content.split('\n');
// Calculate the minimum amount to remove on each line start of the snippet (can be 0)
var pad = lines.reduce(function(acc, line) {
if (line.length > 0 && trimLeft(line).length > 0 && acc > line.length - trimLeft(line).length) {
return line.length - trimLeft(line).length;
}
return acc;
}, Number.POSITIVE_INFINITY);
// Slice each line with this amount
return lines.map(function(line, index) {
return line.slice(pad);
})
.join('\n');
})(snippetEl);
}
var RevealHighlight = {
HIGHLIGHT_STEP_DELIMITER: '|',
HIGHLIGHT_LINE_DELIMITER: ',',
HIGHLIGHT_LINE_RANGE_DELIMITER: '-',
init: function( reveal ) {
// Read the plugin config options and provide fallbacks
var config = Reveal.getConfig().highlight || {};
config.highlightOnLoad = typeof config.highlightOnLoad === 'boolean' ? config.highlightOnLoad : true;
config.escapeHTML = typeof config.escapeHTML === 'boolean' ? config.escapeHTML : true;
[].slice.call( reveal.getRevealElement().querySelectorAll( 'pre code' ) ).forEach( function( block ) {
block.parentNode.className = 'code-wrapper';
// Code can optionally be wrapped in script template to avoid
// HTML being parsed by the browser (i.e. when you need to
// include <, > or & in your code).
let substitute = block.querySelector( 'script[type="text/template"]' );
if( substitute ) {
// textContent handles the HTML entity escapes for us
block.textContent = substitute.innerHTML;
}
// Trim whitespace if the "data-trim" attribute is present
if( block.hasAttribute( 'data-trim' ) && typeof block.innerHTML.trim === 'function' ) {
block.innerHTML = betterTrim( block );
}
// Escape HTML tags unless the "data-noescape" attrbute is present
if( config.escapeHTML && !block.hasAttribute( 'data-noescape' )) {
block.innerHTML = block.innerHTML.replace( /</g,"&lt;").replace(/>/g, '&gt;' );
}
// Re-highlight when focus is lost (for contenteditable code)
block.addEventListener( 'focusout', function( event ) {
hljs.highlightElement( event.currentTarget );
}, false );
if( config.highlightOnLoad ) {
RevealHighlight.highlightBlock( block );
}
} );
// If we're printing to PDF, scroll the code highlights of
// all blocks in the deck into view at once
reveal.on( 'pdf-ready', function() {
[].slice.call( reveal.getRevealElement().querySelectorAll( 'pre code[data-line-numbers].current-fragment' ) ).forEach( function( block ) {
RevealHighlight.scrollHighlightedLineIntoView( block, {}, true );
} );
} );
},
/**
* Highlights a code block. If the <code> node has the
* 'data-line-numbers' attribute we also generate slide
* numbers.
*
* If the block contains multiple line highlight steps,
* we clone the block and create a fragment for each step.
*/
highlightBlock: function( block ) {
hljs.highlightElement( block );
// Don't generate line numbers for empty code blocks
if( block.innerHTML.trim().length === 0 ) return;
if( block.hasAttribute( 'data-line-numbers' ) ) {
hljs.lineNumbersBlock( block, { singleLine: true } );
var scrollState = { currentBlock: block };
// If there is at least one highlight step, generate
// fragments
var highlightSteps = RevealHighlight.deserializeHighlightSteps( block.getAttribute( 'data-line-numbers' ) );
if( highlightSteps.length > 1 ) {
// If the original code block has a fragment-index,
// each clone should follow in an incremental sequence
var fragmentIndex = parseInt( block.getAttribute( 'data-fragment-index' ), 10 );
if( typeof fragmentIndex !== 'number' || isNaN( fragmentIndex ) ) {
fragmentIndex = null;
}
// Generate fragments for all steps except the original block
highlightSteps.slice(1).forEach( function( highlight ) {
var fragmentBlock = block.cloneNode( true );
fragmentBlock.setAttribute( 'data-line-numbers', RevealHighlight.serializeHighlightSteps( [ highlight ] ) );
fragmentBlock.classList.add( 'fragment' );
block.parentNode.appendChild( fragmentBlock );
RevealHighlight.highlightLines( fragmentBlock );
if( typeof fragmentIndex === 'number' ) {
fragmentBlock.setAttribute( 'data-fragment-index', fragmentIndex );
fragmentIndex += 1;
}
else {
fragmentBlock.removeAttribute( 'data-fragment-index' );
}
// Scroll highlights into view as we step through them
fragmentBlock.addEventListener( 'visible', RevealHighlight.scrollHighlightedLineIntoView.bind( Plugin, fragmentBlock, scrollState ) );
fragmentBlock.addEventListener( 'hidden', RevealHighlight.scrollHighlightedLineIntoView.bind( Plugin, fragmentBlock.previousSibling, scrollState ) );
} );
block.removeAttribute( 'data-fragment-index' )
block.setAttribute( 'data-line-numbers', RevealHighlight.serializeHighlightSteps( [ highlightSteps[0] ] ) );
}
// Scroll the first highlight into view when the slide
// becomes visible. Note supported in IE11 since it lacks
// support for Element.closest.
var slide = typeof block.closest === 'function' ? block.closest( 'section:not(.stack)' ) : null;
if( slide ) {
var scrollFirstHighlightIntoView = function() {
RevealHighlight.scrollHighlightedLineIntoView( block, scrollState, true );
slide.removeEventListener( 'visible', scrollFirstHighlightIntoView );
}
slide.addEventListener( 'visible', scrollFirstHighlightIntoView );
}
RevealHighlight.highlightLines( block );
}
},
/**
* Animates scrolling to the first highlighted line
* in the given code block.
*/
scrollHighlightedLineIntoView: function( block, scrollState, skipAnimation ) {
cancelAnimationFrame( scrollState.animationFrameID );
// Match the scroll position of the currently visible
// code block
if( scrollState.currentBlock ) {
block.scrollTop = scrollState.currentBlock.scrollTop;
}
// Remember the current code block so that we can match
// its scroll position when showing/hiding fragments
scrollState.currentBlock = block;
var highlightBounds = RevealHighlight.getHighlightedLineBounds( block )
var viewportHeight = block.offsetHeight;
// Subtract padding from the viewport height
var blockStyles = getComputedStyle( block );
viewportHeight -= parseInt( blockStyles.paddingTop ) + parseInt( blockStyles.paddingBottom );
// Scroll position which centers all highlights
var startTop = block.scrollTop;
var targetTop = highlightBounds.top + ( Math.min( highlightBounds.bottom - highlightBounds.top, viewportHeight ) - viewportHeight ) / 2;
// Account for offsets in position applied to the
// <table> that holds our lines of code
var lineTable = block.querySelector( '.hljs-ln' );
if( lineTable ) targetTop += lineTable.offsetTop - parseInt( blockStyles.paddingTop );
// Make sure the scroll target is within bounds
targetTop = Math.max( Math.min( targetTop, block.scrollHeight - viewportHeight ), 0 );
if( skipAnimation === true || startTop === targetTop ) {
block.scrollTop = targetTop;
}
else {
// Don't attempt to scroll if there is no overflow
if( block.scrollHeight <= viewportHeight ) return;
var time = 0;
var animate = function() {
time = Math.min( time + 0.02, 1 );
// Update our eased scroll position
block.scrollTop = startTop + ( targetTop - startTop ) * RevealHighlight.easeInOutQuart( time );
// Keep animating unless we've reached the end
if( time < 1 ) {
scrollState.animationFrameID = requestAnimationFrame( animate );
}
};
animate();
}
},
/**
* The easing function used when scrolling.
*/
easeInOutQuart: function( t ) {
// easeInOutQuart
return t<.5 ? 8*t*t*t*t : 1-8*(--t)*t*t*t;
},
getHighlightedLineBounds: function( block ) {
var highlightedLines = block.querySelectorAll( '.highlight-line' );
if( highlightedLines.length === 0 ) {
return { top: 0, bottom: 0 };
}
else {
var firstHighlight = highlightedLines[0];
var lastHighlight = highlightedLines[ highlightedLines.length -1 ];
return {
top: firstHighlight.offsetTop,
bottom: lastHighlight.offsetTop + lastHighlight.offsetHeight
}
}
},
/**
* Visually emphasize specific lines within a code block.
* This only works on blocks with line numbering turned on.
*
* @param {HTMLElement} block a <code> block
* @param {String} [linesToHighlight] The lines that should be
* highlighted in this format:
* "1" = highlights line 1
* "2,5" = highlights lines 2 & 5
* "2,5-7" = highlights lines 2, 5, 6 & 7
*/
highlightLines: function( block, linesToHighlight ) {
var highlightSteps = RevealHighlight.deserializeHighlightSteps( linesToHighlight || block.getAttribute( 'data-line-numbers' ) );
if( highlightSteps.length ) {
highlightSteps[0].forEach( function( highlight ) {
var elementsToHighlight = [];
// Highlight a range
if( typeof highlight.end === 'number' ) {
elementsToHighlight = [].slice.call( block.querySelectorAll( 'table tr:nth-child(n+'+highlight.start+'):nth-child(-n+'+highlight.end+')' ) );
}
// Highlight a single line
else if( typeof highlight.start === 'number' ) {
elementsToHighlight = [].slice.call( block.querySelectorAll( 'table tr:nth-child('+highlight.start+')' ) );
}
if( elementsToHighlight.length ) {
elementsToHighlight.forEach( function( lineElement ) {
lineElement.classList.add( 'highlight-line' );
} );
block.classList.add( 'has-highlights' );
}
} );
}
},
/**
* Parses and formats a user-defined string of line
* numbers to highlight.
*
* @example
* RevealHighlight.deserializeHighlightSteps( '1,2|3,5-10' )
* // [
* // [ { start: 1 }, { start: 2 } ],
* // [ { start: 3 }, { start: 5, end: 10 } ]
* // ]
*/
deserializeHighlightSteps: function( highlightSteps ) {
// Remove whitespace
highlightSteps = highlightSteps.replace( /\s/g, '' );
// Divide up our line number groups
highlightSteps = highlightSteps.split( RevealHighlight.HIGHLIGHT_STEP_DELIMITER );
return highlightSteps.map( function( highlights ) {
return highlights.split( RevealHighlight.HIGHLIGHT_LINE_DELIMITER ).map( function( highlight ) {
// Parse valid line numbers
if( /^[\d-]+$/.test( highlight ) ) {
highlight = highlight.split( RevealHighlight.HIGHLIGHT_LINE_RANGE_DELIMITER );
var lineStart = parseInt( highlight[0], 10 ),
lineEnd = parseInt( highlight[1], 10 );
if( isNaN( lineEnd ) ) {
return {
start: lineStart
};
}
else {
return {
start: lineStart,
end: lineEnd
};
}
}
// If no line numbers are provided, no code will be highlighted
else {
return {};
}
} );
} );
},
/**
* Serializes parsed line number data into a string so
* that we can store it in the DOM.
*/
serializeHighlightSteps: function( highlightSteps ) {
return highlightSteps.map( function( highlights ) {
return highlights.map( function( highlight ) {
// Line range
if( typeof highlight.end === 'number' ) {
return highlight.start + RevealHighlight.HIGHLIGHT_LINE_RANGE_DELIMITER + highlight.end;
}
// Single line
else if( typeof highlight.start === 'number' ) {
return highlight.start;
}
// All lines
else {
return '';
}
} ).join( RevealHighlight.HIGHLIGHT_LINE_DELIMITER );
} ).join( RevealHighlight.HIGHLIGHT_STEP_DELIMITER );
}
}
Reveal.registerPlugin( 'highlight', RevealHighlight );
return RevealHighlight;
}));
hljs.configure({
ignoreUnescapedHTML: true,
});
hljs.highlightAll();
</script></body></html>