f30a9326dc15e677a349eb0d18dac6ed6e4ae1c5 — Andrew Zah 4 months ago bc35603
bulk update, refactor scss
A content/talks/05-28-2019-wasm-rust-seoul/index.md => content/talks/05-28-2019-wasm-rust-seoul/index.md +322 -0
@@ 0,0 1,322 @@
+ +++
+ title = "Web Assembly: What is it? Does it do things? Let's find out!"
+ slug = "web-assembly-rust-seoul"
+ date = 2019-05-28
+ template = "talk.html"
+ 
+ [taxonomies]
+ tags = ["rust", "webassembly"]
+ categories = ["talks"]
+ 
+ [extra]
+ summary = "A talk on what WebAssembly actually is, ways to use it in Rust, and a case study."
+ keywords = "talk pdf presentation web assembly rust 2019 seoul what is web assembly"
+ pdflink = "https://s3.amazonaws.com/andrewzah.com/talks/2019-05-28/ZahWebAssemblyRust-05-28-2019.pdf"
+ +++
+ 
+ ```latex
+ % !TEX program = XeLaTeX
+ \documentclass[aspectratio=169]{beamer}
+ \mode<presentation>
+ 
+ \usepackage{tikz}
+ \usepackage{pgfpages} % notes
+ \usepackage{graphicx}
+ \usepackage{color} % for syntax highlighting definitions
+ \usepackage{fontspec} % for custom firacode setup
+ \usepackage{listings} % for formatting codeblocks
+ 
+ \usetheme{AnnArbor}
+ \usecolortheme{spruce}
+ \usecolortheme{rose}
+ 
+ \setbeamertemplate{navigation symbols}{}
+ \setbeamertemplate{enumerate items}[default]
+ \setbeamercolor{item projected}{bg=green!40!black,fg=white}
+ \setbeamercolor{section in toc}{fg=black}
+ %\setbeameroption{show notes on second screen}
+ 
+ %% fonts
+ 
+ \setmonofont{Fira Code}[
+   Contextuals=Alternate  % Activate the calt feature
+ ]
+ \usepackage{lstfiracode}
+ 
+ %% code syntax highlighting
+ 
+ \definecolor{lightgray}{rgb}{.9,.9,.9}
+ \definecolor{darkgray}{rgb}{.4,.4,.4}
+ \definecolor{purple}{rgb}{0.65, 0.12, 0.82}
+ 
+ \lstdefinelanguage{JavaScript}{
+   keywords={break, case, catch, continue, debugger, default, delete, do, else, false, finally, for, function, if, in, instanceof, new, null, return, switch, this, throw, true, try, typeof, var, void, while, with},
+   morecomment=[l]{//},
+   morecomment=[s]{/*}{*/},
+   morestring=[b]',
+   morestring=[b]",
+   ndkeywords={class, export, boolean, throw, implements, import, this},
+   keywordstyle=\color{blue}\ttfamily,
+   ndkeywordstyle=\color{darkgray}\ttfamily,
+   identifierstyle=\color{black}\ttfamily,
+   commentstyle=\color{purple}\ttfamily,
+   stringstyle=\color{red}\ttfamily,
+   sensitive=true
+ }
+ 
+ %% behavior modifications
+ 
+ \newenvironment{wideitemize}{\itemize\addtolength{\itemsep}{10pt}}{\enditemize}
+ \AtBeginSection[]
+ {
+     \begin{frame}
+         \frametitle{Journey}
+         \tableofcontents[currentsection]
+     \end{frame}
+ }
+ 
+ %% metadata
+ 
+ \title[WASM!]{Web Assembly: What does it do? Does it do things? Let's find out!}
+ \author[]{Andrew Zah \texttt{<zah@andrewzah.com>}}
+ \institute[Rust Meetup Seoul]{Rust Meetup Seoul}
+ \date{May 23, 2019}
+ 
+ %% preamble over
+ 
+ \begin{document}
+ \maketitle
+ 
+ \section*{Journey}
+ \begin{frame}
+   \tableofcontents
+ \end{frame}
+ 
+ \section{What is WASM?}
+ \begin{frame}
+   \frametitle{Web Assembly's Definition}
+   \begin{block}{from webassembly.org (emphasis mine)}
+     WebAssembly (abbreviated Wasm) is a \alert{binary instruction format} for a \alert{stack-based virtual machine}. Wasm is designed as a \alert{portable target} for compilation of high-level languages like C/C++/Rust, enabling \alert{deployment on the web} for client and server applications.
+   \end{block}
+ \end{frame}
+ 
+ \begin{frame}
+   \frametitle{What WASM is not}
+   \begin{wideitemize}
+     \item WASM is not a programming language – though you can write by hand
+     \item WASM isn't standalone – it needs a host
+     \item WASM is not intended to replace javascript
+   \end{wideitemize}
+ \end{frame}
+ 
+ \begin{frame}
+   \frametitle{What is it actually, though?}
+   \begin{wideitemize}
+     \item WASM's format isn't coupled to any OS or architecture
+     \item Very similar to Java's bytecode or C\#'s CLR
+     \item Name and definition is a misnomer
+     \item It can run \alert{anywhere} you can build a \alert{host}
+   \end{wideitemize}
+ \end{frame}
+ 
+ \begin{frame}
+   \frametitle{What is it actually, though? pt. 2}
+   \begin{wideitemize}
+     \item WASM is \alert{stack-based}, not register-based
+     \item WASM 1.0 only had 4 primitives
+     \item `i32`, `i64`, `f32`, `f64` 
+     \item Unlike other assembly languages, WASM has no `jmp` instruction
+   \end{wideitemize}
+   \note[item]{Forth is just about the only somewhat-mainline language that is stack-based.}
+   \note[item]{RPL also exists but\ldots}
+ \end{frame}
+ 
+ \begin{frame}
+   \frametitle{Memory}
+   \begin{columns}
+     \begin{column}{0.5\textwidth}
+       \begin{wideitemize}
+         \item WASM has no \alert{new::()} operator or \alert{heap}
+         \item There are no objects or or garbage collection
+         \item Instead, WASM has \alert{linear memory}
+         \item<2-> Modern programming languages have spoiled us
+       \end{wideitemize}
+     \end{column}
+     \begin{column}{0.5\textwidth}
+       \begin{center}
+         \only<2-> {
+           \begin{tikzpicture}<2->
+             \draw [gray] (0,0) rectangle (4,1) node[pos=.5] {unused};
+             \draw [teal] (0,1) rectangle (4,2) node[pos=.5] {var3 [80\ldots119]};
+             \draw [gray] (0,2) rectangle (4,3) node[pos=.5] {var2 [40\ldots79]};
+             \draw [teal] (0,3) rectangle (4,4) node[pos=.5] {var1 [0\ldots39]};
+           \end{tikzpicture}
+         }
+       \end{center}
+     \end{column}
+   \end{columns}
+ \end{frame}
+ 
+ \begin{frame}
+   \frametitle{Anyone can be a WASM host!}
+   
+   \begin{alertblock}{The Host needs to:}
+     \begin{enumerate}
+       \item Load and validate the WASM binary (the file, not the logic)
+       \item Expose Exports
+       \item Satisfy Imports
+       \item Interpret \& Execute Modules
+       \item Isolate Modules
+     \end{enumerate}
+   \end{alertblock}
+ \end{frame}
+ 
+ \begin{frame}
+   \frametitle{Infinity and Beyond}
+ 
+   \begin{wideitemize}
+     \item WebAssembly modules are hotswappable
+     \item This means \alert{\em any host} can swap modules at will
+     \item PLCs (Programmable Logic Controllers) could adhere to a well-known contract
+     \item This would let us program for hardware controllers in \alert{any language}!
+   \end{wideitemize}
+   
+ \end{frame}
+ 
+ \begin{frame}
+   \frametitle{Security}
+   \begin{wideitemize}
+     \item WASM can always be converted back to plaintext
+     \item Do not put secrets in WASM modules
+     \item \alert{Message handoffs} are not always secure!
+     \item One can disassemble, modify, recompile, inject a module
+     \item Accordingly, \alert{sign} and \alert{encrypt} modules!
+   \end{wideitemize}
+ \end{frame}
+ 
+ \begin{frame}[fragile]
+   \frametitle{Example WASM Syntax}
+   \begin{block}{add.wat}
+     \begin{lstlisting}[language=Lisp]
+ (module
+   (func $add (param $lhs i32) (param $rhs i32) (result i32)
+     (i32.add
+         (get_local $lhs)
+         (get_local $rhs)
+     )
+   )
+   (export "add" (func $add))
+ )
+     \end{lstlisting}
+   \end{block}
+ \end{frame}
+ 
+ \begin{frame}[fragile]
+   \frametitle{Add Example: Rust}
+   \begin{block}{main.rs}
+     \begin{lstlisting}[language=c++]
+ #[no_mangle]
+ pub extern "C" fn add_one(x: i32) -> i32 {
+     x + 1
+ }
+     \end{lstlisting}
+   \end{block}
+ \end{frame}
+ 
+ \begin{frame}[fragile]
+   \frametitle{Add Example: WASM}
+   \begin{block}{main.wasm}
+     \begin{lstlisting}[language=Lisp]
+ (module
+   (type $t0 (func (param i32) (result i32)))
+   (func $add_one
+       (export "add_one") (type $t0) (param $p0 i32) (result i32)
+     get_local $p0
+     i32.const 1
+     i32.add)
+   (table $T0 1 1 anyfunc)
+   (memory $memory (export "memory") 17))
+     \end{lstlisting}
+   \end{block}
+ \end{frame}
+ 
+ 
+ \section{How Rust and WASM Intertwine}
+ \begin{frame}[fragile]
+   \frametitle{wasm-pack}
+   \begin{block}{main.rs}
+     \begin{lstlisting}[language=c++]
+ #[wasm_bindgen]
+ extern {
+     fn alert(s: &str);
+ }
+ 
+ #[wasm_bindgen]
+ pub fn greet() {
+     alert("Hello, wasm-game-of-life!");
+ }
+     \end{lstlisting}
+   \end{block}
+ \end{frame}
+ 
+ \begin{frame}[fragile]
+   \frametitle{wasm-pack}
+   \begin{block}{main.js}
+     \begin{lstlisting}[language=javascript]
+ import * as wasm from "wasm-game-of-life";
+ 
+ wasm.greet();
+     \end{lstlisting}
+   \end{block}
+ \end{frame}
+ 
+ \begin{frame}
+   \frametitle{wasm-bindgen}
+   \begin{wideitemize}
+     \item Adds helpers to allow transfer of \alert{complex types}.
+   \end{wideitemize}
+ \end{frame}
+ 
+ \section{A Real, Non-Trivial WASM App}
+ \begin{frame}
+   \frametitle{Korean Apps}
+   \begin{wideitemize}
+     \item Initially I wrote a cargo crate, \alert{korean-numbers}
+     \item I wanted a way to use this logic in a webapp with React
+   \end{wideitemize}
+ \end{frame}
+ 
+ \begin{frame}
+   \begin{center}
+     {\huge Thank you} \\
+     Andrew Zah
+   \end{center}
+ \end{frame}
+ 
+ \section{Appendix}
+ \begin{frame}[plain]
+   \includegraphics[scale=0.34]{webassembly-studio.png}
+ \end{frame}
+ 
+ \begin{frame}
+   \frametitle{Further Reading}
+   \begin{itemize}
+     \item WASM Homepage \texttt{https://webassembly.org}
+     \item WASM Spec \texttt{https://webassembly.github.io/spec/}
+   \end{itemize}
+ \end{frame}
+ 
+ \begin{frame}
+   \frametitle{Bibliography}
+   \begin{thebibliography}{Dijkstra, 1982}
+     \bibitem[Hoffman, 2019]{Hoffman2019}
+       K.~Hoffman.
+       \newblock{\em Programming WebAssembly with Rust \\
+         \small Unified Development for Web, Mobile, and Embedded Applications }
+       \newblock{The Pragmatic Programmers, LLC}
+       \newblock{ISBN-13: 978-1-68050-636-5}
+   \end{thebibliography}
+ \end{frame}
+ 
+ \end{document}
+ ```

