This commit is contained in:
Laurent Peuch 2017-01-30 04:56:50 +01:00
commit 4ddc2d735f
33 changed files with 1648 additions and 0 deletions

BIN
img/actionmap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
img/admin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
img/app_install.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
img/app_install_zerobin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
img/app_root.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

BIN
img/app_scripts.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
img/apps.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

BIN
img/architecture.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
img/brique.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

BIN
img/briquecamp.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

BIN
img/cli.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
img/domain_list.py.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
img/domains.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
img/files.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
img/help.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
img/hotspot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
img/image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
img/ldn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
img/manifest.json.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
img/manifest_zerobin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
img/ssoportal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

BIN
img/tools.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
img/tout_internet.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

BIN
img/vpn_client.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
img/yunohost-admin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
img/yunohost.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

1
index.html Symbolic link
View file

@ -0,0 +1 @@
template.html

82
readme.md Normal file
View file

@ -0,0 +1,82 @@
## Basic usage
**DZSlides** is a **one-file** HTML template to build slides in HTML5 and CSS3.
`template.html` is the only file you need. Edit the file, add your content, change the style, and you're done. To see the slides in action, just load
the file in your browser.
## Features
* Slides can include any HTML5 content (text, image, video, iframes, …);
* Slides transitions are animated with CSS3 (sliding by default);
* Resolution independent (slides are scaled according to the size of the browser. The virtual dimension is 800x600);
* Fullscreen presentation (HTML5 FullScreen API supported) - press `f` to go fullscreen;
* Incremental content;
* Mobile Friendly (supports touch events).
## Shells
The features of DZSlides are intentionally limited to keep the template light
and simple to understand. *Shells* are extensions that bring new features
to your slides. Here, you'll find 2 shells:
* `shells/embedder.html` to embed a presentation in a web page
* `shells/onstage.html` to show your slides with a control panel
To use them, just load the file in your browser, and follow the instructions.
## Specifications
When you press the `left` and `right` keys, you go forward and go back in your slides.
But the slides can also respond to external messages. Messages can be sent through [postMessage](https://developer.mozilla.org/en/DOM/window.postMessage).
So another web page can control the slides.
### Protocol
A `cursor` is a string of this form: `3.5`. The first number represent the current slide index. The second number represent the current sub-item index.
Parameters must be escaped.
***
Messages a DZSlides page can receive:
* `REGISTER` register the source of the message as a target to notify for any events;
* `FORWARD` move forward in the slides;
* `BACK` move back in the slides;
* `START` move to the first slide;
* `END` move to the last slide;
* `SET_CURSOR cursor` jump to the cursor;
* `GET_CURSOR` notify the source of the message of the current cursor;
* `TOGGLE_CONTENT` toggle the current slide content;
* `GET_NOTES cursor` notify the source of the message of the current notes content.
Messages a DZSlides page can send:
* `CURSOR cursor` sent to one target as a response to `GET_CURSOR`, and sent to all the registered target when updated;
* `REGISTERED slides_title slides_count` sent to one target as a response to `REGISTER`;
* `NOTES html_content` sent to one target as a response to `GET_NOTES`.
***
### Hash parameters
* `url&para1=va1`
Parameters a DZSlides page can have:
* `autoplay` (integer, values : `0`/`1`, default : `1`) sets whether multimedia contents (audio, video) should be played automatically.
## License
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

277
shells/embedder.html Normal file
View file

@ -0,0 +1,277 @@
<!DOCTYPE html>
<meta charset="utf8">
<title>...</title>
<div id="slides">
<iframe allowfullscreen mozallowfullscreen webkitallowfullscreen></iframe>
</div>
<div id="controls">
<button title="prev" id="back" onclick="Dz.back()">&#9664;</button>
<button title="next" id="forward" onclick="Dz.forward()">&#9654;</button>
<div id="rightcontrols">
<input onchange="Dz.setCursor(this.value)" size="2" id="slideidx" value="0" />/<span id="slidecount">...</span>
<button title="Go fullscreen or open in a new window" id="fullscreen" onclick="Dz.goFullscreen()">&#8689;</button>
</div>
</div>
<style>
html { height: 100%;}
body {
margin: 0;
background-color: black;
height: 100%;
width: 100%;
}
#slides, #controls {
left: 0;
position: absolute;
right: 0;
}
#controls {
color: white;
font-family: monospace;
height: 30px;
line-height: 30px;
padding: 5px;
}
#slides {
bottom: 40px;
top: 0;
}
iframe {
border: none;
background-color: white;
height: 100%;
width: 100%;
}
#controls {
bottom: 0;
float: right;
font-size: 13px;
text-align: center;
}
#controls button[disabled] {color: #333;}
button {
background-color: transparent;
border: none;
cursor: pointer;
color: #bbb;
padding: 0;
font-size: 20px;
line-height: 100%;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-o-user-select: none;
user-select: none;
position: relative;
}
button:hover {
color: white;
}
button:active {
top: 1px;
left: 1px;
}
#slideidx {
border: none;
background-color: rgba(255, 255, 255, 0.2);
color: white;
text-align: center;
}
#rightcontrols * { vertical-align: middle; }
#rightcontrols {
bottom: 4px;
position: absolute;
top: 4px;
right: 10px;
}
#fullscreen {-moz-transform: scaleX(-1);-webkit-transform: scaleX(-1);-o-transform: scaleX(-1);-ms-transform: scaleX(-1);transform: scaleX(-1);}
</style>
<script>
var Dz = {
view: null,
url: null,
idx: 1,
count: null,
iframe: null
};
Dz.init = function() {
this.loadIframe();
}
Dz.onkeydown = function(aEvent) {
// Don't intercept keyboard shortcuts
if (aEvent.altKey
|| aEvent.ctrlKey
|| aEvent.metaKey
|| aEvent.shiftKey) {
return;
}
if ( aEvent.keyCode == 37 // left arrow
|| aEvent.keyCode == 38 // up arrow
|| aEvent.keyCode == 33 // page up
) {
aEvent.preventDefault();
this.back();
}
if ( aEvent.keyCode == 39 // right arrow
|| aEvent.keyCode == 40 // down arrow
|| aEvent.keyCode == 34 // page down
) {
aEvent.preventDefault();
this.forward();
}
if (aEvent.keyCode == 35) { // end
aEvent.preventDefault();
this.goEnd();
}
if (aEvent.keyCode == 36) { // home
aEvent.preventDefault();
this.goStart();
}
if (aEvent.keyCode == 32) { // space
aEvent.preventDefault();
this.toggleContent();
}
if (aEvent.keyCode == 70) { // f
aEvent.preventDefault();
this.goFullscreen();
}
}
Dz.onmessage = function(aEvent) {
if (aEvent.source === this.view) {
var argv = aEvent.data.split(" "), argc = argv.length;
argv.forEach(function(e, i, a) { a[i] = decodeURIComponent(e) });
if (argv[0] === "CURSOR" && argc === 2) {
var cursor = argv[1].split(".");
this.idx = ~~cursor[0];
this.step = ~~cursor[1];
$("#slideidx").value = this.idx;
$("#back").disabled = this.idx == 1;
$("#forward").disabled = this.idx == this.count;
}
if (argv[0] === "REGISTERED" && argc === 3) {
$("#slidecount").innerHTML = this.count = argv[2];
document.title = argv[1];
}
}
}
/* Get url from hash or prompt and store it */
Dz.getUrl = function() {
var u = window.location.hash.split("#")[1];
if (!u) {
u = window.prompt("What is the URL of the slides?");
if (u) {
window.location.hash = u.split("#")[0];
return u;
}
u = "<style>body{background-color:white;color:black}</style>";
u += "<strong>ERROR:</strong> No URL specified.<br>";
u += "Try<em>: " + document.location + "#yourslides.html</em>";
u = "data:text/html," + encodeURIComponent(u);
}
return u;
}
Dz.loadIframe = function() {
this.iframe = $("iframe");
this.iframe.src = this.url = this.getUrl();
this.iframe.onload = function() {
Dz.view = this.contentWindow;
Dz.postMsg(Dz.view, "REGISTER");
}
}
Dz.toggleContent = function() {
this.postMsg(this.view, "TOGGLE_CONTENT");
}
Dz.onhashchange = function() {
this.loadIframe();
}
Dz.back = function() {
this.postMsg(this.view, "BACK");
}
Dz.forward = function() {
this.postMsg(this.view, "FORWARD");
}
Dz.goStart = function() {
this.postMsg(this.view, "START");
}
Dz.goEnd = function() {
this.postMsg(this.view, "END");
}
Dz.setCursor = function(aCursor) {
this.postMsg(this.view, "SET_CURSOR", aCursor);
}
Dz.goFullscreen = function() {
var requestFullscreen = this.iframe.requestFullscreen || this.iframe.requestFullScreen || this.iframe.mozRequestFullScreen || this.iframe.webkitRequestFullScreen;
if (requestFullscreen) {
requestFullscreen.apply(this.iframe);
} else {
window.open(this.url + "#" + this.idx, '', 'width=800,height=600,personalbar=0,toolbar=0,scrollbars=1,resizable=1');
}
}
Dz.postMsg = function(aWin, aMsg) { // [arg0, [arg1...]]
aMsg = [aMsg];
for (var i = 2; i < arguments.length; i++)
aMsg.push(encodeURIComponent(arguments[i]));
aWin.postMessage(aMsg.join(" "), "*");
}
function init() {
Dz.init();
window.onkeydown = Dz.onkeydown.bind(Dz);
window.onhashchange = Dz.loadIframe.bind(Dz);
window.onmessage = Dz.onmessage.bind(Dz);
}
window.onload = init;
</script>
<script> // Helpers
if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
// closest thing possible to the ECMAScript 5 internal IsCallable
// function
if (typeof this !== "function")
throw new TypeError(
"Function.prototype.bind - what is trying to be fBound is not callable"
);
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply( this instanceof fNOP ? this : oThis || window,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
var $ = (HTMLElement.prototype.$ = function(aQuery) {
return this.querySelector(aQuery);
}).bind(document);
</script>

358
shells/onstage.html Normal file
View file

@ -0,0 +1,358 @@
<!DOCTYPE html>
<meta charset="utf8">
<title>DZSlides</title>
<div id="present">
<iframe></iframe>
</div>
<div id="future">
<iframe></iframe>
</div>
<div id="slideidx" onclick="Dz.setCursor(prompt('Go to slide...','1'));">?</div>
<div id="nextslideidx">?</div>
<div id="notes">
<p id="content"></p>
</div>
<div id="slidecount">?</div>
<button id="popup-button" onclick="Dz.popup()">Pop-up</button>
<div id="time">
<span id="hours">00</span>:<span id="minutes">00</span>:<span id="seconds">00</span>
</div>
<style>
html, body {
height: 100%;
color: white;
}
body {
font-family: sans-serif;
overflow: hidden;
}
#present, #future {
bottom: 234px;
position: absolute;
top: 0;
z-index: 5;
}
#present {
left: 0;
right: 50%;
border-right: 4px solid #555;
}
#future {
left: 50%;
right: 0;
border-left: 4px solid #555;
}
#notes {
background: #EEE;
border-top: 8px solid #555;
bottom: 0;
color: #444;
font-size: 30px;
height: 226px;
left: 0;
padding: 0 250px 0 20px;
position: absolute;
right: 0;
overflow: auto;
}
#time {
background: #888;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
bottom: 0;
font-size: 40px;
font-weight: bold;
height: 52px;
line-height: 52px;
right: 30px;
position: absolute;
text-align: center;
width: 200px;
}
iframe {
border: none;
height: 100%;
pointer-events: none;
width: 100%;
}
#slideidx,
#nextslideidx,
#slidecount {
background: #888;
font-size: 40px;
font-weight: bold;
height: 52px;
line-height: 52px;
margin: 0;
position: absolute;
text-align: center;
z-index: 10;
}
#slideidx,
#nextslideidx {
border-bottom: 4px solid #555;
bottom: 230px;
padding: 0 10px;
}
#slideidx {
border-right: 4px solid #555;
border-top-left-radius: 10px;
cursor: pointer;
right: 50%;
}
#nextslideidx {
border-left: 4px solid #555;
border-top-right-radius: 10px;
left: 50%;
}
#slidecount {
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
border-top: 4px solid #555;
bottom: 174px;
width: 200px;
right: 30px;
}
#popup-button {
bottom: 88px;
background: #888;
border: none;
border-radius: 10px;
color: #FFF;
cursor: pointer;
height: 52px;
font-size: 30px;
font-weight: bold;
position: absolute;
right: 30px;
width: 200px;
z-index: 10;
}
</style>
<script>
var Dz = {
views: {},
notes: null,
url: null,
idx: 1
};
Dz.init = function() {
this.startClock();
this.loadIframes();
}
Dz.onkeydown = function(aEvent) {
// Don't intercept keyboard shortcuts
if (aEvent.altKey
|| aEvent.ctrlKey
|| aEvent.metaKey
|| aEvent.shiftKey) {
return;
}
if ( aEvent.keyCode == 37 // left arrow
|| aEvent.keyCode == 38 // up arrow
|| aEvent.keyCode == 33 // page up
) {
aEvent.preventDefault();
this.back();
}
if ( aEvent.keyCode == 39 // right arrow
|| aEvent.keyCode == 40 // down arrow
|| aEvent.keyCode == 34 // page down
) {
aEvent.preventDefault();
this.forward();
}
if (aEvent.keyCode == 35) { // end
aEvent.preventDefault();
this.goEnd();
}
if (aEvent.keyCode == 36) { // home
aEvent.preventDefault();
this.goStart();
}
if (aEvent.keyCode == 32) { // space
aEvent.preventDefault();
this.toggleContent();
}
}
Dz.onmessage = function(aEvent) {
var argv = aEvent.data.split(" "), argc = argv.length;
argv.forEach(function(e, i, a) { a[i] = decodeURIComponent(e) });
if (argv[0] === "CURSOR" && argc === 2) {
if (aEvent.source === this.views.present) {
var cursor = argv[1].split(".");
this.postMsg(this.views.present, "GET_NOTES");
this.idx = ~~cursor[0];
this.step = ~~cursor[1];
$("#slideidx").innerHTML = argv[1];
this.postMsg(this.views.future, "SET_CURSOR", this.idx + "." + (this.step + 1));
if (this.views.remote)
this.postMsg(this.views.remote, "SET_CURSOR", argv[1]);
} else {
$("#nextslideidx").innerHTML = +argv[1] < 0 ? "END" : argv[1];
}
}
if (aEvent.source === this.views.present) {
if (argv[0] === "NOTES" && argc === 2)
$("#notes > #content").innerHTML = this.notes = argv[1];
if (argv[0] === "REGISTERED" && argc === 3)
$("#slidecount").innerHTML = argv[2];
}
}
/* Get url from hash or prompt and store it */
Dz.getUrl = function() {
var u = window.location.hash.split("#")[1];
if (!u) {
u = window.prompt("What is the URL of the slides?");
if (u) {
window.location.hash = u.split("#")[0];
return u;
}
u = "<style>body{background-color:white;color:black}</style>";
u += "<strong>ERROR:</strong> No URL specified.<br>";
u += "Try<em>: " + document.location + "#yourslides.html</em>";
u = "data:text/html," + encodeURIComponent(u);
}
return u;
}
Dz.loadIframes = function() {
var present = $("#present iframe");
var future = $("#future iframe");
this.url = this.getUrl();
present.src = future.src = this.url + '?autoplay=0';
present.onload = future.onload = function() {
var id = this.parentNode.id;
Dz.views[id] = this.contentWindow;
if (Dz.views.present && Dz.views.future) {
Dz.postMsg(Dz.views.present, "REGISTER");
Dz.postMsg(Dz.views.future, "REGISTER");
}
}
}
Dz.toggleContent = function() {
if (this.views.remote)
this.postMsg(this.views.remote, "TOGGLE_CONTENT");
}
Dz.onhashchange = function() {
this.loadIframe();
}
Dz.back = function() {
this.postMsg(this.views.present, "BACK");
}
Dz.forward = function() {
this.postMsg(this.views.present, "FORWARD");
}
Dz.goStart = function() {
this.postMsg(this.views.present, "START");
}
Dz.goEnd = function() {
this.postMsg(this.views.present, "END");
}
Dz.setCursor = function(aCursor) {
this.postMsg(this.views.present, "SET_CURSOR", aCursor);
}
Dz.popup = function() {
this.views.remote = window.open(this.url + "#" + this.idx, 'slides', 'width=800,height=600,personalbar=0,toolbar=0,scrollbars=1,resizable=1');
}
Dz.postMsg = function(aWin, aMsg) { // [arg0, [arg1...]]
aMsg = [aMsg];
for (var i = 2; i < arguments.length; i++)
aMsg.push(encodeURIComponent(arguments[i]));
aWin.postMessage(aMsg.join(" "), "*");
}
Dz.startClock = function() {
var addZero = function(num) {
return num < 10 ? '0' + num : num;
}
setInterval(function() {
var now = new Date();
$("#hours").innerHTML = addZero(now.getHours());
$("#minutes").innerHTML = addZero(now.getMinutes());
$("#seconds").innerHTML = addZero(now.getSeconds());
}, 1000);
}
function init() {
Dz.init();
window.onkeydown = Dz.onkeydown.bind(Dz);
window.onhashchange = Dz.loadIframes.bind(Dz);
window.onmessage = Dz.onmessage.bind(Dz);
}
window.onload = init;
</script>
<script> // Helpers
if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
// closest thing possible to the ECMAScript 5 internal IsCallable
// function
if (typeof this !== "function")
throw new TypeError(
"Function.prototype.bind - what is trying to be fBound is not callable"
);
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply( this instanceof fNOP ? this : oThis || window,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
var $ = (HTMLElement.prototype.$ = function(aQuery) {
return this.querySelector(aQuery);
}).bind(document);
var $$ = (HTMLElement.prototype.$$ = function(aQuery) {
return this.querySelectorAll(aQuery);
}).bind(document);
</script>

930
template.html Normal file
View file

@ -0,0 +1,930 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>YunoHost</title>
<!-- Your Slides -->
<!-- One section is one slide -->
<section>
<div class="center" style="height: 100%; display: flex">
<img src="img/logo.png" style="margin: auto">
</div>
</section>
<section>
<h2>Me</h2>
</section>
<section>
<h3>YunoHost short history</h3>
<ul class="incremental">
<li>2011 - Beudbeud install his mail server, kload wants the same</li>
<li>2012 - first release</li>
<li>Feature list grows:
<ul class="incremental">
<li>xmpp</li>
<li>several domains</li>
<li>"applications"</li>
<li>SSO</li>
<li>etc...</li>
</ul>
</li>
</ul>
</section>
<section>
<h3>Political context</h3>
<ul>
<li>Internet Centralization</li>
<li>FDN/FFDN</li>
<li>La Quadrature du Net</li>
<li>HADOPI laws & co</li>
<li>GAFAM</li>
<li>mass surveillance</li>
</ul>
</section>
<section>
<h2>But what is YunoHost?</h2>
</section>
<section style="background-image: url('img/admin.png'); background-size: 100%; background-repeat: no-repeat; background-position-y: center;">
</section>
<section style="background-image: url('img/apps.png'); background-size: 100%; background-repeat: no-repeat; background-position-y: center;">
</section>
<section style="background-image: url('img/app_install_zerobin.png'); background-size: 100%; background-repeat: no-repeat; background-position-y: center;">
</section>
<section style="background-image: url('img/tools.png'); background-size: 100%; background-repeat: no-repeat; background-position-y: center;">
</section>
<section>
<h2>Architecture</h2>
</section>
<section>
<div style="display: flex; align-items: center; height: 100%">
<div>
<img style="width: 100%;" src="img/domains.png" />
</div>
<div style="width: 20px">
</div>
<div>
<img style="width: 100%;" src="img/cli.png" />
</div>
</div>
</section>
<section style="background-image: url('img/architecture.png'); background-size: 100%; background-repeat: no-repeat; background-position-y: center;">
</section>
<section>
<div style="display: flex; align-items: center; height: 100%">
<div>
<img style="width: 100%;" src="img/domain_list.py.png" />
</div>
<div style="width: 20px">
</div>
<div>
<img style="width: 100%;" src="img/actionmap.png" />
</div>
</div>
</section>
<section>
<div style="display: flex; align-items: center; height: 100%">
<div>
<img style="width: 100%;" src="img/files.png" />
</div>
<div style="width: 20px">
</div>
<div>
<img style="width: 100%;" src="img/help.png" />
</div>
</div>
</section>
<section style="background-image: url('img/ssoportal.png'); background-size: 100%; background-repeat: no-repeat; background-position-y: center;">
</section>
<section>
<h2>How apps are made</h2>
</section>
<section>
<div style="display: flex; align-items: center; height: 100%">
<div>
<img style="width: 100%;" src="img/app_root.png" />
</div>
<div style="width: 20px">
</div>
<div>
<img style="width: 100%;" src="img/app_scripts.png" />
</div>
<div style="width: 20px">
</div>
<div>
<img style="width: 100%;" src="img/manifest.json.png" />
</div>
</div>
</section>
<section>
<div style="display: flex; align-items: center; height: 100%">
<div>
<img style="width: 100%;" src="img/app_install_jirafeau.png" />
</div>
<div style="width: 20px">
</div>
<div>
<img style="width: 100%;" src="img/app_install.png" />
</div>
</div>
</section>
<section>
<h3 style="margin-bottom: 20px">Features list</h3>
<ul style="margin-top: 0px">
<li>debian based</li>
<li>users management: emails + xmpp</li>
<li>domain management: dyndns, own self-signed CA or Let's Encrypt</li>
<li>applications with SSO</li>
<li>services + regen-conf + hooks</li>
<li>firewall + fail2ban</li>
<li>backup</li>
<li>small monitoring</li>
<li>and growing...</li>
</ul>
</section>
<section>
<h3>Community, organisation and others</h3>
<ul class="incremental">
<li>1000 - 2000 users (hard to count)</li>
<li>20 official app, 63 (129) community</li>
<li>collective with our own constitution</li>
<li>Continuous Integration of apps</li>
<li>apps levels</li>
<li>Forum and xmpp chatrooms</li>
<li>Translations</li>
<li>quite le french</li>
</ul>
</section>
<section>
<h3>Friends</h3>
<ul>
<li>The Internet Cube / La Brique Internet</li>
<li>FFDN (associative ISPs)</li>
<li>Framasoft / CHATONS</li>
<li>and others &lt;3</li>
</ul>
</section>
<section>
<h3>Futur/Dreams/Ideas</h3>
<ul>
<li>borg backup
<li>friends backup each others
<li>monitoring
<li>friends monitor each others
<li>auto detect error
<li>auto repair errors?
<li>"app market"
</ul>
</section>
<section>
<h2>Questions?</h2>
</section>
<!--
moi
"YunoHost est un outil qui vous permet dinstaller et dutiliser facilement votre propre serveur.""
histoire:
* 2011 beudbeud install son serveur mail, kload "je veux le même"
* c'est super chiant à porter -> coder un truc
partant de là YunoHost a évoléu petit à petit:
* emails
* xmpp
* several domains
* dyndns
* "applications"
* services
* firewalls
* backup
* SSO
* etc...
Context fortement politisé: lqdn, ffdn, etc...
graphique architecture
cli vs admin
exemple de code + yaml + commande
regen conf
hooks
community
* forum
* # of users
* very le french
Framasoft
La brique Internet
organisation
* schéma
latest release with LE
Apps:
* levels
* CI
Ideas/future/dreams:
* borg backup
* friends backup each others
* monitoring
* friends monitor each others
* auto detect error (bad domain configuration, blocked ports)
* "app market"
-->
<!-- Your Style -->
<!-- Define the style of your presentation -->
<!-- Maybe a font from http://www.google.com/webfonts ? -->
<link href='http://fonts.googleapis.com/css?family=Oswald' rel='stylesheet'>
<style>
html, .view body {
background-color: #050505;
counter-reset: slideidx;
}
body, .view section {
color: #eee;
}
/* A section is a slide. It's size is 800x600, and this will never change */
section, .view head > title {
/* The font from Google */
font-family: 'Oswald', arial, serif;
font-size: 30px;
}
.view section:after {
counter-increment: slideidx;
content: counter(slideidx, decimal-leading-zero);
position: absolute; bottom: -80px; right: 100px;
color: white;
}
a {
color: #D7AF5F;
text-decoration: none;
}
.table {
margin: auto;
width: 100%;
}
.table td {
padding: 3px;
}
.center {
text-align: center;
}
.date {
color: #bbb;
font-size: normal;
}
.view head > title {
color: white;
text-align: center;
margin: 1em 0 1em 0;
}
h1 {
margin-top: 200px;
text-align: center;
font-size: 70px;
text-transform: uppercase;
}
h2 {
margin-top: 200px;
text-align: center;
font-size: 80px;
}
.background-light {
text-shadow: 1px 1px 1px white;
}
.rainbow {
background-image: -webkit-gradient( linear, left top, right top, color-stop(0, #f22), color-stop(0.15, #f2f), color-stop(0.3, #22f), color-stop(0.45, #2ff), color-stop(0.6, #2f2),color-stop(0.75, #2f2), color-stop(0.9, #ff2), color-stop(1, #f22) );
background-image: gradient( linear, left top, right top, color-stop(0, #f22), color-stop(0.15, #f2f), color-stop(0.3, #22f), color-stop(0.45, #2ff), color-stop(0.6, #2f2),color-stop(0.75, #2f2), color-stop(0.9, #ff2), color-stop(1, #f22) );
color:transparent;
-webkit-background-clip: text;
background-clip: text;
}
h3 {
margin: 100px 0 50px 100px;
}
ul, ol {
margin: 50px 200px;
}
li > ul {
margin: 15px 50px;
}
p {
margin: 75px;
font-size: 50px;
}
.standalone-quote {
margin: auto;
margin-top: 200px;
}
blockquote {
height: 100%;
font-size: 60px;
padding: 50px;
}
blockquote:before {
content: open-quote;
}
blockquote:after {
content: close-quote;
}
/* Figures are displayed full-page, with the caption
on top of the image/video */
figure {
background-color: black;
width: 100%;
height: 100%;
}
figure > * {
position: absolute;
}
figure > img, figure > video {
width: 100%; height: 100%;
}
figcaption {
margin: 70px;
font-size: 50px;
}
footer {
position: absolute;
bottom: 0;
width: 100%;
padding: 40px;
text-align: right;
background-color: #F3F4F8;
border-top: 1px solid #CCC;
}
/* Transition effect */
/* Feel free to change the transition effect for original
animations. See here:
https://developer.mozilla.org/en/CSS/CSS_transitions
How to use CSS3 Transitions: */
section {
/*
-moz-transition: left 400ms linear 0s;
-webkit-transition: left 400ms linear 0s;
-ms-transition: left 400ms linear 0s;
transition: left 400ms linear 0s;
*/
}
.view section {
-moz-transition: none;
-webkit-transition: none;
-ms-transition: none;
transition: none;
}
.view section[aria-selected] {
border: 5px red solid;
}
/* Before */
section { left: -150%; }
/* Now */
section[aria-selected] { left: 0; }
/* After */
section[aria-selected] ~ section { left: +150%; }
/* Incremental elements */
/* By default, visible */
.incremental > * { opacity: 1; }
/* The current item */
.incremental > *[aria-selected] { opacity: 1; }
/* The items to-be-selected */
.incremental > *[aria-selected] ~ * { opacity: 0; }
/* The progressbar, at the bottom of the slides, show the global
progress of the presentation. */
#progress-bar {
height: 0px;
background: #AAA;
}
small {
color: #b6b6b6;
}
</style>
<!-- {{{{ dzslides core
#
#
# __ __ __ . __ ___ __
# | \ / /__` | | | \ |__ /__`
# |__/ /_ .__/ |___ | |__/ |___ .__/ core :€
#
#
# The following block of code is not supposed to be edited.
# But if you want to change the behavior of these slides,
# feel free to hack it!
#
-->
<div id="progress-bar"></div>
<!-- Default Style -->
<style>
* { margin: 0; padding: 0; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; }
[role="note"] { display: none; }
body {
width: 800px; height: 600px;
margin-left: -400px; margin-top: -300px;
position: absolute; top: 50%; left: 50%;
overflow: hidden;
display: none;
}
.view body {
position: static;
margin: 0; padding: 0;
width: 100%; height: 100%;
display: inline-block;
overflow: visible; overflow-x: hidden;
/* undo Dz.onresize */
transform: none !important;
-moz-transform: none !important;
-webkit-transform: none !important;
-o-transform: none !important;
-ms-transform: none !important;
}
.view head, .view head > title { display: block }
section {
position: absolute;
pointer-events: none;
width: 100%; height: 100%;
}
.view section {
pointer-events: auto;
position: static;
width: 800px; height: 600px;
margin: -150px -200px;
float: left;
transform: scale(.4);
-moz-transform: scale(.4);
-webkit-transform: scale(.4);
-o-transform: scale(.4);
-ms-transform: scale(.4);
}
.view section > * { pointer-events: none; }
section[aria-selected] { pointer-events: auto; }
html { overflow: hidden; }
html.view { overflow: visible; }
body.loaded { display: block; }
.incremental {visibility: hidden; }
.incremental[active] {visibility: visible; }
#progress-bar{
bottom: 0;
position: absolute;
-moz-transition: width 400ms linear 0s;
-webkit-transition: width 400ms linear 0s;
-ms-transition: width 400ms linear 0s;
transition: width 400ms linear 0s;
}
.view #progress-bar {
display: none;
}
</style>
<script>
var Dz = {
remoteWindows: [],
idx: -1,
step: 0,
html: null,
slides: null,
progressBar : null,
params: {
autoplay: "1"
}
};
Dz.init = function() {
document.body.className = "loaded";
this.slides = Array.prototype.slice.call($$("body > section"));
this.progressBar = $("#progress-bar");
this.html = document.body.parentNode;
this.setupParams();
this.onhashchange();
this.setupTouchEvents();
this.onresize();
this.setupView();
}
Dz.setupParams = function() {
var p = window.location.search.substr(1).split('&');
p.forEach(function(e, i, a) {
var keyVal = e.split('=');
Dz.params[keyVal[0]] = decodeURIComponent(keyVal[1]);
});
// Specific params handling
if (!+this.params.autoplay)
$$.forEach($$("video"), function(v){ v.controls = true });
}
Dz.onkeydown = function(aEvent) {
// Don't intercept keyboard shortcuts
if (aEvent.altKey
|| aEvent.ctrlKey
|| aEvent.metaKey
|| aEvent.shiftKey) {
return;
}
if ( aEvent.keyCode == 37 // left arrow
|| aEvent.keyCode == 38 // up arrow
|| aEvent.keyCode == 33 // page up
) {
aEvent.preventDefault();
this.back();
}
if ( aEvent.keyCode == 39 // right arrow
|| aEvent.keyCode == 40 // down arrow
|| aEvent.keyCode == 34 // page down
) {
aEvent.preventDefault();
this.forward();
}
if (aEvent.keyCode == 35) { // end
aEvent.preventDefault();
this.goEnd();
}
if (aEvent.keyCode == 36) { // home
aEvent.preventDefault();
this.goStart();
}
if (aEvent.keyCode == 32) { // space
aEvent.preventDefault();
this.toggleContent();
}
if (aEvent.keyCode == 70) { // f
aEvent.preventDefault();
this.goFullscreen();
}
if (aEvent.keyCode == 79) { // o
aEvent.preventDefault();
this.toggleView();
}
}
/* Touch Events */
Dz.setupTouchEvents = function() {
var orgX, newX;
var tracking = false;
var db = document.body;
db.addEventListener("touchstart", start.bind(this), false);
db.addEventListener("touchmove", move.bind(this), false);
function start(aEvent) {
aEvent.preventDefault();
tracking = true;
orgX = aEvent.changedTouches[0].pageX;
}
function move(aEvent) {
if (!tracking) return;
newX = aEvent.changedTouches[0].pageX;
if (orgX - newX > 100) {
tracking = false;
this.forward();
} else {
if (orgX - newX < -100) {
tracking = false;
this.back();
}
}
}
}
Dz.setupView = function() {
document.body.addEventListener("click", function ( e ) {
if (!Dz.html.classList.contains("view")) return;
if (!e.target || e.target.nodeName != "SECTION") return;
Dz.html.classList.remove("view");
Dz.setCursor(Dz.slides.indexOf(e.target) + 1);
}, false);
}
/* Adapt the size of the slides to the window */
Dz.onresize = function() {
var db = document.body;
var sx = db.clientWidth / window.innerWidth;
var sy = db.clientHeight / window.innerHeight;
var transform = "scale(" + (1/Math.max(sx, sy)) + ")";
db.style.MozTransform = transform;
db.style.WebkitTransform = transform;
db.style.OTransform = transform;
db.style.msTransform = transform;
db.style.transform = transform;
}
Dz.getNotes = function(aIdx) {
var s = $("section:nth-of-type(" + aIdx + ")");
var d = s.$("[role='note']");
return d ? d.innerHTML : "";
}
Dz.onmessage = function(aEvent) {
var argv = aEvent.data.split(" "), argc = argv.length;
argv.forEach(function(e, i, a) { a[i] = decodeURIComponent(e) });
var win = aEvent.source;
if (argv[0] === "REGISTER" && argc === 1) {
this.remoteWindows.push(win);
this.postMsg(win, "REGISTERED", document.title, this.slides.length);
this.postMsg(win, "CURSOR", this.idx + "." + this.step);
return;
}
if (argv[0] === "BACK" && argc === 1)
this.back();
if (argv[0] === "FORWARD" && argc === 1)
this.forward();
if (argv[0] === "START" && argc === 1)
this.goStart();
if (argv[0] === "END" && argc === 1)
this.goEnd();
if (argv[0] === "TOGGLE_CONTENT" && argc === 1)
this.toggleContent();
if (argv[0] === "SET_CURSOR" && argc === 2)
window.location.hash = "#" + argv[1];
if (argv[0] === "GET_CURSOR" && argc === 1)
this.postMsg(win, "CURSOR", this.idx + "." + this.step);
if (argv[0] === "GET_NOTES" && argc === 1)
this.postMsg(win, "NOTES", this.getNotes(this.idx));
}
Dz.toggleContent = function() {
// If a Video is present in this new slide, play it.
// If a Video is present in the previous slide, stop it.
var s = $("section[aria-selected]");
if (s) {
var video = s.$("video");
if (video) {
if (video.ended || video.paused) {
video.play();
} else {
video.pause();
}
}
}
}
Dz.setCursor = function(aIdx, aStep) {
// If the user change the slide number in the URL bar, jump
// to this slide.
aStep = (aStep != 0 && typeof aStep !== "undefined") ? "." + aStep : ".0";
window.location.hash = "#" + aIdx + aStep;
}
Dz.onhashchange = function() {
var cursor = window.location.hash.split("#"),
newidx = 1,
newstep = 0;
if (cursor.length == 2) {
newidx = ~~cursor[1].split(".")[0];
newstep = ~~cursor[1].split(".")[1];
if (newstep > Dz.slides[newidx - 1].$$('.incremental > *').length) {
newstep = 0;
newidx++;
}
}
this.setProgress(newidx, newstep);
if (newidx != this.idx) {
this.setSlide(newidx);
}
if (newstep != this.step) {
this.setIncremental(newstep);
}
for (var i = 0; i < this.remoteWindows.length; i++) {
this.postMsg(this.remoteWindows[i], "CURSOR", this.idx + "." + this.step);
}
}
Dz.back = function() {
if (this.idx == 1 && this.step == 0) {
return;
}
if (this.step == 0) {
this.setCursor(this.idx - 1,
this.slides[this.idx - 2].$$('.incremental > *').length);
} else {
this.setCursor(this.idx, this.step - 1);
}
}
Dz.forward = function() {
if (this.idx >= this.slides.length &&
this.step >= this.slides[this.idx - 1].$$('.incremental > *').length) {
return;
}
if (this.step >= this.slides[this.idx - 1].$$('.incremental > *').length) {
this.setCursor(this.idx + 1, 0);
} else {
this.setCursor(this.idx, this.step + 1);
}
}
Dz.goStart = function() {
this.setCursor(1, 0);
}
Dz.goEnd = function() {
var lastIdx = this.slides.length;
var lastStep = this.slides[lastIdx - 1].$$('.incremental > *').length;
this.setCursor(lastIdx, lastStep);
}
Dz.toggleView = function() {
this.html.classList.toggle("view");
if (this.html.classList.contains("view")) {
$("section[aria-selected]").scrollIntoView(true);
}
}
Dz.setSlide = function(aIdx) {
this.idx = aIdx;
var old = $("section[aria-selected]");
var next = $("section:nth-of-type("+ this.idx +")");
if (old) {
old.removeAttribute("aria-selected");
var video = old.$("video");
if (video) {
video.pause();
}
}
if (next) {
next.setAttribute("aria-selected", "true");
if (this.html.classList.contains("view")) {
next.scrollIntoView();
}
var video = next.$("video");
if (video && !!+this.params.autoplay) {
video.play();
}
} else {
// That should not happen
this.idx = -1;
// console.warn("Slide doesn't exist.");
}
}
Dz.setIncremental = function(aStep) {
this.step = aStep;
var old = this.slides[this.idx - 1].$('.incremental > *[aria-selected]');
if (old) {
old.removeAttribute('aria-selected');
}
var incrementals = $$('.incremental');
if (this.step <= 0) {
$$.forEach(incrementals, function(aNode) {
aNode.removeAttribute('active');
});
return;
}
var next = this.slides[this.idx - 1].$$('.incremental > *')[this.step - 1];
if (next) {
next.setAttribute('aria-selected', true);
next.parentNode.setAttribute('active', true);
var found = false;
$$.forEach(incrementals, function(aNode) {
if (aNode != next.parentNode)
if (found)
aNode.removeAttribute('active');
else
aNode.setAttribute('active', true);
else
found = true;
});
} else {
setCursor(this.idx, 0);
}
return next;
}
Dz.goFullscreen = function() {
var html = $('html'),
requestFullscreen = html.requestFullscreen || html.requestFullScreen || html.mozRequestFullScreen || html.webkitRequestFullScreen;
if (requestFullscreen) {
requestFullscreen.apply(html);
}
}
Dz.setProgress = function(aIdx, aStep) {
var slide = $("section:nth-of-type("+ aIdx +")");
if (!slide)
return;
var steps = slide.$$('.incremental > *').length + 1,
slideSize = 100 / (this.slides.length - 1),
stepSize = slideSize / steps;
this.progressBar.style.width = ((aIdx - 1) * slideSize + aStep * stepSize) + '%';
}
Dz.postMsg = function(aWin, aMsg) { // [arg0, [arg1...]]
aMsg = [aMsg];
for (var i = 2; i < arguments.length; i++)
aMsg.push(encodeURIComponent(arguments[i]));
aWin.postMessage(aMsg.join(" "), "*");
}
function init() {
Dz.init();
window.onkeydown = Dz.onkeydown.bind(Dz);
window.onresize = Dz.onresize.bind(Dz);
window.onhashchange = Dz.onhashchange.bind(Dz);
window.onmessage = Dz.onmessage.bind(Dz);
}
window.onload = init;
</script>
<script> // Helpers
if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
// closest thing possible to the ECMAScript 5 internal IsCallable
// function
if (typeof this !== "function")
throw new TypeError(
"Function.prototype.bind - what is trying to be fBound is not callable"
);
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply( this instanceof fNOP ? this : oThis || window,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
var $ = (HTMLElement.prototype.$ = function(aQuery) {
return this.querySelector(aQuery);
}).bind(document);
var $$ = (HTMLElement.prototype.$$ = function(aQuery) {
return this.querySelectorAll(aQuery);
}).bind(document);
$$.forEach = function(nodeList, fun) {
Array.prototype.forEach.call(nodeList, fun);
}
</script>
<!-- vim: set fdm=marker: }}} -->