| <!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, …​</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, …​)</p></li><li><p>Bug & Issue trackers (Jira, …​), Wiki (Confluence, …​)</p></li><li><p>CI Server (Jenkins, …​), Webservers for project websites</p></li><li><p>…​</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’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’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 & 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 & 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 & 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’t happen on the list, it didn’t happen</h2><div class="slide-content"><div class="ulist"><ul><li><p>If something isn’t documented on any of the mailing lists, it didn’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’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’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 → 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, …​)</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’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, …​</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,"<").replace(/>/g, '>' ); |
| } |
| |
| // 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> |