]> Dogcows Code - chaz/talk-level-up-your-perl/commitdiff
initial commit
authorCharles McGarvey <cmcgarvey@bluehost.com>
Fri, 8 Jun 2018 05:35:40 +0000 (23:35 -0600)
committerCharles McGarvey <cmcgarvey@bluehost.com>
Fri, 8 Jun 2018 05:35:40 +0000 (23:35 -0600)
17 files changed:
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
README.md [new file with mode: 0644]
abstract.txt [new file with mode: 0644]
css/common.css [new file with mode: 0644]
css/slides.css [new file with mode: 0644]
img/camelia.png [new file with mode: 0644]
img/cover.png [new file with mode: 0644]
img/endurance.png [new file with mode: 0644]
img/nytprof.png [new file with mode: 0644]
img/raptor.png [new file with mode: 0644]
img/regexp_debugger.png [new file with mode: 0644]
img/talkqr.svg [new file with mode: 0644]
js/common.js [new file with mode: 0644]
js/slides.js [new file with mode: 0644]
notes.txt [new file with mode: 0644]
slides.html [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..846365e
--- /dev/null
@@ -0,0 +1,3 @@
+/img/basic-flow*svg
+/remark.min.js
+/slides-offline.html
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..d42558c
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,38 @@
+
+SLIDES  = level-up-your-perl
+BROWSER = google-chrome
+DOT     = dot
+
+dotfiles = $(shell find . -iname '*.dot')
+svgfiles = $(patsubst %.dot,%.svg,$(dotfiles))
+
+all: offline
+
+clean:
+       rm -f slides-offline.html remark.min.js $(SLIDES).pdf $(svgfiles)
+
+offline: slides-offline.html remark.min.js $(svgfiles)
+
+pdf: $(SLIDES).pdf
+
+run: $(svgfiles)
+       $(BROWSER) slides.html
+
+run-offline: offline
+       $(BROWSER) slides-offline.html
+
+%.svg: %.dot
+       $(DOT) -Tsvg -o$@ $<
+
+$(SLIDES).pdf: slides.html $(wildcard css/*) $(wildcard img/*) $(svgfiles)
+       docker run --rm -v `pwd`:/pwd astefanutti/decktape /pwd/slides.html /pwd/$(SLIDES).pdf
+
+slides-offline.html: slides.html
+       sed -e '1 a <!-- This file is auto-generated - DO NOT EDIT!!! -->' \
+           -e 's!https://.*remark-latest\.min\.js!remark.min.js!' <$< >$@
+
+remark.min.js:
+       curl -Lo $@ https://gnab.github.io/remark/downloads/remark-latest.min.js
+
+.PHONY: all clean offline pdf run run-offline
+
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..d831e75
--- /dev/null
+++ b/README.md
@@ -0,0 +1,18 @@
+
+# Slides for "Level up your Perl"
+
+This directory contains the slides for my talk entitled "Level up your Perl".
+
+The slides were written in [Markdown](https://daringfireball.net/projects/markdown/) format and can be rendered with
+[remark](http://remarkjs.com/).
+
+## Options
+
+To view the slides:
+
+    make run
+
+To build a PDF version of the slides:
+
+    make pdf
+
diff --git a/abstract.txt b/abstract.txt
new file mode 100644 (file)
index 0000000..8540c90
--- /dev/null
@@ -0,0 +1,17 @@
+
+# Level up your Perl
+
+We're all at different places along our path toward ultimate Perl Mastery,
+which is of course the end goal of any devoted Perl hacker. Some of us are
+just beginning and find ourselves facing the perplexities of sigils. Others
+are further along the path, now trying to wrap their heads around contexts.
+And then, once you think you're feeling pretty okay with Perl... bam! Regular
+expressions.
+
+Yeah, there's a lot to learn. But the journey is fun!
+
+In this talk, I'll present a list of various tips, tricks, modules,
+techniques, whatever that have helped me level up my Perl.
+
+You'll get the most out of this talk if you know at least some Perl or at
+least are curious about some of the crazy stuff Perl hackers come up with.
diff --git a/css/common.css b/css/common.css
new file mode 100644 (file)
index 0000000..5fe4e74
--- /dev/null
@@ -0,0 +1,93 @@
+@import url(https://fonts.googleapis.com/css?family=Open+Sans);
+@import url(https://fonts.googleapis.com/css?family=Muli);
+@import url(https://fonts.googleapis.com/css?family=Inconsolata);
+
+.remark-slide-content {
+    font-family: 'Open Sans';
+    font-size: 22px;
+}
+
+.remark-slide-content h1,
+.remark-slide-content h2,
+.remark-slide-content h3 {
+    font-family: Muli;
+    font-weight: bold;
+}
+.remark-slide-content h2 {
+    font-size: 40px;
+}
+.remark-slide-content h3 {
+    font-size: 30px;
+}
+
+.remark-slide-content li {
+    line-height: 2em;
+}
+.remark-slide-content .condensed li {
+    line-height: 1em;
+}
+
+.remark-code, .remark-inline-code {
+    font-family: Inconsolata, monospace;
+}
+.remark-code {
+    border-radius: 5px;
+    border: 1px solid #ccc;
+}
+
+.remark-slide-content blockquote {
+    border-radius: 5px;
+    border: 1px solid #ccc;
+    background: #f0f0f0;
+    margin: 1.5em 0;
+    padding: 1em;
+    quotes: "\201C""\201D""\2018""\2019";
+    position: relative;
+}
+.remark-slide-content blockquote:before {
+    color: #ccc;
+    position: absolute;
+    content: open-quote;
+    font-size: 6em;
+    line-height: 0.1em;
+    margin-right: 0.25em;
+    vertical-align: -0.4em;
+}
+
+.remark-slide-content .col {
+    box-sizing: border-box;
+    display: block;
+    float: left;
+    border: 0;
+    margin: 0;
+    padding: 0;
+    width: 50%;
+}
+.remark-slide-content .col:nth-of-type(odd) {
+    padding: 0 1em 0 0;
+}
+.remark-slide-content .col:nth-of-type(even) {
+    padding: 0 0 0 1em;
+}
+.remark-slide-content .col.sep:nth-of-type(odd) {
+    border-right: 1px solid #ccc;
+}
+.remark-slide-content .col.sep:nth-of-type(even) {
+    border-left: 1px solid #ccc;
+}
+
+/* fix non-collapsing margin */
+.remark-slide-content .marginfix h3,
+.remark-slide-content .marginfix ul {
+    margin-top: 0;
+}
+
+.remark-slide-content .top-right {
+    float: right;
+    margin: 50px 0 0 2em;
+}
+
+.remark-slide-content .highlight {
+    color: #7d9726;
+}
+
diff --git a/css/slides.css b/css/slides.css
new file mode 100644 (file)
index 0000000..2c8f3ca
--- /dev/null
@@ -0,0 +1,107 @@
+
+#slide-endurance img {
+    width: 400px;
+}
+
+#slide-last .talkqr img {
+    display: inline-block;
+    width: 230px;
+    height: 230px;
+}
+
+.ex-deparse .bash {
+    font-size: 36px;
+}
+
+.ex-vimcheck .bash {
+    font-size: 32px;
+}
+
+.ex-vim .perl {
+    font-size: 26px;
+}
+
+.ex-shellpod .bash {
+    font-size: 22px;
+}
+
+.ex-boilerplate .perl {
+    font-size: 26px;
+}
+.ex-boilerplate2 .perl {
+    font-size: 20px;
+}
+.ex-boilerplate .ini {
+    font-size: 32px;
+}
+
+.ex-regexpdebugger .perl {
+    font-size: 32px;
+}
+.regexpdebugger-commands pre {
+    border-radius: 5px;
+    border: 1px solid #ccc;
+    font-size: 20px;
+}
+
+#slide-damian img {
+    width: 400px;
+}
+
+.ex-perl6 .perl {
+    font-size: 32px;
+}
+
+.ex-context .perl {
+    font-size: 32px;
+}
+.ex-context2 .perl {
+    font-size: 28px;
+}
+
+.ex-phases .perl {
+    font-size: 32px;
+}
+
+.ex-obfuscated .perl {
+    font-size: 24px;
+}
+.ex-terse .perl {
+    font-size: 24px;
+}
+
+.ex-asyncawait .perl {
+    font-size: 32px;
+}
+
+.ex-owndebugger1 .bash {
+    font-size: 42px;
+}
+.ex-owndebugger2 .perl {
+    font-size: 32px;
+}
+.ex-owndebugger2 .bash {
+    font-size: 28px;
+}
+
+.ex-develtrace img {
+    width:720px;
+}
+.ex-develtrace .cover-img img {
+    width:480px;
+}
+.ex-develtrace .bash {
+    font-size: 32px;
+}
+
+.ex-debugger .bash {
+    font-size: 32px;
+}
+
+.ex-newfeatures .perl {
+    font-size: 22px;
+}
+.ex-moo .perl {
+    font-size: 29px;
+}
+
diff --git a/img/camelia.png b/img/camelia.png
new file mode 100644 (file)
index 0000000..a239a74
Binary files /dev/null and b/img/camelia.png differ
diff --git a/img/cover.png b/img/cover.png
new file mode 100644 (file)
index 0000000..b89db83
Binary files /dev/null and b/img/cover.png differ
diff --git a/img/endurance.png b/img/endurance.png
new file mode 100644 (file)
index 0000000..6ca90ec
Binary files /dev/null and b/img/endurance.png differ
diff --git a/img/nytprof.png b/img/nytprof.png
new file mode 100644 (file)
index 0000000..2c4c109
Binary files /dev/null and b/img/nytprof.png differ
diff --git a/img/raptor.png b/img/raptor.png
new file mode 100644 (file)
index 0000000..d4209da
Binary files /dev/null and b/img/raptor.png differ
diff --git a/img/regexp_debugger.png b/img/regexp_debugger.png
new file mode 100644 (file)
index 0000000..66c613e
Binary files /dev/null and b/img/regexp_debugger.png differ
diff --git a/img/talkqr.svg b/img/talkqr.svg
new file mode 100644 (file)
index 0000000..c6fec7b
--- /dev/null
@@ -0,0 +1,335 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.1" baseProfile="tiny" xmlns="http://www.w3.org/2000/svg" width="200" height="200">
+<rect shape-rendering="optimizeSpeed"  x="0" y="0" width="200" height="200" fill="white" />
+<rect shape-rendering="optimizeSpeed"  x="12" y="12" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="19" y="12" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="26" y="12" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="33" y="12" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="40" y="12" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="47" y="12" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="54" y="12" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="68" y="12" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="82" y="12" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="96" y="12" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="110" y="12" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="124" y="12" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="138" y="12" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="145" y="12" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="152" y="12" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="159" y="12" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="166" y="12" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="173" y="12" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="180" y="12" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="12" y="19" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="54" y="19" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="75" y="19" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="82" y="19" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="89" y="19" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="96" y="19" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="124" y="19" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="138" y="19" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="180" y="19" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="12" y="26" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="26" y="26" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="33" y="26" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="40" y="26" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="54" y="26" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="68" y="26" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="75" y="26" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="82" y="26" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="103" y="26" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="117" y="26" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="138" y="26" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="152" y="26" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="159" y="26" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="166" y="26" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="180" y="26" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="12" y="33" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="26" y="33" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="33" y="33" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="40" y="33" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="54" y="33" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="68" y="33" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="75" y="33" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="82" y="33" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="96" y="33" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="103" y="33" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="110" y="33" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="138" y="33" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="152" y="33" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="159" y="33" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="166" y="33" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="180" y="33" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="12" y="40" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="26" y="40" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="33" y="40" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="40" y="40" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="54" y="40" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="68" y="40" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="89" y="40" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="96" y="40" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="110" y="40" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="117" y="40" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="138" y="40" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="152" y="40" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="159" y="40" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="166" y="40" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="180" y="40" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="12" y="47" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="54" y="47" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="82" y="47" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="89" y="47" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="103" y="47" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="124" y="47" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="138" y="47" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="180" y="47" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="12" y="54" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="19" y="54" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="26" y="54" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="33" y="54" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="40" y="54" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="47" y="54" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="54" y="54" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="68" y="54" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="82" y="54" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="96" y="54" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="110" y="54" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="124" y="54" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="138" y="54" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="145" y="54" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="152" y="54" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="159" y="54" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="166" y="54" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="173" y="54" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="180" y="54" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="82" y="61" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="96" y="61" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="117" y="61" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="124" y="61" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="12" y="68" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="19" y="68" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="26" y="68" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="33" y="68" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="54" y="68" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="68" y="68" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="82" y="68" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="89" y="68" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="110" y="68" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="117" y="68" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="124" y="68" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="131" y="68" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="152" y="68" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="159" y="68" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="166" y="68" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="180" y="68" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="19" y="75" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="26" y="75" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="33" y="75" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="61" y="75" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="68" y="75" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="82" y="75" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="96" y="75" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="103" y="75" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="124" y="75" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="145" y="75" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="173" y="75" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="12" y="82" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="19" y="82" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="33" y="82" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="40" y="82" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="47" y="82" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="54" y="82" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="61" y="82" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="68" y="82" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="75" y="82" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="82" y="82" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="89" y="82" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="96" y="82" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="124" y="82" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="138" y="82" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="26" y="89" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="40" y="89" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="61" y="89" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="68" y="89" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="75" y="89" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="82" y="89" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="96" y="89" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="103" y="89" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="124" y="89" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="131" y="89" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="138" y="89" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="145" y="89" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="152" y="89" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="159" y="89" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="166" y="89" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="19" y="96" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="26" y="96" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="33" y="96" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="40" y="96" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="47" y="96" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="54" y="96" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="68" y="96" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="75" y="96" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="82" y="96" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="103" y="96" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="110" y="96" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="131" y="96" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="138" y="96" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="152" y="96" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="166" y="96" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="173" y="96" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="180" y="96" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="103" y="103" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="110" y="103" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="117" y="103" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="124" y="103" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="131" y="103" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="138" y="103" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="145" y="103" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="152" y="103" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="180" y="103" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="19" y="110" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="33" y="110" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="54" y="110" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="96" y="110" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="124" y="110" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="138" y="110" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="152" y="110" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="166" y="110" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="173" y="110" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="12" y="117" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="26" y="117" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="33" y="117" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="40" y="117" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="68" y="117" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="75" y="117" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="110" y="117" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="124" y="117" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="131" y="117" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="138" y="117" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="145" y="117" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="152" y="117" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="180" y="117" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="33" y="124" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="47" y="124" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="54" y="124" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="61" y="124" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="89" y="124" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="96" y="124" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="103" y="124" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="110" y="124" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="117" y="124" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="124" y="124" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="131" y="124" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="138" y="124" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="145" y="124" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="152" y="124" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="159" y="124" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="166" y="124" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="173" y="124" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="180" y="124" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="68" y="131" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="75" y="131" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="82" y="131" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="89" y="131" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="124" y="131" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="152" y="131" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="166" y="131" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="180" y="131" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="12" y="138" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="19" y="138" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="26" y="138" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="33" y="138" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="40" y="138" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="47" y="138" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="54" y="138" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="82" y="138" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="103" y="138" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="110" y="138" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="124" y="138" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="138" y="138" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="152" y="138" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="166" y="138" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="173" y="138" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="180" y="138" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="12" y="145" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="54" y="145" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="82" y="145" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="89" y="145" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="124" y="145" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="152" y="145" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="180" y="145" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="12" y="152" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="26" y="152" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="33" y="152" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="40" y="152" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="54" y="152" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="75" y="152" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="89" y="152" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="96" y="152" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="124" y="152" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="131" y="152" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="138" y="152" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="145" y="152" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="152" y="152" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="159" y="152" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="180" y="152" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="12" y="159" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="26" y="159" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="33" y="159" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="40" y="159" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="54" y="159" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="68" y="159" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="82" y="159" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="89" y="159" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="96" y="159" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="110" y="159" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="117" y="159" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="131" y="159" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="138" y="159" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="152" y="159" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="159" y="159" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="166" y="159" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="173" y="159" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="180" y="159" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="12" y="166" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="26" y="166" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="33" y="166" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="40" y="166" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="54" y="166" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="68" y="166" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="89" y="166" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="103" y="166" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="117" y="166" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="131" y="166" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="138" y="166" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="152" y="166" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="166" y="166" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="173" y="166" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="12" y="173" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="54" y="173" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="68" y="173" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="75" y="173" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="82" y="173" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="89" y="173" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="96" y="173" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="103" y="173" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="131" y="173" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="138" y="173" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="152" y="173" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="166" y="173" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="12" y="180" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="19" y="180" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="26" y="180" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="33" y="180" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="40" y="180" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="47" y="180" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="54" y="180" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="68" y="180" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="103" y="180" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="145" y="180" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="152" y="180" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="159" y="180" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="166" y="180" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="173" y="180" width="7" height="7" fill="black" />
+<rect shape-rendering="optimizeSpeed"  x="180" y="180" width="7" height="7" fill="black" /></svg>
\ No newline at end of file
diff --git a/js/common.js b/js/common.js
new file mode 100644 (file)
index 0000000..3832adb
--- /dev/null
@@ -0,0 +1,55 @@
+
+/*
+ * Create a shortcut on a number key to jump to a named slide.
+ *
+ * Using the hotkey on the target slide will go "back" to the slide that was active before jumping
+ * to the target slide.
+ *
+ * Example: Jump to the slide named "myslide" when the "1" key is pressed.
+ *   createHotkey(1, 'myslide');
+ */
+function createHotkey(key, slideName) {
+    var targetSlide = slideshow.getSlideByName(slideName);
+    var lastSlide   = -1;
+    document.addEventListener('keydown', function(e) {
+        if (e.which === key + 48) {
+            var currentNum  = slideshow.getCurrentSlideIndex() + 1;
+            var targetNum   = targetSlide.getSlideIndex() + 1;
+            if (currentNum !== targetNum) {
+                lastSlide = currentNum;
+                slideshow.gotoSlide(targetNum);
+            }
+            else {
+                slideshow.gotoSlide(lastSlide);
+            }
+        }
+    });
+};
+
+/*
+ * Set a hotkey "u" to navigate backwards in time.
+ *
+ * If you get on the wrong slide, this might be the easiest way to get back on track. This is what
+ * you might expect the browser's "Back" button to do if it worked.
+ */
+(function() {
+    var history = [];
+    var skip    = false;
+    slideshow.on('hideSlide', function(slide) {
+        if (skip) {
+            skip = false;
+            return;
+        }
+        history.push(slide.getSlideIndex() + 1);
+    });
+    document.addEventListener('keydown', function(e) {
+        if (e.which === 85 /* [u]ndo */) {
+            var lastNum = history.pop();
+            if (lastNum) {
+                skip = true;
+                slideshow.gotoSlide(lastNum);
+            }
+        }
+    });
+})();
+
diff --git a/js/slides.js b/js/slides.js
new file mode 100644 (file)
index 0000000..1ba4808
--- /dev/null
@@ -0,0 +1,7 @@
+
+createHotkey(1, 'psgi-flow1');
+createHotkey(2, 'psgi-flow2');
+createHotkey(3, 'psgi-flow3');
+createHotkey(4, 'psgi-flow4');
+createHotkey(5, 'psgi-flow5');
+
diff --git a/notes.txt b/notes.txt
new file mode 100644 (file)
index 0000000..e0f8673
--- /dev/null
+++ b/notes.txt
@@ -0,0 +1,42 @@
+
+This talk I'm going to go over things that you don't need to know if you just
+want to get by, but if you actually want to be good.
+
+Ground rules:
+- If you have a question, get my attention and ask it. Don't save it until the
+  end because the format of this talk doesn't lend itself to that.
+
+
+
+I Use CPAN.
+X Use B::Deparse. https://metacpan.org/pod/B::Deparse
+X Document your shell scripts with pod.
+X Know regular expressions.
+X Use Regexp::Debugger. https://metacpan.org/pod/Regexp::Debugger
+X Write vim plugins in Perl.
+X Understand calling context.
+X Understand execution phases.
+X Understand when to be terse and when to be verbose
+X Use Future::AsyncAwait. https://metacpan.org/pod/Future::AsyncAwait
+- Know some XS.
+- Know Unicode.
+  - https://youtu.be/TmTeXcEixEg 2016 - A Million Billion Squiggly Characters - rjbs
+  - https://stackoverflow.com/a/6163129 Best Stackoverflow answer, ever. - tchrist
+X Write your own boilerplate.
+X Write your own debugger.
+X Don't write your own debugger because there are already some awesome ones on CPAN.
+X Know the default perl debugger.
+X Write modern Perl.
+  X Use some new features (postfix dereferencing, function signatures)
+  X Moo or Moose
+  X method signatures
+X Learn Perl 6
+- Learn another language.
+  - Makes you write better Perl (maybe).
+  - Can bring some good ideas from other languages back to Perl (PSGI, async await)
+- Know software design patterns.
+
+Cool stuff:
+use aliased 'Big::Long::Package::Thing';
+my $thing = Thing->new;
+
diff --git a/slides.html b/slides.html
new file mode 100644 (file)
index 0000000..4f97d8d
--- /dev/null
@@ -0,0 +1,1737 @@
+<!DOCTYPE html>
+<html><head><meta charset="utf-8"><title>Level up your Perl</title><link rel="stylesheet" href="css/common.css"><link rel="stylesheet" href="css/slides.css"></head><body><textarea id="source">
+
+class:  center, middle
+name:   title
+
+# Level up your Perl
+
+Charles McGarvey
+
+---
+class:  center, middle
+name:   endurance
+
+![Endurance](img/endurance.png)
+
+### https://jobs.endurance.com/bluehost
+
+---
+class: center, middle
+
+![The Raptor](img/raptor.png)
+
+---
+class: center, middle
+
+## Use [`B::Deparse`](https://metacpan.org/pod/B::Deparse).
+
+???
+`B::Deparse` is a backend module for the compiler. It takes the parse tree after compiling and generates Perl code from
+it.
+
+So, why compile Perl only to turn it back into Perl?
+It is useful for checking that perl and you are both understanding the code the same way.
+
+---
+class: ex-deparse
+
+## Example: Use the `-p` flag to understand precedence
+
+```bash
+perl -MO=Deparse,-p -e'$a && not $b && not $c'
+*($a and not(($b && (!$c))));
+-e syntax OK
+```
+
+```bash
+perl -MO=Deparse,-p -e'$a && ! $b && ! $c'
+*(($a and not($b)) and not($c));
+-e syntax OK
+```
+
+???
+These example snippets demonstrate an actual bug found in real code.
+
+The first snippet is mixing high and low-precedence logical operators. Comparing the output of Deparse, it's fairly
+clear to see that these are not doing the same thing.
+
+Deparse supports other flags that may be useful. Read the pod to find out more.
+
+Aside: Be careful about mixing high and low-precedence logical operators.
+
+---
+class: ex-shellpod
+
+## Document your shell scripts with pod.
+
+```bash
+#!/bin/sh
+
+: <<'=cut'
+=head1 NAME
+
+therapist.sh - This script can save you a bunch of cash
+
+=cut
+
+echo 'Hello. Now, tell me about your problems.'
+
+while read response
+do
+    printf "Patient said: %s" "$response" >>therapist_notes.txt
+
+    echo 'And how did that make you feel?'
+done
+
+echo "Goodbye! Let's meet again in two weeks."
+```
+
+---
+class: ex-shellpod
+
+## Document your shell scripts with pod.
+
+```bash
+#!/bin/sh
+
+: <<'=cut'
+*=head1 NAME
+*
+*therapist.sh - This script can save you a bunch of cash
+*
+*=cut
+
+echo 'Hello. Now, tell me about your problems.'
+
+while read response
+do
+    printf "Patient said: %s" "$response" >>therapist_notes.txt
+
+    echo 'And how did that make you feel?'
+done
+
+echo "Goodbye! Let's meet again in two weeks."
+```
+
+???
+It's pod! In a shell script.
+
+---
+class: ex-shellpod
+
+## Document your shell scripts with pod.
+
+```bash
+#!/bin/sh
+
+*: <<'=cut'
+=head1 NAME
+
+therapist.sh - This script can save you a bunch of cash
+
+=cut
+
+echo 'Hello. Now, tell me about your problems.'
+
+while read response
+do
+    printf "Patient said: %s" "$response" >>therapist_notes.txt
+
+    echo 'And how did that make you feel?'
+done
+
+echo "Goodbye! Let's meet again in two weeks."
+```
+
+???
+This is the key right here. Anybody know what this is?
+
+It's a heredoc.
+
+The colon command in bourne shell is just noop. Sometimes you'll see the colon used as a type of comment, but unlike
+a comment the shell does parse the arguments to colon.
+
+---
+class: center, middle
+
+## Know regular expressions.
+
+???
+Like, really know them.
+
+---
+class: center, middle
+
+### It's easy.
+
+???
+All you have to do in order to read and write regular expressions *without looking at a help resource every time* is
+know the X parts of a regular expression.
+
+---
+class: center, middle
+
+### Two basic parts:
+
+# (what to match) (how many to match)
+
+???
+Regular expressions let you match strings.
+
+---
+### What to match: Literals
+
+- Match a specific character
+- `a`
+- `7`
+- `~`
+- `ÿ`
+- `\^`
+- `\t`
+
+---
+### What to match: Character classes
+
+- Match a character within a set
+- `[a-z-]`
+- `[^0-9]`
+- `[q]`
+- `\h`
+- `[[:digit:]]`
+- `.`
+- `\X`
+
+---
+### How many to match: Quantifiers
+
+- Match a certain number of the preceding single character or character class
+- `*` - zero or more
+- `+` - one or more
+- `?` - zero or one
+- `{2}`
+- `{2,}`
+
+---
+class: center, middle
+
+### That's it! Just:
+
+# (what to match) (how many to match)
+
+---
+class: center, middle
+
+## Okay, there is more...
+
+---
+### Boundaries
+
+- Look for the edges surrounding or between things
+- `^`
+- `$`
+- `\b`
+- `\b{sb}` - sentence boundary
+- `\b{gcb}`
+
+???
+I say "look for" instead of "match" because the boundary isn't something that shows up in the results.
+
+---
+### The pipe
+
+- Match this or that
+- `cat|dog`
+
+---
+### Groups
+
+- Separate the regexp into logical chunks
+- `(blah)`
+- `(?:whatever)` - noncapturing
+
+---
+### Backreferences
+
+- Match something again
+- `\1`
+- `\2`
+- etc.
+
+---
+### Lookaround
+
+- Require presence of something without actually matching it
+- `(?=regexp)` and `(?!regexp)` - lookahead
+- `(?<=regexp)` and `(?<!regexp)` - lookbehind
+
+???
+These are zero-length assertions. Like boundaries, these don't actually match anything; they just make sure something is
+or isn't present at the position where it exists relative to its surroundings.
+
+---
+class: center, middle
+
+## Use [`Regexp::Debugger`](https://metacpan.org/pod/Regexp::Debugger).
+
+---
+class: ex-regexpdebugger
+
+```perl
+use Regexp::Debugger;
+
+my $not_png_or_jpg = qr/(?<!\.(png|jpg))$/;
+my $filename = 'log.txt';
+
+$filename =~ $not_png_or_jpg;
+```
+
+---
+class: ex-regexpdebugger
+
+```perl
+*use Regexp::Debugger;
+
+my $not_png_or_jpg = qr/(?<!\.(png|jpg))$/;
+my $filename = 'log.txt';
+
+$filename =~ $not_png_or_jpg;
+```
+
+--
+![Regexp::Debugger in action](img/regexp_debugger.png)
+
+---
+class: regexpdebugger-commands
+
+## Things you can do with Regexp::Debugger
+
+--
+- The basics: step forward ("s") and backwards ("-").
+
+--
+- Hit "d" to get a detailed description of the regexp:
+
+```text
+    (?<!                  Match negative lookbehind
+      \.                    Match a literal '.' character
+      (                     The start of a capturing block ($1)
+        png                   Match a literal sequence ("png")
+      |                     Or...
+        jpg                   Match a literal sequence ("jpg")
+      )                     The end of $1
+    )                     The end of negative lookbehind
+    $                     Match only if at end of string (or final newline)
+```
+
+--
+- Try different modes, like "e" for event log.
+
+--
+- Hit "?" for help.
+
+--
+- Hit "q" to exit the debugger.
+
+---
+class: center, middle
+
+### Also, check out [PPR](https://metacpan.org/pod/PPR).
+
+???
+This module was brought to us by Damian Conway. Speaking of, if your interest in regular expressions continues, check
+out this module. `PPR` is a packaged regular expression with subpatterns that can match Perl code.
+
+Really cool stuff.
+
+---
+class: center, middle
+
+## Write Vim plugins in Perl.
+
+---
+class: center, middle
+
+### It's easy.
+
+---
+class: ex-vimcheck, center, middle
+
+### Does your Vim support Perl?
+
+```bash
+vim --version |grep +perl && echo 'Aww yeah!'
+```
+
+???
+Some minimal builds of Vim do not have Perl support compiled in.
+Check with this.
+
+---
+class: ex-vimcheck, center, middle
+
+### You'll need this...
+
+```bash
+:h usr_41
+```
+
+Chapter 41 in the Vim manual is all about scripting.
+
+---
+class: ex-vim
+
+```perl
+function! color#random()
+    let l:colorlist = globpath(&rtp, "colors/*.vim")
+    perl <<END
+my ($result, $colors) = VIM::Eval("l:colorlist");
+return if $result != 1;
+my @available_colors = split(/\n/, $colors);
+my %bad_colors = eval {
+    open(my $fh, '<', "$ENV{HOME}/.vim/color_blacklist.txt");
+    map { chomp; ($_ => 1) } <$fh>;
+};
+for (my $tries = 0; $tries < 100; ++$tries) {
+    my $colorpath = $available_colors[int(rand(@available_colors))];
+    my ($color) = $colorpath =~ m!([^/]+)\.vim!;
+    if (!$bad_colors{$color}) {
+        VIM::DoCommand("colorscheme $color");
+        last;
+    }
+}
+END
+endfunction
+```
+
+---
+class: ex-vim
+
+```perl
+*function! color#random()
+*   let l:colorlist = globpath(&rtp, "colors/*.vim")
+*   perl <<END
+my ($result, $colors) = VIM::Eval("l:colorlist");
+return if $result != 1;
+my @available_colors = split(/\n/, $colors);
+my %bad_colors = eval {
+    open(my $fh, '<', "$ENV{HOME}/.vim/color_blacklist.txt");
+    map { chomp; ($_ => 1) } <$fh>;
+};
+for (my $tries = 0; $tries < 100; ++$tries) {
+    my $colorpath = $available_colors[int(rand(@available_colors))];
+    my ($color) = $colorpath =~ m!([^/]+)\.vim!;
+    if (!$bad_colors{$color}) {
+        VIM::DoCommand("colorscheme $color");
+        last;
+    }
+}
+*END
+*endfunction
+```
+
+???
+This is Vimscript.
+
+---
+class: ex-vim
+
+```perl
+function! color#random()
+    let l:colorlist = globpath(&rtp, "colors/*.vim")
+    perl <<END
+*my ($result, $colors) = VIM::Eval("l:colorlist");
+return if $result != 1;
+my @available_colors = split(/\n/, $colors);
+my %bad_colors = eval {
+    open(my $fh, '<', "$ENV{HOME}/.vim/color_blacklist.txt");
+    map { chomp; ($_ => 1) } <$fh>;
+};
+for (my $tries = 0; $tries < 100; ++$tries) {
+    my $colorpath = $available_colors[int(rand(@available_colors))];
+    my ($color) = $colorpath =~ m!([^/]+)\.vim!;
+    if (!$bad_colors{$color}) {
+*       VIM::DoCommand("colorscheme $color");
+        last;
+    }
+}
+END
+endfunction
+```
+
+???
+By the way, Vim supports embedded interpreters for other languages like Python, Ruby, and Lua in similar fashion.
+
+---
+class: center, middle
+
+## Understand calling context.
+
+???
+- One of the baffling things about Perl5 to newcomers is that subroutines can
+ do different things based on *where* they are used. This is called context.
+
+---
+## The three main contexts:
+- Scalar
+- List
+- Void
+
+---
+## The wantarray() function
+- True if caller called in **list** context.
+- False if **scalar** context.
+- `undef` if **void** context.
+
+???
+Unfortunately this function was misnamed. It should have been "wantlist" since
+there really is no "array context."
+
+---
+class: ex-context
+
+## Example: localtime()
+
+```perl
+@time = localtime();    # -> (1, 43, 13, 7, 5, 118, 4, 157, 1)
+$time = localtime();    # -> "Thu Jun  7 13:43:01 2018"
+```
+
+---
+class: ex-context
+
+## Operators help determine context.
+
+--
+```perl
+$thing_one . $thing_two
+```
+
+???
+String concatenation is a scalar thing, so the concat operator "creates" a scalar context on either side.
+
+--
+```perl
+$income - $expenses
+```
+
+???
+Numerical and comparison operators typically operator in the same way. So that's easy.
+
+--
+### Scalar context on both sides.
+
+---
+class: ex-context
+
+## Operators help determine context.
+
+```perl
+!ready()
+```
+
+```perl
+$count++
+```
+
+### Also evaluated in scalar context.
+
+???
+- Generally the prefix and postfix operators also create scalar context.
+
+---
+class: center, middle
+
+## The assignment operator... is different.
+
+???
+What makes it different is that the assignment operator is really two different
+operators in Perl 5.
+
+---
+class: ex-context2
+
+## The scalar assignment operator
+
+```perl
+$scalar = $another_scalar;      # copy scalar on the right to the left
+```
+
+--
+```perl
+$scalar = @array;
+```
+
+---
+class: ex-context2
+
+## The scalar assignment operator
+
+```perl
+$scalar = $another_scalar;      # copy scalar on the right to the left
+```
+
+```perl
+$scalar = @array;               # $scalar => length of @array
+```
+
+---
+class: ex-context2
+
+## The scalar assignment operator
+
+```perl
+$scalar = $another_scalar;      # copy scalar on the right to the left
+```
+
+```perl
+$scalar = @array;               # $scalar => length of @array
+```
+
+```perl
+$scalar = qw(list of things);
+```
+
+---
+class: ex-context2
+
+## The scalar assignment operator
+
+```perl
+$scalar = $another_scalar;      # copy scalar on the right to the left
+```
+
+```perl
+$scalar = @array;               # $scalar => length of @array
+```
+
+```perl
+$scalar = qw(list of things);   # $scalar => "things"
+```
+
+--
+### Lists and arrays are **not** the same thing!
+
+---
+class: ex-context2
+
+## The list assignment operator
+
+```perl
+@array = @another_array;        # copy array on the right to the left
+```
+
+--
+```perl
+@array = $scalar;
+```
+
+---
+class: ex-context2
+
+## The list assignment operator
+
+```perl
+@array = @another_array;        # copy array on the right to the left
+```
+
+```perl
+@array = $scalar;               # $scalar copied; @array has one item
+```
+
+--
+```perl
+@array = qw(list of things);    # contents of list copied to @array
+```
+
+---
+class: ex-context
+
+## Subroutines determine context of their parameters.
+
+```perl
+sub i_can_haz_scalar :prototype($) {
+    say @_;
+}
+
+my @arr = qw(foo bar baz);
+*i_can_haz_scalar(@arr);
+```
+
+???
+Not only can subroutines branch and do different things based on the context
+that calls them -- based on `wantarray()` -- they also control the context of
+their parameters.
+
+---
+class: ex-context
+
+## Subroutines determine context of their parameters.
+
+```perl
+sub i_can_haz_scalar :prototype($) {
+    say @_;
+}
+
+my @arr = qw(foo bar baz);
+*i_can_haz_scalar(@arr);         # => 3
+```
+
+---
+class: ex-context
+
+## Subroutines determine context of their parameters.
+
+```perl
+sub i_can_haz_scalar :prototype($) {
+    say @_;
+}
+
+*i_can_haz_scalar(qw{2 4 6 8});
+```
+
+---
+class: ex-context
+
+## Subroutines determine context of their parameters.
+
+```perl
+sub i_can_haz_scalar :prototype($) {
+    say @_;
+}
+
+*i_can_haz_scalar(qw{2 4 6 8});  # => 8
+```
+
+???
+Remember: Arrays and lists are no the same thing!
+
+---
+class: ex-context
+
+## Be vigilant.
+
+```perl
+my %account_details = (
+    first_name  => (split / /, $user_name)[0],
+    job_title   => fetch_job_title($user_name),
+);
+```
+
+???
+The reason it is important to understand contexts is because you will get
+caught by gotchas if you don't.
+
+Spot any potential problems here?
+
+---
+class: ex-context
+
+## Be vigilant.
+
+```perl
+my %account_details = (
+    first_name  => (split / /, $user_name)[0],
+*   job_title   => fetch_job_title($user_name),
+);
+```
+
+```perl
+sub fetch_job_title {
+    return;     # -> ()
+}
+```
+
+--
+### Can use the `scalar` function to force scalar context.
+
+```perl
+    job_title   => scalar fetch_job_title($user_name),
+```
+
+---
+class: ex-context
+
+## Be vigilant.
+
+```perl
+my %account_details = (
+*   first_name  => (split / /, $user_name)[0],
+    job_title   => fetch_job_title($user_name),
+);
+```
+
+### `(split /regexp/, $str)[$index]` can evaluate to `()`!
+
+???
+This is surprising, right? Usually when you have a post-circumfix index
+operator on either a list or an array, even if you go out of bounds you'll get
+an `undef`.
+
+I should also mention that not only can things like this cause bugs that are
+annoying and hard to find, there are security implications. If you're not aware
+of how all the code within a hash declaration responds to being in list
+context, you could potentially open the door for crafted user input to
+overwrite completely unrelated keys in the hash.
+
+---
+class: center, middle
+
+## Understand execution phases.
+
+---
+## Two main phases
+
+- **Compile** phase
+- **Run** phase
+
+???
+That's easy enough. What's to know, right?
+
+Well, it turns out that it's not so straightforward because unlike many other
+languages, Perl can run code in the compile phase and compile code in the run
+phase.
+
+---
+class: ex-phases
+
+## Example script
+
+```perl
+#!/usr/bin/perl
+
+print "O hai.\n";
+```
+
+---
+class: ex-phases
+
+## Example script
+
+```perl
+#!/usr/bin/perl
+
+*print "O hai.\n";
+```
+
+???
+By the time this line executes we are already in the **run** phase.
+
+So how do you actually run code in the compile phase?
+
+---
+class: ex-phases
+
+## Run code in compile phase
+
+```perl
+#!/usr/bin/perl
+
+print "O hai.\n";
+
+*BEGIN {
+*   print "Hello.\n";
+*}
+```
+
+```
+Hello.
+O hai.
+```
+
+???
+One way to run code in the compile phase is to create a `BEGIN` block.
+
+---
+class: ex-phases
+
+## Run code in compile phase
+
+```perl
+#!/usr/bin/perl
+
+*use Data::Dumper qw(Dumper);
+
+print Dumper({
+    picard  => 'jean-luc',
+    kirk    => 'james',
+});
+```
+
+???
+`use` statements are also fulfilled in the compile phase, so it doesn't matter
+where they appear within the code.
+
+Similarly, `no` statements are also performed at compile time.
+
+--
+```perl
+BEGIN {
+    require Data::Dumper;
+    Data::Dumper->import('Dumper');
+}
+```
+
+???
+A `use` statement is *almost* the equivalent of this here.
+
+Also worth pointing out, the fact that code can be ran during the compile phase means that using the `-c` flag on an
+untrusted script is not advised.
+
+---
+class: ex-phases
+
+## Compile code in run phase
+
+--
+### String `eval`!
+
+```perl
+my $calculate_answer = eval q[
+    sub {
+        return ] . ($hgttg ? 42 : 7) . q[;
+    }
+];
+
+print "The answer is ", $calculate_answer->(), ".\n";
+```
+
+???
+String `eval` both compiles and runs strings as Perl code.
+
+It gets a bad rap because of its security implications. Yes, generating code to compile and run on the fly, when based
+on user input, must be done very carefully or not at all.
+
+This technique is used by many Perl modules to "inline" optimized versions of their subroutines. For example, `Moo` and
+`Moose` can generate constructors tailored for each class rather than always using one big constructor that can is able
+to handle all the possibilities.
+
+---
+## Code blocks associated with execution phases
+
+- `BEGIN` - Runs the block immediately after it is compiled.
+
+--
+- `CHECK` - Runs the block after the main compile phase and before the main run phase.
+
+--
+- `CHECKUNIT` - Same, but for each "unit" (file).
+
+--
+- `INIT` - Runs the block immediately before the main run phase.
+
+--
+- `END` - Runs the block at program end.
+
+Source: [Know the phases of a Perl program’s execution](https://www.effectiveperlprogramming.com/2011/03/know-the-phases-of-a-perl-programs-execution/) by brian d foy
+
+???
+By the way, it runs the blocks in a defined order, which is nice: `BEGIN` and `INIT` run in top to bottom order, while
+the others run in the opposite order.
+
+---
+class: center, middle
+
+## Know when to be terse and when not to.
+
+---
+class: ex-obfuscated, center, middle
+
+```perl
+@P=split//,".URRUU\c8R";@d=split//,"\nrekcah xinU / lreP rehtona tsuJ";sub p{
+@p{"r$p","u$p"}=(P,P);pipe"r$p","u$p";++$p;($q*=2)+=$f=!fork;map{$P=$P[$f^ord
+($p{$_})&6];$p{$_}=/ ^$P/ix?$P:close$_}keys%p}p;p;p;p;p;map{$p{$_}=~/^[P.]/&&
+close$_}%p;wait until$?;map{/^r/&&<$_>}%p;$_=$d[$q];sleep rand(2)if/\S/;print
+```
+
+Source: [Just Another Perl / Unix Hacker](http://perl.plover.com/obfuscated/) by Mark Jason Dominus
+
+???
+This is what terse code looks like. At least I think it is... If I knew what it was doing, I would probably conclude
+that it is in fact terse.
+
+But actually, it might not be. For all I know this could be a very roundabout and verbose way to accomplish the work
+it's doing. I can't tell because it's too "obfuscated."
+
+---
+class: center, middle
+
+# obfuscation ≠ terseness
+
+???
+The concepts of obfuscation and terseness are not materially equivalent.
+
+Obfuscation is always bad (except in "toy" code like "Just another hacker" snippets and obfuscation challenges).
+Terseness can be bad (if it's too obfuscated for the audience), but sometimes it can be better.
+
+---
+class: ex-terse
+
+## Be terse without obfuscating
+
+- Be idiomatic.
+
+```perl
+@coordinates = @geodata[2, 3];
+@coordinates = ($geodata[2], $geodata[3]);
+$coordinates[0] = $geodata[2]; $coordinates[1] = $geodata[3]; 
+```
+
+???
+Some language features are so common, they are idiomatic among users of the language even if the code may be somewhat
+perplexing to newcomers.
+
+Here are three more-or-less equivalent ways to do the same thing. The first way, using and array slice, is
+definitionally the tersest. Is it too terse? Is it obfuscated?
+
+In my subjective opinion, all three of these statements are equally fine. Array slicing is a language feature of Perl
+that doesn't exist in every other language, so it might perplex newcomers for a bit, but I think the intent is pretty
+clear even for those new to the syntax.
+
+So this is a great place to be terse.
+
+--
+- Terse code can actually be faster for humans to parse.
+
+???
+If only because there's less to read.
+
+--
+- Talk to your peers (or downstream "users") and establish expectations.
+
+???
+Some language features and style may just be too perplexing, so pay attention to who will probably be working with your
+code in the future.
+
+You don't always have to code for the lowest possible common denominator.
+
+Example: A lot of code could be written in the functional style versus imperatively. Keep in mind that functional code
+is easier to read and write for math-minded programmers. Perl can do either, but which one you choose should depend more
+on who else is going to be working in your code rather than your own personal preference.
+
+--
+- But **never** ever sacrifice clarity of intent for shorter code.
+
+???
+Anyway, I don't have any solid wisdom for you on this topic. Just be mindful.
+
+---
+class: center, middle
+
+## Use [`Future::AsyncAwait`](https://metacpan.org/pod/Future::AsyncAwait).
+
+???
+If you have used JavaScript recently, you may have used its "async/await" feature to clean up your non-blocking code.
+
+---
+class: center, middle
+
+### Yes, Perl can do it, too!
+
+---
+class: ex-asyncawait
+
+## Without async and await
+
+```perl
+use Future;
+
+sub do_two_things {
+    return do_first_thing()->then(sub {
+        my $first = shift;
+
+        return do_second_thing($first)->then(sub {
+            my $second = shift;
+
+            return Future->done([$first, $second]);
+        });
+    });
+}
+```
+
+---
+class: ex-asyncawait
+
+## With async and await
+
+```perl
+use Future::AsyncAwait;
+
+async sub do_two_things
+{
+    my $first = await do_first_thing();
+    my $second = await do_second_thing($first);
+    return [$first, $second];
+}
+```
+
+???
+There are caveats: Localized variable assignments don't work, nor anything that has implied local-like behavior.
+
+---
+class: center, middle
+
+## Write your own boilerplate.
+
+---
+class: ex-boilerplate
+
+### The boilerplate can get unwieldy...
+
+```perl
+package My::Package;
+
+use utf8;
+use warnings FATAL => 'all';
+use strict;
+use feature ':5.14';
+use open qw(:encoding(UTF-8) :std);
+use charnames qw(:full :short);
+
+use Encoding qw(decode encode);
+use Function::Parameters;
+use Locale::TextDomain 'AppName';
+use Scalar::Util qw(blessed refaddr reftype weaken unweaken isweak);
+use Unicode::Normalize qw(NFC NFC);
+```
+
+In every file.
+
+---
+class: center, middle
+
+### Solution: Put all that junk in a separate package.
+
+---
+class: ex-boilerplate2
+
+```perl
+package My::boilerplate;
+
+use Import::Into;
+
+sub import {
+    my $class  = shift;
+    my %args   = @_;
+
+    my $target = caller;
+
+    feature     ->import::into($target, qw{:5.14});
+    strict      ->import::into($target);
+    warnings    ->import::into($target, qw{FATAL all});
+    utf8        ->import::into($target);
+    open::      ->import::into($target, qw{:encoding(UTF-8) :std});
+    charnames   ->import::into($target, qw{:full :short});
+
+    Encode              ->import::into($target, qw{decode encode});
+    Function::Parameters->import::into($target);
+    Locale::TextDomain  ->import::into($target, $args{textdomain} || 'AppName');
+    Scalar::Util        ->import::into($target, qw{blessed refaddr reftype weaken unweaken isweak});
+    Unicode::Normalize  ->import::into($target, qw{NFD NFC});
+}
+
+1;
+```
+
+---
+class: ex-boilerplate2
+
+```perl
+package My::boilerplate;
+
+*use Import::Into;
+
+sub import {
+    my $class  = shift;
+    my %args   = @_;
+
+    my $target = caller;
+
+    feature     ->import::into($target, qw{:5.14});
+    strict      ->import::into($target);
+    warnings    ->import::into($target, qw{FATAL all});
+    utf8        ->import::into($target);
+    open::      ->import::into($target, qw{:encoding(UTF-8) :std});
+    charnames   ->import::into($target, qw{:full :short});
+
+    Encode              ->import::into($target, qw{decode encode});
+    Function::Parameters->import::into($target);
+    Locale::TextDomain  ->import::into($target, $args{textdomain} || 'AppName');
+    Scalar::Util        ->import::into($target, qw{blessed refaddr reftype weaken unweaken isweak});
+    Unicode::Normalize  ->import::into($target, qw{NFD NFC});
+}
+
+1;
+```
+
+---
+class: ex-boilerplate
+
+### Use your boilerplate.
+
+```perl
+package My::Package;
+
+use My::boilerplate;
+
+sub say_hello {
+    say __"Hello";
+}
+
+1;
+```
+
+???
+Now I can use `say` without having to use perl 5.10 in my package, and I can use gettext to translate my greeting.
+Warnings and strict are also enabled. All that stuff I need in every module is there. 
+
+---
+class: ex-boilerplate
+
+## Tip: Add this to your project's `.perlcriticrc`.
+
+```ini
+[TestingAndDebugging::RequireUseStrict]
+equivalent_modules = My::boilerplate
+```
+
+---
+class: center, middle
+
+## Write your own debugger.
+
+???
+Perl provides rather convenient mechanisms for hooking into the interpreter.
+
+The idea for this topic, by the way, is from a lightning talk by rjbs in YAPC 2014. His talks are always entertaining,
+so look them up.
+
+---
+class: ex-owndebugger1
+
+```bash
+perl -d:MyFancyDebugger program.pl
+```
+
+???
+This does at least two important things.
+
+--
+### `use Devel::MyFancyDebugger;`
+### `$^P = 1855;`
+
+???
+`$^P` is a bitfield that lets you turn on and off various features related to debugging. The value 1855 isn't important;
+just know that using this flag turns on a lot of those bits.
+
+---
+class: ex-owndebugger2
+
+```perl
+package Devel::PackageOrder;
+
+my %seen;
+
+{
+    package DB;
+    sub DB {
+        my ($package, $filename, $line) = caller;
+        return if $seen{$package}++;
+        print STDERR "Package: $package\n";
+    }
+}
+
+1;
+```
+
+```bash
+perl -d:PackageOrder program.pl
+```
+
+???
+As it happens, the second bit of `$^P` arranges for a subroutine named `DB::DB` to be called per statement. 
+
+---
+class: ex-owndebugger2
+
+```perl
+package Devel::PackageOrder;
+
+my %seen;
+
+{
+*   package DB;
+*   sub DB {
+        my ($package, $filename, $line) = caller;
+        return if $seen{$package}++;
+        print STDERR "Package: $package\n";
+    }
+}
+
+1;
+```
+
+```bash
+perl -d:PackageOrder program.pl
+```
+
+???
+So, for each statement that gets run in your program, this subroutine is called. My simple example here just does some
+simple things. It uses the `caller` function to figure out where the program is at in its execution.
+
+The first item we get off of `caller` is the package name (actually we could also just call `caller` in scalar context
+to get just the package). Then, if we've seen the package before, we don't do anything, otherwise we print the name of
+the package.
+
+So, this effectively tells us in what order packages 
+
+Is this useful? I don't know. I guess it useful at some point because I wrote it. The point is, you can write your own
+debuggers to do whatever useful thing you have need of, when you have the need.
+
+And by the way, I've shown you the entirety of the debugger. There is no other code needed. It's really cool.
+
+---
+class: center, middle
+
+## Don't write your own debugger.
+
+???
+As you can imagine, there are a lot of awesome debuggers on CPAN already.
+
+You should probably check before writing your own.
+
+---
+class: ex-develtrace
+
+## [`Devel::Trace`](https://metacpan.org/pod/Devel::Trace)
+
+```bash
+perl -d:Trace -e'print scalar localtime, "\n"'
+*>> -e:1: print scalar localtime, "\n"
+Thu Jun  7 20:43:57 2018
+```
+
+---
+class: ex-develtrace
+
+## [`Devel::Trace::Syscall`](https://metacpan.org/pod/Devel::Trace::Syscall)
+
+```bash
+perl -d:Trace::Syscall=open -e'print scalar localtime, "\n"'
+Thu Jun  7 20:45:59 2018
+*open("/etc/localtime", 0x80000, 0666) = 3 at -e line 1.
+```
+
+---
+class: ex-develtrace
+
+## [`Devel::NYTProf`](https://metacpan.org/pod/Devel::NYTProf)
+
+```bash
+perl -d:NYTProf -e'print scalar localtime, "\n"'
+Thu Jun  7 20:53:42 2018
+```
+
+![NYTProf html report](img/nytprof.png)
+
+---
+class: ex-develtrace
+
+## [`Devel::Cover`](https://metacpan.org/pod/Devel::Cover)
+
+```bash
+cover -test
+```
+
+.cover-img[
+![Cover html report](img/cover.png)
+]
+
+---
+class: center, middle
+
+## Know the default perl5 debugger.
+
+???
+Of course those other debuggers are cool, but don't forget that perl also comes with its own general-purpose debugger.
+You should know it.
+
+---
+class: ex-debugger
+
+## `perl5db.pl`
+
+```bash
+perl -d program.pl 
+Enter h or 'h h' for help, or 'man perldebug' for more help.
+  DB<1>
+```
+
+--
+#### That's about it...
+
+???
+Obviously you can use it to step through code.
+
+Anyway, I don't have much to say about it. Just use it.
+
+---
+class: center, middle
+
+## Write modern Perl.
+
+---
+class: ex-newfeatures
+
+## Try some newer perl5 features.
+
+```perl
+use v5.24;
+use feature qw(signatures);    # available in v5.20
+no warnings qw(experimental::signatures);
+
+my $missile_inventory = {
+    ID  => 20,
+    WY  => 25,
+    CA  => 195,
+};
+
+sub get_default_silo_id () {
+    return $_ if 0 < $missile_inventory->{$_} for (sort keys $missile_inventory->%*);
+    die "No more missiles. :-(\n";
+}
+
+sub launch_missile ( $silo_id = get_default_silo_id() ) {
+    die "Silo is empty.\n" if $missile_inventory->{$silo_id} <= 0;
+    $missile_inventory->{$silo_id} -= 1;
+    say "Missile launched from silo $silo_id.";
+}
+```
+
+---
+class: ex-newfeatures
+
+## Try some newer perl5 features.
+
+```perl
+*use v5.24;
+*use feature qw(signatures);    # available in v5.20
+*no warnings qw(experimental::signatures);
+
+my $missile_inventory = {
+    ID  => 20,
+    WY  => 25,
+    CA  => 195,
+};
+
+*sub get_default_silo_id () {
+    return $_ if 0 < $missile_inventory->{$_} for (sort keys $missile_inventory->%*);
+    die "No more missiles. :-(\n";
+}
+
+*sub launch_missile ( $silo_id = get_default_silo_id() ) {
+    die "Silo is empty.\n" if $missile_inventory->{$silo_id} <= 0;
+    $missile_inventory->{$silo_id} -= 1;
+    say "Missile launched from silo $silo_id.";
+}
+```
+
+---
+class: ex-newfeatures
+
+## Try some newer perl5 features.
+
+```perl
+use v5.24;
+use feature qw(signatures);    # available in v5.20
+no warnings qw(experimental::signatures);
+
+my $missile_inventory = {
+    ID  => 20,
+    WY  => 25,
+    CA  => 195,
+};
+
+sub get_default_silo_id () {
+*   return $_ if 0 < $missile_inventory->{$_} for (sort keys $missile_inventory->%*);
+    die "No more missiles. :-(\n";
+}
+
+sub launch_missile ( $silo_id = get_default_silo_id() ) {
+    die "Silo is empty.\n" if $missile_inventory->{$silo_id} <= 0;
+    $missile_inventory->{$silo_id} -= 1;
+    say "Missile launched from silo $silo_id.";
+}
+```
+
+---
+class: ex-moo
+
+## Use [`Moo`](https://metacpan.org/pod/Moo) and [`Moose`](https://metacpan.org/pod/Moose).
+
+```perl
+package ToySoldier;
+
+use Function::Parameters;
+use Moo;
+use namespace::clean;
+
+extends 'Toy';
+
+with qw(HasSpear);
+
+method fight($opponent) {
+    $self->spear->thrust_at($opponent);
+}
+
+1;
+```
+
+???
+- Gives perl5 an improved object model.
+- It partially is just syntactic sugar, right? But these modules do provide a lot of value about perl5's own object
+  model.
+  - Attributes and a constructor.
+  - Roles (a.k.a. mixins).
+  - And if you use Moose, you get the whole metaobject as well.
+    - The metaobject provides introspection and runtime altering of classes. It's powerful.
+
+I'm not going to go any further into Moo or Moose, but do learn them and use them with a caveat: I don't know how anyone
+else feels about this, but I kinda like modules on CPAN that don't depend on Moo or especially Moose, because modules
+with fewer dependencies are just easier to work with generally. So, if you are releasing on CPAN, consider not depending
+on this. Or at least use Moo and not full Moose if you don't actually need the metaobject. Of course, in your own
+non-distributed programs, go all out.
+
+---
+class: center, middle
+
+## Learn Perl 6.
+
+![Camelia](img/camelia.png)
+
+???
+- It's easy to install and fun to play with.
+
+---
+class: center, middle
+
+## Go download it and just start playing around.
+
+### https://perl6.org/downloads/
+
+(Really, do it.)
+
+---
+class: ex-perl6
+
+### Meta operators
+
+```perl
+[*] 1, 2, 3, 4, 5
+```
+
+---
+class: ex-perl6
+
+### Meta operators
+
+```perl
+[*] 1, 2, 3, 4, 5           # -> 120
+```
+
+???
+- This one is called the **reduce** meta operator.
+- Also notice that in Perl 6, you don't need to surround a list in parentheses.
+
+--
+```perl
+sub some-reducer($a, $b) { $a + $b }
+
+[[&some-reducer]] 1 .. 5    # -> 15
+[+] 1 .. 5                  # -> 15
+```
+
+???
+- Can reduce using any binary operator.
+- Oh yeah, and you can use dashes in subroutine names.
+
+---
+class: ex-perl6
+
+### Meta operators
+
+```perl
+1, 3 ... 9
+2, 4, 8 ... 256
+```
+
+???
+You've seen the dot dot operator, but check out dot dot dot!
+
+---
+class: ex-perl6
+
+### Meta operators
+
+```perl
+1, 3 ... 9                  # -> 1, 3, 5, 7, 9
+2, 4, 8 ... 256             # -> 2, 4, 8, 16, 32, 64, 128, 256
+```
+
+--
+```perl
+my @fib = 1, 1, -> $a, $b { $a + $b } ... *;
+
+@fib[6]                     # -> 13
+@fib[3 .. 5]                # -> 3, 5, 8
+@fib[^8]                    # -> 1, 1, 2, 3, 5, 8, 13, 21
+```
+
+???
+- Of course you can do even awesomer things like create infinite lists with more complicated sequence logic.
+- The list elements are evaluated lazily.
+
+---
+class: ex-perl6
+
+### Create your own operators
+
+```perl
+sub postfix:<!>(Int $n) { [*] 2 .. $n }
+
+5!                          # -> 120
+```
+
+???
+Lots of languages (even perl5) allows you to override operators, but none come close to perl6 in functionality.
+
+--
+
+Types of operators you can create in Perl 6:
+
+- Prefix (like `!` as in `!True`)
+- Postfix (like `++` in `$num++`)
+- Infix (like `+` in `1 + 2`)
+- Circumfix (like `[]` in `[1, 2]`)
+- Post-circumfix (like `[]` in `@array[5]`)
+
+---
+class: ex-perl6
+
+### Destructure your structures
+
+```perl
+sub salut(% (:name($name), :title($title))) {
+    say "Hello there, $name the $title!";
+}
+
+salut({name => 'Bob', title => 'Consultant'});
+
+my %person = {name => 'Jean Luc', title => 'Captain'};
+salut(%person);
+```
+
+???
+I guess the first thing to say is that, yes, Perl 6 has function signatures.
+
+As this example shows, you can also do nifty stuff like destructure.
+
+---
+
+### Other cool stuff in Perl 6
+
+- Sigils that make [more] sense.
+
+--
+- A real object model.
+
+--
+- Types! -- If you want.
+
+--
+- Multiple dispatch for subroutines.
+
+--
+- Control over passing semantics.
+
+???
+- Args are immutable by default, but can be set to copy or be mutable (like perl5 aliasing).
+
+--
+- Lambdas
+
+---
+
+## Summary
+
+.col[
+- Use [`B::Deparse`](https://metacpan.org/pod/B::Deparse).
+- Document your shell scripts with pod.
+- Know regular expressions.
+- Use [`Regexp::Debugger`](https://metacpan.org/pod/Regexp::Debugger).
+- Write Vim plugins in Perl.
+- Understand calling context.
+- Understand execution phases.
+- Know when to be terse and when not to.
+]
+
+.col[
+- Use [`Future::AsyncAwait`](https://metacpan.org/pod/Future::AsyncAwait).
+- Write your own boilerplate.
+- Write your own debugger.
+- Don't write your own debugger.
+- Know the default perl debugger.
+- Write modern Perl.
+- Learn Perl 6.
+]
+
+---
+
+## Other topics
+- Learn XS.
+- Learn Unicode.
+- Learn another language.
+- Learn software design patterns.
+
+---
+class: center, middle
+name:  conclusion
+
+## Conclusion:
+
+### Perl is fun.
+
+---
+class:  center, middle
+name:   last
+
+.col.sep[
+## Thank you
+
+Email me: Charles McGarvey
+<chazmcgarvey@brokenzipper.com>
+
+.talkqr.center[
+Leave me feedback, if you want:
+
+![Page on Joind.in](img/talkqr.svg)
+
+<https://joind.in/talk/66955>
+]
+]
+
+.col[
+## Credits
+
+.left[
+- Thanks rjbs for your inspiring talks.
+- Thanks brian d foy for your instructive articles.
+- Thanks Damian Conway, Paul Evans, et al. for writing and sharing cool modules.
+- Thanks Larry Wall for Perl.
+]
+]
+
+</textarea><script src="https://gnab.github.io/remark/downloads/remark-latest.min.js"></script><script>var slideshow = remark.create({countIncrementalSlides: true, highlightLanguage: '', highlightLines: true, ratio: '16:9', /*slideNumberFormat: '',*/ navigation: {scroll: false, touch: false, click: false}})</script><script src="js/common.js"></script><script src="js/slides.js"></script></body></html>
+<!-- vim: set ts=4 sts=4 sw=4 tw=120 et ft=markdown nowrap: -->
This page took 0.06596 seconds and 4 git commands to generate.