A content/talks/_index.md => content/talks/_index.md +6 -0
@@ 0,0 1,6 @@
+ +++
+ title = "Talks"
+ template = "section.html"
+ sort_by = "date"
+ render = true
+ +++

A sass/_container.scss => sass/_container.scss +158 -0
@@ 0,0 1,158 @@
+ .container {
+   .image-desc {
+     font-style: italic;
+     color: $headers;
+     text-align: center;
+     font-size: 15px;
+   }
+ 
+   .page-date {
+     font-family: $serif-stack;
+     margin-top: -.75rem;
+     font-size: 18px;
+     display: block;
+     color: $light_text;
+     font-style: italic;
+   }
+ 
+   hr {
+     margin-top: 1rem;
+     margin-bottom: 1rem;
+   }
+ 
+   code, ul li code {
+     @include wrap-word;
+ 
+     font-family: $monospace-stack;
+     font-size: 14px;
+     padding: 2px 4px;
+     color: $code_text;
+     background-color: $code_background;
+     border-radius: 4px;
+   }
+ 
+   pre {
+     @include wrap-word;
+     padding: 0.5em 1em;
+     font-size: 14px;
+     background-color: $code_background !important;
+     box-shadow: 0 4px 2px hsla(0, 0%, 0%, 0.2);
+ 
+     span {
+       background-color: $code_background !important;
+     }
+   }
+ 
+   p {
+     @include anchor-colors;
+     @include anchor-style;
+ 
+     margin-bottom: 1rem;
+   }
+ 
+   img.smol-img {
+     display: block;
+     max-height: 25rem;
+     width: auto;
+     margin: 0px auto 2rem auto
+   }
+ 
+   p img.full {
+     max-width: 100%;
+     display: block;
+     margin: 0 auto;
+     box-shadow: 0 4px 6px 0 hsla(0, 0%, 0%, 0.2);
+   }
+ 
+   p, li, h6 {
+     font-family: 'Libre Baskerville', 'Baskerville', serif;
+     line-height: 1.5;
+   }
+ 
+   /* Post Headers */
+   h1 {
+     text-align: left;
+     font-weight: bold;
+     margin-bottom: 0px;
+   }
+ 
+   h6 {
+     text-align: center;
+     font-size: 14px;
+     color: $med_text;
+     margin-top: -1.5rem;
+   }
+ 
+   h1,h2,h3,h4,h5 {
+     font-family: $serif-stack;
+     font-weight: bold;
+     margin-bottom: .5rem;
+   }
+ 
+   table {
+     border-spacing: 1;
+     border-collapse: collapse;
+     background: white;
+     border-radius: 10px;
+     overflow: hidden;
+     width: 100%;
+     margin: 1rem auto;
+     position: relative;
+ 
+     * {
+       position: relative;
+     }
+ 
+     td, th {
+       padding: 6px 8px;
+       padding-left: 15px;
+     }
+ 
+     thead tr {
+       background-color: $primary;
+       color: rgb(248, 248, 248);
+       font-weight: bold;
+       border-bottom: 1px solid #ccc;
+     }
+ 
+     tbody tr {
+       &:nth-child(odd) {
+         background-color: $table_lighter;
+       }
+ 
+       &:nth-child(even) {
+         background-color: $table_darker;
+       }
+ 
+ 
+       &:last-child {
+         td {
+           border: none;
+         }
+       }
+ 
+       &:hover {
+         background-color: $table_highlight;
+         cursor: pointer;
+       }
+     }
+   }
+ 
+   blockquote {
+     border-left: 4px solid $primary;
+ 
+     @media (min-width: $mobile-screen) {
+       margin-left: 2rem;
+     }
+ 
+     p {
+       margin-bottom: 10px;
+     }
+ 
+     ul {
+       &:last-child {
+         margin-bottom: 2.5rem;
+       }
+     }
+   }
+ }

