aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEuAndreh <eu@euandre.org>2023-04-15 16:21:40 -0300
committerEuAndreh <eu@euandre.org>2023-04-15 16:21:40 -0300
commitbcd1d0be109aae75ed7d34545f893208a671e316 (patch)
tree1f7aa11a29131430a649b8b10c249c1abda0710e
parentv2: Generate sitemap.xml (diff)
downloadeuandre.org-bcd1d0be109aae75ed7d34545f893208a671e316.tar.gz
euandre.org-bcd1d0be109aae75ed7d34545f893208a671e316.tar.xz
v2: WIP support for slides
-rw-r--r--v2/.gitignore1
-rw-r--r--v2/dynamic.mk7
-rw-r--r--v2/po/euandre.org.pot36
-rw-r--r--v2/po/pt.po51
-rwxr-xr-xv2/src/bin/makemake17
-rw-r--r--v2/src/content/en/slide/local-first.ps522
-rw-r--r--v2/src/content/en/slide/local-first.slides204
-rw-r--r--v2/src/content/en/slide/rollouts.ps500
-rw-r--r--v2/src/content/en/slide/rollouts.slides208
-rw-r--r--v2/src/lib/base.en.conf11
-rw-r--r--v2/src/lib/base.pt.conf11
-rw-r--r--v2/src/lib/commencement.en.conf2
-rw-r--r--v2/src/lib/commencement.pt.conf2
13 files changed, 1564 insertions, 8 deletions
diff --git a/v2/.gitignore b/v2/.gitignore
index ac25e0d..e824ac3 100644
--- a/v2/.gitignore
+++ b/v2/.gitignore
@@ -27,4 +27,5 @@
/src/content/**/*.indexentry
/src/content/**/*.xmlentry
/src/content/**/*.xml
+/src/content/*/slide/*.pdf
/src/content/.gitignore
diff --git a/v2/dynamic.mk b/v2/dynamic.mk
index c0a3132..77c7e77 100644
--- a/v2/dynamic.mk
+++ b/v2/dynamic.mk
@@ -8,6 +8,7 @@ include generated.mk
.SUFFIXES:
.SUFFIXES: .page .md .content .conf .html .categoryentry .indexentry .xmlentry .mapentry .uncolored
+.SUFFIXES: .slides .ps .pdf
.page.md:
@@ -43,6 +44,11 @@ include generated.mk
"`tail -n +3 $<`" \
> $@
+.slides.ps:
+ exit 88
+
+.ps.pdf:
+ ps2pdf $< $@
all: public
@@ -96,6 +102,7 @@ content = \
$(all-generated.html) \
$(all-generated.index) \
$(all-generated.xml) \
+ $(all-generated.pdf) \
$(static-content) \
$(svgs) \
src/content/sitemap.xml \
diff --git a/v2/po/euandre.org.pot b/v2/po/euandre.org.pot
index 78a1d89..0b0f044 100644
--- a/v2/po/euandre.org.pot
+++ b/v2/po/euandre.org.pot
@@ -7,7 +7,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
-"POT-Creation-Date: 2023-04-10 16:03-0300\n"
+"POT-Creation-Date: 2023-04-10 21:07-0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -168,11 +168,36 @@ msgid "export index_til_url=\"$(url-for \"$lang/$(coll2path \"$lang\" til)\")\""
msgstr ""
#. type: Plain text
-#: src/lib/base.en.conf:50
+#: src/lib/base.en.conf:51
msgid "export feed_til_title=\"EuAndreh's TIL\""
msgstr ""
#. type: Plain text
+#: src/lib/base.en.conf:54
+msgid "export index_slide_title='Slides'"
+msgstr ""
+
+#. type: Plain text
+#: src/lib/base.en.conf:56
+msgid "export index_recent_slide_title='Slides listing'"
+msgstr ""
+
+#. type: Plain text
+#: src/lib/base.en.conf:58
+msgid "export index_category_slide_title='Slides by category'"
+msgstr ""
+
+#. type: Plain text
+#: src/lib/base.en.conf:60
+msgid "export index_slide_url=\"$(url-for \"$lang/$(coll2path \"$lang\" slide)\")\""
+msgstr ""
+
+#. type: Plain text
+#: src/lib/base.en.conf:61
+msgid "export feed_slide_title=\"EuAndreh's slides\""
+msgstr ""
+
+#. type: Plain text
#: src/lib/commencement.en.conf:2
msgid "#!/bin/sh"
msgstr ""
@@ -188,10 +213,15 @@ msgid "export pastebin_collection_name='pastebin'"
msgstr ""
#. type: Plain text
-#: src/lib/commencement.en.conf:7
+#: src/lib/commencement.en.conf:8
msgid "export til_collection_name='til'"
msgstr ""
+#. type: Plain text
+#: src/lib/commencement.en.conf:9
+msgid "export slide_collection_name='slide'"
+msgstr ""
+
#. type: Content of: <p>
#: src/lib/comment.en.html:3
msgid ""
diff --git a/v2/po/pt.po b/v2/po/pt.po
index faa51af..a0b99f7 100644
--- a/v2/po/pt.po
+++ b/v2/po/pt.po
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
-"POT-Creation-Date: 2023-04-10 16:03-0300\n"
+"POT-Creation-Date: 2023-04-10 21:07-0300\n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
@@ -169,11 +169,49 @@ msgstr ""
"export index_til_url=\"$(url-for \"$lang/$(coll2path \"$lang\" til)\")\""
#. type: Plain text
-#: src/lib/base.en.conf:50
+#: src/lib/base.en.conf:51
msgid "export feed_til_title=\"EuAndreh's TIL\""
msgstr "export feed_til_title=\"HEA do EuAndreh\""
#. type: Plain text
+#: src/lib/base.en.conf:54
+#, fuzzy
+#| msgid "export index_article_title='Blog'"
+msgid "export index_slide_title='Slides'"
+msgstr "export index_article_title='Blog'"
+
+#. type: Plain text
+#: src/lib/base.en.conf:56
+#, fuzzy
+#| msgid "export index_recent_til_title='TIL listing'"
+msgid "export index_recent_slide_title='Slides listing'"
+msgstr "export index_recent_til_title='HEA recentes'"
+
+#. type: Plain text
+#: src/lib/base.en.conf:58
+#, fuzzy
+#| msgid "export index_category_article_title='Articles by category'"
+msgid "export index_category_slide_title='Slides by category'"
+msgstr "export index_category_article_title='Artigos por categoria'"
+
+#. type: Plain text
+#: src/lib/base.en.conf:60
+#, fuzzy
+#| msgid ""
+#| "export index_til_url=\"$(url-for \"$lang/$(coll2path \"$lang\" til)\")\""
+msgid ""
+"export index_slide_url=\"$(url-for \"$lang/$(coll2path \"$lang\" slide)\")\""
+msgstr ""
+"export index_til_url=\"$(url-for \"$lang/$(coll2path \"$lang\" til)\")\""
+
+#. type: Plain text
+#: src/lib/base.en.conf:61
+#, fuzzy
+#| msgid "export feed_article_title=\"EuAndreh's articles\""
+msgid "export feed_slide_title=\"EuAndreh's slides\""
+msgstr "export feed_article_title=\"Artigos do EuAndreh\""
+
+#. type: Plain text
#: src/lib/commencement.en.conf:2
msgid "#!/bin/sh"
msgstr ""
@@ -189,10 +227,17 @@ msgid "export pastebin_collection_name='pastebin'"
msgstr "export pastebin_collection_name='pastebin'"
#. type: Plain text
-#: src/lib/commencement.en.conf:7
+#: src/lib/commencement.en.conf:8
msgid "export til_collection_name='til'"
msgstr "export til_collection_name='hea'"
+#. type: Plain text
+#: src/lib/commencement.en.conf:9
+#, fuzzy
+#| msgid "export til_collection_name='til'"
+msgid "export slide_collection_name='slide'"
+msgstr "export til_collection_name='hea'"
+
#. type: Content of: <p>
#: src/lib/comment.en.html:3
msgid ""
diff --git a/v2/src/bin/makemake b/v2/src/bin/makemake
index c6e3407..3956844 100755
--- a/v2/src/bin/makemake
+++ b/v2/src/bin/makemake
@@ -144,6 +144,17 @@ for lang in $(langs); do
printf '\n\n'
done
+ coll_path="$(coll2path "$lang" slide)"
+ git ls-files "$CONTENT_PREFIX/$lang/$coll_path"*.slides |
+ varlist "slide.$lang.slides"
+ git ls-files "$CONTENT_PREFIX/$lang/$coll_path"*.slides |
+ sed 's/^\(.*\)\.slides$/\1.pdf: \1.ps/'
+ printf '\n\n'
+
+ echo "slide.$lang.pdf = \$(slide.$lang.slides:.slides=.pdf)"
+ echo "all-generated.$lang.slides = \$(slide.$lang.slides)"
+ echo "all-generated.$lang.pdf = \$(slide.$lang.pdf)"
+
for e in $(extensions); do
{
if ! printf '%s\n' "$e" | grep -qE "$page_ext_filter"; then
@@ -185,7 +196,7 @@ for lang in $(langs); do
sed "s|^\(.*\)\$|$CONTENT_PREFIX/$lang/\1feed.xml|" |
varlist "all-generated.$lang.xml"
- extensions '.series' '.categories' '.extrahtml' '.extrafeeds' '.index' '.xml' |
+ extensions '.series' '.categories' '.extrahtml' '.extrafeeds' '.index' '.xml' '.pdf' |
sed "s|^\(.*\)\$|\$(all-generated.$lang\1)|" |
varlist "all-generated.$lang"
@@ -212,7 +223,7 @@ printf 'svgs = $(svgs.uncolored:.uncolored=)\n\n'
} > "$CONTENT_PREFIX"/.gitignore
-for e in $(extensions '.series' '.categories' '.extrahtml' '.extrafeeds' '.index' '.xml'); do
+for e in $(extensions '.series' '.categories' '.extrahtml' '.extrafeeds' '.index' '.xml' '.pdf'); do
langs |
sed "s|^\(.*\)\$|\$(all-generated.\1$e)|" |
varlist "all-generated$e"
@@ -237,4 +248,6 @@ git ls-files "$CONTENT_PREFIX"/ |
grep -v '\.md$' |
grep -v '\.page$' |
grep -v '\.uncolored$' |
+ grep -v '\.slides$' |
+ grep -v '\.ps$' |
varlist 'static-content'
diff --git a/v2/src/content/en/slide/local-first.ps b/v2/src/content/en/slide/local-first.ps
new file mode 100644
index 0000000..44c5858
--- /dev/null
+++ b/v2/src/content/en/slide/local-first.ps
@@ -0,0 +1,522 @@
+%!PS-Adobe-3.0
+%%DocumentMedia: SLIDE 842 595 0 () ()
+%%EndComments
+%%BeginDefaults
+%%PageMedia: SLIDE
+%%EndDefaults
+<< /PageSize [842 595] /ImagingBBox null >> setpagedevice
+
+/reencode {
+ exch
+ findfont
+ dup length dict
+ begin
+ {
+ 1 index /FID ne
+ { def }
+ { pop pop }
+ ifelse
+ } forall
+ /Encoding ISOLatin1Encoding def
+ currentdict
+ end
+ definefont pop
+} def
+/Courier /Courier reencode
+/Helvetica /Helvetica reencode
+/Times /Times reencode
+/Times-Italic /Times-Italic reencode
+
+
+/headerheight 77 def
+
+/frontfontsz 60 def
+/authorfontsz 40 def
+/titlefontsz 40 def
+/mainfontsz 30 def
+/codefontsz 18 def
+/tinyfontsz 18 def
+
+/titlefont /Helvetica findfont titlefontsz scalefont def
+/mainfont /Courier findfont mainfontsz scalefont def
+/codefont /Courier findfont codefontsz scalefont def
+/tinyfont /Times findfont tinyfontsz scalefont def
+/frontfont /Helvetica findfont frontfontsz scalefont def
+/authorfont /Times-Italic findfont authorfontsz scalefont def
+/authorfonttwo /Times findfont authorfontsz scalefont def
+
+
+/pagewidth 842 def
+/pageheight 595 def
+/leftmargin 30 def
+/topmargin 595 def
+
+/pad 10 def
+
+/titlefonth titlefontsz pad add def
+/mainfonth mainfontsz pad add def
+/codefonth codefontsz pad add def
+/tinyfonth tinyfontsz pad add def
+/frontfonth frontfontsz pad add def
+/authorfonth authorfontsz pad add def
+
+/headermargin
+ pageheight headerheight titlefonth sub 2 div titlefontsz add sub
+def
+/rightmargin pagewidth leftmargin sub def
+/tbtop topmargin def
+/ypos topmargin def
+
+/xcur { currentpoint pop } def
+/ycur { currentpoint exch pop } def
+
+/wordbreak ( ) def
+/linewrap {
+ /proc exch def
+ /linelength exch def
+ /textstring exch def
+ /breakwidth wordbreak stringwidth pop def
+ /curwidth 0 def
+ /lastwordbreak 0 def
+ /startchar 0 def
+ /restoftext textstring def
+ {
+ restoftext wordbreak search
+ {
+ /nextword exch def pop
+ /restoftext exch def
+ /wordwidth nextword stringwidth pop def
+ curwidth wordwidth add linelength gt
+ {
+ textstring startchar
+ lastwordbreak startchar sub
+ getinterval proc
+ /startchar lastwordbreak def
+ /curwidth wordwidth breakwidth add def
+ }
+ {
+ /curwidth curwidth wordwidth add
+ breakwidth add def
+ } ifelse
+ /lastwordbreak lastwordbreak
+ nextword length add 1 add def
+ }
+ {
+ pop exit
+ } ifelse
+ } loop
+ /lastchar textstring length def
+ textstring startchar lastchar startchar sub
+ getinterval proc
+} def
+
+/line {
+ 0 0 0 setrgbcolor
+ 0.5 setlinewidth
+ leftmargin ypos moveto
+ rightmargin ypos lineto
+ stroke
+} def
+
+/center {
+ dup
+ /str exch def
+ /sw str stringwidth pop def
+ /xpos pagewidth sw sub 2 div xcur sub def
+ xpos 0 rmoveto
+} def
+
+/objcenter {
+ pagewidth exch sub 2 div 0 translate
+} def
+
+/s {
+ /tbtop topmargin def
+ /ypos topmargin def
+ 1 1 1 setrgbcolor
+ 0 setlinewidth
+ newpath
+ 0 pageheight moveto
+ pagewidth pageheight lineto
+ pagewidth 0 lineto
+ 0 0 lineto
+ closepath
+ fill
+ stroke
+} def
+
+/l {
+ /h exch def
+ /ypos ypos h sub def
+ leftmargin ypos moveto
+} def
+
+/title {
+ frontfonth l
+ frontfont setfont
+ 0.5 0.5 0.9 setrgbcolor
+ { pagewidth leftmargin 2 mul sub }
+ { frontfonth l center show }
+ linewrap
+ frontfonth 2 div l
+ frontfonth l
+} def
+
+/author {
+ authorfont setfont
+ 0 0 0 setrgbcolor
+ { pagewidth leftmargin 2 mul sub }
+ { authorfonth l center show }
+ linewrap
+} def
+
+/authortwo {
+ authorfonttwo setfont
+ 0 0 0 setrgbcolor
+ { pagewidth leftmargin 2 mul sub }
+ { authorfonth l center show }
+ linewrap
+} def
+
+/header {
+ /ypos pageheight headerheight sub def
+ 0 0 0 setrgbcolor
+ 0 setlinewidth
+ newpath
+ 0 pageheight moveto
+ pagewidth pageheight lineto
+ pagewidth ypos lineto
+ 0 ypos lineto
+ closepath
+ fill
+ stroke
+ leftmargin headermargin moveto
+ titlefont setfont
+ 0.5 0.5 0.9 setrgbcolor
+ center show
+ leftmargin ypos moveto
+} def
+
+/n {
+ mainfont setfont
+ 0 0 0 setrgbcolor
+ { pagewidth leftmargin 2 mul sub }
+ { mainfonth l show }
+ linewrap
+} def
+
+/cn {
+ codefont setfont
+ 0 0 0 setrgbcolor
+ { pagewidth leftmargin 2 mul sub }
+ { codefonth l show }
+ linewrap
+} def
+
+/tn {
+ tinyfont setfont
+ 0 0 0 setrgbcolor
+ { pagewidth leftmargin 2 mul sub }
+ { tinyfonth l show }
+ linewrap
+} def
+
+/is {
+ /level1 save def
+ /showpage {} def
+} def
+
+/ie {
+ level1 restore
+} def
+
+/bs {
+ /tbtop ypos def
+} def
+
+/be {
+ /tm tbtop pad sub def
+ /bm ypos pad sub def
+ newpath
+ leftmargin 10 sub tm moveto
+ rightmargin tm lineto
+ rightmargin bm lineto
+ leftmargin 10 sub bm lineto
+ closepath
+ 0 0 0 setrgbcolor
+ 0.5 setlinewidth
+ stroke
+} def
+( On "local-first") title
+(Beyond the CRDT silver bullet) authortwo
+showpage
+%%Page: 1 1
+s
+( Part 1) header
+( Exposition) title
+showpage
+%%Page: 2 2
+s
+( Target) header
+() n
+() n
+() n
+(- documents) n
+(- files) n
+(- personal data repositories) n
+() n
+() n
+(Not: banking services, e-commerce, social networking, ride-sharing, etc.) n
+showpage
+%%Page: 3 3
+s
+() n
+() n
+() n
+( 7 ideals for local-first software) title
+showpage
+%%Page: 4 4
+s
+() n
+() n
+() n
+( 1 - no spinners: your work at your fingertips) title
+showpage
+%%Page: 5 5
+s
+() n
+() n
+() n
+( 2 - your work is not trapped on one device) title
+showpage
+%%Page: 6 6
+s
+() n
+() n
+() n
+( 3 - the network is optional) title
+showpage
+%%Page: 7 7
+s
+() n
+() n
+() n
+( 4 - seamless collaboration with your colleagues) title
+showpage
+%%Page: 8 8
+s
+() n
+() n
+() n
+( 5 - the long now) title
+showpage
+%%Page: 9 9
+s
+() n
+() n
+() n
+( 6 - security and privacy by default ) title
+showpage
+%%Page: 10 10
+s
+() n
+() n
+() n
+( 7 - you retain ultimate ownership and control) title
+showpage
+%%Page: 11 11
+s
+( Towards a better future) header
+() n
+() n
+() n
+() n
+( CRDTs \(Conflict-free Replicated Data Types\) as a Foundational Technology) authortwo
+showpage
+%%Page: 12 12
+s
+( Use case) header
+() n
+bs
+(# in node A and node B) cn
+(s = "Hello, World") cn
+() cn
+(# in node A) cn
+(s = "Hello, Alice") cn
+() cn
+(# in node B) cn
+(s = "Hello, Bob") cn
+be
+(How to reconcile those?) n
+(- Hello, ABloibce) n
+(- Hello, AliceBob) n
+(- Hello, BobAlice) n
+(- Hello, Alice) n
+(...) n
+showpage
+%%Page: 13 13
+s
+( Existing CRDTs differ) title
+(- performance) n
+(- storage) n
+(- compression) n
+(- metadata overhead) n
+showpage
+%%Page: 14 14
+s
+() n
+() n
+() n
+( Hint towards the "automerge" CRDT) title
+showpage
+%%Page: 15 15
+s
+() n
+() n
+() n
+() n
+() n
+() n
+(show comparison table, page 9) author
+showpage
+%%Page: 16 16
+s
+( Part 2) header
+( Critique) title
+showpage
+%%Page: 17 17
+s
+( Software license) header
+() n
+() n
+() n
+("In our opinion, maintaining control and ownership of data does not mean that the software must necessarily be open source.") author
+showpage
+%%Page: 18 18
+s
+( Example 1 - intentional restriction) header
+() n
+bs
+(#!/bin/sh) cn
+(TODAY="$\(date +%s\)") cn
+(LICENSE_EXPIRATION="$\(date -d 2020-10-27 +%s\)") cn
+(if [ "$TODAY" -ge "$LICENSE_EXPIRATION" ]; then) cn
+( echo 'License expired!') cn
+( exit 1) cn
+(fi) cn
+(echo $\(\(2 + 2\)\)) cn
+be
+() n
+bs
+(# today) cn
+($ ./useful-adder.sh) cn
+(4) cn
+(# tomorrow) cn
+($ ./useful-adder.sh) cn
+(License expired!) cn
+be
+showpage
+%%Page: 19 19
+s
+( Example 2 - unintentional restriction) header
+() n
+bs
+(# today) cn
+($ useful-program) cn
+(# ... useful output ...) cn
+() cn
+(# tomorrow, with more data) cn
+($ useful-program) cn
+(ERROR: Panic! Stack overflow!) cn
+be
+showpage
+%%Page: 20 20
+s
+() n
+() n
+( local-first *requires* free software ) title
+(Otherwise "The Long Now" \(ideal nº5\) is lost) n
+showpage
+%%Page: 21 21
+s
+( Denial of existing solutions) header
+() n
+() n
+("In principle it is possible to collaborate without a repository service, e.g. by sending patch files by email, but the majority of Git users rely on GitHub." ) author
+() n
+(Solution: either GitHub+CRDTs or git send-email ) n
+showpage
+%%Page: 22 22
+s
+( Plain-text formats) header
+() n
+("Git is highly optimized for code and similar line-based text file") author
+() n
+(It even pulls software to the plain text directtion, e.g.:) n
+(- delivery-templates) n
+(- common-core.protocols.config) n
+() n
+(Why not exploit that more?) n
+showpage
+%%Page: 23 23
+s
+( Ditching of web applications) header
+() n
+() n
+("The architecture of web apps remains fundamentally server-centric) author
+() n
+(Disagree. Contrast PouchDB with Android Instant Apps) n
+showpage
+%%Page: 24 24
+s
+( Costs are underrated) header
+() n
+(- storage) n
+(- backups) n
+(- maintenance) n
+() n
+(Example: blog vs vlog) n
+showpage
+%%Page: 25 25
+s
+( Real-time collaboration a bit overrated) header
+() n
+(It is only possible on the presence of reliable, medium-quality network connection) n
+() n
+() n
+("X also works when inside an elevator, subway or plane!") author
+showpage
+%%Page: 26 26
+s
+( On CRDTs and developer experience) header
+() n
+("For an app developer, how does the use of a CRDT-based data layer compare to existing storage layers like a SQL database, a filesystem, or CoreData? Is a distributed system harder to write software for?) author
+() n
+(YES.) authortwo
+() n
+(See "A Note on Distributed Computing") n
+showpage
+%%Page: 27 27
+s
+( Conclusion) header
+() n
+(Why this is a "paper I love": it took offline-first and ran with it.) n
+() n
+(But a pinch of CRDT won't make the world local-first. ) n
+() n
+(The tricky part is the end of the sentence: "in spite of the Cloud".) n
+showpage
+%%Page: 28 28
+s
+( References) header
+() n
+(1. "Local-First Software: You Own Your Data, in spite of the Cloud", by M. Kleppmann, A. Wiggins, P. Van Hardenberg and M. F. McGranaghan) n
+(2. The Morning Paper article) n
+(3. "A Note on Distributed Compiting", by J. Waldo, G. Wyant, A. Wollrath and S. Kendall) n
+(4. these slides: euandre.org/slide/) n
+(5. prose version of this presentation) n
+(6. view source) n
+
+showpage
+
+%%EOF
diff --git a/v2/src/content/en/slide/local-first.slides b/v2/src/content/en/slide/local-first.slides
new file mode 100644
index 0000000..fd83115
--- /dev/null
+++ b/v2/src/content/en/slide/local-first.slides
@@ -0,0 +1,204 @@
+# On "local-first"
+
+@Beyond the CRDT silver bullet
+
+---
+## Part 1
+# Exposition
+
+---
+## Target
+...
+- documents
+- files
+- personal data repositories
+..
+Not: banking services, e-commerce, social networking, ride-sharing, etc.
+
+---
+...
+# 7 ideals for local-first software
+
+---
+...
+# 1 - no spinners: your work at your fingertips
+
+---
+...
+# 2 - your work is not trapped on one device
+
+---
+...
+# 3 - the network is optional
+
+---
+...
+# 4 - seamless collaboration with your colleagues
+
+---
+...
+# 5 - the long now
+
+---
+...
+# 6 - security and privacy by default
+
+---
+...
+# 7 - you retain ultimate ownership and control
+
+---
+## Towards a better future
+....
+@ CRDTs (Conflict-free Replicated Data Types) as a Foundational Technology
+
+---
+## Use case
+.
+ # in node A and node B
+ s = "Hello, World"
+
+ # in node A
+ s = "Hello, Alice"
+
+ # in node B
+ s = "Hello, Bob"
+
+How to reconcile those?
+- Hello, ABloibce
+- Hello, AliceBob
+- Hello, BobAlice
+- Hello, Alice
+\...
+
+---
+# Existing CRDTs differ
+- performance
+- storage
+- compression
+- metadata overhead
+
+---
+...
+# Hint towards the "automerge" CRDT
+
+---
+......
+@@show comparison table, page 9
+
+---
+## Part 2
+# Critique
+
+---
+## Software license
+...
+@@"In our opinion, maintaining control and ownership of data does not mean that the software must necessarily be open source."
+
+---
+## Example 1 - intentional restriction
+.
+ #!/bin/sh
+ TODAY="$(date +%s)"
+ LICENSE_EXPIRATION="$(date -d 2020-10-27 +%s)"
+ if [ "$TODAY" -ge "$LICENSE_EXPIRATION" ]; then
+ echo 'License expired!'
+ exit 1
+ fi
+ echo $((2 + 2))
+.
+ # today
+ $ ./useful-adder.sh
+ 4
+
+ # tomorrow
+ $ ./useful-adder.sh
+ License expired!
+---
+## Example 2 - unintentional restriction
+.
+ # today
+ $ useful-program
+ # ... useful output ...
+
+ # tomorrow, with more data
+ $ useful-program
+ ERROR: Panic! Stack overflow!
+
+---
+..
+# local-first *requires* free software
+
+Otherwise "The Long Now" (ideal nº5) is lost
+
+---
+## Denial of existing solutions
+..
+@@"In principle it is possible to collaborate without a repository service, e.g. by sending patch files by email, but the majority of Git users rely on GitHub."
+.
+Solution: either GitHub+CRDTs or git send-email
+
+---
+## Plain-text formats
+.
+@@"Git is highly optimized for code and similar line-based text file"
+.
+It even pulls software to the plain text directtion, e.g.:
+- delivery-templates
+- common-core.protocols.config
+.
+Why not exploit that more?
+
+---
+## Ditching of web applications
+..
+@@"The architecture of web apps remains fundamentally server-centric
+.
+% FIXME: links
+Disagree. Contrast PouchDB with Android Instant Apps
+
+---
+## Costs are underrated
+.
+- storage
+- backups
+- maintenance
+.
+Example: blog vs vlog
+
+---
+## Real-time collaboration a bit overrated
+.
+It is only possible on the presence of reliable, medium-quality network connection
+..
+@@"X also works when inside an elevator, subway or plane!"
+
+---
+## On CRDTs and developer experience
+.
+@@"For an app developer, how does the use of a CRDT-based data layer compare to existing storage layers like a SQL database, a filesystem, or CoreData? Is a distributed system harder to write software for?
+.
+@YES.
+.
+% FIXME: link
+See "A Note on Distributed Computing"
+
+---
+## Conclusion
+.
+Why this is a "paper I love": it took offline-first and ran with it.
+.
+But a pinch of CRDT won't make the world local-first.
+.
+The tricky part is the end of the sentence: "in spite of the Cloud".
+
+---
+## References
+.
+% FIXME: links
+1. "Local-First Software: You Own Your Data, in spite of the Cloud", by M. Kleppmann, A. Wiggins, P. Van Hardenberg and M. F. McGranaghan
+2. The Morning Paper article
+3. "A Note on Distributed Compiting", by J. Waldo, G. Wyant, A. Wollrath and S. Kendall
+4. these slides: euandre.org/slide/
+5. prose version of this presentation
+6. view source
diff --git a/v2/src/content/en/slide/rollouts.ps b/v2/src/content/en/slide/rollouts.ps
new file mode 100644
index 0000000..0a8b39f
--- /dev/null
+++ b/v2/src/content/en/slide/rollouts.ps
@@ -0,0 +1,500 @@
+%!PS-Adobe-3.0
+%%DocumentMedia: SLIDE 842 595 0 () ()
+%%EndComments
+%%BeginDefaults
+%%PageMedia: SLIDE
+%%EndDefaults
+<< /PageSize [842 595] /ImagingBBox null >> setpagedevice
+
+/reencode {
+ exch
+ findfont
+ dup length dict
+ begin
+ {
+ 1 index /FID ne
+ { def }
+ { pop pop }
+ ifelse
+ } forall
+ /Encoding ISOLatin1Encoding def
+ currentdict
+ end
+ definefont pop
+} def
+/Times /Times reencode
+/Courier /Courier reencode
+/Times-Italic /Times-Italic reencode
+/Helvetica /Helvetica reencode
+
+
+/headerheight 75 def
+
+/frontfontsz 60 def
+/authorfontsz 40 def
+/titlefontsz 40 def
+/mainfontsz 30 def
+/codefontsz 18 def
+/tinyfontsz 18 def
+
+/titlefont /Helvetica findfont titlefontsz scalefont def
+/mainfont /Courier findfont mainfontsz scalefont def
+/codefont /Courier findfont codefontsz scalefont def
+/tinyfont /Times findfont tinyfontsz scalefont def
+/frontfont /Helvetica findfont frontfontsz scalefont def
+/authorfont /Times-Italic findfont authorfontsz scalefont def
+/authorfonttwo /Times findfont authorfontsz scalefont def
+
+
+/pagewidth 842 def
+/pageheight 595 def
+/leftmargin 30 def
+/topmargin 595 def
+
+/pad 10 def
+
+/titlefonth titlefontsz pad add def
+/mainfonth mainfontsz pad add def
+/codefonth codefontsz pad add def
+/tinyfonth tinyfontsz pad add def
+/frontfonth frontfontsz pad add def
+/authorfonth authorfontsz pad add def
+
+/headermargin
+ pageheight headerheight titlefonth sub 2 div titlefontsz add sub
+def
+/rightmargin pagewidth leftmargin sub def
+/tbtop topmargin def
+/ypos topmargin def
+
+/xcur { currentpoint pop } def
+/ycur { currentpoint exch pop } def
+
+/wordbreak ( ) def
+/linewrap {
+ /proc exch def
+ /linelength exch def
+ /textstring exch def
+ /breakwidth wordbreak stringwidth pop def
+ /curwidth 0 def
+ /lastwordbreak 0 def
+ /startchar 0 def
+ /restoftext textstring def
+ {
+ restoftext wordbreak search
+ {
+ /nextword exch def pop
+ /restoftext exch def
+ /wordwidth nextword stringwidth pop def
+ curwidth wordwidth add linelength gt
+ {
+ textstring startchar
+ lastwordbreak startchar sub
+ getinterval proc
+ /startchar lastwordbreak def
+ /curwidth wordwidth breakwidth add def
+ }
+ {
+ /curwidth curwidth wordwidth add
+ breakwidth add def
+ } ifelse
+ /lastwordbreak lastwordbreak
+ nextword length add 1 add def
+ }
+ {
+ pop exit
+ } ifelse
+ } loop
+ /lastchar textstring length def
+ textstring startchar lastchar startchar sub
+ getinterval proc
+} def
+
+/line {
+ 0 0 0 setrgbcolor
+ 0.5 setlinewidth
+ leftmargin ypos moveto
+ rightmargin ypos lineto
+ stroke
+} def
+
+/center {
+ dup
+ /str exch def
+ /sw str stringwidth pop def
+ /xpos pagewidth sw sub 2 div xcur sub def
+ xpos 0 rmoveto
+} def
+
+/objcenter {
+ pagewidth exch sub 2 div 0 translate
+} def
+
+/s {
+ /tbtop topmargin def
+ /ypos topmargin def
+ 1 1 1 setrgbcolor
+ 0 setlinewidth
+ newpath
+ 0 pageheight moveto
+ pagewidth pageheight lineto
+ pagewidth 0 lineto
+ 0 0 lineto
+ closepath
+ fill
+ stroke
+} def
+
+/l {
+ /h exch def
+ /ypos ypos h sub def
+ leftmargin ypos moveto
+} def
+
+/title {
+ frontfonth l
+ frontfont setfont
+ 0.5 0.5 0.9 setrgbcolor
+ { pagewidth leftmargin 2 mul sub }
+ { frontfonth l center show }
+ linewrap
+ frontfonth 2 div l
+ frontfonth l
+} def
+
+/author {
+ authorfont setfont
+ 0 0 0 setrgbcolor
+ { pagewidth leftmargin 2 mul sub }
+ { authorfonth l center show }
+ linewrap
+} def
+
+/authortwo {
+ authorfonttwo setfont
+ 0 0 0 setrgbcolor
+ { pagewidth leftmargin 2 mul sub }
+ { authorfonth l center show }
+ linewrap
+} def
+
+/header {
+ /ypos pageheight headerheight sub def
+ 0 0 0 setrgbcolor
+ 0 setlinewidth
+ newpath
+ 0 pageheight moveto
+ pagewidth pageheight lineto
+ pagewidth ypos lineto
+ 0 ypos lineto
+ closepath
+ fill
+ stroke
+ leftmargin headermargin moveto
+ titlefont setfont
+ 0.5 0.5 0.9 setrgbcolor
+ center show
+ leftmargin ypos moveto
+} def
+
+/n {
+ mainfont setfont
+ 0 0 0 setrgbcolor
+ { pagewidth leftmargin 2 mul sub }
+ { mainfonth l show }
+ linewrap
+} def
+
+/cn {
+ codefont setfont
+ 0 0 0 setrgbcolor
+ { pagewidth leftmargin 2 mul sub }
+ { codefonth l show }
+ linewrap
+} def
+
+/tn {
+ tinyfont setfont
+ 0 0 0 setrgbcolor
+ { pagewidth leftmargin 2 mul sub }
+ { tinyfonth l show }
+ linewrap
+} def
+
+/is {
+ /level1 save def
+ /showpage {} def
+} def
+
+/ie {
+ level1 restore
+} def
+
+/bs {
+ /tbtop ypos def
+} def
+
+/be {
+ /tm tbtop pad sub def
+ /bm ypos pad sub def
+ newpath
+ leftmargin 10 sub tm moveto
+ rightmargin tm lineto
+ rightmargin bm lineto
+ leftmargin 10 sub bm lineto
+ closepath
+ 0 0 0 setrgbcolor
+ 0.5 setlinewidth
+ stroke
+} def
+showpage
+%%Page: 1 1
+s
+( Rollout, feature flag, experiment, operational toggle) title
+(Different use cases for backend, frontend and mobile ) authortwo
+showpage
+%%Page: 2 2
+s
+() n
+() n
+() n
+( "Feature flags" tend to come up when talking about continuous deployment) title
+showpage
+%%Page: 3 3
+s
+() n
+() n
+() n
+() n
+(CI: continuous integration) authortwo
+() n
+(CD: continuous delivery) authortwo
+() n
+(CD: continuous deployment) authortwo
+showpage
+%%Page: 4 4
+s
+( Types) header
+() n
+() n
+() n
+(1. rollout) n
+(2. feature flag) n
+(3. experiment) n
+(4. operational toggle) n
+showpage
+%%Page: 5 5
+s
+( Rollout) header
+( For *rolling out* a new version of software) title
+(Short-lived using percentages) n
+(- a new deployment of kubernetes) n
+(- new APK released to the Play Store) n
+showpage
+%%Page: 6 6
+s
+( Feature flag) header
+( For turning a feature *on* or *off* ) title
+(Medium-lived using allow list, A/B test, percentage, app version, etc.) n
+(- :new-chargeback-flow) n
+(- :new-debit-card-activation-screen) n
+showpage
+%%Page: 7 7
+s
+( Experiment) header
+( For analysing behaviour) title
+(Medium-lived using allow list and A/B test) n
+(- :debit-withdrawal-test) n
+showpage
+%%Page: 8 8
+s
+( Operational toggle) header
+( For disabling features in #crash-like situations) title
+(Long-lived using percentage) n
+(- :bank-barcode-payment) n
+(- :savings-bank-barcode-query-provider) n
+showpage
+%%Page: 9 9
+s
+() n
+() n
+(We know know about the types) authortwo
+( But they have different relevance for backend, frontend and mobile) title
+showpage
+%%Page: 10 10
+s
+( backend) header
+() n
+() n
+(1. rollout: k8s blue/green, canary and ~common-rollout~ common-xp) n
+(2. feature flag: ~common-rollout~ common-xp and datasets) n
+(3. experiment: common-xp) n
+(4. operational toggle: ~common-rollout~ common-xp ) n
+showpage
+%%Page: 11 11
+s
+( frontend) header
+() n
+() n
+(1. rollout: CDN and page refreshes) n
+(2. feature flag: percentages and maybe IPs \(no :customer/id on the website\)) n
+(3. experiment: via dynamic backend control) n
+(4. operational toggle: via dynamic backend control ) n
+showpage
+%%Page: 12 12
+s
+( backend) header
+() n
+() n
+(1. rollout: app stores) n
+(2. feature flag: via dynamic backend control) n
+(3. experiment: via dynamic backend control) n
+(4. operational toggle: via dynamic backend control ) n
+showpage
+%%Page: 13 13
+s
+() n
+() n
+(Key differentiator is) authortwo
+( how much *control* we have over the environment) title
+showpage
+%%Page: 14 14
+s
+( backend) header
+( full control) title
+showpage
+%%Page: 15 15
+s
+( frontend) header
+( partial control) title
+(We choose when to make a new version available ) n
+showpage
+%%Page: 16 16
+s
+( mobile) header
+( very limited control) title
+(- app stores can restrict updates \(worse for iOS\)) n
+(- customers still have to download new versions ) n
+showpage
+%%Page: 17 17
+s
+( Costs) title
+(- more complex code) n
+(- compatibility with old app versions) n
+(- nesting is exponential) n
+showpage
+%%Page: 18 18
+s
+( Benefits) title
+(- dynamicity) n
+showpage
+%%Page: 19 19
+s
+( weighting costs × benefits) header
+( The less control we have, the more we value dynamicity ) title
+showpage
+%%Page: 20 20
+s
+( weighting costs × benefits) header
+() n
+() n
+() n
+(- backend: sometimes worth the cost) n
+(- frontend: almost always worth the cost) n
+(- mobile: *always* worth the cost) n
+showpage
+%%Page: 21 21
+s
+() n
+() n
+() n
+( Best practices) title
+showpage
+%%Page: 22 22
+s
+( dynamic content > feature flag) title
+(Always true for mobile, almost always for frontend ) n
+showpage
+%%Page: 23 23
+s
+( Use :include-list for named groups ) title
+(Always true for backend, frontend and mobile ) n
+bs
+({:rules) cn
+( #{{:types :include-list) cn
+( :content {:filename "debit-team-members.txt"}}}}) cn
+be
+showpage
+%%Page: 24 24
+s
+( Always use :app-version) title
+(Only for mobile) n
+bs
+({:rules) cn
+( #{{:types :app-version) cn
+( :content {:min-version #{{:platform :android) cn
+( :code 1000000}) cn
+( {:platform :ios) cn
+( :code 2000000}}}}}}) cn
+be
+showpage
+%%Page: 25 25
+s
+( Extend ~common-rollout~ common-xp if required) title
+(That's how :include-list, :app-version, etc. were born) n
+showpage
+%%Page: 26 26
+s
+( Beware of many nested feature flags) title
+(True for backend, frontend and mobile) n
+showpage
+%%Page: 27 27
+s
+( Don't delete app-facing feature flags) title
+(True for mobile) n
+showpage
+%%Page: 28 28
+s
+() n
+() n
+() n
+( Include a feature flag on the whiteboarding phase) title
+showpage
+%%Page: 29 29
+s
+() n
+() n
+() n
+( Include deleting/retiring the feature flag at the end) title
+showpage
+%%Page: 30 30
+s
+( Avoid renaming a feature flag) title
+(Use :app-version with :min-version instead) n
+showpage
+%%Page: 31 31
+s
+() n
+() n
+() n
+( And most importantly...) title
+showpage
+%%Page: 32 32
+s
+( *Always* rely on a feature flag on the app) title
+(Never do a hotfix, avoid expedited releases at all costs) n
+showpage
+%%Page: 33 33
+s
+( References) header
+() n
+(1. "Feature Toggles \(aka Feature Flags\)", by Pete Hodgson) n
+(2. "Continuous integration vs. delivery vs. deployment", by Sten Pittet) n
+(3. Accelerate, by N. Forsgren, J. Humble and G. Kim) n
+(4. these slides: euandre.org/slide/) n
+(5. prose version of this presentation) n
+(6. view source) n
+
+showpage
+
+%%EOF
diff --git a/v2/src/content/en/slide/rollouts.slides b/v2/src/content/en/slide/rollouts.slides
new file mode 100644
index 0000000..aed745e
--- /dev/null
+++ b/v2/src/content/en/slide/rollouts.slides
@@ -0,0 +1,208 @@
+---
+# Rollout, feature flag, experiment, operational toggle
+
+@Different use cases for backend, frontend and mobile
+
+---
+...
+# "Feature flags" tend to come up when talking about continuous deployment
+
+---
+....
+@CI: continuous integration
+.
+@CD: continuous delivery
+.
+@CD: continuous deployment
+
+---
+## Types
+...
+1. rollout
+2. feature flag
+3. experiment
+4. operational toggle
+
+% {favicon.svg}
+---
+## Rollout
+
+# For *rolling out* a new version of software
+
+Short-lived using percentages
+
+% FIXME: links
+- a new deployment of kubernetes
+- new APK released to the Play Store
+
+---
+## Feature flag
+
+# For turning a feature *on* or *off*
+
+Medium-lived using allow list, A/B test, percentage, app version, etc.
+
+- :new-chargeback-flow
+- :new-debit-card-activation-screen
+
+---
+## Experiment
+
+# For analysing behaviour
+
+Medium-lived using allow list and A/B test
+
+- :debit-withdrawal-test
+
+---
+## Operational toggle
+
+# For disabling features in #crash-like situations
+
+Long-lived using percentage
+
+- :bank-barcode-payment
+- :savings-bank-barcode-query-provider
+
+---
+..
+@We know know about the types
+# But they have different relevance for backend, frontend and mobile
+
+---
+## backend
+..
+1. rollout: k8s blue/green, canary and ~common-rollout~ common-xp
+2. feature flag: ~common-rollout~ common-xp and datasets
+3. experiment: common-xp
+4. operational toggle: ~common-rollout~ common-xp
+
+---
+## frontend
+..
+1. rollout: CDN and page refreshes
+2. feature flag: percentages and maybe IPs (no :customer/id on the website)
+3. experiment: via dynamic backend control
+4. operational toggle: via dynamic backend control
+
+---
+## backend
+..
+1. rollout: app stores
+2. feature flag: via dynamic backend control
+3. experiment: via dynamic backend control
+4. operational toggle: via dynamic backend control
+
+---
+..
+@Key differentiator is
+# how much *control* we have over the environment
+
+---
+## backend
+# full control
+% FIXME: emoji
+% 🎉
+
+---
+## frontend
+# partial control
+We choose when to make a new version available
+
+---
+## mobile
+# very limited control
+- app stores can restrict updates (worse for iOS)
+- customers still have to download new versions
+
+---
+# Costs
+- more complex code
+- compatibility with old app versions
+- nesting is exponential
+
+---
+# Benefits
+- dynamicity
+
+---
+## weighting costs × benefits
+# The less control we have, the more we value dynamicity
+
+---
+## weighting costs × benefits
+...
+- backend: sometimes worth the cost
+- frontend: almost always worth the cost
+- mobile: *always* worth the cost
+
+---
+...
+# Best practices
+
+---
+# dynamic content > feature flag
+Always true for mobile, almost always for frontend
+
+---
+# Use :include-list for named groups
+Always true for backend, frontend and mobile
+
+ {:rules
+ #{{:types :include-list
+ :content {:filename "debit-team-members.txt"}}}}
+
+---
+# Always use :app-version
+Only for mobile
+
+ {:rules
+ #{{:types :app-version
+ :content {:min-version #{{:platform :android
+ :code 1000000}
+ {:platform :ios
+ :code 2000000}}}}}}
+
+---
+# Extend ~common-rollout~ common-xp if required
+
+That's how :include-list, :app-version, etc. were born
+
+---
+# Beware of many nested feature flags
+True for backend, frontend and mobile
+
+---
+# Don't delete app-facing feature flags
+True for mobile
+
+---
+...
+# Include a feature flag on the whiteboarding phase
+
+---
+...
+# Include deleting/retiring the feature flag at the end
+
+---
+# Avoid renaming a feature flag
+Use :app-version with :min-version instead
+
+---
+...
+# And most importantly...
+
+---
+# *Always* rely on a feature flag on the app
+Never do a hotfix, avoid expedited releases at all costs
+
+---
+## References
+.
+% FIXME: links
+1. "Feature Toggles (aka Feature Flags)", by Pete Hodgson
+2. "Continuous integration vs. delivery vs. deployment", by Sten Pittet
+3. Accelerate, by N. Forsgren, J. Humble and G. Kim
+4. these slides: euandre.org/slide/
+5. prose version of this presentation
+6. view source
diff --git a/v2/src/lib/base.en.conf b/v2/src/lib/base.en.conf
index ba0200b..144f0a0 100644
--- a/v2/src/lib/base.en.conf
+++ b/v2/src/lib/base.en.conf
@@ -48,3 +48,14 @@ export index_category_til_title='TIL by category'
export index_til_url="$(url-for "$lang/$(coll2path "$lang" til)")"
export feed_til_title="EuAndreh's TIL"
+
+
+export index_slide_title='Slides'
+
+export index_recent_slide_title='Slides listing'
+
+export index_category_slide_title='Slides by category'
+
+export index_slide_url="$(url-for "$lang/$(coll2path "$lang" slide)")"
+
+export feed_slide_title="EuAndreh's slides"
diff --git a/v2/src/lib/base.pt.conf b/v2/src/lib/base.pt.conf
index 502aa1d..cb071c8 100644
--- a/v2/src/lib/base.pt.conf
+++ b/v2/src/lib/base.pt.conf
@@ -48,3 +48,14 @@ export index_category_til_title='HEA por categoria'
export index_til_url="$(url-for "$lang/$(coll2path "$lang" til)")"
export feed_til_title="HEA do EuAndreh"
+
+
+export index_slide_title='Slides'
+
+export index_recent_slide_title='Slides listing'
+
+export index_category_slide_title='Slides by category'
+
+export index_slide_url="$(url-for "$lang/$(coll2path "$lang" slide)")"
+
+export feed_slide_title="EuAndreh's slides"
diff --git a/v2/src/lib/commencement.en.conf b/v2/src/lib/commencement.en.conf
index 9b19b18..70978a2 100644
--- a/v2/src/lib/commencement.en.conf
+++ b/v2/src/lib/commencement.en.conf
@@ -5,3 +5,5 @@ export article_collection_name=''
export pastebin_collection_name='pastebin'
export til_collection_name='til'
+
+export slide_collection_name='slide'
diff --git a/v2/src/lib/commencement.pt.conf b/v2/src/lib/commencement.pt.conf
index e3b9544..ba6693c 100644
--- a/v2/src/lib/commencement.pt.conf
+++ b/v2/src/lib/commencement.pt.conf
@@ -5,3 +5,5 @@ export article_collection_name=''
export pastebin_collection_name='pastebin'
export til_collection_name='hea'
+
+export slide_collection_name='slide'