M sass/_posts.scss => sass/_posts.scss +6 -167
@@ 43,175 43,14 @@ margin-bottom: 1.25rem;
  }
  
+ .container {
+   .post {
+     max-width: 680px;
  
- .container.page {
-   max-width: 680px;
- 
-   .image-desc {
-     font-style: italic;
-     color: $headers;
-     text-align: center;
-     font-size: 15px;
-   }
- 
-   time {
-     font-family: $serif-stack;
-     margin-top: -1rem;
-     font-size: 18px;
-     display: block;
-     color: $light_text;
-     font-style: italic;
-   }
- 
-   hr {
-     margin-top: 1rem;
-     margin-bottom: 1rem;
-   }
- 
-   code, ul li code {
-     @media (max-width: $mobile-screen) {
-       @include wrap-word;
-     }
- 
-     font-family: $monospace-stack;
-     font-size: 14px;
-     padding: 2px 4px;
-     color: $code_text;
-     background-color: $code_background;
-     border-radius: 4px;
-   }
- 
-   pre {
-     padding: 0.5em 1em;
-     font-size: 14px;
-     background-color: $code_background !important;
-     box-shadow: 0 4px 2px hsla(0, 0%, 0%, 0.2);
- 
-     span {
-       background-color: $code_background !important;
-     }
- 
-     @media (max-width: $mobile-screen) {
-       @include wrap-word;
-     }
-   }
-   p {
-     @include anchor-colors;
-     @include anchor-style;
-     @include wrap-word;
- 
-     margin-bottom: 1rem;
-   }
- 
-   img.smol-img {
-     display: block;
-     max-height: 25rem;
-     width: auto;
-     margin: 0px auto 2rem auto
-   }
- 
-   p img.full {
-     max-width: 100%;
-     display: block;
-     margin: 0 auto;
-     box-shadow: 0 4px 6px 0 hsla(0, 0%, 0%, 0.2);
-   }
- 
-   p, li, h6 {
-     font-family: 'Libre Baskerville', 'Baskerville', serif;
-     line-height: 1.5;
-   }
- 
-   /* Post Headers */
-   h1 {
-     text-align: left;
-     font-weight: bold;
-     margin-bottom: 0px;
-   }
- 
-   h6 {
-     text-align: center;
-     font-size: 14px;
-     color: $med_text;
-     margin-top: -1.5rem;
-   }
- 
-   h1,h2,h3,h4,h5 {
-     font-family: $serif-stack;
-     font-weight: bold;
-     margin-bottom: .5rem;
-   }
- 
-   h2 {
-     border-bottom: 1px solid #ccc;
-     padding-bottom: 0.5rem;
-     margin-bottom: 1rem;
-   }
- 
-   table {
-     border-spacing: 1;
-     border-collapse: collapse;
-     background: white;
-     border-radius: 10px;
-     overflow: hidden;
-     width: 100%;
-     margin: 1rem auto;
-     position: relative;
- 
-     * {
-       position: relative;
-     }
- 
-     td, th {
-       padding: 6px 8px;
-       padding-left: 15px;
-     }
- 
-     thead tr {
-       background-color: $primary;
-       color: rgb(248, 248, 248);
-       font-weight: bold;
+     h2 {
        border-bottom: 1px solid #ccc;
-     }
- 
-     tbody tr {
-       &:nth-child(odd) {
-         background-color: $table_lighter;
-       }
- 
-       &:nth-child(even) {
-         background-color: $table_darker;
-       }
- 
- 
-       &:last-child {
-         td {
-           border: none;
-         }
-       }
- 
-       &:hover {
-         background-color: $table_highlight;
-         cursor: pointer;
-       }
-     }
-   }
- 
-   blockquote {
-     border-left: 4px solid $primary;
- 
-     @media (min-width: $mobile-screen) {
-       margin-left: 2rem;
-     }
- 
-     p {
-       margin-bottom: 10px;
-     }
- 
-     ul {
-       &:last-child {
-         margin-bottom: 2.5rem;
-       }
+       padding-bottom: 0.5rem;
+       margin-bottom: 1rem;
      }
    }
  }

A sass/_talks.scss => sass/_talks.scss +3 -0
@@ 0,0 1,3 @@
+ .container.talks {
+   max-width: 845px;
+ }

A sass/components/_button.scss => sass/components/_button.scss +23 -0
@@ 0,0 1,23 @@
+ .button.button-primary,
+ button.button-primary,
+ input[type="submit"].button-primary,
+ input[type="reset"].button-primary,
+ input[type="button"].button-primary {
+   color: #FFF;
+   background-color: $primary;
+   border-color: $primary; }
+ 
+ .button.button-primary:hover,
+ button.button-primary:hover,
+ input[type="submit"].button-primary:hover,
+ input[type="reset"].button-primary:hover,
+ input[type="button"].button-primary:hover,
+ .button.button-primary:focus,
+ button.button-primary:focus,
+ input[type="submit"].button-primary:focus,
+ input[type="reset"].button-primary:focus,
+ input[type="button"].button-primary:focus {
+   color: #FFF;
+   background-color: $primary-hover;
+   border-color: $primary-hover;
+ }

M sass/components/_random_quote.scss => sass/components/_random_quote.scss +1 -1
@@ 16,7 16,7 @@ }
  
    #random-quote-citation {
-     margin-left: 30px;
+     margin-left: 4rem;
      #random-quote-source {
        font-style: italic;
      }

M sass/main.scss => sass/main.scss +4 -2
@@ 2,10 2,9 @@ @import 'vendor/skeleton';
  @import 'vendor/lity';
  
- @import '_variables';
- @import '_colors';
  @import '_mixins';
  @import '_variables';
+ @import '_colors';
  
  /* No need to enable these yet, until I write
   * a post making use of them.


@@ 16,6 15,7 @@   @import 'components/_after_post';
  @import 'components/_anchor';
+ @import 'components/_button';
  @import 'components/_codeblocks';
  @import 'components/_footer';
  @import 'components/_footnote';


@@ 27,7 27,9 @@   @import '_landing';
  @import '_misc';
+ @import '_container';
  @import '_posts';
+ @import '_talks';
  @import '_projects';
  @import '_section';
  @import '_tags';

M sass/vendor/skeleton.scss => sass/vendor/skeleton.scss +0 -8
@@ 206,14 206,6 @@ color: #333;
    border-color: #888;
    outline: 0; }
- .button.button-primary,
- button.button-primary,
- input[type="submit"].button-primary,
- input[type="reset"].button-primary,
- input[type="button"].button-primary {
-   color: #FFF;
-   background-color: #33C3F0;
-   border-color: #33C3F0; }
  .button.button-primary:hover,
  button.button-primary:hover,
  input[type="submit"].button-primary:hover,

M templates/categories/single.html => templates/categories/single.html +1 -1
@@ 2,7 2,7 @@   {% block main %}
  <article id="taxonomy" class="container post">
-     <h2>Posts categorized under {{ term.name }}</h2>
+     <h2>Pages categorized under {{ term.name }}</h2>
      {% for page in term.pages %}
        <div class="row">
          <tr>

M templates/landing.html => templates/landing.html +3 -2
@@ 20,8 20,9 @@ </div>
        <div class="row">
          <h4> Hi, I do stuff with computers. Take a look at my
-           <a href="./projects">programming projects</a>, or my
-           <a href="./posts">blog</a>.
+           <a href="./projects">programming projects</a>, my
+           <a href="./posts">blog</a>, or my
+           <a href="./talks">talks</a>.
          </h4>
        </div>
      </div>

M templates/macros.html => templates/macros.html +15 -2
@@ 1,8 1,8 @@-{% macro post_link(page) %}
+ {% macro post_link(page, section) %}
    {% if page.draft %}
    {% else %}
      <h2 class="post-title">
-       <a href="/posts/{{page.slug | safe}}/">
+       <a href="/{{section.components[0]}}/{{page.slug | safe}}/">
          * {{ page.title }}
        </a>
      </h2>


@@ 112,6 112,7 @@ <li><a href="/">Home</a></li>
          <li {% if path == 'posts' %}class="active"{% endif %}><a href="/posts/">Posts</a></li>
          <li {% if path == 'proje' %}class="active"{% endif %}><a href="/projects/">Projects</a></li>
+         <li {% if path == 'talks' %}class="active"{% endif %}><a href="/talks/">Talks</a></li>
          <li {% if path == 'conta' %}class="active"{% endif %}><a href="/contact/">Contact</a></li>
          <li {% if path == 'quote' %}class="active"{% endif %}><a href="/quotes/">Quotes</a></li>
          <li><a href="/rss.xml">RSS</a></li>


@@ 119,3 120,15 @@ </div>
    </nav>
  {% endmacro render_nav %}
+ 
+ {% macro render_term(term) %}
+   <div class="row">
+     <tr>
+       <td><time datetime="{{ term.date }}">{{ term.date  }}</time></td>
+         {% if term.components[0] == "talks" %}
+           <td> (talk) </td>
+         {% endif %}
+       <td><a href="/{{ term.path }}">{{ term.title }}</a></td>
+     </tr>
+   </div>
+ {% endmacro render_term %}

M templates/post.html => templates/post.html +1 -1
@@ 17,7 17,7 @@ {% endblock head %}
  
  {% block main %}
-   <div itemtype="http://schema.org/Article" class="container page">
+   <div itemtype="http://schema.org/Article" class="container post">
      <h1 itemprop="name">{{ page.title }}</h1>
      <time itemprop="datePublished" content="{{ page.date | date(format="%Y-%m-%d")}}" datetime="{{ page.date }}" class="page-date">
          {{ page.date | date(format="%b %d, %Y") }}

M templates/section.html => templates/section.html +2 -2
@@ 5,7 5,7 @@   {% block main %}
    <div class="container section">
-     {% set section = get_section(path="posts/_index.md") %}
+     {% set section = get_section(path=section.components[0] ~ "/_index.md") %}
      <h2 id="section-title"><a href="{{section.permalink}}">{{ section.title }}</a></h2>
  
      {% block introduction %}{% endblock introduction %}


@@ 13,7 13,7 @@ <div class="posts neutral">
          {% for page in section.pages %}
            <div class="section-post page">
-             {{ macros::post_link(page=page) }}
+             {{ macros::post_link(page=page, section=section) }}
            </div>
          {% endfor %}
      </div>

M templates/tags/single.html => templates/tags/single.html +5 -8
@@ 1,19 1,16 @@ {% extends "base.html" %}
  
+ {% import "macros.html" as macros %}
  {% block title %} {{ term.name }} | {{ config.title }} {% endblock title %}
  
  {% block main %}
+   {% set posts = term.pages | filter(attribute="components.0", value="posts") %}
+   {% set talks = term.pages | filter(attribute="components.0", value="talks") %}
    <div id="taxonomy" class="container">
-     <h2 class="tag-header"> Posts tagged with {{ term.name | title }}</h2>
- 
+     <h1 class="tag-header"> Pages tagged with {{ term.name | title }}</h1>
      <div class="tag-pages">
        {% for page in term.pages %}
-         <div class="row">
-           <tr>
-               <td><time datetime="{{ page.date }}">{{ page.date | date(format="%B %e, %Y") }}</time></td>
-               <td><a href="/{{ page.path }}">{{ page.title }}</a></td>
-           </tr>
-         </div>
+         {{ macros::render_term(term=page) }}
        {% endfor %}
      </div>
    </div>

A templates/talk.html => templates/talk.html +73 -0
@@ 0,0 1,73 @@
+ {% extends "base.html" %}
+ 
+ {% import "macros.html" as macros %}
+ {% block page %}{{ page }}{% endblock page %}
+ {% block title %}{{ page.title }} | {{ config.title }}{% endblock title %}
+ {% block ogtitle %}{{ page.title }} | {{ config.title }}{% endblock ogtitle %}
+ {% block twittertitle %}{{ page.title }} | {{ config.title }}{% endblock twittertitle %}
+ {% block summary %}{{ page.extra.summary | safe | striptags }}{% endblock summary %}
+ {% block ogsummary %}{{ page.extra.summary | safe | striptags }}{% endblock ogsummary %}
+ {% block keywords %}{{ page.extra.keywords }}{% endblock keywords %}
+ {% block permalink %}{{ page.permalink }}{% endblock permalink %}
+ 
+ {% block main %}
+   <div itemtype="http://schema.org/Article" class="container talks">
+     <h1 itemprop="name">{{ page.title }}</h1>
+     <time itemprop="datePublished" content="{{ page.date | date(format="%Y-%m-%d")}}" datetime="{{ page.date }}" class="page-date">
+         {{ page.date | date(format="%b %d, %Y") }}
+         {% if page.extra.updated %} <time itemprop="dateModified" content={{ page.extra.updated }}>(updated on {{ page.extra.updated }})</time> {% endif %}
+     </time>
+     <div itemtype="PresentationDigitalDocument">
+       <a class="button button-primary" href="{{page.extra.pdflink}}">Download PDF</a>
+     </div>
+     <hr>
+     <article itemprop="articleBody">
+       <div id="email-me">
+         <p>The following is the source code for this PDF.</p>
+ 
+         <p>Have any observations, criticisms, or corrections? Feel free to <a href="mailto:talks@andrewzah.com">email me</a>. Have a nice day!</p>
+       </div>
+       {{ page.content | safe }}
+     </article>
+   </div>
+ {% endblock main %}
+ 
+ {% block after_main %}
+   <div id="after-main" class="container">
+     <div id="random-quote">
+       <h2> Random quote </h2>
+       <blockquote id="random-quote-quote"></blockquote>
+       <p id="random-quote-citation">
+         <span id="random-quote-author"></span>
+         <span id="random-quote-source"></span>
+       </p>
+     </div>
+     <hr>
+ 
+     <div class="container after-post">
+         {% if page.earlier %}
+           <div id="previous_post">
+             Previous: <i>
+               <a class="prev" href="/talks/{{ page.earlier.slug | safe }}">{{ page.earlier.title }}</a>
+             </i>
+           </div>
+         {% endif %}
+ 
+         {% if page.later %}
+           <div id="next_post">
+             Next: <i>
+               <a class="next" href="/talks/{{ page.later.slug | safe }}">{{ page.later.title }}</a>
+             </i>
+           </div>
+         {% endif %}
+ 
+         {% if page.taxonomies %}
+           {{ macros::render_taxonomies(taxonomies=page.taxonomies) }}
+         {% endif %}
+     </div>
+ 
+     <hr>
+     </div>
+ 
+     {% include "_footer.html" %}
+     {% endblock after_main %}