diff --git a/.ruby-version b/.ruby-version
new file mode 100644
index 000000000..944880fa1
--- /dev/null
+++ b/.ruby-version
@@ -0,0 +1 @@
+3.2.0
diff --git a/Gemfile b/Gemfile
index b3b1956fc..f24d05f4a 100644
--- a/Gemfile
+++ b/Gemfile
@@ -2,5 +2,7 @@ source 'https://rubygems.org'
 
 gem 'github-pages'
 gem 'json', '>= 2.0.0'
-
-gem "webrick", "~> 1.8"
+gem 'webrick', '>= 1.8'
+gem 'csv', '~> 3.3'
+gem 'base64', '~> 0.2.0'
+gem 'bigdecimal', '~> 3.1'
diff --git a/Gemfile.lock b/Gemfile.lock
index 195c57b7c..bb36d1087 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -8,6 +8,8 @@ GEM
       tzinfo (~> 2.0)
     addressable (2.8.1)
       public_suffix (>= 2.0.2, < 6.0)
+    base64 (0.2.0)
+    bigdecimal (3.1.9)
     coffee-script (2.4.1)
       coffee-script-source
       execjs
@@ -15,6 +17,7 @@ GEM
     colorator (1.1.0)
     commonmarker (0.23.10)
     concurrent-ruby (1.2.2)
+    csv (3.3.3)
     dnsruby (1.61.9)
       simpleidn (~> 0.1)
     em-websocket (0.5.3)
@@ -206,14 +209,14 @@ GEM
       rb-fsevent (~> 0.10, >= 0.10.3)
       rb-inotify (~> 0.9, >= 0.9.10)
     mercenary (0.3.6)
-    mini_portile2 (2.8.1)
+    mini_portile2 (2.8.6)
     minima (2.5.1)
       jekyll (>= 3.5, < 5.0)
       jekyll-feed (~> 0.9)
       jekyll-seo-tag (~> 2.1)
     minitest (5.19.0)
-    nokogiri (1.14.3)
-      mini_portile2 (~> 2.8.0)
+    nokogiri (1.16.5)
+      mini_portile2 (~> 2.8.2)
       racc (~> 1.4)
     octokit (4.25.1)
       faraday (>= 1, < 3)
@@ -221,11 +224,11 @@ GEM
     pathutil (0.16.2)
       forwardable-extended (~> 2.6)
     public_suffix (4.0.7)
-    racc (1.6.2)
+    racc (1.7.3)
     rb-fsevent (0.11.2)
     rb-inotify (0.10.1)
       ffi (~> 1.0)
-    rexml (3.2.5)
+    rexml (3.3.9)
     rouge (3.26.0)
     ruby2_keywords (0.0.5)
     rubyzip (2.3.2)
@@ -250,15 +253,18 @@ GEM
       unf_ext
     unf_ext (0.0.8.2)
     unicode-display_width (1.8.0)
-    webrick (1.8.1)
+    webrick (1.8.2)
 
 PLATFORMS
   ruby
 
 DEPENDENCIES
+  base64 (~> 0.2.0)
+  bigdecimal (~> 3.1)
+  csv (~> 3.3)
   github-pages
   json (>= 2.0.0)
-  webrick (~> 1.8)
+  webrick (>= 1.8)
 
 BUNDLED WITH
-   2.3.7
+   2.5.23
diff --git a/_config.yml b/_config.yml
index 4481c167a..635db0b94 100644
--- a/_config.yml
+++ b/_config.yml
@@ -26,3 +26,4 @@ defaults:
     values:
       layout: post
       permalink: /blog/:year/:month/:day/:title/
+      image: /images/social/elixir-og-card.jpg
diff --git a/_data/elixir-versions.yml b/_data/elixir-versions.yml
index d33a48967..4d2593c70 100644
--- a/_data/elixir-versions.yml
+++ b/_data/elixir-versions.yml
@@ -1,10 +1,30 @@
-stable: v1_15
+stable: v1_18
+
+v1_18:
+  name: v1.18
+  minimum_otp: 26.0
+  recommended_otp: 27.3.4
+  otp_versions: [27, 26, 25]
+  version: 1.18.4
+
+v1_17:
+  name: v1.17
+  minimum_otp: 25.0
+  recommended_otp: 27.1.2
+  otp_versions: [27, 26, 25]
+  version: 1.17.3
+
+v1_16:
+  name: v1.16
+  minimum_otp: 24.0
+  otp_versions: [26, 25, 24]
+  version: 1.16.3
 
 v1_15:
   name: v1.15
   minimum_otp: 24.0
   otp_versions: [26, 25, 24]
-  version: 1.15.7
+  version: 1.15.8
 
 v1_14:
   name: v1.14
diff --git a/_data/getting-started.yml b/_data/getting-started.yml
deleted file mode 100644
index 515e578b9..000000000
--- a/_data/getting-started.yml
+++ /dev/null
@@ -1,123 +0,0 @@
-- title: Getting Started
-  dir: /getting-started/
-  pages:
-    - title: Introduction
-      slug: introduction
-
-    - title: Basic types
-      slug: basic-types
-
-    - title: Basic operators
-      slug: basic-operators
-
-    - title: Pattern matching
-      slug: pattern-matching
-
-    - title: case, cond, and if
-      slug: case-cond-and-if
-
-    - title: Binaries, strings, and charlists
-      slug: binaries-strings-and-char-lists
-
-    - title: Keyword lists and maps
-      slug: keywords-and-maps
-
-    - title: Modules and Functions
-      slug: modules-and-functions
-
-    - title: Recursion
-      slug: recursion
-
-    - title: Enumerables and streams
-      slug: enumerables-and-streams
-
-    - title: Processes
-      slug: processes
-
-    - title: IO and the file system
-      slug: io-and-the-file-system
-
-    - title: alias, require, and import
-      slug: alias-require-and-import
-
-    - title: Module attributes
-      slug: module-attributes
-
-    - title: Structs
-      slug: structs
-
-    - title: Protocols
-      slug: protocols
-
-    - title: Comprehensions
-      slug: comprehensions
-
-    - title: Sigils
-      slug: sigils
-
-    - title: try, catch, and rescue
-      slug: try-catch-and-rescue
-
-    - title: Optional syntax sheet
-      slug: optional-syntax
-
-    - title: Erlang libraries
-      slug: erlang-libraries
-
-    - title: Debugging
-      slug: debugging
-
-    - title: Typespecs and behaviours
-      slug: typespecs-and-behaviours
-
-    - title: Where to go next
-      slug: where-to-go-next
-
-- title: Mix and OTP
-  dir: /getting-started/mix-otp/
-  pages:
-    - title: Introduction to Mix
-      slug: introduction-to-mix
-
-    - title: Agent
-      slug: agent
-
-    - title: GenServer
-      slug: genserver
-
-    - title: Supervisor and Application
-      slug: supervisor-and-application
-
-    - title: Dynamic supervisors
-      slug: dynamic-supervisor
-
-    - title: ETS
-      slug: ets
-
-    - title: Dependencies and umbrella projects
-      slug: dependencies-and-umbrella-projects
-
-    - title: Task and gen_tcp
-      slug: task-and-gen-tcp
-
-    - title: Doctests, patterns and with
-      slug: docs-tests-and-with
-
-    - title: Distributed tasks and tags
-      slug: distributed-tasks
-
-    - title: Configuration and releases
-      slug: config-and-releases
-
-
-- title: Meta-programming in Elixir
-  dir: /getting-started/meta/
-  pages:
-    - title: Quote and unquote
-      slug: quote-and-unquote
-
-    - title: Macros
-      slug: macros
-
-    - title: Domain-specific languages
-      slug: domain-specific-languages
diff --git a/_includes/events.html b/_includes/events.html
index e6845ed63..7aedcfb1f 100644
--- a/_includes/events.html
+++ b/_includes/events.html
@@ -1,11 +1,11 @@
 <div class="widget events">
   <h3 class="widget-title">Upcoming events</h3>
-  <a href="https://2023.elixirconf.com/">
+  <a href="https://elixirconf.com/">
     <img src="https://2022.elixirconf.com/images/resources/elixirconf-logo.svg" alt="ElixirConf" />
     <br />
     <ul>
-      <li><b>Sep 5-8, 2023</b> - Orlando, FL.</li>
-      <li><b>8 training classes, 60+ speakers</b></li>
+      <li><b>Aug 28-29, 2025</b> - Orlando, FL.</li>
+      <li><b>Aug 27 - Seven Workshops to choose from</b></li>
     </ul>
   </a>
 </div>
\ No newline at end of file
diff --git a/_includes/important-links.html b/_includes/important-links.html
index ee22c3eaa..c4d5c0702 100644
--- a/_includes/important-links.html
+++ b/_includes/important-links.html
@@ -1,13 +1,19 @@
 <div class="widget">
   <h3 class="widget-title">Important links</h3>
   <ul>
-    <li class="menu-item development"><a class="spec" href="/development.html">Development & Team</a></li>
-    <li><a class="spec" href="https://github.com/elixir-lang/elixir">Source code & issues tracker</a></li>
+    <li class="menu-item development">
+      <a class="spec" href="/development.html">Development & Team</a>
+    </li>
+    <li>
+      <a class="spec" href="https://github.com/elixir-lang/elixir"
+        >Source code & issues tracker</a
+      >
+    </li>
   </ul>
 </div>
 
 <div id="mini-docu" class="widget">
-  <a href="https://cult.honeypot.io/originals/elixir-the-documentary">
+  <a href="https://www.youtube.com/watch?v=lxYFOM3UJzo">
     <div class="mini-docu-cta">
       <div class="mini-docu-copy">Watch the Elixir<br />mini-documentary!</div>
     </div>
@@ -23,14 +29,35 @@ <h3 class="widget-title">Join the Community</h3>
     <li><a class="spec" href="https://twitter.com/elixirlang">@elixirlang on Twitter</a></li>
     <li><a class="spec" href="irc://irc.libera.chat/elixir">#elixir on irc.libera.chat</a></li>
     <li><a class="spec" href="http://elixirforum.com">Elixir Forum</a></li>
+    <li><a class="spec" href="https://elixir-slack.community">Elixir on Slack</a></li>
     <li><a class="spec" href="https://discord.gg/elixir">Elixir on Discord</a></li>
-    <li><a class="spec" href="https://www.meetup.com/topics/elixir/">Meetups around the world</a></li>
-    <li><a class="spec" href="https://github.com/elixir-lang/elixir/wiki/Hiring-Elixir-Developers">Jobs and hiring (community wiki)</a></li>
-    <li><a class="spec" href="https://github.com/elixir-lang/elixir/wiki">Events and resources (community wiki)</a></li>
+    <li>
+      <a class="spec" href="https://github.com/elixir-lang/elixir/wiki/Code-Editor-Support"
+        >IDE/Editor support</a
+      >
+    </li>
+    <li>
+      <a class="spec" href="https://www.meetup.com/topics/elixir/">Meetups around the world</a>
+    </li>
+    <li>
+      <a class="spec" href="https://github.com/elixir-lang/elixir/wiki/Hiring-Elixir-Developers"
+        >Jobs and hiring (community wiki)</a
+      >
+    </li>
+    <li>
+      <a class="spec" href="https://github.com/elixir-lang/elixir/wiki"
+        >Events and resources (community wiki)</a
+      >
+    </li>
   </ul>
 </div>
 
 <div id="eef" class="widget">
-  <a href="https://erlef.org/" title="Join the Erlang Ecosystem Foundation"><img src="/images/logo/eef.png"
-      alt="Join the Erlang Ecosystem Foundation" width="174" style="margin-top:-10px" /></a>
-</div>
\ No newline at end of file
+  <a href="https://erlef.org/" title="Join the Erlang Ecosystem Foundation"
+    ><img
+      src="/images/logo/eef.png"
+      alt="Join the Erlang Ecosystem Foundation"
+      width="174"
+      style="margin-top: -10px"
+  /></a>
+</div>
diff --git a/_includes/mix-otp-preface.html b/_includes/mix-otp-preface.html
deleted file mode 100644
index 6354bcdf2..000000000
--- a/_includes/mix-otp-preface.html
+++ /dev/null
@@ -1,2 +0,0 @@
-> This chapter is part of the <i>Mix and OTP guide</i> and it depends on previous chapters in this guide.
-> For more information, <a href="/getting-started/mix-otp/introduction-to-mix.html">read the introduction guide</a> or check out the chapter index in the sidebar.
diff --git a/_includes/search.html b/_includes/search.html
index 2ab39ede8..fa32f4f56 100644
--- a/_includes/search.html
+++ b/_includes/search.html
@@ -1,15 +1,33 @@
 <div class="widget news">
   <h3>
-    News: <a href="/blog/2023/06/19/elixir-v1-15-0-released/">Elixir v1.15 released</a>
+    News: <a href="/blog/2025/08/05/global-elixir-meetups/">Global Elixir Meetups announced</a>
   </h3>
 </div>
 
 <div class="widget search">
-  <form method="post" role="search" id="search-form" class="search-form" action="https://duckduckgo.com/?kg=p"
-    onsubmit="document.getElementById('searchq').value = document.getElementById('searchfield').value + ' (site:elixir-lang.org | site:hexdocs.pm/elixir | site:hexdocs.pm/mix | site:hexdocs.pm/eex | site:hexdocs.pm/logger | site:hexdocs.pm/iex | site:hexdocs.pm/ex_unit)'; return true;">
-    <input type="hidden" id="searchq" name="q" value="" aria-hidden="true">
+  <form
+    method="post"
+    role="search"
+    id="search-form"
+    class="search-form"
+    action="https://duckduckgo.com/?kg=p"
+    onsubmit="document.getElementById('searchq').value = document.getElementById('searchfield').value + ' (site:elixir-lang.org | site:hexdocs.pm/elixir | site:hexdocs.pm/mix | site:hexdocs.pm/eex | site:hexdocs.pm/logger | site:hexdocs.pm/iex | site:hexdocs.pm/ex_unit)'; return true;"
+  >
+    <input type="hidden" id="searchq" name="q" value="" aria-hidden="true" />
 
-    <input class="search-text" type="search" placeholder="Search..." id="searchfield" aria-label="Search box">
-    <input class="search-submit button" name="submit" type="submit" value="Search" aria-label="Search button">
+    <input
+      class="search-text"
+      type="search"
+      placeholder="Search..."
+      id="searchfield"
+      aria-label="Search box"
+    />
+    <input
+      class="search-submit button"
+      name="submit"
+      type="submit"
+      value="Search"
+      aria-label="Search button"
+    />
   </form>
 </div>
diff --git a/_includes/top.html b/_includes/top.html
index e030141aa..13ecc8304 100644
--- a/_includes/top.html
+++ b/_includes/top.html
@@ -38,7 +38,7 @@
           <li class="menu-item install"><a class="spec" href="/install.html">Install</a></li>
           <li class="menu-item learning"><a class="spec" href="/learning.html">Learning</a></li>
           <li class="menu-item docs"><a class="spec" href="/docs.html">Docs</a></li>
-          <li class="menu-item getting-started"><a class="spec" href="/getting-started/introduction.html">Guides</a></li>
+          <li class="menu-item getting-started"><a class="spec" href="https://hexdocs.pm/elixir/introduction.html">Guides</a></li>
           <li class="menu-item cases"><a class="spec" href="/cases.html">Cases</a></li>
           <li class="menu-item blog"><a class="spec" href="/blog/">Blog</a></li>
         </ul>
diff --git a/_layouts/blog.html b/_layouts/blog.html
index aa043b029..92a81743d 100644
--- a/_layouts/blog.html
+++ b/_layouts/blog.html
@@ -7,7 +7,7 @@
 <div id="sidebar-primary" class="sidebar">
   {% include search.html %}
   <div class="rss-button">
-    <a href="https://elixir-lang.org/atom.xml" target="_blank"><img src="/images/social/RSSButton.png" alt="RSS button" /></a>
+    <a href="https://elixir-lang.org/atom.xml" target="_blank"><img src="/images/social/rss-feed-icon.svg" alt="RSS button" width="32" /></a>
   </div>
   {% include categories-list.html %}
   {% include important-links.html %}
diff --git a/_layouts/getting-started.html b/_layouts/getting-started.html
deleted file mode 100644
index 7883837c9..000000000
--- a/_layouts/getting-started.html
+++ /dev/null
@@ -1,73 +0,0 @@
-{% include top.html %}
-
-<div id="sidebar-primary" class="sidebar">
-  {% include search.html %}
-
-  <a class="spec" href="/docs.html" style="display: block;margin-bottom: 20px">API Documentation</a>
-
-  {% assign guides = site.data.getting-started  %}
-  {% for guide in site.data.getting-started %}
-    <div class="widget">
-     <h3 class="widget-title">{{guide.title}}</h3>
-      <ol>
-        {% for node in guide.pages %}
-          {% assign page_url = guide.dir | append: node.slug | append: '.html' %}
-          {% if page.url == page_url %}
-            <li><span title="{{node.title | escape}}">{{node.title}}</span></li>
-          {% else %}
-            <li><a class="spec" href="{{page_url}}" title="{{node.title | escape}}">{{node.title}}</a></li>
-          {% endif %}
-        {% endfor %}
-      </ol>
-    </div>
-  {% endfor %}
-</div>
-
-<div id="content">
-  <article>
-    <div class="getting-started-title">
-      <small>{{ page.category | default: "Getting Started" }}</small>
-      <h1>{{ page.title }}</h1>
-    </div>
-
-    {% include toc.html %}
-
-    {{ content }}
-  </article><!-- .hfeed -->
-
-  {% assign url_parts = page.url | split: '/' %}
-  {% assign url_parts_size = url_parts | size %}
-  {% assign file_name = url_parts | last %}
-  {% assign guide_base_url = page.url | replace: file_name %}
-  {% assign page_slug = file_name | replace: '.html' %}
-
-  {% assign guides = site.data.getting-started  %}
-  {% for guide in site.data.getting-started %}
-    {% if guide.dir == guide_base_url %}
-      {% for node in guide.pages %}
-        {% if node.slug == page_slug %}
-          <div class="pagination loop-pagination">
-            {% unless forloop.first %}
-              <a href="{{guide.dir}}{{prev.slug}}.html" class="previous page-numbers spec" title="{{prev.title | escape}}">&larr; Previous</a>
-            {% endunless %}
-              <a class="page-numbers spec" href="#container">Top</a>
-            {% unless forloop.last %}
-              {% assign next = guide.pages[forloop.index] %}
-              <a href="{{guide.dir}}{{next.slug}}.html" class="previous page-numbers spec" title="{{next.title | escape}}">Next &rarr;</a>
-            {% endunless %}
-          </div>
-        {% endif %}
-        {% assign prev = node %}
-      {% endfor %}
-    {% endif %}
-  {% endfor %}
-
-  <div id="edit-on-github">
-    <span>Is something wrong?</span>
-    <a href="{{ site.github.repository_url }}/edit/main/{{ page.path }}">
-      Edit this page on GitHub.
-    </a>
-  </div>
-</div><!-- #content -->
-
-{% include bottom.html %}
diff --git a/_layouts/post.html b/_layouts/post.html
index 8cde0eff9..4cab9e33a 100644
--- a/_layouts/post.html
+++ b/_layouts/post.html
@@ -11,7 +11,7 @@ <h1>{{ page.title }}</h1>
         {% if page.subtitle %}
         <h2>{{ page.subtitle }}</h2>
         {% endif %}
-        <div class="byline">{{ page.date | date: "%B %d, %Y" }}{% if page.author %} &middot; by {{ page.author}}{% endif %} &middot; in {% for category in page.categories %}
+        <div class="byline">{{ page.date | date: "%B %d, %Y" }}{% if page.authors %} &middot; by {{ page.authors | join: ", " }}{% endif %} &middot; in {% for category in page.categories %}
           {% if category == "Elixir in Production" %}
             <a class="category" href="/cases.html">{{ category }}</a>
           {% else %}
diff --git a/_layouts/redirect.html b/_layouts/redirect.html
new file mode 100644
index 000000000..464f54e82
--- /dev/null
+++ b/_layouts/redirect.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link rel="canonical" href="https://hexdocs.pm/elixir/{{ page.redirect_to }}.html"/>
+<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+<meta http-equiv="refresh" content="0;url=https://hexdocs.pm/elixir/{{ page.redirect_to }}.html" />
+</head>
+<body>
+  <h3>Redirecting...</h3>
+  <a href="https://hexdocs.pm/elixir/{{ page.redirect_to }}.html">Click here if you are not redirected.<a>
+  <script>location='https://hexdocs.pm/elixir/{{ page.redirect_to }}.html'</script>
+</body>
+</html>
+
diff --git a/_posts/2012-04-24-a-peek-inside-elixir-s-parallel-compiler.markdown b/_posts/2012-04-24-a-peek-inside-elixir-s-parallel-compiler.markdown
index e4f0fe17f..591610198 100644
--- a/_posts/2012-04-24-a-peek-inside-elixir-s-parallel-compiler.markdown
+++ b/_posts/2012-04-24-a-peek-inside-elixir-s-parallel-compiler.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: A peek inside Elixir's Parallel Compiler
-author: José Valim
+authors:
+-  José Valim
 category: Internals
 excerpt: Today, a parallel compiler just landed in Elixir main. The goal of the parallel compiler is to compile files in parallel, automatically detecting dependencies between files. In this blog post, we are going to take a peek into the parallel compiler internals and learn more about Erlang and Elixir in the process.
 ---
diff --git a/_posts/2012-05-25-elixir-v0-5-0-released.markdown b/_posts/2012-05-25-elixir-v0-5-0-released.markdown
index 50ab28e44..a5701a60d 100644
--- a/_posts/2012-05-25-elixir-v0-5-0-released.markdown
+++ b/_posts/2012-05-25-elixir-v0-5-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v0.5.0 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: We have finally released Elixir v0.5.0! This marks the first release since the language was rewritten. In this blog post, we will discuss what we achieved during this time and what are the next steps!
 
@@ -9,7 +10,7 @@ excerpt: We have finally released Elixir v0.5.0! This marks the first release si
 
 We have finally released [Elixir](/) v0.5.0! This marks the first release since the language was rewritten. In this blog post, we will discuss what we achieved during this time and what are the next steps!
 
-If you don't care about any of these, you can go straight to our [Getting Started guide](/getting-started/introduction.html). If you do, keep on reading!
+If you don't care about any of these, you can go straight to our [Getting Started guide](https://hexdocs.pm/elixir/introduction.html). If you do, keep on reading!
 
 ## Looking back
 
@@ -45,4 +46,4 @@ In parallel, we will improve our [documentation generation tool](https://github.
 
 Finally, we will continue improving the Standard Library. Although Elixir's goal is to rely on Erlang the most as possible, we also want to provide a small Standard Library which makes better use of Elixir semantics. For the next weeks, we will focus on improving the IO and File manipulation modules. New data types may also appear, for example, ranges come to my mind.
 
-Check out our [home page](/) and the [getting started guide](/getting-started/introduction.html) for more information. Welcome aboard and grab a cup of Elixir, because you are certainly going to enjoy the ride!
+Check out our [home page](/) and the [getting started guide](https://hexdocs.pm/elixir/introduction.html) for more information. Welcome aboard and grab a cup of Elixir, because you are certainly going to enjoy the ride!
diff --git a/_posts/2012-08-01-elixir-v0-6-0-released.markdown b/_posts/2012-08-01-elixir-v0-6-0-released.markdown
index ff8fbe828..becafdf7c 100644
--- a/_posts/2012-08-01-elixir-v0-6-0-released.markdown
+++ b/_posts/2012-08-01-elixir-v0-6-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v0.6.0 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: We have finally released Elixir v0.6.0! This release includes a build tool called Mix, support for Erlang typespecs, many improvements to IEx and improved IO, File and Macro support.
 
@@ -24,4 +25,4 @@ Our interactive shell (IEx) also had many improvements, thanks to the Elixir dev
 
 That's it. For the next months, we will continue improving Elixir (you can see some ideas floating around in the [issues tracker](https://github.com/elixir-lang/elixir/issues)) but we will start to focus on other tools and libraries for the community.
 
-Thank you and don't forget to [give Elixir a try](/getting-started/introduction.html)!
+Thank you and don't forget to [give Elixir a try](https://hexdocs.pm/elixir/introduction.html)!
diff --git a/_posts/2012-10-20-elixir-v0-7-0-released.markdown b/_posts/2012-10-20-elixir-v0-7-0-released.markdown
index 16db42d47..d2f181612 100644
--- a/_posts/2012-10-20-elixir-v0-7-0-released.markdown
+++ b/_posts/2012-10-20-elixir-v0-7-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v0.7.0 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: Elixir v0.7.0 is released with many improvements! Read on for more information.
 
@@ -15,4 +16,4 @@ This release also includes some backwards incompatible changes, but the majority
 
 For more information, read out the [CHANGELOG](https://github.com/elixir-lang/elixir/blob/v0.7.0/CHANGELOG.md).
 
-Thank you and don't forget to [give Elixir a try](/getting-started/introduction.html)!
+Thank you and don't forget to [give Elixir a try](https://hexdocs.pm/elixir/introduction.html)!
diff --git a/_posts/2012-11-18-elixir-v0-7-1-released.markdown b/_posts/2012-11-18-elixir-v0-7-1-released.markdown
index 825fbd2c0..113bcd31f 100644
--- a/_posts/2012-11-18-elixir-v0-7-1-released.markdown
+++ b/_posts/2012-11-18-elixir-v0-7-1-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v0.7.1 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: Elixir v0.7.1 was released to celebrate the end of a two months journey traveling around Europe, United States and Brazil talking about Elixir.
 
@@ -15,7 +16,7 @@ During this time traveling around, we have spoken at many conferences, as [Stran
 
 In case you missed any of those conferences, [the talk I presented at Øredev is available and you can watch it now](https://vimeo.com/53221562). The slides are also available below.
 
-If you want to hear more about Elixir at a conference or an event, please let us know. Thank you and don't forget to [give Elixir a try](/getting-started/introduction.html)!
+If you want to hear more about Elixir at a conference or an event, please let us know. Thank you and don't forget to [give Elixir a try](https://hexdocs.pm/elixir/introduction.html)!
 
 <script async class="speakerdeck-embed" data-id="cf4727401449013077d112313d1a82a3" data-ratio="1.2994923857868" src="//speakerdeck.com/assets/embed.js"></script>
 
diff --git a/_posts/2012-12-04-elixir-v0-7-2-released.markdown b/_posts/2012-12-04-elixir-v0-7-2-released.markdown
index fd5280660..b4ec972c7 100644
--- a/_posts/2012-12-04-elixir-v0-7-2-released.markdown
+++ b/_posts/2012-12-04-elixir-v0-7-2-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v0.7.2 released
-author: Yurii Rashkovskii
+authors:
+-  Yurii Rashkovskii
 category: Releases
 excerpt: Elixir v0.7.2 is released, new, improved type specifications syntax and many other improvements.
 
@@ -50,4 +51,4 @@ under some circumstances when using records.
 
 Lastly, but not least importantly, I'd like to mention that we're very excited about how the community around Elixir is building up. Thank you all for being around and supporting us!
 
-[Learn more about Elixir](/getting-started/introduction.html)!
+[Learn more about Elixir](https://hexdocs.pm/elixir/introduction.html)!
diff --git a/_posts/2013-01-27-elixir-v0-8-0-released.markdown b/_posts/2013-01-27-elixir-v0-8-0-released.markdown
index 9aa5452e8..9f6236b10 100644
--- a/_posts/2013-01-27-elixir-v0-8-0-released.markdown
+++ b/_posts/2013-01-27-elixir-v0-8-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v0.8.0 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: On the last 9th January, we celebrated two years since Elixir's first commit and to celebrate this occasion we have prepared a big release. Elixir v0.8 is out, with documentation, optimizations, bug fixes and shiny new features. Let's take a look at them!
 ---
@@ -18,7 +19,7 @@ And applications can be started directly from the command line as well:
 
     elixir --app my_app
 
-We have written a whole [guide chapter about creating OTP applications, supervisors and servers](/getting-started/mix-otp/supervisor-and-application.html). Give it a try!
+We have written a whole [guide chapter about creating OTP applications, supervisors and servers](https://hexdocs.pm/elixir/supervisor-and-application.html). Give it a try!
 
 ## Improved Unicode support
 
@@ -70,7 +71,7 @@ When some code call the `unless` macro above, in previous Elixir versions, it wo
 
 Elixir v0.8 ensures that the `unless` macro above will expand to the same `if` macro available when quoted, guaranteeing different libraries can integrate easily without imposing hidden requirements.
 
-You can read more about [macros in the getting started guide](/getting-started/case-cond-and-if.html) or [go deep into the quote macro docs](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#quote/2).
+You can read more about [macros in the getting started guide](https://hexdocs.pm/elixir/case-cond-and-if.html) or [go deep into the quote macro docs](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#quote/2).
 
 ## A new way to manipulate pathnames
 
@@ -100,4 +101,4 @@ We continue actively working on Elixir and this release is the [result of our ef
 
 Also, we previously announced Elixir is going to be released frequently, every 2 to 4 weeks. We have made a small detour to get v0.8.0 out of the door, but we are back to our regular schedule as of today!
 
-[Celebrate with us and give Elixir a try](/getting-started/introduction.html)!
+[Celebrate with us and give Elixir a try](https://hexdocs.pm/elixir/introduction.html)!
diff --git a/_posts/2013-04-19-google-summer-of-code-2013.markdown b/_posts/2013-04-19-google-summer-of-code-2013.markdown
index b025579f6..d964d7c1b 100644
--- a/_posts/2013-04-19-google-summer-of-code-2013.markdown
+++ b/_posts/2013-04-19-google-summer-of-code-2013.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Google Summer of Code 2013
-author: José Valim
+authors:
+-  José Valim
 category: Announcements
 excerpt: Elixir is taking part in Google Summer of Code 2013! Are you a student? Join us!
 ---
diff --git a/_posts/2013-04-29-elixir-v0-8-2-released.markdown b/_posts/2013-04-29-elixir-v0-8-2-released.markdown
index 9579766ac..fea64d566 100644
--- a/_posts/2013-04-29-elixir-v0-8-2-released.markdown
+++ b/_posts/2013-04-29-elixir-v0-8-2-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v0.8.2 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: Elixir v0.8.2 is released with bug fixes, better Erlang R16 support and doctests.
 ---
@@ -46,4 +47,4 @@ end
 
 You can learn more about [doctests on our documentation page](https://hexdocs.pm/ex_unit/ExUnit.DocTest.html) and get more information about our latest release [on the CHANGELOG](https://github.com/elixir-lang/elixir/blob/ed27611f48ba150404c95fe15f1d6058a4287330/CHANGELOG.md).
 
-If you are new to Elixir, [it's easy to get started with](/getting-started/introduction.html)!
+If you are new to Elixir, [it's easy to get started with](https://hexdocs.pm/elixir/introduction.html)!
diff --git a/_posts/2013-05-02-elixir-on-xen.markdown b/_posts/2013-05-02-elixir-on-xen.markdown
index a4dd2de42..9f1de4c2b 100644
--- a/_posts/2013-05-02-elixir-on-xen.markdown
+++ b/_posts/2013-05-02-elixir-on-xen.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir on Xen
-author: José Valim
+authors:
+-  José Valim
 category: Announcements
 excerpt: The Erlang on Xen team has added support for Elixir and we will tell you how you can use it!
 ---
diff --git a/_posts/2013-05-23-elixir-v0-9-0-released.markdown b/_posts/2013-05-23-elixir-v0-9-0-released.markdown
index 573a77058..edee304e1 100644
--- a/_posts/2013-05-23-elixir-v0-9-0-released.markdown
+++ b/_posts/2013-05-23-elixir-v0-9-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v0.9.0 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: Elixir v0.9.0 is released with support for reducers, umbrella projects, faster compilation times and dropped support for R15 and earlier OTP versions.
 ---
@@ -130,4 +131,4 @@ We have also many other smaller improvements:
 
 A huge thank you to our community for sending bug reports, providing bug fixes and contributing all those amazing features. And when are **you** joining us? :)
 
-Give Elixir a try! You can start with our [getting started guide](/getting-started/introduction.html), or [check this 30 minute video from PragProg](https://www.youtube.com/watch?v=a-off4Vznjs&feature=youtu.be) or buy the beta version of [Programming Elixir](https://pragprog.com/book/elixir/programming-elixir).
+Give Elixir a try! You can start with our [getting started guide](https://hexdocs.pm/elixir/introduction.html), or [check this 30 minute video from PragProg](https://www.youtube.com/watch?v=a-off4Vznjs&feature=youtu.be) or buy the beta version of [Programming Elixir](https://pragprog.com/book/elixir/programming-elixir).
diff --git a/_posts/2013-07-13-elixir-v0-10-0-released.markdown b/_posts/2013-07-13-elixir-v0-10-0-released.markdown
index 3d28ad7ba..c00858ea8 100644
--- a/_posts/2013-07-13-elixir-v0-10-0-released.markdown
+++ b/_posts/2013-07-13-elixir-v0-10-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v0.10.0 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: Elixir v0.10.0 is out with support for streams, sets, pretty printing and many improvements for Mix and ExUnit.
 ---
@@ -82,4 +83,4 @@ Other notable improvements are:
 
 There are also improvements to typespecs, error messages, many bug fixes and some backwards incompatible changes. We have posted a detailed [upgrade instructions on the mailing list](https://groups.google.com/forum/?fromgroups#!topic/elixir-lang-talk/ksrefrgK1eY). For a general overview, [check out the CHANGELOG](https://github.com/elixir-lang/elixir/blob/v0.10.0/CHANGELOG.md).
 
-Give Elixir a try! You can start with our [getting started guide](/getting-started/introduction.html), or check out our sidebar for other learning resources.
+Give Elixir a try! You can start with our [getting started guide](https://hexdocs.pm/elixir/introduction.html), or check out our sidebar for other learning resources.
diff --git a/_posts/2013-08-08-elixir-design-goals.markdown b/_posts/2013-08-08-elixir-design-goals.markdown
index a71db2b76..5959dab92 100644
--- a/_posts/2013-08-08-elixir-design-goals.markdown
+++ b/_posts/2013-08-08-elixir-design-goals.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir Design Goals
-author: José Valim
+authors:
+-  José Valim
 category: Internals
 excerpt: Highlight of Elixir design goals.
 ---
@@ -212,4 +213,4 @@ The goal of this post was to sumarize the language goals: compatibility, product
 
 We also hope to have clarified what Elixir brings to the Erlang VM, in particular, meta-programming through macros, polymorphic constructs for extensibility and a data-focused standard library with extensible and consistent APIs for diverse types, including strict and lazy enumeration, unicode handling, a test framework and more.
 
-Give Elixir a try! You can start with our [getting started guide](/getting-started/introduction.html), or check out our sidebar for other learning resources.
+Give Elixir a try! You can start with our [getting started guide](https://hexdocs.pm/elixir/introduction.html), or check out our sidebar for other learning resources.
diff --git a/_posts/2013-11-05-elixir-v0-11-0-released.markdown b/_posts/2013-11-05-elixir-v0-11-0-released.markdown
index 80e3bb825..1a668262c 100644
--- a/_posts/2013-11-05-elixir-v0-11-0-released.markdown
+++ b/_posts/2013-11-05-elixir-v0-11-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v0.11.0 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: Elixir v0.11.0 is out and it focus on improving and optimizing the patterns often used by the community.
 ---
@@ -67,6 +68,6 @@ In the optimization front, we have pushed the first iteration of a [feature call
 
 And finally, a minor but frequently asked feature has finally arrived into Elixir: variables follow the same rules as other identifiers in the language, which means developers can now name their variables `is_atom?`. For a general overview, [check out the CHANGELOG](https://github.com/elixir-lang/elixir/blob/v0.11.0/CHANGELOG.md).
 
-Give Elixir a try! You can start with our [getting started guide](/getting-started/introduction.html), or check out our sidebar for other learning resources.
+Give Elixir a try! You can start with our [getting started guide](https://hexdocs.pm/elixir/introduction.html), or check out our sidebar for other learning resources.
 
 **PS:** We have just released v0.11.1 which addresses a regression in Mix and improves the dependencies update process.
diff --git a/_posts/2013-12-11-elixir-s-new-continuable-enumerators.markdown b/_posts/2013-12-11-elixir-s-new-continuable-enumerators.markdown
index 9a0670d9f..b29807cb4 100644
--- a/_posts/2013-12-11-elixir-s-new-continuable-enumerators.markdown
+++ b/_posts/2013-12-11-elixir-s-new-continuable-enumerators.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir's new continuable enumerators
-author: Peter Minten
+authors:
+-  Peter Minten
 category: Internals
 excerpt: In 0.12.0 Elixir's enumerators have gained the ability to suspend value
          production and to terminate early.
diff --git a/_posts/2013-12-15-elixir-v0-12-0-released.markdown b/_posts/2013-12-15-elixir-v0-12-0-released.markdown
index 7040da8ee..fe8a349e3 100644
--- a/_posts/2013-12-15-elixir-v0-12-0-released.markdown
+++ b/_posts/2013-12-15-elixir-v0-12-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v0.12.0 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: Elixir v0.12.0 is out with improved enumerables, build patterns and welcoming a new member to our team
 ---
@@ -49,4 +50,4 @@ Eric is also maintainer of both [Ecto](https://github.com/elixir-ecto/ecto) and
 
 There were other small changes, like additions to the `Float` module and improvements the to the typespec syntax. To see the full list, please [see the CHANGELOG](https://github.com/elixir-lang/elixir/blob/v0.12.0/CHANGELOG.md).
 
-Give Elixir a try! You can start with our [getting started guide](/getting-started/introduction.html), or check out our sidebar for other learning resources.
+Give Elixir a try! You can start with our [getting started guide](https://hexdocs.pm/elixir/introduction.html), or check out our sidebar for other learning resources.
diff --git a/_posts/2014-04-21-elixir-v0-13-0-released.markdown b/_posts/2014-04-21-elixir-v0-13-0-released.markdown
index 6fef928aa..995e4d68c 100644
--- a/_posts/2014-04-21-elixir-v0-13-0-released.markdown
+++ b/_posts/2014-04-21-elixir-v0-13-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v0.13.0 released, hex.pm and ElixirConf announced
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: "Elixir v0.13.0 comes with substantial improvements to the language: maps, structs, comprehensiona and more. It also marks the announcement of the hex.pm package manager and the announcement of ElixirConf!"
 ---
@@ -28,7 +29,7 @@ In a nutshell, here is what new:
 
 * Elixir v0.13 also provides structs, an alternative to Elixir records. Structs are more flexible than records, provide faster polymorphic operations, and still provide the same compile-time guarantees many came to love in records;
 
-* The [Getting Started guide](/getting-started/introduction.html) was rewritten from scratch. The previous guide was comprised of 7 chapters and was about to become 2 years old. The new guide features 20 chapters, it explores the new maps and structs (which are part of this release), and it goes deeper into topics like IO and File handling. It also includes an extra guide, still in development, about [Meta-Programming in Elixir](/getting-started/meta/quote-and-unquote.html);
+* The [Getting Started guide](https://hexdocs.pm/elixir/introduction.html) was rewritten from scratch. The previous guide was comprised of 7 chapters and was about to become 2 years old. The new guide features 20 chapters, it explores the new maps and structs (which are part of this release), and it goes deeper into topics like IO and File handling. It also includes an extra guide, still in development, about [Meta-Programming in Elixir](https://hexdocs.pm/elixir/quote-and-unquote.html);
 
 * Elixir v0.13 provides a new comprehension syntax that not only works with lists, but with any [`Enumerable`](https://hexdocs.pm/elixir/Enumerable.html). The output of a comprehension is also extensible via the [`Collectable`](https://hexdocs.pm/elixir/Collectable.html) protocol;
 
@@ -68,7 +69,7 @@ iex> %{"other" => value} = map
 
 A map pattern will match any map that has all the keys specified in the pattern. The values for the matching keys must also match. For example, `%{"hello" => world}` will match any map that has the key `"hello"` and assign the value to `world`, while `%{"hello" => "world"}` will match any map that has the key `"hello"` with value equals to `"world"`. An empty map pattern (`%{}`) will match all maps.
 
-Developers can use the functions in the [`Map` module](https://hexdocs.pm/elixir/Map.html) to work with maps. For more information on maps and how they compare to other associative data structures in the language, please check the [Maps chapter in our new Getting Started guide](/getting-started/keywords-and-maps.html). Elixir Sips has also released two episodes that cover maps ([part 1](http://elixirsips.com/episodes/054_maps_part_1.html) and [part 2](http://elixirsips.com/episodes/055_maps_part_2.html)).
+Developers can use the functions in the [`Map` module](https://hexdocs.pm/elixir/Map.html) to work with maps. For more information on maps and how they compare to other associative data structures in the language, please check the [Maps chapter in our new Getting Started guide](https://hexdocs.pm/elixir/keywords-and-maps.html). Elixir Sips has also released two episodes that cover maps ([part 1](http://elixirsips.com/episodes/054_maps_part_1.html) and [part 2](http://elixirsips.com/episodes/055_maps_part_2.html)).
 
 Maps also provide special syntax for creating, accessing and updating maps with atom keys:
 
@@ -179,7 +180,7 @@ The `__struct__` field is also used for polymorphic dispatch in protocols, addre
 
 It is interesting to note that structs solve both drawbacks we have earlier mentioned regarding records. Structs are purely data and polymorphic dispatch is now faster and more robust as it happens only for explicitly tagged structs.
 
-For more information on structs, check out the [Structs chapter in the getting started guide](/getting-started/structs.html) (you may also want to read the new [Protocols chapter](/getting-started/protocols.html) after it).
+For more information on structs, check out the [Structs chapter in the getting started guide](https://hexdocs.pm/elixir/structs.html) (you may also want to read the new [Protocols chapter](https://hexdocs.pm/elixir/protocols.html) after it).
 
 ## Maps, structs and the future
 
@@ -279,4 +280,4 @@ That said, in the next months we plan to:
 * Study how patterns like tasks and agents can be integrated into the language, often picking up the lessons learned by libraries like [e2](http://e2project.org/erlang.html) and [functionality exposed by OTP itself](http://www.erlang.org/doc/man/rpc.html);
 * Rewrite the Mix and ExUnit guides to focus on applications and OTP as a whole, rebranding it to "Building Apps with Mix and OTP";
 
-You can learn more about Elixir in our [Getting Started guide](/getting-started/introduction.html) and download this release in the [v0.13 announcement](https://github.com/elixir-lang/elixir/releases/tag/v0.13.0). We hope to see you at [ElixirConf](http://elixirconf.com/) as well as pushing your packages to [hex.pm](https://hex.pm/).
+You can learn more about Elixir in our [Getting Started guide](https://hexdocs.pm/elixir/introduction.html) and download this release in the [v0.13 announcement](https://github.com/elixir-lang/elixir/releases/tag/v0.13.0). We hope to see you at [ElixirConf](http://elixirconf.com/) as well as pushing your packages to [hex.pm](https://hex.pm/).
diff --git a/_posts/2014-06-17-elixir-v0-14-0-released.markdown b/_posts/2014-06-17-elixir-v0-14-0-released.markdown
index b1955d87b..cfa23e5ca 100644
--- a/_posts/2014-06-17-elixir-v0-14-0-released.markdown
+++ b/_posts/2014-06-17-elixir-v0-14-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v0.14.0 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: "Elixir v0.14.0 is released and expands the work on structs and bringing more of OTP right into Elixir and Mix"
 ---
@@ -144,9 +145,9 @@ In v0.14.0, Elixir closely integrates with OTP by providing modules for building
 
 We have also introduced the concepts of [agents](https://hexdocs.pm/elixir/Agent.html) and the idea of [tasks](https://hexdocs.pm/elixir/Task.html), which can be supervised and distributed. Application configuration has been made first class in Mix, allowing developers to configure their dependencies, sometimes even using different configurations per environment (dev, test or prod by default).
 
-This functionality is at the core of building applications in Erlang and Elixir. For this reason we have published a new guide called [Mix and OTP](/getting-started/mix-otp/introduction-to-mix.html) where we build a distributed key-value store to help explore all concepts mentioned above. The guide is quite fresh, so please do submit pull requests for typos and mistakes. Feedback is also welcome!
+This functionality is at the core of building applications in Erlang and Elixir. For this reason we have published a new guide called [Mix and OTP](https://hexdocs.pm/elixir/introduction-to-mix.html) where we build a distributed key-value store to help explore all concepts mentioned above. The guide is quite fresh, so please do submit pull requests for typos and mistakes. Feedback is also welcome!
 
-Note "Mix and OTP" is our most advanced guide so far and it expects you to have read our introductory guide. In case you haven't yet, you can [get started here](/getting-started/introduction.html).
+Note "Mix and OTP" is our most advanced guide so far and it expects you to have read our introductory guide. In case you haven't yet, you can [get started here](https://hexdocs.pm/elixir/introduction.html).
 
 ## What's next?
 
@@ -160,6 +161,6 @@ With v0.14.0 we have reached many of the milestones [we have set in the previous
 
 * Solve all remaining [open issues](https://github.com/elixir-lang/elixir/issues?state=open). We have always kept the issues tracker tidy and there is little work left to solve the existing issues. Note we have also listed all [upcoming backwards incompatible changes](https://github.com/elixir-lang/elixir/issues?labels=Note%3ABackwards+incompatible&page=1&state=open). Many of those changes will actually be deprecated first and developers should be able to follow along without breaking changes in minor releases, but they are breaking changes in the sense they work in v0.14.0 but will work differently by the time v1.0 is released;
 
-That's all for now! Elixir developers can see [a summary of all changes in v0.14.0 in the release notes](https://github.com/elixir-lang/elixir/releases/tag/v0.14.0). In case you are new around here, you can get started with Elixir by reading [our Getting Started guide](/getting-started/introduction.html).
+That's all for now! Elixir developers can see [a summary of all changes in v0.14.0 in the release notes](https://github.com/elixir-lang/elixir/releases/tag/v0.14.0). In case you are new around here, you can get started with Elixir by reading [our Getting Started guide](https://hexdocs.pm/elixir/introduction.html).
 
 We hope to see you all this July at [ElixirConf](http://elixirconf.com/)!
diff --git a/_posts/2014-08-07-elixir-v0-15-0-released.markdown b/_posts/2014-08-07-elixir-v0-15-0-released.markdown
index dee1c607e..32b579555 100644
--- a/_posts/2014-08-07-elixir-v0-15-0-released.markdown
+++ b/_posts/2014-08-07-elixir-v0-15-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v0.15.0 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: "Elixir v0.15.0 introduces Elixir's Logger, Mix aliases and is the last stop before Elixir v1.0. We are also glad to welcome Alexei into our team!"
 ---
@@ -162,4 +163,4 @@ Alexei is also interested in how we can extend our tooling to the Erlang ecosyst
 
 We are very close to launch Elixir v1.0! All planned features are already in Elixir's codebase and at the moment there are only [four open issues in our tracker tagged with the v1.0 milestone](https://github.com/elixir-lang/elixir/issues?q=is%3Aopen+is%3Aissue+milestone%3Av1.0).
 
-Our estimated date for the first release candidate for Elixir v1.0 is August 30th. This means there is no better time to learn Elixir than now! If you haven't started yet, you can get started with Elixir by reading [our Getting Started guide](/getting-started/introduction.html) or by checking one of the many "Learning Resources" on the sidebar.
+Our estimated date for the first release candidate for Elixir v1.0 is August 30th. This means there is no better time to learn Elixir than now! If you haven't started yet, you can get started with Elixir by reading [our Getting Started guide](https://hexdocs.pm/elixir/introduction.html) or by checking one of the many "Learning Resources" on the sidebar.
diff --git a/_posts/2014-09-18-elixir-v1-0-0-released.markdown b/_posts/2014-09-18-elixir-v1-0-0-released.markdown
index c1499fa2b..72929864c 100644
--- a/_posts/2014-09-18-elixir-v1-0-0-released.markdown
+++ b/_posts/2014-09-18-elixir-v1-0-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v1.0 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: Elixir v1.0 is finally out!
 ---
@@ -53,7 +54,7 @@ These expectations also apply to future releases under the v1 branch, except for
 
 ## Learn more
 
-You can get started with Elixir via our [Getting Started guide](/getting-started/introduction.html). There are quite some Elixir books out there too, now getting sent to the presses, quite a few can be found in the sidebar, which also includes screencasts and other resources.
+You can get started with Elixir via our [Getting Started guide](https://hexdocs.pm/elixir/introduction.html). There are quite some Elixir books out there too, now getting sent to the presses, quite a few can be found in the sidebar, which also includes screencasts and other resources.
 
 You can also learn more about Elixir by checking out [the videos from ElixirConf 2014](http://www.confreaks.com/events/elixirconf2014), the first (and so far the best) Elixir conference ever! You can learn more about [the language history](http://www.confreaks.com/videos/4134-elixirconf2014-keynote-elixir), [how Elixir can change the way you code](http://www.confreaks.com/videos/4119-elixirconf2014-opening-keynote-think-different) or [even hear stories of how Elixir is being used in production](http://www.confreaks.com/videos/4131-elixirconf2014-otp-in-production-the-nitty-gritty-details-of-game-servers).
 
diff --git a/_posts/2015-09-28-elixir-v1-1-0-released.markdown b/_posts/2015-09-28-elixir-v1-1-0-released.markdown
index e5f85c7a5..5adecea87 100644
--- a/_posts/2015-09-28-elixir-v1-1-0-released.markdown
+++ b/_posts/2015-09-28-elixir-v1-1-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v1.1 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: Elixir v1.1 brings enhancements, bug fixes, performance improvements and more into Elixir.
 ---
diff --git a/_posts/2016-01-03-elixir-v1-2-0-released.markdown b/_posts/2016-01-03-elixir-v1-2-0-released.markdown
index 374156362..1b8a7efd8 100644
--- a/_posts/2016-01-03-elixir-v1-2-0-released.markdown
+++ b/_posts/2016-01-03-elixir-v1-2-0-released.markdown
@@ -1,14 +1,15 @@
 ---
 layout: post
 title: Elixir v1.2 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: Elixir v1.2 brings enhancements, bug fixes, performance improvements and more into Elixir.
 ---
 
 v1.2 brings enhancements, bug fixes, performance improvements and more into Elixir. Elixir v1.2 relies on many features in Erlang 18, requiring at least Erlang 18+. Upgrading to Erlang 18 is therefore necessary before upgrading Elixir.
 
-To celebrate this release and the new year, we have also reviewed both the [Getting Started](http://elixir-lang.org/getting-started/introduction.html) and [Mix & OTP](http://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html) guides, bringing it up to date and exploring new functionalities added since Elixir v1.0.
+To celebrate this release and the new year, we have also reviewed both the [Getting Started](https://hexdocs.pm/elixir/introduction.html) and [Mix & OTP](https://hexdocs.pm/elixir/introduction-to-mix.html) guides, bringing it up to date and exploring new functionalities added since Elixir v1.0.
 
 ## Erlang 18 support
 
@@ -112,6 +113,6 @@ These are great additions on top of the faster compilation times we have achieve
 
 With Rebar 3 gaining more adoption in the Erlang community, Mix is now able to fetch and compile Rebar 3 dependencies. This feature is currently experimental and therefore opt-in: if you have a Rebar 3 dependency, you can ask Mix to use Rebar 3 to compile it by passing the `manager: :rebar3` option. Once configured, Mix will prompt you to install Rebar 3 if it is not yet available.
 
-The full list of changes is available in our [release notes](https://github.com/elixir-lang/elixir/releases/tag/v1.2.0). Don't forget to check [the Install section](/install.html) to get Elixir installed and our [Getting Started guide](http://elixir-lang.org/getting-started/introduction.html) to learn more.
+The full list of changes is available in our [release notes](https://github.com/elixir-lang/elixir/releases/tag/v1.2.0). Don't forget to check [the Install section](/install.html) to get Elixir installed and our [Getting Started guide](https://hexdocs.pm/elixir/introduction.html) to learn more.
 
 Happy coding!
diff --git a/_posts/2016-06-21-elixir-v1-3-0-released.markdown b/_posts/2016-06-21-elixir-v1-3-0-released.markdown
index be1fb29fc..3ee45d0e0 100644
--- a/_posts/2016-06-21-elixir-v1-3-0-released.markdown
+++ b/_posts/2016-06-21-elixir-v1-3-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v1.3 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: Elixir v1.3 brings many improvements to the language, the compiler and its tooling, specially Mix (Elixir's build tool) and ExUnit (Elixir's test framework).
 ---
@@ -282,6 +283,6 @@ By restricting hierarchies in favor of named setups, it is straight-forward for
 
 ## Summing up
 
-The full list of changes is available in our [release notes](https://github.com/elixir-lang/elixir/releases/tag/v1.3.0). Don't forget to check [the Install section](/install.html) to get Elixir installed and our [Getting Started guide](http://elixir-lang.org/getting-started/introduction.html) to learn more.
+The full list of changes is available in our [release notes](https://github.com/elixir-lang/elixir/releases/tag/v1.3.0). Don't forget to check [the Install section](/install.html) to get Elixir installed and our [Getting Started guide](https://hexdocs.pm/elixir/introduction.html) to learn more.
 
 Happy coding!
diff --git a/_posts/2016-07-14-announcing-genstage.markdown b/_posts/2016-07-14-announcing-genstage.markdown
index 8b5bd31a5..7a853d043 100644
--- a/_posts/2016-07-14-announcing-genstage.markdown
+++ b/_posts/2016-07-14-announcing-genstage.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Announcing GenStage
-author: José Valim
+authors:
+-  José Valim
 category: Announcements
 excerpt: GenStage is a new Elixir behaviour for exchanging events with back-pressure between Elixir processes. In this blog post we will cover the background that led us to GenStage, some example use cases, and what we are exploring for future releases.
 ---
diff --git a/_posts/2017-01-05-elixir-v1-4-0-released.markdown b/_posts/2017-01-05-elixir-v1-4-0-released.markdown
index 7c963a54d..f110bb07e 100644
--- a/_posts/2017-01-05-elixir-v1-4-0-released.markdown
+++ b/_posts/2017-01-05-elixir-v1-4-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v1.4 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: Elixir v1.4 brings many improvements to the language, its standard library and the Mix build tool.
 ---
@@ -129,6 +130,6 @@ It is also possible to install escripts and archives by providing a Git/GitHub r
 
 ## Summing up
 
-The full list of changes is available in our [release notes](https://github.com/elixir-lang/elixir/releases/tag/v1.4.0). Don't forget to check [the Install section](/install.html) to get Elixir installed and our [Getting Started guide](http://elixir-lang.org/getting-started/introduction.html) to learn more.
+The full list of changes is available in our [release notes](https://github.com/elixir-lang/elixir/releases/tag/v1.4.0). Don't forget to check [the Install section](/install.html) to get Elixir installed and our [Getting Started guide](https://hexdocs.pm/elixir/introduction.html) to learn more.
 
 Happy coding!
diff --git a/_posts/2017-07-25-elixir-v1-5-0-released.markdown b/_posts/2017-07-25-elixir-v1-5-0-released.markdown
index 2dae4ed80..c4f38f788 100644
--- a/_posts/2017-07-25-elixir-v1-5-0-released.markdown
+++ b/_posts/2017-07-25-elixir-v1-5-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v1.5 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: Elixir v1.5 integrates with Erlang/OTP 20 and bring changes that improves the language reach and the developer experience
 ---
@@ -175,4 +176,4 @@ Overall, using `@impl` has the following advantages:
 
 The full list of changes is available in our [release notes](https://github.com/elixir-lang/elixir/releases/tag/v1.5.0). There are many other exciting changes, such as compiler enhancements that reduces compilation times by 10%-15% on averages. When taken into account with the compiler improvements in Erlang/OTP 20 itself, some applications have seen gains up to 30% in compilation times.
 
-Don't forget to check [the Install section](/install.html) to get Elixir installed and our [Getting Started guide](http://elixir-lang.org/getting-started/introduction.html) to learn more.
+Don't forget to check [the Install section](/install.html) to get Elixir installed and our [Getting Started guide](https://hexdocs.pm/elixir/introduction.html) to learn more.
diff --git a/_posts/2017-10-31-stream-data-property-based-testing-and-data-generation-for-elixir.markdown b/_posts/2017-10-31-stream-data-property-based-testing-and-data-generation-for-elixir.markdown
index 6aa52bf6e..242c28635 100644
--- a/_posts/2017-10-31-stream-data-property-based-testing-and-data-generation-for-elixir.markdown
+++ b/_posts/2017-10-31-stream-data-property-based-testing-and-data-generation-for-elixir.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: "StreamData: Property-based testing and data generation"
-author: Andrea Leopardi
+authors:
+-  Andrea Leopardi
 category: Announcements
 excerpt: We are working on data generation and property-based testing for the next versions of Elixir.
 ---
diff --git a/_posts/2018-01-17-elixir-v1-6-0-released.markdown b/_posts/2018-01-17-elixir-v1-6-0-released.markdown
index 9012cb332..99bc8c441 100644
--- a/_posts/2018-01-17-elixir-v1-6-0-released.markdown
+++ b/_posts/2018-01-17-elixir-v1-6-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v1.6 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: Elixir v1.6 includes a code formatter, defguard, dynamic supervision and new module attributes that improves code quality and the developer experience
 ---
@@ -153,4 +154,4 @@ The full list of changes is available in our [release notes](https://github.com/
 
 Work on Elixir v1.7 has already started. We still welcome developers to try out the [previously announced StreamData library](https://elixir-lang.org/blog/2017/10/31/stream-data-property-based-testing-and-data-generation-for-elixir/), that aims to bring data generation and property-based testing to Elixir. The other [features scheduled for v1.7 can be found in the issues tracker](https://github.com/elixir-lang/elixir/issues).
 
-Don't forget to check [the Install section](/install.html) to get Elixir installed and our [Getting Started guide](http://elixir-lang.org/getting-started/introduction.html) to learn more.
+Don't forget to check [the Install section](/install.html) to get Elixir installed and our [Getting Started guide](https://hexdocs.pm/elixir/introduction.html) to learn more.
diff --git a/_posts/2018-06-28-gsoc-projects.markdown b/_posts/2018-06-28-gsoc-projects.markdown
index 703275a59..168f6126e 100644
--- a/_posts/2018-06-28-gsoc-projects.markdown
+++ b/_posts/2018-06-28-gsoc-projects.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Google Summer of Code 2018 projects
-author: Andrea Leopardi
+authors:
+-  Andrea Leopardi
 category: Announcements
 excerpt: Once again Elixir is participating in Google Summer of Code 2018. In this post, we'll have a look at the active projects.
 ---
diff --git a/_posts/2018-07-25-elixir-v1-7-0-released.markdown b/_posts/2018-07-25-elixir-v1-7-0-released.markdown
index 4ac36f478..51e8f7a66 100644
--- a/_posts/2018-07-25-elixir-v1-7-0-released.markdown
+++ b/_posts/2018-07-25-elixir-v1-7-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v1.7 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: Elixir v1.7 includes many quality of life improvements, focusing on documentation, Logger and ExUnit, as well as a new Elixir Core team member!
 ---
@@ -147,10 +148,10 @@ We have also seen important developments in other areas not directly related to
 
   * We have added [a "Development" section](https://elixir-lang.org/development.html) to the website, that outlines the Elixir team structure and goals
 
-  * [Elixir now has its own mini-documentary](http://doc.honeypot.io/elixir-documentary-2018/), by [Honeypot](https://www.honeypot.io/)
+  * [Elixir now has its own mini-documentary](https://www.youtube.com/watch?v=lxYFOM3UJzo) by Honeypot
 
   * We have already highlighted some of the improvements in the ExDoc tool. Another improvement worth mentioning is the syntax highlighting is now done in Elixir itself, via the [Makeup](https://github.com/tmbb/makeup) library. This gives us more control over the grammar, the style, and improves load times. If you would like to add support for other languages, [reach out](https://github.com/tmbb/makeup)!
 
 Finally, don't forget [ElixirConf US](https://elixirconf.com/) is coming soon, in Bellevue, WA, September 4-7. Last year my keynote focused on the last 5 years with Elixir. This year we are ready to look into the 5 years ahead.
 
-Check [the Install section](/install.html) to get Elixir installed and read our [Getting Started guide](http://elixir-lang.org/getting-started/introduction.html) to learn more.
+Check [the Install section](/install.html) to get Elixir installed and read our [Getting Started guide](https://hexdocs.pm/elixir/introduction.html) to learn more.
diff --git a/_posts/2019-01-14-elixir-v1-8-0-released.markdown b/_posts/2019-01-14-elixir-v1-8-0-released.markdown
index c415f2a4e..6da84a7dc 100644
--- a/_posts/2019-01-14-elixir-v1-8-0-released.markdown
+++ b/_posts/2019-01-14-elixir-v1-8-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v1.8 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: Elixir v1.8 comes with many improvements at the infrastructure level, improving compilation time, speeding up common patterns, and adding features around introspection of the system.
 ---
@@ -77,6 +78,6 @@ There is only one last major feature planned for upcoming Elixir versions, which
 
 During [my keynote at ElixirConf 2018 US](https://www.youtube.com/watch?v=suOzNeMJXl0), I talked about the next five years for Elixir and much of the emphasis is put on the community. Elixir was designed to be an extensible language and therefore the work on the language itself is meant to reduce with time, which we have seen in the last two releases. We trust the community to continue building on this solid foundation, bringing new challenges to the ecosystem and taking the language to new domains.
 
-Check [the Install section](/install.html) to get Elixir installed and read our [Getting Started guide](http://elixir-lang.org/getting-started/introduction.html) to learn more.
+Check [the Install section](/install.html) to get Elixir installed and read our [Getting Started guide](https://hexdocs.pm/elixir/introduction.html) to learn more.
 
 Your turn. :)
\ No newline at end of file
diff --git a/_posts/2019-02-25-mint-a-new-http-library-for-elixir.markdown b/_posts/2019-02-25-mint-a-new-http-library-for-elixir.markdown
index 3f3b4bead..3868b94e6 100644
--- a/_posts/2019-02-25-mint-a-new-http-library-for-elixir.markdown
+++ b/_posts/2019-02-25-mint-a-new-http-library-for-elixir.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Mint, a new HTTP client for Elixir
-author: Eric Meadows-Jönsson
+authors:
+-  Eric Meadows-Jönsson
 category: Announcements
 excerpt: Mint is a new low-level HTTP client that aims to provide a small and functional core that others can build on top.
 ---
diff --git a/_posts/2019-06-24-elixir-v1-9-0-released.markdown b/_posts/2019-06-24-elixir-v1-9-0-released.markdown
index e4bab9c37..b1b72fd4c 100644
--- a/_posts/2019-06-24-elixir-v1-9-0-released.markdown
+++ b/_posts/2019-06-24-elixir-v1-9-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v1.9 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: Elixir v1.9 is out with releases support, improved configuration and more.
 ---
@@ -96,6 +97,6 @@ First of all, Elixir is built on top of Erlang/OTP and we simply leverage all of
 
 Second, Elixir was designed to be an extensible language. The same tools and abstractions we used to create and enhance the language are also available to libraries and frameworks. This means the community can continue to improve the ecosystem without a need to change the language itself, which would effectively become a bottleneck for progress.
 
-Check [the Install section](/install.html) to get Elixir installed and read our [Getting Started guide](http://elixir-lang.org/getting-started/introduction.html) to learn more. We have also updated our [advanced Mix & OTP](https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html) to talk about releases. If you are looking for a more fast paced introduction to the language, see the [How I Start: Elixir](http://howistart.org/posts/elixir/1/index.html) tutorial, which has also been brought to the latest and greatest.
+Check [the Install section](/install.html) to get Elixir installed and read our [Getting Started guide](https://hexdocs.pm/elixir/introduction.html) to learn more. We have also updated our [advanced Mix & OTP](https://hexdocs.pm/elixir/introduction-to-mix.html) to talk about releases. If you are looking for a more fast paced introduction to the language, see the [How I Start: Elixir](http://howistart.org/posts/elixir/1/index.html) tutorial, which has also been brought to the latest and greatest.
 
 Have fun!
diff --git a/_posts/2020-01-27-elixir-v1-10-0-released.markdown b/_posts/2020-01-27-elixir-v1-10-0-released.markdown
index d58f44d3a..f2eac58ce 100644
--- a/_posts/2020-01-27-elixir-v1-10-0-released.markdown
+++ b/_posts/2020-01-27-elixir-v1-10-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v1.10 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: Elixir v1.10 is out with standard library, compiler, and releases improvements.
 ---
@@ -165,6 +166,6 @@ Finally, this release also adds two new guards, `is_struct/1` and `is_map_key/2`
 
 To learn what else is new, you can read the [full release notes](https://github.com/elixir-lang/elixir/releases/tag/v1.10.0).
 
-Check [the Install section](/install.html) to get Elixir installed and read our [Getting Started guide](http://elixir-lang.org/getting-started/introduction.html) to learn more.
+Check [the Install section](/install.html) to get Elixir installed and read our [Getting Started guide](https://hexdocs.pm/elixir/introduction.html) to learn more.
 
 Have fun!
diff --git a/_posts/2020-08-20-embedded-elixir-at-farmbot.markdown b/_posts/2020-08-20-embedded-elixir-at-farmbot.markdown
index 2d5660e8b..0471d047f 100644
--- a/_posts/2020-08-20-embedded-elixir-at-farmbot.markdown
+++ b/_posts/2020-08-20-embedded-elixir-at-farmbot.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Embedded Elixir at Farmbot
-author: José Valim
+authors:
+-  José Valim
 category: Elixir in Production
 excerpt: A case study of how Elixir is being used at Farmbot.
 logo: /images/cases/logos/farmbot.png
@@ -47,4 +48,4 @@ Because it's written in Elixir and built within the Erlang runtime system, Nerve
 
 FarmBot now has around 300 devices live in NervesHub, with a different deployment for each of their device models. Nerves is built to scale, so as Farmbot continues to grow its user base and expand their product capabilities, they'll be able to continue developing and releasing reliable firmware updates using Nerves.
 
-*This case study has first been published on [Nerves' website](https://www.nerves-project.org/customer-farmbot)*.
+*This case study has first been published on [Nerves' website](https://nerves-project.org/cases/farmbot)*.
diff --git a/_posts/2020-09-24-paas-with-elixir-at-Heroku.markdown b/_posts/2020-09-24-paas-with-elixir-at-Heroku.markdown
index 357f61cdf..bf97dd5f3 100644
--- a/_posts/2020-09-24-paas-with-elixir-at-Heroku.markdown
+++ b/_posts/2020-09-24-paas-with-elixir-at-Heroku.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: PaaS with Elixir at Heroku
-author: José Valim
+authors:
+-  José Valim
 category: Elixir in Production
 excerpt: A case study of how Elixir is being used at Heroku.
 logo: /images/cases/logos/heroku.png
diff --git a/_posts/2020-10-06-elixir-v1-11-0-released.markdown b/_posts/2020-10-06-elixir-v1-11-0-released.markdown
index 313d683be..7aaaefefb 100644
--- a/_posts/2020-10-06-elixir-v1-11-0-released.markdown
+++ b/_posts/2020-10-06-elixir-v1-11-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v1.11 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: Elixir v1.11 is out with improvements to the compiler and tighter integration with Erlang/OTP
 ---
@@ -219,6 +220,6 @@ Finally, to bring visibility to the compiler tracking improvements described in
 
 For a complete list of all changes, see the [full release notes](https://github.com/elixir-lang/elixir/releases/tag/v1.11.0).
 
-Check [the Install section](/install.html) to get Elixir installed and read our [Getting Started guide](http://elixir-lang.org/getting-started/introduction.html) to learn more.
+Check [the Install section](/install.html) to get Elixir installed and read our [Getting Started guide](https://hexdocs.pm/elixir/introduction.html) to learn more.
 
 Have fun!
diff --git a/_posts/2020-10-08-real-time-communication-at-scale-with-elixir-at-discord.markdown b/_posts/2020-10-08-real-time-communication-at-scale-with-elixir-at-discord.markdown
index 669578ae6..ac4f42ef8 100644
--- a/_posts/2020-10-08-real-time-communication-at-scale-with-elixir-at-discord.markdown
+++ b/_posts/2020-10-08-real-time-communication-at-scale-with-elixir-at-discord.markdown
@@ -1,9 +1,11 @@
 ---
 layout: post
 title: Real time communication at scale with Elixir at Discord
-author: José Valim
+authors:
+-  José Valim
 category: Elixir in Production
 excerpt: A case study of how Elixir is being used at Discord.
+flagship: true
 logo: /images/cases/logos/discord.png
 tags: real-time genstage otp
 ---
diff --git a/_posts/2020-10-27-delivering-social-change-with-elixir-at-change.org.markdown b/_posts/2020-10-27-delivering-social-change-with-elixir-at-change.org.markdown
index 3261bc1da..8e58ec64c 100644
--- a/_posts/2020-10-27-delivering-social-change-with-elixir-at-change.org.markdown
+++ b/_posts/2020-10-27-delivering-social-change-with-elixir-at-change.org.markdown
@@ -1,9 +1,11 @@
 ---
 layout: post
 title: Delivering social change with Elixir at Change.org
-author: José Valim
+authors:
+-  José Valim
 category: Elixir in Production
 excerpt: A case study of how Elixir is being used at Change.org.
+flagship: true
 logo: /images/cases/logos/change.png
 tags: social broadway
 ---
diff --git a/_posts/2020-11-17-real-time-collaboration-with-elixir-at-slab.markdown b/_posts/2020-11-17-real-time-collaboration-with-elixir-at-slab.markdown
index 0f797ecd6..e699b459a 100644
--- a/_posts/2020-11-17-real-time-collaboration-with-elixir-at-slab.markdown
+++ b/_posts/2020-11-17-real-time-collaboration-with-elixir-at-slab.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Real-time collaboration with Elixir at Slab
-author: José Valim
+authors:
+-  José Valim
 category: Elixir in Production
 excerpt: A case study of how Elixir is being used at Slab.
 logo: /images/cases/logos/slab.png
diff --git a/_posts/2020-12-10-integrating-travel-with-elixir-at-duffel.markdown b/_posts/2020-12-10-integrating-travel-with-elixir-at-duffel.markdown
index 1a2661571..44f8c66cb 100644
--- a/_posts/2020-12-10-integrating-travel-with-elixir-at-duffel.markdown
+++ b/_posts/2020-12-10-integrating-travel-with-elixir-at-duffel.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Integrating travel with Elixir at Duffel
-author: José Valim
+authors:
+-  José Valim
 category: Elixir in Production
 excerpt: A case study of how Elixir is being used at Duffel.
 logo: /images/cases/logos/duffel.png
diff --git a/_posts/2021-01-13-orchestrating-computer-vision-with-elixir-at-v7.markdown b/_posts/2021-01-13-orchestrating-computer-vision-with-elixir-at-v7.markdown
index 7dd1fa5f2..8e402cae7 100644
--- a/_posts/2021-01-13-orchestrating-computer-vision-with-elixir-at-v7.markdown
+++ b/_posts/2021-01-13-orchestrating-computer-vision-with-elixir-at-v7.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Orchestrating computer vision with Elixir at V7
-author: José Valim
+authors:
+-  José Valim
 category: Elixir in Production
 excerpt: A case study of how Elixir is being used at V7.
 logo: /images/cases/logos/v7.png
diff --git a/_posts/2021-02-03-social-messaging-with-elixir-at-community.markdown b/_posts/2021-02-03-social-messaging-with-elixir-at-community.markdown
index 15afd237d..e105822f1 100644
--- a/_posts/2021-02-03-social-messaging-with-elixir-at-community.markdown
+++ b/_posts/2021-02-03-social-messaging-with-elixir-at-community.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Social messaging with Elixir at Community
-author: José Valim
+authors:
+-  José Valim
 category: Elixir in Production
 excerpt: A case study of how Elixir is being used at Community.
 logo: /images/cases/logos/community.png
diff --git a/_posts/2021-04-02-marketing-and-sales-intelligence-with-elixir-at-pepsico.markdown b/_posts/2021-04-02-marketing-and-sales-intelligence-with-elixir-at-pepsico.markdown
index 892a8c6e1..dc81c1aa8 100644
--- a/_posts/2021-04-02-marketing-and-sales-intelligence-with-elixir-at-pepsico.markdown
+++ b/_posts/2021-04-02-marketing-and-sales-intelligence-with-elixir-at-pepsico.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Marketing and sales intelligence with Elixir at PepsiCo
-author: José Valim
+authors:
+-  José Valim
 category: Elixir in Production
 excerpt: A case study of how Elixir is being used at PepsiCo.
 logo: /images/cases/logos/pepsico.png
diff --git a/_posts/2021-05-19-elixir-v1-12-0-released.markdown b/_posts/2021-05-19-elixir-v1-12-0-released.markdown
index 075de6f79..676f3d2e2 100644
--- a/_posts/2021-05-19-elixir-v1-12-0-released.markdown
+++ b/_posts/2021-05-19-elixir-v1-12-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v1.12 released
-author: José Valim
+authors:
+-  José Valim
 category: Releases
 excerpt: Elixir v1.12 is out with improvements to scripting, tighter Erlang/OTP 24 integration, stepped ranges, and dozen of new functions across the standard library
 ---
@@ -96,6 +97,6 @@ The `Code` module got a [`cursor_context/2`](https://hexdocs.pm/elixir/1.12/Code
 
 The EEx application has also been extended to provide metadata on text segments. This has enabled the Surface and Phoenix LiveView teams to implement [a new template language called HEEx](https://github.com/phoenixframework/phoenix_live_view/pull/1440), which validates both HTML and EEx. Finally, the `Registry` module supports the `:compressed` option, which is useful for GraphQL applications managing hundreds of thousands of subscriptions via [Absinthe](http://absinthe-graphql.org/).
 
-For a complete list of all changes, see the [full release notes](https://github.com/elixir-lang/elixir/releases/tag/v1.12.0). Check [the Install section](/install.html) to get Elixir installed and read our [Getting Started guide](http://elixir-lang.org/getting-started/introduction.html) to learn more.
+For a complete list of all changes, see the [full release notes](https://github.com/elixir-lang/elixir/releases/tag/v1.12.0). Check [the Install section](/install.html) to get Elixir installed and read our [Getting Started guide](https://hexdocs.pm/elixir/introduction.html) to learn more.
 
 Have fun!
diff --git a/_posts/2021-06-02-social-virtual-spaces-with-elixir-at-mozilla.markdown b/_posts/2021-06-02-social-virtual-spaces-with-elixir-at-mozilla.markdown
index 591401f66..51244a2e2 100644
--- a/_posts/2021-06-02-social-virtual-spaces-with-elixir-at-mozilla.markdown
+++ b/_posts/2021-06-02-social-virtual-spaces-with-elixir-at-mozilla.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Social virtual spaces with Elixir at Mozilla
-author: José Valim
+authors:
+-  José Valim
 category: Elixir in Production
 excerpt: A case study of how Elixir is being used at Mozilla.
 logo: /images/cases/logos/mozilla-hubs.png
diff --git a/_posts/2021-07-29-bootstraping-a-multiplayer-server-with-elixir-at-x-plane.markdown b/_posts/2021-07-29-bootstraping-a-multiplayer-server-with-elixir-at-x-plane.markdown
index c0656e338..e0563549c 100644
--- a/_posts/2021-07-29-bootstraping-a-multiplayer-server-with-elixir-at-x-plane.markdown
+++ b/_posts/2021-07-29-bootstraping-a-multiplayer-server-with-elixir-at-x-plane.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Bootstrapping a multiplayer server with Elixir at X-Plane
-author: José Valim
+authors:
+-  José Valim
 category: Elixir in Production
 excerpt: A case study of how Elixir is being used at X-Plane.
 logo: /images/cases/logos/x-plane.png
@@ -36,7 +37,7 @@ They eventually settled on three top contenders: Rust, Go, and Elixir. Elixir to
 
 ## Modeling multiplayer with Elixir
 
-Ready to give Elixir a try, Tyler picked up a couple books but soon realized the language's [Getting Started guide](https://elixir-lang.org/getting-started/introduction.html) provided the background he needed. He explains: "while the introductory guide covers the language constructs, the advanced guide on the website has you build an actual project with TCP connections, with the basic architectural patterns we would use in production."
+Ready to give Elixir a try, Tyler picked up a couple books but soon realized the language's [Getting Started guide](https://hexdocs.pm/elixir/introduction.html) provided the background he needed. He explains: "while the introductory guide covers the language constructs, the advanced guide on the website has you build an actual project with TCP connections, with the basic architectural patterns we would use in production."
 
 However, instead of jumping headfirst into the multiplayer server, he decided to give Elixir a try on a smaller problem. He wrote a web proxy to the National Oceanic and Atmospheric Administration (NOAA) weather services and put it in production. This experience taught him the importance of leveraging all of the instrumentation and metrics provided by the Erlang VM. They chose [AppSignal](https://www.appsignal.com/) to help consume and digest this information.
 
diff --git a/_posts/2021-11-10-embracing-open-data-with-elixir-at-the-ministry-of-ecological-transition-in-france.markdown b/_posts/2021-11-10-embracing-open-data-with-elixir-at-the-ministry-of-ecological-transition-in-france.markdown
index d7d294fab..7326c7d57 100644
--- a/_posts/2021-11-10-embracing-open-data-with-elixir-at-the-ministry-of-ecological-transition-in-france.markdown
+++ b/_posts/2021-11-10-embracing-open-data-with-elixir-at-the-ministry-of-ecological-transition-in-france.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Embracing open data with Elixir at the Ministry of Ecological Transition in France
-author: José Valim
+authors:
+-  José Valim
 category: Elixir in Production
 excerpt: A case study of how Elixir is being used at the Ministry of Ecological Transition in France.
 logo: /images/cases/logos/met-france.svg
diff --git a/_posts/2021-12-03-elixir-v1-13-0-released.markdown b/_posts/2021-12-03-elixir-v1-13-0-released.markdown
index 5e6deb187..486d27699 100644
--- a/_posts/2021-12-03-elixir-v1-13-0-released.markdown
+++ b/_posts/2021-12-03-elixir-v1-13-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v1.13 released
-author: José Valim
+authors:
+- José Valim
 category: Releases
 excerpt: Elixir v1.13 is out with a focus on developer tooling
 ---
@@ -147,6 +148,6 @@ The `Code` module has also been augmented with two functions: [`Code.string_to_q
 
 For a complete list of all changes, see the [full release notes](https://github.com/elixir-lang/elixir/releases/tag/v1.13.0). You can also [watch my ElixirConf 2021 keynote about Elixir v1.13](https://youtu.be/ydjx2kKHzrM) to learn more.
 
-Check [the Install section](/install.html) to get Elixir installed and read our [Getting Started guide](http://elixir-lang.org/getting-started/introduction.html) to learn more.
+Check [the Install section](/install.html) to get Elixir installed and read our [Getting Started guide](https://hexdocs.pm/elixir/introduction.html) to learn more.
 
 Have fun!
diff --git a/_posts/2022-09-01-elixir-v1-14-0-released.markdown b/_posts/2022-09-01-elixir-v1-14-0-released.markdown
index 9584974cb..7ae52d259 100644
--- a/_posts/2022-09-01-elixir-v1-14-0-released.markdown
+++ b/_posts/2022-09-01-elixir-v1-14-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v1.14 released
-author: Andrea Leopardi
+authors:
+- Andrea Leopardi
 category: Releases
 excerpt: Elixir v1.14 is out with a focus on debugging and developer experience
 ---
@@ -186,6 +187,6 @@ Finally, we have improved the `Inspect` protocol for structs so that fields are
 
 For a complete list of all changes, see the [full release notes](https://github.com/elixir-lang/elixir/releases/tag/v1.14.0).
 
-Check [the Install section](/install.html) to get Elixir installed and read our [Getting Started guide](http://elixir-lang.org/getting-started/introduction.html) to learn more.
+Check [the Install section](/install.html) to get Elixir installed and read our [Getting Started guide](https://hexdocs.pm/elixir/introduction.html) to learn more.
 
 Happy debugging!
diff --git a/_posts/2022-10-05-my-future-with-elixir-set-theoretic-types.markdown b/_posts/2022-10-05-my-future-with-elixir-set-theoretic-types.markdown
index 15d873521..11f8d06c6 100644
--- a/_posts/2022-10-05-my-future-with-elixir-set-theoretic-types.markdown
+++ b/_posts/2022-10-05-my-future-with-elixir-set-theoretic-types.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: "My Future with Elixir: set-theoretic types"
-author: José Valim
+authors:
+- José Valim
 category: Announcements
 excerpt: We announce and explore the possibilities for bringing set-theoretic types into Elixir.
 ---
diff --git a/_posts/2022-12-22-cheatsheets-and-8-other-features-in-exdoc-that-improve-the-developer-experience.markdown b/_posts/2022-12-22-cheatsheets-and-8-other-features-in-exdoc-that-improve-the-developer-experience.markdown
index 0c029806c..505bf15bf 100644
--- a/_posts/2022-12-22-cheatsheets-and-8-other-features-in-exdoc-that-improve-the-developer-experience.markdown
+++ b/_posts/2022-12-22-cheatsheets-and-8-other-features-in-exdoc-that-improve-the-developer-experience.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: "Cheatsheets and other 8 ExDoc features that improve the developer experience"
-author: Hugo Baraúna
+authors:
+- Hugo Baraúna
 category: Announcements
 excerpt: This post explains the motivation behind the new ExDoc Cheatsheet feature. It also highlights other ExDoc features that show how ExDoc has been evolving to make the documentation experience in Elixir better and better.
 ---
diff --git a/_posts/2023-03-09-embedded-and-cloud-elixir-at-sparkmeter.markdown b/_posts/2023-03-09-embedded-and-cloud-elixir-at-sparkmeter.markdown
index 566105928..2a5fa73ce 100644
--- a/_posts/2023-03-09-embedded-and-cloud-elixir-at-sparkmeter.markdown
+++ b/_posts/2023-03-09-embedded-and-cloud-elixir-at-sparkmeter.markdown
@@ -1,11 +1,12 @@
 ---
 layout: post
 title: "Embedded and cloud Elixir for grid-management at Sparkmeter"
-author: Hugo Baraúna
+authors:
+- Hugo Baraúna
 category: Elixir in Production
 excerpt: A case study of how Elixir is being used at SparkMeter.
 logo: /images/cases/logos/sparkmeter.png
-tags: nerves cloud phoenix
+tags: energy iot nerves
 ---
 
 *Welcome to our series of case studies about companies using Elixir in production. [See all](https://elixir-lang.org/cases.html) cases we have published so far.*
diff --git a/_posts/2023-06-19-elixir-v1-15-0-released.markdown b/_posts/2023-06-19-elixir-v1-15-0-released.markdown
index 8db6c8737..ffc23b810 100644
--- a/_posts/2023-06-19-elixir-v1-15-0-released.markdown
+++ b/_posts/2023-06-19-elixir-v1-15-0-released.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: Elixir v1.15 released
-author: José Valim
+authors:
+- José Valim
 category: Releases
 excerpt: Elixir v1.15 with improvements to compilation and boot times.
 ---
@@ -163,7 +164,7 @@ For a complete list of all changes, see the
 [full release notes](https://github.com/elixir-lang/elixir/releases/tag/v1.15.0).
 
 Check [the Install section](/install.html) to get Elixir installed and
-read our [Getting Started guide](http://elixir-lang.org/getting-started/introduction.html)
+read our [Getting Started guide](https://hexdocs.pm/elixir/introduction.html)
 to learn more.
 
 Happy compiling!
diff --git a/_posts/2023-06-22-type-system-updates-research-dev.markdown b/_posts/2023-06-22-type-system-updates-research-dev.markdown
index 98a6ec5e9..1765f7830 100644
--- a/_posts/2023-06-22-type-system-updates-research-dev.markdown
+++ b/_posts/2023-06-22-type-system-updates-research-dev.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: "Type system updates: moving from research into development"
-author: José Valim
+authors:
+- José Valim
 category: Announcements
 excerpt: A short status update on the effort to bring a type system into Elixir.
 ---
diff --git a/_posts/2023-09-20-strong-arrows-gradual-typing.markdown b/_posts/2023-09-20-strong-arrows-gradual-typing.markdown
index 9aa5a6997..cd62f8c33 100644
--- a/_posts/2023-09-20-strong-arrows-gradual-typing.markdown
+++ b/_posts/2023-09-20-strong-arrows-gradual-typing.markdown
@@ -1,7 +1,8 @@
 ---
 layout: post
 title: "Strong arrows: a new approach to gradual typing"
-author: José Valim
+authors:
+- José Valim
 category: Announcements
 excerpt: An introduction to strong arrows and how it leverages the Erlang VM to provide sound gradual typing.
 ---
@@ -16,7 +17,7 @@ In this article, we will discuss how the proposed type system will tackle gradua
 
 The type system we are currently researching and developing for Elixir is based on set-theoretic types, which is to say its operations are based on the fundamental set operations of union, intersection, and negation.
 
-For example, the atom `:ok` is a value in Elixir, that can be represented by the type `:ok`. All atoms in Elixir as represented by themselves in the type system. A function that returns either `:ok` or `:error` is said to return `:ok or :error`, where the `or` operator represents the union.
+For example, the atom `:ok` is a value in Elixir, that can be represented by the type `:ok`. All atoms in Elixir are represented by themselves in the type system. A function that returns either `:ok` or `:error` is said to return `:ok or :error`, where the `or` operator represents the union.
 
 The types `:ok` and `:error` are contained by the type `atom()`, which is an infinite set representing all atoms. The union of the types `:ok` and `atom()` can be written as `:ok or atom()`, and is equivalent to `atom()` (as `:ok` is a subset of `atom()`). The intersection of the types `:ok` and `atom()` can be written as `:ok and atom()`, and is equivalent to `:ok`.
 
diff --git a/_posts/2023-12-22-elixir-v1-16-0-released.markdown b/_posts/2023-12-22-elixir-v1-16-0-released.markdown
new file mode 100644
index 000000000..6e4a61dca
--- /dev/null
+++ b/_posts/2023-12-22-elixir-v1-16-0-released.markdown
@@ -0,0 +1,189 @@
+---
+layout: post
+title: Elixir v1.16 released
+authors:
+- José Valim
+category: Releases
+excerpt: Elixir v1.16 released with compiler diagnostics and extensive documentation
+---
+
+Elixir v1.16 has just been released. 🎉
+
+The Elixir team continues improving the developer experience
+via tooling, documentation, and precise feedback, while keeping
+the language stable and compatible.
+
+The notable improvements in this release are the addition of
+compiler diagnostics and extensive improvements to our docs
+in the forms of guides, anti-patterns, diagrams and more.
+
+## Code snippets in diagnostics
+
+Elixir v1.15 introduced a new compiler diagnostic format and
+the ability to print multiple error diagnostics per compilation
+(in addition to multiple warnings).
+
+With Elixir v1.16, we also include code snippets in exceptions
+and diagnostics raised by the compiler, including ANSI coloring
+on supported terminals. For example, a syntax error now includes
+a pointer to where the error happened:
+
+```
+** (SyntaxError) invalid syntax found on lib/my_app.ex:1:17:
+    error: syntax error before: '*'
+    │
+  1 │ [1, 2, 3, 4, 5, *]
+    │                 ^
+    │
+    └─ lib/my_app.ex:1:17
+```
+
+For mismatched delimiters, it now shows both delimiters:
+
+```
+** (MismatchedDelimiterError) mismatched delimiter found on lib/my_app.ex:1:18:
+    error: unexpected token: )
+    │
+  1 │ [1, 2, 3, 4, 5, 6)
+    │ │                └ mismatched closing delimiter (expected "]")
+    │ └ unclosed delimiter
+    │
+    └─ lib/my_app.ex:1:18
+```
+
+For unclosed delimiters, it now shows where the unclosed delimiter starts:
+
+```
+** (TokenMissingError) token missing on lib/my_app:8:23:
+    error: missing terminator: )
+    │
+  1 │ my_numbers = (1, 2, 3, 4, 5, 6
+    │              └ unclosed delimiter
+ ...
+  8 │ IO.inspect(my_numbers)
+    │                       └ missing closing delimiter (expected ")")
+    │
+    └─ lib/my_app:8:23
+```
+
+Errors and warnings diagnostics also include code snippets.
+When possible, we will show precise spans, such as on undefined variables:
+
+```
+  error: undefined variable "unknown_var"
+  │
+5 │     a - unknown_var
+  │         ^^^^^^^^^^^
+  │
+  └─ lib/sample.ex:5:9: Sample.foo/1
+```
+
+Otherwise the whole line is underlined:
+
+```
+error: function names should start with lowercase characters or underscore, invalid name CamelCase
+  │
+3 │   def CamelCase do
+  │   ^^^^^^^^^^^^^^^^
+  │
+  └─ lib/sample.ex:3
+```
+
+A huge thank you to Vinícius Müller for working on the new diagnostics.
+
+## Revamped documentation
+
+The [ExDoc](https://github.com/elixir-lang/ex_doc) package provides Elixir developers
+with one of the most complete and robust documentation generator. It [supports API
+references, tutorials, cheatsheets, and more](/blog/2022/12/22/cheatsheets-and-8-other-features-in-exdoc-that-improve-the-developer-experience/).
+
+However, because many of the language tutorials and reference documentation
+were written before ExDoc, they were maintained separately as part of the
+official website, separate from the language source code. With Elixir v1.16,
+[we have moved our learning material to the language repository](https://hexdocs.pm/elixir/introduction.html).
+This provides several benefits:
+
+1. Tutorials are versioned alongside their relevant Elixir version
+
+2. You get full-text search across all API reference and tutorials
+
+3. ExDoc will autolink module and function names in tutorials to their relevant API documentation
+
+Another feature we have incorporated in this release is the addition
+of cheatsheets, starting with [a cheatsheet for the Enum module](https://hexdocs.pm/elixir/main/enum-cheat.html).
+If you would like to contribute future cheatsheets to Elixir itself,
+feel free to start a discussion and collect feedback on the
+[Elixir Forum](https://elixirforum.com/).
+
+Finally, we have started enriching our documentation with
+[Mermaid.js](https://mermaid.js.org/) diagrams. You can find examples
+in the [GenServer](https://hexdocs.pm/elixir/GenServer.html)
+and [Supervisor](https://hexdocs.pm/elixir/Supervisor.html) docs.
+
+Elixir has always been praised by its excellent documentation and
+we are glad to continue to raise the bar for the whole ecosystem.
+
+## Living anti-patterns reference
+
+Elixir v1.16 incorporates and extends the work on [Understanding Code Smells
+in Elixir Functional Language](https://github.com/lucasvegi/Elixir-Code-Smells/blob/main/etc/2023-emse-code-smells-elixir.pdf),
+by Lucas Vegi and Marco Tulio Valente, from [ASERG/DCC/UFMG](http://aserg.labsoft.dcc.ufmg.br/),
+into [the official documention in the form of anti-patterns](https://hexdocs.pm/elixir/what-anti-patterns.html).
+Our goal is to provide examples of potential pitfalls for library and
+application developers, with additional context and guidance on how
+to improve their codebases.
+
+In earlier versions, Elixir's official reference for library authors
+included a list of anti-patterns for library developers. Lucas Vegi and
+Marco Tulio Valente extended and refined this list based on the existing
+literature, articles, and community input (including feedback based on
+their prevalence in actual codebases).
+
+To incorporate the anti-patterns into the language, we trimmed the list down
+to keep only anti-patterns which are unambiguous and actionable, and divided
+them into four categories: [code-related](https://hexdocs.pm/elixir/code-anti-patterns.html),
+[design-related](https://hexdocs.pm/elixir/design-anti-patterns.html),
+[process-related](https://hexdocs.pm/elixir/process-anti-patterns.html),
+and [meta-programming](https://hexdocs.pm/elixir/macro-anti-patterns.html).
+Then we collected more community feedback during the release candidate
+period, further refining and removing unclear guidance.
+
+We are quite happy with the current iteration of anti-patterns but
+this is just the beginning. As they become available to the whole community,
+we expect to receive more input, questions, and concerns. We will
+continue listening and improving, as our ultimate goal is to provide
+a live reference that reflects the practices of the ecosystem,
+rather than a document that is written in stone and ultimately gets
+out of date. A perfect example of this is [the recent addition of
+"Sending unnecessary data" anti-pattern](https://github.com/elixir-lang/elixir/pull/13194),
+which was contributed by the community and describes a pitfall that may
+happen across codebases.
+
+## Type system updates
+
+As we get Elixir v1.16 out of door, the Elixir team will focus on bringing
+the initial core for set-theoretic types into the Elixir compiler, with the
+goal of running automated analysis in patterns and guards. This is [the first
+step outlined in a previous article](/blog/2023/06/22/type-system-updates-research-dev/)
+and is sponsored by [Fresha](https://www.fresha.com) ([they are hiring!](https://www.fresha.com/careers/openings?department=engineering)),
+[Starfish*](https://starfish.team) ([they are hiring!](https://starfish.team/jobs/experienced-elixir-developer)),
+and [Dashbit](https://dashbit.co).
+
+## Learn more
+
+Other notable changes in this release are:
+
+* the addition of [`String.replace_invalid/2`](https://hexdocs.pm/elixir/String.html#replace_invalid/2), to help deal with invalid UTF-8 encoding
+
+* the addition of the `:limit` option in [`Task.yield_many/2`](https://hexdocs.pm/elixir/Task.html#yield_many/2) that limits the maximum number of tasks to yield
+
+* improved binary pattern matching by allowing prefix binary matches, such as `<<^prefix::binary, rest::binary>>`
+
+For a complete list of all changes, see the
+[full release notes](https://github.com/elixir-lang/elixir/releases/tag/v1.16.0).
+
+Check [the Install section](/install.html) to get Elixir installed and
+read our [Getting Started guide](https://hexdocs.pm/elixir/introduction.html)
+to learn more.
+
+Happy learning!
diff --git a/_posts/2024-03-05-veeps-elixir-case.markdown b/_posts/2024-03-05-veeps-elixir-case.markdown
new file mode 100644
index 000000000..f0e60b7d1
--- /dev/null
+++ b/_posts/2024-03-05-veeps-elixir-case.markdown
@@ -0,0 +1,135 @@
+---
+layout: post
+title: "Scaling a streaming service to hundreds of thousands of concurrent viewers at Veeps"
+authors:
+- Hugo Baraúna
+category: Elixir in Production
+excerpt: A case study of how Elixir is being used at Veeps.
+logo: /images/cases/logos/veeps.svg
+tags: streaming scaling web
+---
+
+*Welcome to our series of [case studies about companies using Elixir in production](/cases.html).*
+
+[Veeps](https://veeps.com/) is a streaming service that offers direct access to live and on-demand events by award-winning artists at the most iconic venues. Founded in 2018, it became part of Live Nation Entertainment in 2021.
+
+Veeps have been named [one of the ten most innovative companies in music](https://www.fastcompany.com/90848907/most-innovative-companies-music-2023) and nominated for an Emmy. They currently hold the [Guinness World Record](https://www.guinnessworldrecords.com/world-records/650975-most-tickets-sold-for-a-livestreamed-concert-by-a-solo-male-artist-current-year) for the world's largest ticketed livestream by a solo male artist—a performance where Elixir and Phoenix played an important role in the backend during the streaming.
+
+This case study examines how Elixir drove Veeps' technical transformation, surpassing high-scale demands while keeping the development team engaged and productive.
+
+
+## The challenge: scaling to hundreds of thousands of simultaneous users
+
+Imagine you are tasked with building a system that can livestream a music concert to hundreds of thousands of viewers around the world at the same time.
+
+In some cases, users must purchase a ticket before the concert can be accessed. For a famous artist, it’s not uncommon to see thousands of fans continuously refreshing their browsers and attempting to buy tickets within the first few minutes of the announcement.
+
+The Veeps engineering team needed to handle both challenges.
+
+Early on, the Veeps backend was implemented in [Ruby on Rails](https://rubyonrails.org/). Its first version could handle a few thousand simultaneous users watching a concert without any impact to stream quality, which was fine when you have a handful of shows but would be insufficient with the expected show load and massive increase in concurrent viewership across streams. It was around that time that [Vincent Franco](https://twitter.com/vinniefranco) joined Veeps as their CTO.
+
+Vincent had an extensive background in building and maintaining ticketing and event management software at scale. So, he used that experience to further improve the system to handle tens of thousands of concurrent users. However, it became clear that improving it to *hundreds* of thousands would be a difficult challenge, requiring substantial engineering efforts and increased operational costs. The team began evaluating other stacks that could provide the out-of-the-box tooling for scaling in order to reach both short and long-term goals.
+
+
+## Adopting Elixir, hiring, and rewriting the system
+
+Vincent, who had successfully deployed Elixir as part of high-volume systems in the past, believed Elixir was an excellent fit for Veeps' requirements.
+
+Backed by his experience and several case studies from the Elixir community, such as [the one from Discord](/blog/2020/10/08/real-time-communication-at-scale-with-elixir-at-discord/), Vincent convinced management that Elixir could address their immediate scaling needs and become a reliable foundation on which the company could build.
+
+With buy-in from management, the plan was set in motion. They had two outstanding goals:
+
+* Prepare the platform to welcome the most famous artists in the world.
+* Build their own team of engineers to help innovate and evolve the product.
+
+Vincent knew that hiring right-fit technical people can take time and he didn't want to rush the process. Hence, he hired [DockYard](https://dockyard.com/) to rebuild the system while simultaneously searching for the right candidates to build out the team.
+
+Eight months later, the system had been entirely rewritten in Elixir and Phoenix. Phoenix Channels were used to enrich the live concert experience, while Phoenix LiveView empowered the ticket shopping journey.
+
+The rewrite was put to the test shortly after with a livestream that remains one of Veeps’ biggest, still to this day. Before the rewrite, 20 Rails nodes were used during big events, whereas now, the same service requires only 2 Elixir nodes. And the new platform was able to handle 83x more concurrent users than the previous system.
+
+The increase in infrastructure efficiency significantly reduced the need for complex auto-scaling solutions while providing ample capacity to handle high-traffic spikes.
+
+> The rewrite marked the most extensive and intricate system migration in my career, and yet, it was also the smoothest.
+>
+> \- Vincent Franco, CTO
+
+
+This was a big testament to Elixir and Phoenix's scalability and gave the team confidence that they made the right choice.
+
+By the time the migration was completed, Veeps had also assembled an incredibly talented team of two backend and two frontend engineers, which continued to expand and grow the product.
+
+
+## Perceived benefits of using Elixir and its ecosystem
+
+After using Elixir for more than two years, Veeps has experienced significant benefits. Here are a few of them.
+
+
+### Architectural simplicity
+
+Different parts of the Veeps system have different scalability requirements. For instance, when streaming a show, the backend receives metadata from users' devices every 30 seconds to track viewership. This is the so-called *Beaconing service*.
+
+Say you have 250,000 people watching a concert: the Beaconing service needs to handle thousands of requests per second for a few hours at a time. As a result, it needs to scale differently from other parts of the system, such as the merchandise e-commerce or backstage management.
+
+To tackle this issue, they built a distributed system. They packaged each subsystem as an [Elixir release](https://hexdocs.pm/elixir/config-and-releases.html#releases), totaling five releases. For the communication layer, they used distributed Erlang, which is built into Erlang/OTP, allowing seamless inter-process communication across networked nodes.
+
+In a nutshell, each node contains several processes with specific responsibilities. Each of these processes belongs to their respective [distributed process group](https://www.erlang.org/doc/man/pg.html). If node A needs billing information, it will reach out to any process within the "billing process group", which may be anywhere in the cluster.
+
+When deploying a new version of the system, they deploy a new cluster altogether, with all five subsystems at once. Given Elixir's scalability, the whole system uses 9 nodes, making a simple deployment strategy affordable and practical. As we will see, this approach is well-supported during development too, thanks to the use of Umbrella Projects.
+
+
+### Service-oriented architecture within a monorepo
+
+Although they run a distributed system, they organize the code in only one repository, following the monorepo approach. To do that, they use the [Umbrella Project feature](https://hexdocs.pm/elixir/dependencies-and-umbrella-projects.html#content) from Mix, the build tool that ships with Elixir.
+
+Their umbrella project consists of 16 applications (at the time of writing), which they [sliced into five OTP releases](https://hexdocs.pm/mix/Mix.Tasks.Release.html#module-umbrellas). The remaining applications contain code that needs to be shared between multiple applications. For example, one of the shared applications defines all the structs sent as messages across the subsystems, guaranteeing that all subsystems use the same schemas for that exchanged data.
+
+> With umbrella projects, you can have the developer experience benefits of a single code repository, while being able to build a service-oriented architecture.
+>
+> \- Andrea Leopardi, Principal Engineer
+
+
+### Reducing complexity with the Erlang/Elixir toolbox
+
+Veeps has an e-commerce platform that allows concert viewers to purchase artist merchandise. In e-commerce, a common concept is a shopping cart. Veeps associates each shopping cart as a [GenServer](https://hexdocs.pm/elixir/GenServer.html), which is a lightweight process managed by the Erlang VM.
+
+This decision made it easier for them to implement other business requirements, such as locking the cart during payments and shopping cart expiration. Since each cart is a process, the expiration is as simple as sending a message to a cart process based on a timer, which is easy to do using GenServers.
+
+For caching, the team relies on [ETS (Erlang Term Storage)](https://www.erlang.org/doc/man/ets.html), a high-performing key-value store part of the Erlang standard library. For cache busting between multiple parts of the distributed system, they use [Phoenix PubSub](https://github.com/phoenixframework/phoenix_pubsub), a real-time publisher/subscriber library that comes with [Phoenix](https://phoenixframework.org/).
+
+Before the rewrite, the Beaconing service used Google's Firebase. Now, the system uses [Broadway](https://elixir-broadway.org/) to ingest data from hundreds of thousands of HTTP requests from concurrent users. Broadway is an Elixir library for building concurrent data ingestion and processing pipelines. They utilized the library's capabilities to efficiently send requests to AWS services, regulating batch sizes to comply with AWS limits. They also used it to handle rate limiting to adhere to AWS service constraints. All of this was achieved with Broadway's built-in functionality.
+
+Finally, they use [Oban](https://getoban.pro/), an Elixir library for background jobs, for all sorts of background-work use cases.
+
+Throughout the development journey, Veeps consistently found that Elixir and its ecosystem had built-in solutions for their technical challenges. Here's what Vincent, CTO of Veeps, had to say about that:
+
+> Throughout my career, I've worked with large-scale systems at several companies. However, at Veeps, it's unique because we achieve this scale with minimal reliance on external tools. It's primarily just Elixir and its ecosystem that empower us.
+>
+> \- Vincent Franco, CTO
+
+This operational simplicity benefitted not only the production environment but also the development side. The team could focus on learning Elixir and its ecosystem without the need to master additional technologies, resulting in increased productivity.
+
+
+### LiveView: simplifying the interaction between front-end and back-end developers
+
+After the rewrite, [LiveView](https://github.com/phoenixframework/phoenix_live_view), a Phoenix library for building interactive, real-time web apps, was used for every part of the front-end except for the "Onstage" subsystem (responsible for the live stream itself).
+
+The two front-end developers, who came from a React background, also started writing LiveView. After this new experience, the team found the process of API negotiation between the front-end and back-end engineers much simpler compared to when using React. This was because they only had to use Elixir modules and functions instead of creating additional HTTP API endpoints and all the extra work that comes with them, such as API versioning.
+
+> Our front-end team, originally proficient in React, has made a remarkable transition to LiveView. They've wholeheartedly embraced its user-friendly nature and its smooth integration into our system.
+>
+> \- Vincent Franco, CTO
+
+
+## Conclusion: insights from Veeps' Elixir experience
+
+The decision to use Elixir has paid dividends beyond just system scalability. The team, with varied backgrounds in Java, PHP, Ruby, Python, and Javascript, found Elixir's ecosystem to be a harmonious balance of simplicity and power.
+
+By embracing Elixir's ecosystem, including Erlang/OTP, Phoenix, LiveView, and Broadway, they built a robust system, eliminated the need for numerous external dependencies, and kept productively developing new features.
+
+
+> Throughout my career, I've never encountered a developer experience as exceptional as this. Whether it's about quantity or complexity, tasks seem to flow effortlessly. The team's morale is soaring, everyone is satisfied, and there's an unmistakable atmosphere of positivity. We're all unequivocally enthusiastic about this language.
+>
+> \- Vincent Franco, CTO
+
+Veeps' case illustrates how Elixir effectively handles high-scale challenges while keeping the development process straightforward and developer-friendly.
diff --git a/_posts/2024-06-12-elixir-v1-17-0-released.markdown b/_posts/2024-06-12-elixir-v1-17-0-released.markdown
new file mode 100644
index 000000000..c857c906e
--- /dev/null
+++ b/_posts/2024-06-12-elixir-v1-17-0-released.markdown
@@ -0,0 +1,178 @@
+---
+layout: post
+title: "Elixir v1.17 released: set-theoretic data types, calendar durations, and Erlang/OTP 27 support"
+authors:
+- Andrea Leopardi
+category: Releases
+excerpt: "Elixir v1.17 released: set-theoretic data types, calendar durations, and Erlang/OTP 27 support"
+---
+
+Elixir v1.17 has just been released. 🎉
+
+This release introduces set-theoretic types into a handful of language constructs. While there are still [many steps ahead of us](https://elixir-lang.org/blog/2023/06/22/type-system-updates-research-dev/), this important milestone already brings benefits to developers in the form of new warnings for common mistakes. This new version also adds support for [Erlang/OTP 27](https://www.erlang.org/downloads/27), the latest and greatest Erlang release. You'll also find a new calendar-related data type (`Duration`) and a `Date.shift/2` function.
+
+Let's dive in.
+
+## Warnings from gradual set-theoretic types
+
+This release introduces gradual set-theoretic types to infer types from patterns and use them to type check programs, enabling the Elixir compiler to find faults and bugs in codebases without requiring changes to existing software. The underlying principles, theory, and roadmap of our work have been outlined in ["The Design Principles of the Elixir Type System" by Giuseppe Castagna, Guillaume Duboc, José Valim](https://arxiv.org/abs/2306.06391).
+
+At the moment, Elixir developers will interact with set-theoretic types only through **warnings** found by the type system. The current implementation models all data types in the language:
+
+  * `binary()`, `integer()`, `float()`, `pid()`, `port()`, `reference()` - these
+    types are indivisible. This means both `1` and `13` get the same `integer()`
+    type.
+
+  * `atom()` - it represents all atoms and it is divisible. For instance, the
+    atom `:foo` and `:hello_world` are also valid (distinct) types.
+
+  * `map()` and structs - maps can be "closed" or "open". Closed maps only allow
+    the specified keys, such as `%{key: atom(), value: integer()}`. Open maps
+    support any other keys in addition to the ones listed and their definition
+    starts with `...`, such as `%{..., key: atom(), value: integer()}`. Structs
+    are closed maps with the `__struct__` key.
+
+  * `tuple()`, `list()`, and `function()` - currently they are modelled as
+    indivisible types. The next Elixir versions will also introduce fine-grained
+    support to them.
+
+We focused on *atoms* and *maps* on this initial release as they are respectively the simplest and the most complex types representations, so we can stress the performance of the type system and quality of error messages. Modelling these types will also provide the most immediate benefits to Elixir developers. Assuming there is a variable named `user`, holding a `%User{}` struct with a `address` field, Elixir v1.17 will emit the following warnings at compile-time:
+
+  * Pattern matching against a map or a struct that does not have the given key,
+    such as `%{adress: ...} = user` (notice `address` vs `adress`).
+
+  * Accessing a key on a map or a struct that does not have the given key, such
+    as `user.adress`.
+
+  * Invoking a function on non-modules, such as `user.address()`.
+
+  * Capturing a function on non-modules, such as `&user.address/0`.
+
+  * Attempting to call an anonymous function without an actual function, such as
+    `user.()`.
+
+  * Performing structural comparisons between structs, such as `my_date <
+    ~D[2010-04-17]`.
+
+  * Performing structural comparisons between non-overlapping types, such as
+    `integer >= string`.
+
+  * Building and pattern matching on binaries without the relevant specifiers,
+    such as `<<name>>` (this warns because by default it expects an integer, it
+    should have been `<<name::binary>>` instead).
+
+  * Attempting to rescue an undefined exception or a struct that is not an
+    exception.
+
+  * Accessing a field that is not defined in a rescued exception.
+
+Here's an example of how the warning for accessing a misspelled field of a
+struct looks like:
+
+![Example of a warning when accessing a mispelled struct field](/images/contents/type-warning-on-struct-field.png)
+
+Another example, this time it's a warning for structural comparison across two
+`Date` structs:
+
+![Example of a warning when comparing two structs with ">"](/images/contents/type-warning-on-date-comparison.png)
+
+These warnings also work natively in text editors, as they are standard Elixir
+compiler warnings:
+
+![Example of a type warning inline in an editor](/images/contents/type-warning-in-editor.png)
+
+These new warnings will help Elixir developers find bugs earlier and give more
+confidence when refactoring code, especially around maps and structs. While
+Elixir already emitted some of these warnings in the past, those were discovered
+using syntax analysis. The new warnings are more reliable, precise, and with
+better error messages. Keep in mind, however, that the Elixir typechecker only
+infers types from patterns within the same function at the moment. Analysis from
+guards and across function boundaries will be added in future releases. For more
+details, see our new [reference document on gradual set-theoretic
+types](https://hexdocs.pm/elixir/gradual-set-theoretic-types.html).
+
+The type system was made possible thanks to a partnership between
+[CNRS](https://www.cnrs.fr/) and [Remote](https://remote.com/). The development
+work is currently sponsored by [Fresha](https://www.fresha.com/)
+([they are hiring!](https://www.fresha.com/careers/openings?department=engineering)),
+[Starfish*](https://starfish.team/), and [Dashbit](https://dashbit.co/).
+
+## Erlang/OTP support
+
+This release adds support for Erlang/OTP 27 and drops support for Erlang/OTP 24.
+We recommend Elixir developers to migrate to Erlang/OTP 26 or later, especially
+on Windows. Support for WERL (a graphical user interface for the Erlang terminal
+on Windows) will be removed in Elixir v1.18.
+
+You can read more about Erlang/OTP 27 in [their release
+announcement](https://www.erlang.org/downloads/27). The bits that are
+particularly interesting for Elixir developers are the addition of a [`json`
+module](https://erlang.org/documentation/doc-15.0-rc3/lib/stdlib-6.0/doc/html/json.html)
+and process labels (`proc_lib:set_label/1`). The latter will also be available
+in this Elixir release as `Process.set_label/1`.
+
+## New `Duration` data type and shifting functions
+
+This Elixir version introduces the `Duration` data type and APIs to shift dates,
+times, and date times by a given duration, considering different calendars and
+time zones.
+
+```elixir
+iex> Date.shift(~D[2016-01-31], month: 2)
+~D[2016-03-31]
+```
+
+We chose the name *"shift"* for this operation (instead of "add") since working
+with durations does not obey properties such as **associativity**. For instance,
+adding one month and then one month does not give the same result as adding two
+months:
+
+```elixir
+iex> ~D[2016-01-31] |> Date.shift(month: 1) |> Date.shift(month: 1)
+~D[2016-03-29]
+```
+
+Still, durations are essential for building intervals, recurring events, and
+modelling scheduling complexities found in the world around us. For `DateTime`s,
+Elixir will correctly deal with time zone changes (such as Daylight Saving
+Time). However, provisions are also available in case you want to surface
+conflicts, such as shifting to a wall clock that does not exist, because the
+clock has been moved forward by one hour. See `DateTime.shift/2` for examples.
+
+Finally, we added a new `Kernel.to_timeout/1` function, which helps developers
+normalize durations and integers to a timeout used by many APIs—like `Process`,
+`GenServer`, and more. For example, to send a message after one hour, you can
+now write:
+
+```elixir
+Process.send_after(pid, :wake_up, to_timeout(hour: 1))
+```
+
+## Learn more
+
+Here are other notable changes in this release:
+
+  * There are new `Keyword.intersect/2,3` functions to mirror the equivalent in
+    the `Map` module.
+
+  * A new Mix profiler was added, `mix profile.tprof`, which lets you use the
+    new [tprof](https://www.erlang.org/doc/apps/tools/tprof.html)
+    profiler released with Erlang/OTP 27. This profiler leads to the
+    soft-deprecation of `mix profile.cprof` and `mix profile.eprof`.
+
+  * We added `Kernel.is_non_struct_map/1`, a new guard to help with the common
+    pitfall of matching on `%{}`, which also successfully matches structs (as
+    they are maps underneath).
+
+  * Elixir's Logger now formats
+    [`gen_statem`](https://www.erlang.org/doc/apps/stdlib/gen_statem.html)
+    reports and includes Erlang/OTP 27 *process labels* in logger events.
+
+For a complete list of all changes, see the
+[full release notes](https://github.com/elixir-lang/elixir/releases/tag/v1.17.0).
+
+Check [the Install section](/install.html) to get Elixir installed and
+read our [Getting Started guide](https://hexdocs.pm/elixir/introduction.html)
+to learn more.
+
+Happy learning!
diff --git a/_posts/2024-08-15-welcome-elixir-language-server-team.markdown b/_posts/2024-08-15-welcome-elixir-language-server-team.markdown
new file mode 100644
index 000000000..2df6af2d1
--- /dev/null
+++ b/_posts/2024-08-15-welcome-elixir-language-server-team.markdown
@@ -0,0 +1,89 @@
+---
+layout: post
+title: "Announcing the official Elixir Language Server team"
+authors:
+- José Valim
+category: Announcements
+excerpt: "Announcing the official Elixir Language Server team to work on the code intelligence infrastructure to be used across tools and editors"
+---
+
+I am glad to welcome Elixir's official Language Server team, formed by (in alphabetical order):
+
+* [Jonatan Kłosko](https://github.com/jonatanklosko)
+* [Łukasz Samson](https://github.com/lukaszsamson)
+* [Mitch Hanberg](https://www.mitchellhanberg.com/)
+* [Steve Cohen](https://github.com/scohen)
+
+The team will work on the code intelligence infrastructure to be used across tools and editors. These efforts are partially funded by [Fly.io](https://fly.io/) and [Livebook](https://livebook.dev/).
+
+## A brief history
+
+The [Language Server Protocol (LSP)](https://en.wikipedia.org/wiki/Language_Server_Protocol) was created by Microsoft as a protocol between IDEs and programming languages to provide language intelligence tools.
+
+The first implementation of said protocol for Elixir was started by [Jake Becker](https://github.com/JakeBecker/elixir-ls/), back in 2017, alongside an implementation for Visual Studio Code, and it relied on [the ElixirSense project from Marlus Saraiva](https://github.com/msaraiva/elixir_sense) to extract and provide some of the language intelligence.
+
+As the Language Server Protocol adoption grew as a whole, so did the usage of Elixir's implementation, which eventually became the main mechanism Elixir users interacted with the language from their editors.
+
+Eventually, Elixir's language server implementation got its [own organization on GitHub](https://github.com/elixir-lsp/), and maintenance reins were given to Łukasz Samson and Jason Axelson.
+
+Over time, the Elixir Language Server has accrued technical debt. Some of it exists due to intrinsic complexities (for example, the Language Server Protocol uses UTF-16 for text encoding, instead of the more widely used UTF-8), while others are a consequence of working on codebase while both the programming language and the protocol themselves were still evolving.
+
+This led to Mitch Hanberg and Steve Cohen to create alternative language server implementations, exploring different trade-offs.
+
+For example, both [Next LS](https://github.com/elixir-tools/next-ls) and [Lexical](https://github.com/lexical-lsp/lexical) use Erlang Distribution to isolate the Language Server runtime from the user code.
+
+Next LS also focused on extracting the LSP protocol parts into [GenLSP](https://github.com/elixir-tools/gen_lsp) (which can be used by anyone to easily create a language server), single binary distribution with [Burrito](https://github.com/burrito-elixir/burrito), and experimenting with SQLite for the symbol index.
+
+[Lexical](https://github.com/lexical-lsp/lexical) concerned itself with speed and abstractions to deal with documents, ranges, and more.
+
+This means the Elixir community had, for some time, three distinct language server implementations, each with their own strengths.
+
+## Looking forward
+
+The current language server maintainers have agreed to move forward with a _single Language Server Protocol project_, relying on the strengths of each implementation:
+
+* Lexical provides a stable foundation
+* ElixirLS, through ElixirSense, provides the most complete implementation and wider functionality
+* Next LS, through GenLSP, provides a general interface for LSP implementations and straight-forward packaging via [Burrito](https://github.com/burrito-elixir/burrito)
+
+The above is a rough outline, as the specific details of how the projects will move forward are still being discussed. While some of the team members also maintain direct integration with some editors, we will continue relying on the community's help and efforts to get full coverage across all available editors.
+
+And there is still a lot more to do!
+
+Many underestimate the complexity behind implementing the Language Server Protocol. That's not surprising: we mostly interact with it from an editor, allowing us to freely ignore what makes it tick.
+
+In practice, the Language Server needs, in many ways, to reimplement several parts of the language and its compiler.
+
+If the Elixir compiler sees the code `some_value +`, it can immediately warn and say: "this expression is incomplete". However, the Language Server still needs to make sense of invalid code to provide features like completion. And that applies to everything: missing do-end blocks, invalid operators, invoking macros that do not exist, etc. Mitch has made [Spitfire](https://github.com/elixir-tools/spitfire), an error tolerant parser to tackle this particular problem.
+
+Some ecosystems have undertaken [multi-year efforts to redesign their compilers and toolchains](https://en.wikipedia.org/wiki/Roslyn_(compiler)) to provide better tools for lexical and semantic code analysis (which most likely took a significant investment of time and resources to conclude). That's to say some of the problems faced by Language Server implementations will be best tackled if they are also solved as part of Elixir itself.
+
+For example, every Language Server implementation compiles their own version of a project, making it so every application and its dependencies have to be compiled twice in development: once for Mix and once for the Language Server. Wouldn't it be nice if Elixir and the Language Servers could all rely on the same compilation artifacts?
+
+This is not news to the Elixir team either: almost every Elixir release within the last 3 years has shipped new code analysis APIs, such as [Code.Fragment](https://hexdocs.pm/elixir/Code.Fragment.html), with the goal of removing duplication across Language Servers, [IEx](https://hexdocs.pm/iex), and [Livebook](https://livebook.dev/), as well as reduce their reliance on internal Elixir modules. Most recently, Elixir v1.17 shipped with [new APIs to help developers emulate the compiler behaviour](https://hexdocs.pm/elixir/Macro.Env.html). Our goal is to make these building blocks available for all Elixir developers, so their benefits are reaped beyond the language server tooling.
+
+Furthermore, as [set-theoretic types make their way into Elixir](https://elixir-lang.org/blog/2024/06/12/elixir-v1-17-0-released/), we also want to provide official APIs to integrate them into our tools.
+
+## Sponsorships
+
+Currently, [Fly.io](https://fly.io/) is sponsoring Łukasz Samson to work part-time on the Language Server and editor integration. The [Livebook](https://livebook.dev/) project is donating development time from Jonatan Kłosko, creator of Livebook, to improve the Elixir compiler and its code intelligence APIs.
+
+We are grateful to both companies for investing into the community and you should check them out.
+
+As mentioned above, Language Server implementations are complex projects, and unifying efforts is an important step in the right direction. However, we also need community help, and one of the ways to do so is by sponsoring the developers making this possible:
+
+* [Łukasz Samson](https://github.com/sponsors/lukaszsamson)
+* [Mitch Hanberg](https://github.com/sponsors/mhanberg)
+* [Steve Cohen](https://github.com/sponsors/scohen)
+
+Companies who can afford to sponsor part-time development are welcome to reach out and help us achieve this important milestone.
+
+## Progress updates
+
+A new project website and social media accounts will be created soon, and you can follow them to stay up to date with our progress and any interesting developments.
+
+The name of the new project is still in the works as well as many of the decisions we'll need to make, so please have patience!
+
+In the meantime, you can continue to use the language server of your choice, and we’ll be sure to make the transition to the fourth and final project as smooth as possible.
+
+Thank you!
diff --git a/_posts/2024-08-28-typing-lists-and-tuples.markdown b/_posts/2024-08-28-typing-lists-and-tuples.markdown
new file mode 100644
index 000000000..d8548371c
--- /dev/null
+++ b/_posts/2024-08-28-typing-lists-and-tuples.markdown
@@ -0,0 +1,173 @@
+---
+layout: post
+title: "Typing lists and tuples in Elixir"
+authors:
+- José Valim
+category: Announcements
+excerpt: "This article explores the design decisions of typing lists and tuples in Elixir within a sound gradual type system"
+---
+
+We have been working on [a type system for the Elixir programming language](https://elixir-lang.org/blog/2023/06/22/type-system-updates-research-dev/). The type system provides sound gradual typing: it can safely interface static and dynamic code, and if the program type checks, it will not produce type errors at runtime.
+
+It is important to emphasize **type errors**. The type systems used at scale today do not guarantee the absense of any runtime errors, but only typing ones. Many programming languages error when accessing the "head" of an empty list, most languages raise on division by zero or when computing the logarithm of negative numbers on a real domain, and others may fail to allocate memory or when a number overflows/underflows.
+
+Language designers and maintainers must outline the boundaries of what can be represented as typing errors and how that impacts the design of libraries. The goal of this article is to highlight some of these decisions in the context of lists and tuples in Elixir's on-going type system work.
+
+> In this article, the words "raise" and "exceptions" describe something unexpected happened, and not a mechanism for control-flow. Other programming languages may call them "panics" or "faults".
+
+## The `head` of a list
+
+Imagine you are designing a programming language and you want to provide a `head` function, which returns the head - the first element - of a list, you may consider three options.
+
+The first option, the one found in many programming languages, is to raise if an empty list is given. Its implementation in Elixir would be something akin to:
+
+```elixir
+$ list(a) -> a
+def head([head | _]), do: head
+def head([]), do: raise "empty list"
+```
+
+Because the type system cannot differentiate between an empty list and a non-empty list, you won't find any typing violations at compile-time, but an error is raised at runtime for empty lists.
+
+An alternative would be to return an `option` type, properly encoding that the function may fail (or not):
+
+```elixir
+$ list(a) -> option(a)
+def head([head | _]), do: {:ok, head}
+def head([]), do: :none
+```
+
+This approach may be a bit redundant. Returning an `option` type basically forces the caller to pattern match on the returned `option`. While many programming languages provide functions to compose `option` values, one may also get rid of the additional wrapping and directly pattern match on the list instead. So instead of:
+
+```elixir
+case head(list) do
+  {:ok, head} -> # there is a head
+  :none -> # do what you need to do
+end
+```
+
+You could just write:
+
+```elixir
+case list do
+  [head | _] -> # there is a head
+  [] -> # do what you need to do
+end
+```
+
+Both examples above are limited by the fact the type system cannot distinguish between empty and non-empty lists and therefore their handling must happen at runtime. If we get rid of this limitations, we could define `head` as follows:
+
+```elixir
+$ non_empty_list(a) -> a
+def head([head | _]), do: head
+```
+
+And now we get a typing violation at compile-time if an empty list is given as argument. There is no `option` tagging and no runtime exceptions. Win-win?
+
+The trouble with the above is that now it is responsibility of the language users to prove the list is not empty. For example, imagine this code:
+
+```elixir
+list = convert_json_array_to_elixir_list(json_array_as_string)
+head(list)
+```
+
+In the example above, since `convert_json_array_to_elixir_list` may return an empty list, there is a typing violation at compile-time. To resolve it, we need to prove the result of `convert_json_array_to_elixir_list` is not an empty list before calling `head`:
+
+```elixir
+list = convert_json_array_to_elixir_list(json_array_as_string)
+
+if list == [] do
+  raise "empty list"
+end
+
+head(list)
+```
+
+But, at this point, we might as well just use pattern matching and once again get rid of `head`:
+
+```elixir
+case convert_json_array_to_elixir_list(json_array_as_string) do
+  [head | _] -> # there is a head
+  [] -> # do what you need to do
+end
+```
+
+Most people would expect that encoding more information into the type system would bring only benefits but there is a tension here: the more you encode into types, the more you might have to prove in your programs.
+
+While different developers will prefer certain idioms over others, I am not convinced there is one clearly superior approach here. Having `head` raise a runtime error may be the most pragmatic approach _if_ the developer expects the list to be non-empty in the first place. Returning `option` gets rid of the exception by forcing users to explicitly handle the result, but leads to more boilerplate compared to pattern matching, especially if the user does not expect empty lists. And, finally, adding precise types means there could be more for developers to prove.
+
+### What about Elixir?
+
+Thanks to set-theoretic types, we will most likely distinguish between empty lists and non-empty lists in Elixir's type system, since pattern matching on them is a common language idiom. Furthermore, several functions in Elixir, such as `String.split/2` are guaranteed to return non-empty lists, which can then be nicely encoded into a function's return type.
+
+Elixir also has the functions `hd` (for head) and `tl` (for tail) inherited from Erlang, which are [valid guards](https://hexdocs.pm/elixir/patterns-and-guards.html). They only accept non-empty lists as arguments, which will now be enforced by the type system too.
+
+This covers almost all use cases but one: what happens if you want to access the first element of a list, which has not been proven to be empty? You could use pattern matching and conditionals for those cases, but as seen above, this can lead to common boilerplate such as:
+
+```elixir
+if list == [] do
+  raise "unexpected empty list"
+end
+```
+
+Luckily, it is common in Elixir to use the `!` suffix to encode the possibility of runtime errors for _valid_ inputs. For these circumstances, we may introduce `List.first!` (and potentially `List.drop_first!` for the tail variant).
+
+## Accessing tuples
+
+Now that we have discussed lists, we can talk about tuples. In a way, tuples are more challenging than lists for two reasons:
+
+1. A list is a collection where all elements have the same type (be it a `list(integer())` or `list(integer() or float())`), while tuples carry the types of each element
+
+2. We natively access tuples by index, instead of its head and tail, such `elem(tuple, 0)`
+
+In the upcoming v1.18 release, Elixir's new type system will support tuple types, and they are written between curly brackets. For example, the [`File.read/1` function](https://hexdocs.pm/elixir/File.html#read/1) would have the return type `{:ok, binary()} or {:error, posix()}`, quite similar to today's typespecs.
+
+The tuple type can also specify a minimum size, as you can also write: `{atom(), integer(), ...} `. This means the tuple has at least two elements, the first being an `atom()` and the second being an `integer()`. This definition is required for type inference in patterns and guards. After all, a guard `is_integer(elem(tuple, 1))` tells you the tuple has at least two elements, with the second one being an integer, but nothing about the other elements and the tuple overall size.
+
+With tuples support merged into main, we need to answer questions such as which kind of compile-time warnings and runtime exceptions tuple operations, such as `elem(tuple, index)` may emit. Today, we know that it raises if:
+
+1. the index is out of bounds, as in `elem({:ok, "hello"}, 3)`
+
+2. the index is negative, as in `elem({:ok, 123}, -1)`
+
+When typing `elem(tuple, index)`, one option is to use "avoid all runtime errors" as our guiding light and make `elem` return `option` types, such as: `{:ok, value}` or `:none`. This makes sense for an out of bounds error, but should it also return `:none` if the index is negative? One could argue that they are both out of bounds. On the other hand, a positive index may be correct depending on the tuple size but **a negative index is always invalid**. From this perspective, encoding an always invalid value as an `:none` can be detrimental to the developer experience, hiding logical bugs instead of (loudly) blowing up.
+
+Another option is to make these programs invalid. If we completely remove `elem/2` from the language and you can only access tuples via pattern matching (or by adding a literal notation such as `tuple.0`), then all possible bugs can be caught by the type checker. However, some data structures, such as [array in Erlang](https://www.erlang.org/doc/apps/stdlib/array.html) rely on dynamic tuple access, and implementing those would be no longer possible.
+
+Yet another option is to encode integers themselves as values in the type system. In the same way that Elixir's type system supports the values `:ok` and `:error` as types, we could support each integer, such as `13` and  `-42` as types as well (or specific subsets, such as `neg_integer()`, `zero()` and `pos_integer()`). This way, the type system would know the possible values of `index` during type checking, allowing us to pass complex expressions to `elem(tuple, index)`, and emit typing errors if the indexes are invalid. However, remember that encoding more information into types may force developers to also prove that those indexes are within bounds in many other cases.
+
+Once again, there are different trade-offs, and we must select one that best fit into Elixir use and semantics today.
+
+### What about Elixir?
+
+The approach we are taking in Elixir is two-fold:
+
+* If the index is a literal integer, it will perform an exact access on the tuple element. This means `elem(tuple, 1)` will work if we can prove the tuple has at least size 2, otherwise you will have a type error
+
+* If the index is not a literal integer, the function will fallback to a dynamic type signature
+
+Let's expand on the second point.
+
+At a fundamental level, we could describe `elem` with the type signature of `tuple(a), integer() -> a`. However, the trouble with this signature is that it does not tell the type system (nor users) the possibility of a runtime error. Luckily, because Elixir will offer a gradual type system, we could encode the type signature as `dynamic({...a}), integer() -> dynamic(a)`. By encoding the argument and return type as dynamic, developers who want a fully static program will be notified of a typing error, while existing developers who rely on dynamic features of the language can continue to do so, and those choices are now encoded into the types.
+
+Overall,
+
+* For static programs (the ones that do not use the `dynamic()` type), `elem/2` will validate that the first argument is a tuple of known shape, and the second argument is a literal integer which is greater than or equal to zero and less than the tuple size. This guarantees no runtime exceptions.
+
+* Gradual programs will have the same semantics (and runtime exceptions) as today.
+
+## Summary
+
+I hope this article outlines some of the design decisions as we bring a gradual type system to Elixir. Although supporting tuples and lists is a "table stakes" feature in most type systems, bringing them to Elixir is an opportunity to understand how the type system will interact with several language idioms, as well as provide a foundation for future decisions. The most important take aways are:
+
+1. Type safety is a commitment from both sides. If you want your type system to find even more bugs through more precise types, you will need to prove more frequently that your programs are free of certain typing violations.
+
+2. It is not a goal of the type system to avoid all runtime errors. This would require either a type system that is too precise (and require more proofs) or it would require functions to mask hard errors (such as a negative index) as error values. Exceptions still play an important role in typed Elixir and, given they are modelled as structs, they will also be typed in the future.
+
+3. Elixir's convention of using the suffix `!` to provide variants that encode the possibility of runtime exceptions for a valid domain (the input types) nicely complements the type system, as it can help static programs avoid the boilerplate of converting `:none`/`:error` into exceptions for unexpected scenarios.
+
+4. Using `dynamic()` in function signatures is a mechanism available in Elixir's type system to signal that a function has dynamic behaviour and may raise runtime errors, allowing violations to be reported on programs that wish to remain fully static. Similar to how other static languages provide dynamic behaviour via `Any` or `Dynamic` types.
+
+The type system was made possible thanks to a partnership between [CNRS](https://www.cnrs.fr/) and [Remote](https://remote.com/). The development work is currently sponsored by [Fresha](https://www.fresha.com/) ([they are hiring!](https://www.fresha.com/careers/openings?department=engineering)), [Starfish*](https://starfish.team/), and [Dashbit](https://dashbit.co/).
+
+Happy typing!
diff --git a/_posts/2024-12-19-elixir-v1-18-0-released.markdown b/_posts/2024-12-19-elixir-v1-18-0-released.markdown
new file mode 100644
index 000000000..22edc0364
--- /dev/null
+++ b/_posts/2024-12-19-elixir-v1-18-0-released.markdown
@@ -0,0 +1,218 @@
+---
+layout: post
+title: "Elixir v1.18 released: type checking of calls, LSP listeners, built-in JSON, and more"
+authors:
+- José Valim
+category: Releases
+excerpt: "Elixir v1.18 released: type checking of function calls, Language Server listeners, built-in JSON, ExUnit improvements, mix format --migrate, and more"
+---
+
+Elixir v1.18 is an impressive release with improvements across the two main efforts happening within the Elixir ecosystem right now: set-theoretic types and language servers. It also comes with built-in JSON support and adds new capabilities to its unit testing library. Let's go over each of those in detail.
+
+## Type inference of patterns and return types
+
+There are several updates in the typing department, so let's break them down.
+
+#### A type system? In my Elixir?
+
+There is an on-going [research and development](https://elixir-lang.org/blog/2023/06/22/type-system-updates-research-dev/) effort to bring static types to Elixir. Elixir's type system is:
+
+  * **sound** - the types inferred and assigned by the type system align with the behaviour of the program
+
+  * **gradual** - Elixir's type system includes the `dynamic()` type, which can be used when the type of a variable or expression is checked at runtime. In the absence of `dynamic()`, Elixir's type system behaves as a static one
+
+  * **developer friendly** - the types are described, implemented, and composed using basic set operations: unions, intersections, and negation (hence it is a set-theoretic type system)
+
+More interestingly, you can compose `dynamic()` with any type. For example, `dynamic(integer() or float())` means the type is either `integer()` or `float()` at runtime. This allows the type system to emit warnings if none of the types are satisfied, even in the presence of dynamism.
+
+#### What has already been done?
+
+[Elixir v1.17 was the first release to incorporate the type system in the compiler](https://elixir-lang.org/blog/2024/06/12/elixir-v1-17-0-released/). In particular, we have added support for primitive types (integer, float, binary, pids, references, ports), atoms, and maps. We also added type checking to a handful of operations related to those types, such as accessing fields in maps, as in `user.adress` (mind the typo), performing structural comparisons between structs, as in `my_date < ~D[2010-04-17]`, etc.
+
+#### What is new in v1.18?
+
+The most exciting change in Elixir v1.18 is type checking of function calls, alongside gradual inference of patterns and return types. To understand how this will impact your programs, consider the following code defined in `lib/user.ex`:
+
+```elixir
+defmodule User do
+  defstruct [:age, :car_choice]
+
+  def drive(%User{age: age, car_choice: car}, car_choices) when age >= 18 do
+    if car in car_choices do
+      {:ok, car}
+    else
+      {:error, :no_choice}
+    end
+  end
+
+  def drive(%User{}, _car_choices) do
+    {:error, :not_allowed}
+  end
+end
+```
+
+Elixir's type system will infer the `drive` function expects a `User` struct as input and returns either `{:ok, dynamic()}` or `{:error, :no_choice}` or `{:error, :not_allowed}`. Therefore, the following code
+
+```elixir
+User.drive({:ok, %User{}}, car_choices)
+```
+
+will emit a warning stating that we are passing an invalid argument:
+
+![Example of a warning when passing wrong argument to a function](/images/contents/type-warning-function-clause.png)
+
+Now consider the expression below. We are expecting the `User.drive/2` call to return `:error`, which cannot possibly be true:
+
+```elixir
+case User.drive(user, car_choices) do
+  {:ok, car} -> car
+  :error -> Logger.error("User cannot drive")
+end
+```
+
+Therefore the code above would emit the following warning:
+
+![Example of a warning when a case clause won't ever match](/images/contents/type-warning-case.png)
+
+Our goal is for the warnings to provide enough contextual information that lead to clear reports and that's an area we are actively looking for feedback. If you receive a warning that is unclear, please open up a bug report.
+
+Elixir v1.18 also augments the type system with support for tuples and lists, plus type checking of almost all Elixir language constructs, except `for`-comprehensions, `with`, and closures. Here is a non-exaustive list of the new violations that can be detected by the type system:
+
+  * if you define a pattern that will never match any argument, such as `def function(x = y, x = :foo, y = :bar)`
+
+  * matching or accessing tuples at an invalid index, such as `elem(two_element_tuple, 2)`
+
+  * if you have a branch in a `try` that will never match the given expression
+
+  * if you have a branch in a `cond` that always passes (except the last one) or always fails
+
+  * if you attempt to use the return value of a call to `raise/2` (which by definition returns no value)
+
+In summary, this release takes us further in our journey of providing type checking and type inference of existing Elixir programs, without requiring Elixir developers to explicitly add type annotations.
+
+For existing codebases with reasonable code coverage, most type system reports will come from uncovering dead code - code which won't ever be executed - as seen in a [few](https://github.com/phoenixframework/phoenix_live_view/commit/6c6e2aaf6a01957cc6bb8a27d2513bff273e8ca2) [distinct](https://github.com/elixir-ecto/postgrex/commit/3308f277f455ec64f2d0d7be6263f77f295b1325) [projects](https://github.com/phoenixframework/flame/commit/0c0c2875e42952d2691cbdb7928fc32f4715e746). A notable example is the type system ability to track how private functions are used throughout a module and then point out which clauses are unused:
+
+```elixir
+defmodule Example do
+  def public(x) do
+    private(Integer.parse(x))
+  end
+
+  defp private(nil), do: nil
+  defp private("foo"), do: "foo"
+  defp private({int, _rest}), do: int
+  defp private(:error), do: 0
+  defp private("bar"), do: "bar"
+end
+```
+
+![Example of a warning for unused private clauses](/images/contents/type-warning-private.png)
+
+Keep in mind the current implementation does not perform type inference of guards yet, which is an important source of typing information in programs. There is a lot the type system can learn about our codebases, that it does not yet. This brings us to the next topic.
+
+#### Future work
+
+The next Elixir release should improve the typing of maps, tuples, and closures, allowing us to type even more constructs. We also plan to fully type the `with` construct, `for`-comprehensions, as well as protocols.
+
+But more importantly, we want to focus on complete type inference of guards, which in turn will allow us to explore ideas such as redundant pattern matching clauses and exhaustiveness checks. Our goal with inference is to strike the right balance between developer experience, compilation times, and the ability of finding provable errors in existing codebases. You can learn more [about the trade-offs we made for inference in our documentation](https://hexdocs.pm/elixir/1.18/gradual-set-theoretic-types.html#type-inference).
+
+Future Elixir versions will introduce user-supplied type signatures, which should bring the benefits of a static type system without relying on inference. [Check our previous article on the overall milestones for more information](https://elixir-lang.org/blog/2023/06/22/type-system-updates-research-dev/).
+
+#### Sponsors
+
+The type system was made possible thanks to a partnership between [CNRS](https://www.cnrs.fr/) and [Remote](https://remote.com/). The development work is currently sponsored by [Fresha](https://www.fresha.com/) ([they are hiring!](https://www.fresha.com/careers/openings?department=engineering)), [Starfish*](https://starfish.team/), and [Dashbit](https://dashbit.co/).
+
+## Language server listeners
+
+Three months ago, we welcomed [the Official Language Server team](https://elixir-lang.org/blog/2024/08/15/welcome-elixir-language-server-team/), with the goal of unifying the efforts behind code intelligence, tools, and editors in Elixir. Elixir v1.18 brings new features on this front by introducing locks and listeners to its compilation. Let's understand what it means.
+
+At the moment, all language server implementations have their own compilation environment. This means that your project and dependencies during development are compiled once, for your own use, and then again for the language server. This duplicate effort could cause the language server experience to lag, when it could be relying on the already compiled artifacts of your project.
+
+This release addresses the issue by introducing a compiler lock, ensuring that only a single operating system running Elixir compiles your project at a given moment, and by providing the ability for one operating system process to listen to the compilation results of others. In other words, different Elixir instances can now communicate over the same compilation build, instead of racing each other.
+
+These enhancements do not only improve editor tooling, but they also directly benefit projects like IEx and Phoenix. Here is a quick snippet showing how to enable auto-reloading inside IEx, then running `mix compile` in one shell automatically reloads the module inside the IEx session:
+
+<video controls>
+  <source src="/images/contents/iex-auto-reload.mp4" type="video/mp4">
+  Your browser does not support the video tag.
+</video>
+
+## Built-in JSON
+
+[Erlang/OTP 27 added built-in support for JSON](https://www.erlang.org/doc/apps/stdlib/json.html) and we are now bringing it to Elixir. A new module, called [`JSON`](https://hexdocs.pm/elixir/1.18/JSON.html), has been added with functions to encode and decode JSON. Its most basic APIs reflect the ones [from the Jason project](https://hexdocs.pm/jason/Jason.html) (the de-facto JSON library in the Elixir community up to this point).
+
+A new protocol, called [`JSON.Encoder`](https://hexdocs.pm/elixir/1.18/JSON.Encoder.html), is also provided for those who want to customize how their own data types are encoded to JSON. You can also derive protocols for structs, with a single-line of code:
+
+```elixir
+@derive {JSON.Encoder, only: [:id, :name]}
+defstruct [:id, :name, :email]
+```
+
+The deriving API mirrors the one from `Jason`, helping those who want to migrate to the new `JSON` module.
+
+## Parameterized tests and ExUnit groups
+
+[ExUnit now supports parameterized tests](https://hexdocs.pm/ex_unit/1.18/ExUnit.Case.html#module-parameterized-tests). This allows your test modules to run multiple times under different parameters.
+
+For example, Elixir ships [a local, decentralized and scalable key-value process storage called `Registry`](https://hexdocs.pm/elixir/Registry.html). The registry can be partitioned and its implementation differs depending if partitioning is enabled or not. Therefore, during tests, we want to ensure both modes are exercised. With Elixir v1.18, we can achieve this by writing:
+
+```elixir
+defmodule Registry.Test do
+  use ExUnit.Case,
+    async: true,
+    parameterize: [
+      %{partitions: 1},
+      %{partitions: 8}
+    ]
+
+  # ... the actual tests ...
+end
+```
+
+Once specified, the number of partitions is available as part of the test configuration. For example, to start one registry per test with the correct number of partitions, you can write:
+
+```elixir
+  setup config do
+    partitions = config.partitions
+    name = :"#{config.test}_#{partitions}"
+    opts = [keys: :unique, name: name, partitions: partitions]
+    start_supervised!({Registry, opts})
+    opts
+  end
+```
+
+Prior to parameterized tests, Elixir resorted on code generation, which increased compilation times. Furthermore, ExUnit parameterizes the whole test modules, which also allows the different parameters to run concurrently if the `async: true` option is given. Overall, this features allows you to compile and run multiple scenarios more efficiently.
+
+Finally, ExUnit also comes with the ability of specifying test groups. While ExUnit supports running tests concurrently, those tests must not have shared state between them. However, in large applications, it may be common for some tests to depend on some shared state, and other tests to depend on a completely separate state. For example, part of your tests may depend on Cassandra, while others depend on Redis. Prior to Elixir v1.18, these tests could not run concurrently, but in v1.18 they might as long as they are assigned to different groups:
+
+```elixir
+defmodule MyApp.PGTest do
+  use ExUnit.Case, async: true, group: :pg
+
+  # ...
+end
+```
+
+Tests modules within the same group do not run concurrently, but across groups, they might.
+
+With features like async tests, suite partitioning, and now grouping, Elixir developers have plenty of flexibility to make the most use of their machine resources, both in development and in CI.
+
+## `mix format --migrate`
+
+The `mix format` command now supports an explicit `--migrate` flag, which will convert constructs that have been deprecated in Elixir to their latest version. Because this flag rewrites the AST, it is not guaranteed the migrated format will always be valid when used in combination with macros that also perform AST rewriting.
+
+As of this release, the following migrations are executed:
+
+  * Normalize parens in bitstring modifiers - it removes unnecessary parentheses in known bitstring modifiers, for example `<<foo::binary()>>` becomes `<<foo::binary>>`, or adds parentheses for custom modifiers, where `<<foo::custom_type>>` becomes `<<foo::custom_type()>>`.
+
+  * Charlists as sigils - formats charlists as `~c` sigils, for example `'foo'` becomes `~c"foo"`.
+
+  * `unless` as negated `if`s - rewrites `unless` expressions using `if` with a negated condition, for example `unless foo do` becomes `if !foo do`. We plan to deprecate `unless` in future releases.
+
+More migrations will be added in future releases to help us push towards more consistent codebases.
+
+## Summary
+
+Other notable changes include [`PartitionSupervisor.resize!/2`](https://hexdocs.pm/elixir/1.18/PartitionSupervisor.html#resize!/2), for resizing the number of partitions (aka processes) of a supervisor at runtime, [Registry.lock/3](https://hexdocs.pm/elixir/1.18/Registry.html#lock/3) for simple in-process key locks, PowerShell versions of `elixir` and `elixirc` scripts for better DX on Windows, and more. [See the CHANGELOG](https://hexdocs.pm/elixir/1.18/changelog.html) for the complete release notes.
+
+Happy coding!
diff --git a/_posts/2025-01-21-remote-elixir-case.markdown b/_posts/2025-01-21-remote-elixir-case.markdown
new file mode 100644
index 000000000..10d47c32d
--- /dev/null
+++ b/_posts/2025-01-21-remote-elixir-case.markdown
@@ -0,0 +1,111 @@
+---
+layout: post
+title: "Remote: growing from zero to unicorn with Elixir"
+authors:
+- Hugo Baraúna
+category: Elixir in Production
+excerpt: A case study of how Elixir is being used at Remote.
+flagship: true
+logo: /images/cases/logos/remote.png
+tags: growth team web
+---
+
+*Welcome to our series of [case studies about companies using Elixir in production](/cases.html).*
+
+Remote is the everywhere employment platform enabling companies to find, hire, manage, and pay people anywhere across the world.
+
+Founded in 2019, they reached unicorn status in just over two years and have continued their rapid growth trajectory since.
+
+Since day zero, Elixir has been their primary technology. Currently, their engineering organization as a whole consists of nearly 300 individuals.
+
+This case study focuses on their experience using Elixir in a high-growth environment.
+
+![Remote website screenshot](/images/cases/bg/remote.png)
+
+## Why Elixir?
+
+Marcelo Lebre, co-founder and president of Remote, had worked with many languages and frameworks throughout his career, often encountering the same trade-off: easy-to-code versus easy-to-scale.
+
+In 2015, while searching for alternatives, he discovered Elixir. Intrigued, Marcelo decided to give it a try and immediately saw its potential. At the time, Elixir was still in its early days, but he noticed how fast the community was growing, with support for packages and frameworks starting to show up aggressively.
+
+In December 2018, when Marcelo and his co-founder decided to start the company, they had to make a decision about the technology that would support their vision. Marcelo wanted to prioritize building a great product quickly without worrying about scalability issues from the start. He found Elixir to be the perfect match:
+
+> I wanted to focus on building a great product fast and not really worry about its scalability. Elixir was the perfect match—reliable performance, easy-to-read syntax, strong community, and a learning curve that made it accessible to new hires.
+>
+> \- 	Marcelo Lebre, Co-founder and President
+
+The biggest trade-off Marcelo identified was the smaller pool of Elixir developers compared to languages like Ruby or Python. However, he quickly realized that the quality of candidates more than made up for it:
+
+> The signal-to-noise ratio in the quality of Elixir candidates was much higher, which made the trade-off worthwhile.
+>
+> \- 	Marcelo Lebre, Co-founder and President
+
+## Growing with a monolithic architecture
+
+Remote operates primarily with a monolith, with Elixir in the backend and React in the front-end.
+
+The monolith enabled speed and simplicity, allowing the team to iterate quickly and focus on building features. However, as the company grew, they needed to invest in tools and practices to manage almost 180 engineers working in the same codebase.
+
+One practice was boundary enforcement. They used the [Boundary library](https://github.com/sasa1977/boundary) to maintain strict boundaries between modules and domains inside the codebase.
+
+Another key investment was optimizing their compilation time in the CI pipeline. Since their project has around 15,000 files, compiling it in every build would take too long. So, they implemented incremental builds in their CI pipeline, recompiling only the files affected by changes instead of the entire codebase.
+
+> I feel confident making significant changes in the codebase. The combination of using a functional language and our robust test suite allows us to keep moving forward without too much worry.
+>
+> \- André Albuquerque, Staff Engineer
+
+Additionally, as their codebase grew, the Elixir language continued to evolve, introducing better abstractions for developers working with large codebases. For example, with the release of Elixir v1.11, the [introduction of config/runtime.exs](/blog/2020/10/06/elixir-v1-11-0-released/) provided the Remote team with a better foundation for managing configuration. This enabled them to move many configurations from compile-time to runtime, significantly reducing unnecessary recompilations caused by configuration updates.
+
+## Infra-structure and operations
+
+One might expect Remote’s infrastructure to be highly complex, given their global scale and the size of their engineering team. Surprisingly, their setup remains relatively simple, reflecting a thoughtful balance between scalability and operational efficiency.
+
+Remote runs on AWS, using EKS (Elastic Kubernetes Service). The main backend (the monolith) operates in only five pods, each with 10 GB of memory. They use [Distributed Erlang](https://www.erlang.org/doc/system/distributed.html) to connect the nodes in their cluster, enabling seamless communication between processes running on different pods.
+
+For job processing, they rely on [Oban](https://github.com/oban-bg/oban), which runs alongside the monolith in the same pods.
+
+Remote also offers a public API for partners. While this API server runs separately from the monolith, it is the same application, configured to start a different part of its supervision tree. The separation was deliberate, as the team anticipated different load patterns for the API and wanted the flexibility to scale it independently.
+
+The database setup includes a primary PostgreSQL instance on AWS RDS, complemented by a read-replica for enhanced performance and scalability. Additionally, a separate Aurora PostgreSQL instance is dedicated to storing Oban jobs. Over time, the team has leveraged tools like PG Analyze to optimize performance, addressing bottlenecks such as long queries and missing indexes.
+
+This streamlined setup has proven resilient, even during unexpected spikes in workload. The team shared an episode where a worker’s job count unexpectedly grew by two orders of magnitude. Remarkably, the system handled the increase seamlessly, continuing to run as usual without requiring any design changes or manual intervention.
+
+> We once noticed two weeks later that a worker’s load had skyrocketed. But the scheduler worked fine, and everything kept running smoothly. That was fun.
+>
+> \- Alex Naser, Staff Engineer
+
+## Team organization and responsibilities
+
+Around 90% of their backend team works in the monolith, while the rest work in a few satellite services, also written in Elixir.
+
+Within the monolith, teams are organized around domains such as onboarding, payroll, and billing. Each team owns one or multiple domains.
+
+To streamline accountability in a huge monolith architecture, Remote invested heavily in team assignment mechanisms.
+
+They implemented a tagging system that assigns ownership down to the function level. This means any trace—whether sent to tools like Sentry or Datadog—carries a tag identifying the responsible team. This tagging also extends to endpoints, allowing teams to monitor their areas effectively and even set up dashboards for alerts, such as query times specific to their domain.
+
+The tagging system also simplifies CI workflows. When a test breaks, it’s automatically linked to the responsible team based on the Git commit. This ensures fast issue identification and resolution, removing the need for manual triaging.
+
+## Hiring and training
+
+Remote’s hiring approach prioritizes senior engineers, regardless of their experience with Elixir.
+
+During the hiring process, all candidates are required to complete a coding exercise in Elixir. For those unfamiliar with the language, a tailored version of the exercise is provided, designed to introduce them to Elixir while reflecting the challenges they would face if hired.
+
+Once hired, new engineers are assigned an engineering buddy to guide them through the onboarding process.
+
+For hires without prior Elixir experience, Remote developed an internal Elixir training camp, a curated collection of best practices, tutorials, and other resources to introduce new hires to the language and ecosystem. This training typically spans two to four weeks.
+
+After completing the training, engineers are assigned their first tasks—carefully selected tickets designed to build confidence and familiarity with the codebase.
+
+## Summing up
+
+Remote’s journey highlights how thoughtful technology, infrastructure, and team organization decisions can support rapid growth.
+
+By leveraging Elixir’s strengths, they built a monolithic architecture that balanced simplicity with scalability. This approach allowed their engineers to iterate quickly in the early stages while effectively managing the complexities of a growing codebase.
+
+Investments in tools like the Boundary library and incremental builds ensured their monolith remained efficient and maintainable even as the team and codebase scaled dramatically.
+
+Remote's relatively simple infrastructure demonstrates that scaling doesn't always require complexity. Their ability to easily handle unexpected workload spikes reflects the robustness of their architecture and operational practices.
+
+Finally, their focus on team accountability and streamlined onboarding allowed them to maintain high productivity while integrating engineers from diverse technical backgrounds, regardless of their prior experience with Elixir.
diff --git a/_posts/2025-02-26-elixir-openchain-certification.markdown b/_posts/2025-02-26-elixir-openchain-certification.markdown
new file mode 100644
index 000000000..76285ea70
--- /dev/null
+++ b/_posts/2025-02-26-elixir-openchain-certification.markdown
@@ -0,0 +1,72 @@
+---
+layout: post
+title: "Announcing Elixir OpenChain Certification"
+authors:
+  - Jonatan Männchen
+  - José Valim
+category: Announcements
+excerpt: "The Elixir project now meets OpenChain (ISO/IEC 5230). Each release ships with Source SBoMs in CycloneDX 1.6 and SPDX 2.3, plus attestation."
+tags: openchain compliance
+---
+
+We are pleased to share that the Elixir project now complies with
+[OpenChain][openchain] ([ISO/IEC 5230][iso_5230]), an international
+standard for open source license compliance. This step aligns with broader
+efforts to meet industry standards for supply chain and cybersecurity best
+practices.
+
+“Today’s announcement around Elixir’s conformance represents another significant
+example of community maturity,” says Shane Coughlan, OpenChain General Manager.
+“With projects - the final upstream - using ISO standards for compliance and
+security with increasing frequency, we are seeing a shift to longer-term
+improvements to trust in the supply chain.”
+
+## Why OpenChain Compliance Helps
+
+By following OpenChain (ISO/IEC 5230), we demonstrate clear processes around
+license compliance. This benefits commercial and community users alike, making
+Elixir easier to adopt and integrate with confidence.
+
+## Changes for Elixir Users
+
+Elixir has an automated release process where its artifacts are signed. This
+change strengthens this process by:
+
+- All future Elixir releases will include a Source SBoM in
+  [CycloneDX 1.6 or later][cyclonedx] and [SPDX 2.3 or later][spdx] formats.
+- Each release will be attested along with the Source SBoM.
+
+These additions offer greater transparency into the components and licenses of
+each release, supporting more rigorous supply chain requirements.
+
+## Changes for Contributors
+
+Contributing to Elixir remains largely the same, we have added more clarity and
+guidelines around it:
+
+- Contributions remain under the Apache-2.0 License. Other licenses cannot be
+  accepted.
+- The project now enforces the [Developer Certificate of Origin (DCO)][dco],
+  ensuring clarity around contribution ownership.
+
+Contributors will notice minimal procedural changes, as standard practices
+around licensing remain in place.
+
+For more details, see the [CONTRIBUTING guidelines][contributing].
+
+## Commitment
+
+These updates were made in collaboration with the
+[Erlang Ecosystem Foundation][erlef], reflecting a shared
+commitment to robust compliance and secure development practices. Thank you to
+everyone who supported this milestone. We appreciate the community’s ongoing
+contributions and look forward to continuing the growth of Elixir under these
+established guidelines.
+
+[openchain]: https://openchainproject.org/
+[erlef]: https://erlef.org/
+[spdx]: https://spdx.org/rdf/terms/
+[cyclonedx]: https://cyclonedx.org/specification/overview/
+[iso_5230]: https://www.iso.org/standard/81039.html
+[dco]: https://developercertificate.org/
+[contributing]: https://github.com/elixir-lang/elixir/blob/main/CONTRIBUTING.md
diff --git a/_posts/2025-03-25-cyanview-elixir-case.markdown b/_posts/2025-03-25-cyanview-elixir-case.markdown
new file mode 100644
index 000000000..48c021eae
--- /dev/null
+++ b/_posts/2025-03-25-cyanview-elixir-case.markdown
@@ -0,0 +1,92 @@
+---
+layout: post
+title: "Cyanview: Coordinating Super Bowl's visual fidelity with Elixir"
+authors:
+- Lars Wikman
+- José Valim
+category: Elixir in Production
+excerpt: A case study of how Elixir is being used at Cyanview.
+logo: /images/cases/logos/cyanview.png
+tags: superbowl mqtt
+---
+
+How do you coordinate visual fidelity across two hundred cameras for a live event like the Super Bowl?
+
+The answer is: by using the craft of camera shading, which involves adjusting each camera to ensure they match up in color, exposure and various other visual aspects. The goal is to turn the live event broadcast into a cohesive and consistent experience. For every angle used, you want the same green grass and the same skin tones. Everything needs to be very closely tuned across a diverse set of products and brands. From large broadcast cameras, drone cameras, and PTZ cameras to gimbal-held mirrorless cameras and more. This is what Cyanview does. Cyanview is a small Belgian company that sells products for the live video broadcast industry, and its primary focus is shading.
+
+Broadcast is a business where you only get one chance to prove that your tool is up to the task. Reliability is king. There can be no hard failures.
+
+A small team of three built a product so powerful and effective that it spread across the industry purely on the strength of its functionality. Without any marketing, it earned a reputation among seasoned professionals and became a staple at the world’s top live events. Cyanview's Remote Control Panel (RCP) is now used by specialist video operators on the Olympics, Super Bowl, NFL, NBA, ESPN, Amazon and many more. Even most fashion shows in Paris use Cyanview’s devices.
+
+These devices put Elixir right in the critical path for serious broadcast operations. By choosing Elixir, Cyanview gained best-in-class networking features, state-of-the-art resilience and an ecosystem that allowed fast iteration on product features.
+
+![Operating many displays with Cyanview products](/images/cases/bg/cyanview-4.jpg "Operating many displays with Cyanview products")
+
+## Why Elixir?
+
+The founding team of Cyanview primarily had experience with embedded development, and the devices they produce involve a lot of low-level C code and plenty of FPGA. This is due to the low-level details of color science and the really tight timing requirements.
+
+If you’ve ever worked with camera software, you know it can be a mixed bag. Even after going fully digital, much of it remained tied to analog systems or relied on proprietary connectivity solutions. Cyanview has been targeting IP (as in Internet Protocol) from early on. This means Cyanview's software can operate on commodity networks that work in well-known and well-understood ways. This has aligned well with an increase in remote production, partially due to the pandemic, where production crews operate from a central location with minimal crew on location. Custom radio frequency or serial wire protocols have a hard time scaling to cross-continent distances.
+
+This also paved the way for Elixir, as the Erlang VM was designed to communicate and coordinate millions of devices, reliably, over the network.
+
+Elixir was brought in by the developer Ghislain, who needed to build integrations with cameras and interact with the other bits of required video gear, with many different protocols over the network. The language comes with a lot of practical features for encoding and decoding binary data down to the individual bits. Elixir gave them a strong foundation and the tools to iterate fast.
+
+Ghislain has been building the core intellectual property of Cyanview ever since. While the physical device naturally has to be solid, reliable, and of high quality, a lot of the secret sauce ultimately lies in the massive number of integrations and huge amounts of reverse engineering. Thus, the product is able to work with as many professional camera systems and related equipment as possible. It is designed to be compatible with everything and anything a customer is using. Plus, it offers an API to ensure smooth integration with other devices.
+
+David Bourgeois, the founder of Cyanview, told us a story how these technical decisions alongside Elixir helped them tackle real-world challenges:
+
+"During the Olympics in China, a studio in Beijing relied on a large number of Panasonic PTZ cameras. Most of their team, however, was based in Paris and needed to control the cameras remotely to run various shows throughout the day. The problem? Panasonic’s camera protocols were never designed for internet use — they require precise timing and multiple messages for every adjustment. With network latency, that leads to timeouts, disconnects, and system failures... So they ended up placing our devices next to the cameras in Beijing and controlled them over IP from Paris — just as designed."
+
+![Cyanview RIO device mounted on a camera at a sports field](/images/cases/bg/cyanview-2.jpg "Cyanview RIO device mounted on a camera at a sports field")
+
+The devices in a given location communicate and coordinate on the network over a custom MQTT protocol. Over a hundred cameras without issue on a single Remote Control Panel (RCP), implemented on top of Elixir's network stack.
+
+## Technical composition
+
+The system as a whole consists of RCP devices running a Yocto Linux system, with most of the logic built in Elixir and C. While Python is still used for scripting and tooling, its role has gradually diminished. The setup also includes multiple microcontrollers and the on-camera device, all communicating over MQTT. Additionally, cloud relays facilitate connectivity, while dashboards and controller UIs provide oversight and control. The two critical devices are the RCP offering control on the production end and the RIO handling low-latency manipulation of the camera. Both run Elixir.
+
+The configuration UI is currently built in Elm, but - depending on priorities - it might be converted to [Phoenix LiveView](https://phoenixframework.org/) over time to reduce the number of languages in use. The controller web UI is already in LiveView, and it is performing quite well on a very low-spec embedded Linux machine.
+
+The cloud part of the system is very limited today, which is unusual in a world of SaaS. There are cloud relays for distributing and sharing camera control as well as forwarding network ports between locations and some related features, also built in Elixir, but cloud is not at the core of the business. The devices running Elixir on location form a cluster over IP using a custom MQTT-based protocol suited to the task and are talking to hundreds of cameras and other video devices.
+
+It goes without saying that integration with so much proprietary equipment comes with challenges. Some integrations are more reliable than others. Some devices are more common, and their quirks are well-known through hard-won experience. A few even have good documentation that you can reference while others offer mystery and constant surprises. In this context, David emphasizes the importance of Elixir's mechanisms for recovering from failures:
+
+"If one camera connection has a blip, a buggy protocol or the physical connection to a device breaks it is incredibly important that everything else keeps working. And this is where Elixir’s supervision trees provide a critical advantage."
+
+## Growth & team composition
+
+The team has grown over the 9 years that the company has been operating, but it did so at a slow and steady pace. On average, the company has added just one person per year. With nine employees at the time of writing, Cyanview supports some of the biggest broadcast events in the world.
+
+There are two Elixir developers on board: Daniil who is focusing on revising some of the UI as well as charting a course into more cloud functionality, and Ghislain, who works on cameras and integration. Both LiveView and Elm are used to power device UIs and dashboards.
+
+What’s interesting is that, overall, the other embedded developers say that they don't know much about Elixir and they don't use it in their day-to-day work. Nonetheless, they are very comfortable implementing protocols and encodings in Elixir. The main reason they haven’t fully learned the language is simply time — they have plenty of other work to focus on, and deep Elixir expertise hasn’t been necessary. After all, there’s much more to their work beyond Elixir: designing PCBs, selecting electronic components, reverse engineering protocols, interfacing with displays, implementing FPGAs, managing production tests, real productions and releasing firmware updates.
+
+## Innovation and customer focus
+
+![Operator using Cyanview RCP for a massive crowd in an arena](/images/cases/bg/cyanview-3.jpg "Operator using Cyanview RCP for a massive crowd in an arena")
+
+Whether it’s providing onboard cameras in 40+ cars during the 24 hours of Le Mans, covering Ninja Warrior, the Australian Open, and the US Open, operating a studio in the Louvre, being installed in NFL pylons, or connecting over 200 cameras simultaneously – the product speaks for itself. Cyanview built a device for a world that runs on top of IP, using Elixir, a language with networking and protocols deep in its bones. This choice enabled them to do both: implement support for all the equipment and provide features no one else had.
+
+By shifting from conventional local-area radio frequency, serial connections, and inflexible proprietary protocols to IP networking, Cyanview’s devices redefined how camera systems operate. Their feature set is unheard of in the industry: Unlimited multicam. Tally lights. Pan & Tilt control. Integration with color correctors. World-spanning remote production.
+
+The ease and safety of shipping new functionality have allowed the company to support new features very quickly. One example is the increasing use of mirrorless cameras on gimbals to capture crowd shots. Cyanview were able to prototype gimbal control, test it with a customer and validate that it worked in a very short amount of time. This quick prototyping and validation of features is made possible by a flexible architecture that ensures that critical fundamentals don't break.
+
+Camera companies that don't produce broadcast shading remotes, such as Canon or RED, recommend Cyanview to their customers. Rather than competing with most broadcast hardware companies, Cyanview considers itself a partner. The power of a small team, a quality product and powerful tools can be surprising. Rather than focusing on marketing, Cyanview works very closely with its customers by supporting the success of their events and providing in-depth customer service.
+
+## Looking back and forward
+
+When asked if he would choose Elixir again, David responded:
+
+"Yes. We've seen what the Erlang VM can do, and it has been very well-suited to our needs. You don't appreciate all the things Elixir offers out of the box until you have to try to implement them yourself. It was not pure luck that we picked it, but we were still lucky. Elixir turned out to bring a lot that we did not know would be valuable to us. And we see those parts clearly now."
+
+Cyanview hopes to grow the team more, but plans to do so responsibly over time. Currently there is a lot more to do than the small team can manage.
+
+Development is highly active, with complementary products already in place alongside the main RCP device, and the future holds even more in that regard. Cloud offerings are on the horizon, along with exciting hardware projects that build on the lessons learned so far. As these developments unfold, we’ll see Elixir play an increasingly critical role in some of the world’s largest live broadcasts.
+
+![Cyanview Remote Control Panels in a control room](/images/cases/bg/cyanview-1.jpg "Cyanview Remote Control Panels in a control room")
+
+## In summary
+
+A high-quality product delivering the right innovation at the right time in an industry that's been underserved in terms of good integration. Elixir provided serious leverage for developing a lot of integrations with high confidence and consistent reliability. In an era where productivity and lean, efficient teams are everything, Cyanview is a prime example of how Elixir empowers small teams to achieve an outsized impact.
+
diff --git a/_posts/2025-06-02-elixir-outreach-stipend-for-speakers.markdown b/_posts/2025-06-02-elixir-outreach-stipend-for-speakers.markdown
new file mode 100644
index 000000000..1bca122fc
--- /dev/null
+++ b/_posts/2025-06-02-elixir-outreach-stipend-for-speakers.markdown
@@ -0,0 +1,42 @@
+---
+layout: post
+title: "Elixir Outreach stipend for speakers and trainers"
+authors:
+- José Valim
+category: Announcements
+excerpt: "We announce the Elixir Outreach stipend in partnership with Dashbit, Oban, and the Erlang Ecosystem Foundation"
+---
+
+[Dashbit](https://dashbit.co), [Oban](https://oban.pro), and the [Erlang Ecosystem Foundation (EEF)](https://erlef.org) are glad to announce a new program, which we will trial over the next 12 months, called "Elixir Outreach". Our goal is to provide funds to community members who want to present Elixir and Erlang to other ecosystems and communities, while respecting our joint values.
+
+In a nutshell:
+
+* We will provide funds to community members to speak **in-person** about anything related to Elixir and the Erlang VM.
+
+* We will cover hotel and transportation costs for up to $700 USD. Please reach out, even if you expect to exceed that limit. This is our first time running the program and we're refining the budget.
+
+* The event must expect at least 150 attendees and happen outside of the Elixir, overall BEAM, and functional programming communities. In other words, we won't cover costs for attending Erlang, Elixir, or other BEAM/FP conferences nor meetups. Consider it as an opportunity to learn and bring external knowledge and experiences to the BEAM community.
+
+* You will be expected to send a report about your experience. The format and duration is up to you. We'd prefer that you write a blog post or an article sharing your overall experience with the involved communities. However, if you would prefer to only send it privately to us, that's fine too!
+
+The event should take place within your area. Our overall goal is to support multiple individuals, rather than drain our budget on a few long-distance flights (such as across coasts or continents). We are flexible on event location, distance, or type. If in doubt, reach out to [elixir_outreach at erlef dot org](mailto:elixir_outreach@erlef.org)
+
+Our initial budget of $7000 was donated by Dashbit ($5000) and Oban ($2000) to the Erlang Ecosystem Foundation (EEF), specifically for this program. The EEF will oversee the distribution of the funds.
+
+## Requesting a stipend
+
+To request a stipend, visit the [Erlang Ecosystem Foundation website and choose "Elixir Outreach" as the stipend type](https://erlef.org/stipends/form?type=elixir-outreach).
+
+Given we have limited funds, we cannot guarantee they will be available when you request them. We recommend reaching out to us before submitting or acceptance your talk. Therefore, by contacting us early, we can validate if the event matches the criteria above, ask questions, and earmark the funds. Once your talk is accepted, send us any itemized travel and accommodation costs so we can transfer the stipend to you, (not in excess of $700 USD).
+
+You can also request a stipend after your talk has already been accepted, but then there are no guarantees a stipend will be available.
+
+Our goal is to make this process simple and as straight-forward as possible. Although, we reserve the right to refuse a request for any reason. If in doubt, reach out to [elixir_outreach at erlef dot org](mailto:elixir_outreach@erlef.org).
+
+## Acknowledgements
+
+This is a new effort for all involved! Please be patient while we figure out the details.
+
+If you are looking for conferences to speak at, [Dave Aronson keeps a list of CFPs closing soon](https://www.codosaur.us/speaking/cfps-ending-soon) and there are likely others available. Note, we don’t necessarily endorse all of the conferences listed nor guarantee they meet the requirements above, but the list may help you get the ball rolling.
+
+Thanks to Parker Selbert, Shannon Selbert, Brian Cardarella, Alistair Woodman, and Lee Barney for feedback and helping make this a reality.
\ No newline at end of file
diff --git a/_posts/2025-08-05-global-elixir-meetups.markdown b/_posts/2025-08-05-global-elixir-meetups.markdown
new file mode 100644
index 000000000..941789de0
--- /dev/null
+++ b/_posts/2025-08-05-global-elixir-meetups.markdown
@@ -0,0 +1,18 @@
+---
+layout: post
+title: "Take part in the Global Elixir Meetups week"
+authors:
+- José Valim
+category: Announcements
+excerpt: "We are launching Global Elixir Meetups - a week where the Elixir community organizes meetups around the world to meet, learn from each other, and discuss everything related to Elixir and the Erlang VM."
+---
+
+We are launching [Global Elixir Meetups (GEMs)](https://globalelixirmeetups.com) - a week where the Elixir community organizes meetups around the world to meet, learn from each other, and discuss everything related to Elixir and the Erlang VM.
+
+Our first GEM will happen on 22-28 September and, if you were looking for an opportunity to organize a meetup, now is the perfect time: visit [the Global Elixir Meetups website](https://globalelixirmeetups.com) to learn how to organize and attend. Organizers may also opt-in to live stream their meetups to the whole world directly from the website.
+
+![Global Elixir Meetup banner](/images/contents/gem.jpeg "Global Elixir Meetup banner")
+
+The Global Elixir Meetup is organized by [Software Mansion](https://swmansion.com), who brought their expertise as creators of [Membrane](https://membrane.stream) and [Elixir WebRTC](https://elixir-webrtc.org) to make it all possible. At launch, we are already counting with 7 meetups across Europe, South America, and North America, with hopefully more continents joining us soon.
+
+Go ahead and find your closest GEM or run your own!
diff --git a/atom.xml b/atom.xml
index 09471fd0d..052b63a8e 100644
--- a/atom.xml
+++ b/atom.xml
@@ -15,11 +15,11 @@ elixir_url: http://elixir-lang.org
 <entry>
   <title>{{ post.title }}</title>
   <link href="{{ page.elixir_url }}{{ post.url }}"/>
-  {% if post.author %}
-  <author>
-    <name>{{ post.author }}</name>
-  </author>
-  {% endif %}
+  {% for author in post.authors %}
+    <author>
+      <name>{{ author }}</name>
+    </author>
+  {% endfor %}
   <updated>{{ post.date | date_to_xmlschema }}</updated>
   <id>{{ post.id }}</id>
   <content type="html">{{ post.content | xml_escape }}</content>
diff --git a/blog/index.html b/blog/index.html
index 196e39159..75d152e14 100644
--- a/blog/index.html
+++ b/blog/index.html
@@ -9,7 +9,7 @@
     <div class="hentry post">
       <div class="sticky-header">
         <h2 class="entry-title"><a class="spec" href="{{ post.url }}" title="{{ post.title }}" rel="bookmark">{{ post.title }}</a></h2>
-        <div class="byline">{{ post.date | date: "%B %d, %Y" }}{% if post.author %} · by {{ post.author}}{% endif %} . in {% for category in post.categories %}<a href="/blog/categories.html#{{category}}" class="category">{{ category }}</a>{% endfor %}</div>
+        <div class="byline">{{ post.date | date: "%B %d, %Y" }}{% if post.authors %} · by {{ post.authors | join: ", " }}{% endif %} · in {% for category in post.categories %}<a href="/blog/categories.html#{{category}}" class="category">{{ category }}</a>{% endfor %}</div>
       </div><!-- .sticky-header -->
 
       <div class="entry-summary">
diff --git a/cases.html b/cases.html
index 63d5502f7..42d49e97a 100644
--- a/cases.html
+++ b/cases.html
@@ -1,6 +1,7 @@
 ---
 section: cases
 layout: default
+image: /images/social/elixir-og-card.jpg
 ---
 
 <h1>Cases</h1>
@@ -8,8 +9,9 @@ <h1>Cases</h1>
 <p>Click on the cases below to learn more about how companies across different industries are using the power of Elixir and its ecosystem to create and grow their businesses. Cases are listed in the order they have been published.</p>
 
 <div class="cases-boxes">
-  {% assign sorted_posts = site.categories["Elixir in Production"] | sort: 'date' %}
+  {% assign sorted_posts = site.categories["Elixir in Production"] | sort: 'date' | reverse %}
   {% for post in sorted_posts %}
+    {%- if post.flagship %}
     <a class="cases-box" href="{{ post.url }}" title="Case: {{ post.title }}">
       {% if post.logo == nil %}
         <div class="cases-image" style="background-image: url('/images/cases/logos/default-image.png')"></div>
@@ -22,6 +24,23 @@ <h1>Cases</h1>
         {% endfor %}
       </div>
     </a>
+    {%- endif -%}
+  {% endfor %}
+  {% for post in sorted_posts %}
+    {%- unless post.flagship %}
+    <a class="cases-box" href="{{ post.url }}" title="Case: {{ post.title }}">
+      {% if post.logo == nil %}
+        <div class="cases-image" style="background-image: url('/images/cases/logos/default-image.png')"></div>
+      {% else %}
+        <div class="cases-image" style="background-image: url('{{ post.logo }}')"></div>
+      {% endif %}
+      <div class="cases-tag">
+        {% for tag in post.tags %}
+          <span>#{{tag}}</span>
+        {% endfor %}
+      </div>
+    </a>
+    {%- endunless -%}
   {% endfor %}
 </div>
 
diff --git a/crash-course.markdown b/crash-course.markdown
index 4eca6ced4..acbb6da09 100644
--- a/crash-course.markdown
+++ b/crash-course.markdown
@@ -2,6 +2,7 @@
 title: "Erlang/Elixir Syntax: A Crash Course"
 section: home
 layout: default
+image: /images/social/elixir-og-card.jpg
 ---
 
 # {{ page.title }}
@@ -166,7 +167,7 @@ Invoking a function from a module uses different syntax. In Erlang, you would wr
 lists:last([1, 2]).
 ```
 
-to invoke the `last` function from the `List` module. In Elixir, use the dot `.` in place of the colon `:`
+to invoke the `last` function from the `lists` module. In Elixir, use the dot `.` in place of the colon `:`
 
 ```elixir
 List.last([1, 2])
@@ -311,7 +312,7 @@ kw[:another_key]
 
 ### Maps
 
-Erlang R17 introduced maps, a key-value store, with no ordering. Keys and values can be any term. Creating, updating and matching maps in both languages is shown below:
+Maps are key-value pairs with no ordering. Keys and values can be any term. Creating, updating and matching maps in both languages is shown below:
 
 **Erlang**
 
@@ -360,18 +361,6 @@ Regex.run(~r/abc\s/, "abc ")
 #=> ["abc "]
 ```
 
-Regexes are also supported in heredocs, which is convenient when defining multiline regexes:
-
-```elixir
-Regex.regex?(~r"""
-This is a regex
-spanning several
-lines.
-""")
-#=> true
-```
-
-
 ## Modules
 
 Each Erlang module lives in its own file which has the following structure:
@@ -449,10 +438,9 @@ HelloModule.Utils.priv()
 #=> ** (UndefinedFunctionError) undefined function: HelloModule.Utils.priv/0
 ```
 
-
 ## Function syntax
 
-[This chapter][3] from the Erlang book provides a detailed description of pattern matching and function syntax in Erlang. Here, I'm briefly covering the main points and provide sample code both in Erlang and Elixir.
+[This chapter][3] from the Erlang book provides a detailed description of pattern matching and function syntax in Erlang. Here, we briefly cover the main points and provide sample code both in Erlang and Elixir.
 
 [3]: http://learnyousomeerlang.com/syntax-in-functions
 
@@ -530,8 +518,8 @@ sum(1, 2).
 sum([1], [2]).
 %=> [1, 2]
 
-sum("a", "b").
-%=> "ab"
+sum(<<"a">>, <<"b">>).
+%=> <<"ab">>
 ```
 
 **Elixir**
@@ -834,7 +822,6 @@ after
 end
 ```
 
-
 ## Adding Elixir to existing Erlang programs
 
 Elixir compiles into BEAM byte code (via Erlang Abstract Format). This means that Elixir code can be called from Erlang and vice versa, without the need to write any bindings. All Elixir modules start with the `Elixir.` prefix followed by the regular Elixir name. For example, here is how to use the UTF-8 aware `String` downcase from Elixir in Erlang:
@@ -847,33 +834,6 @@ downcase(Bin) ->
   'Elixir.String':downcase(Bin).
 ```
 
-### Rebar integration
-
-If you are using rebar, you should be able to include Elixir git repository as a dependency:
-
-    https://github.com/elixir-lang/elixir.git
-
-Elixir is structured similar to Erlang's OTP. It is divided into applications that are placed inside the `lib` directory, as seen in its [source code repository](https://github.com/elixir-lang/elixir). Since rebar does not recognize such structure, we need to explicitly add to our `rebar.config` which Elixir apps we want to use, for example:
-
-```erlang
-{lib_dirs, [
-  "deps/elixir/lib"
-]}.
-```
-
-This should be enough to invoke Elixir functions straight from your Erlang code. If you are also going to write Elixir code, you can [install Elixir's rebar plugin for automatic compilation](https://github.com/yrashk/rebar_elixir_plugin).
-
-### Manual integration
-
-If you are not using rebar, the easiest approach to use Elixir in your existing Erlang software is to install Elixir using one of the different ways specified in the [Getting Started guide](/getting-started/introduction.html) and add the `lib` directory in your checkout to `ERL_LIBS`.
-
-
 ## Further reading
 
-Erlang's official documentation site has a nice [collection][4] of programming examples. It can be a good exercise to translate them into Elixir.
-
-Elixir also provides a [Getting Started guide][6] and has [documentation available online][7].
-
-[4]: http://www.erlang.org/doc/programming_examples/users_guide.html
-[6]: /getting-started/introduction.html
-[7]: /docs.html
+Both programming languages have plenty of resources available to dig deeper. Check out their respective websites ([Elixir](https://elixir-lang.org) and [Erlang](https://www.erlang.org)) for more information.
\ No newline at end of file
diff --git a/development.markdown b/development.markdown
index db2f9cd42..b84d2552e 100644
--- a/development.markdown
+++ b/development.markdown
@@ -2,6 +2,7 @@
 title: "Development & Team"
 section: development
 layout: default
+image: /images/social/elixir-og-card.jpg
 ---
 
 # {{ page.title }}
diff --git a/docs.markdown b/docs.markdown
index 67f3b6ce1..b0095bf05 100644
--- a/docs.markdown
+++ b/docs.markdown
@@ -2,14 +2,15 @@
 title: Elixir Documentation
 section: docs
 layout: default
+image: /images/social/elixir-og-card.jpg
 ---
 
 # Documentation
 
 The Elixir programming language is broken into 6 applications. The links below
 reference the documentation for the modules and functions in each of those
-applications. For guides, books, courses, and other resources, visit our
-[Learning](/learning.html) page.
+applications. See also [our Getting Started guide](https://hexdocs.pm/elixir/introduction.html)
+and [the Learning page](/learning.html) for books, courses, videos, and more.
 
 {% assign stable = site.data.elixir-versions[site.data.elixir-versions.stable] %}
 
diff --git a/getting-started/alias-require-and-import.markdown b/getting-started/alias-require-and-import.markdown
index 376b055a3..eb771d715 100644
--- a/getting-started/alias-require-and-import.markdown
+++ b/getting-started/alias-require-and-import.markdown
@@ -1,243 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: alias, require, and import
+layout: redirect
+sitemap: false
+redirect_to: alias-require-and-import
 ---
-
-In order to facilitate software reuse, Elixir provides three directives (`alias`, `require` and `import`) plus a macro called `use` summarized below:
-
-```elixir
-# Alias the module so it can be called as Bar instead of Foo.Bar
-alias Foo.Bar, as: Bar
-
-# Require the module in order to use its macros
-require Foo
-
-# Import functions from Foo so they can be called without the `Foo.` prefix
-import Foo
-
-# Invokes the custom code defined in Foo as an extension point
-use Foo
-```
-
-We are going to explore them in detail now. Keep in mind the first three are called directives because they have **lexical scope**, while `use` is a common extension point that allows the used module to inject code.
-
-## alias
-
-`alias` allows you to set up aliases for any given module name.
-
-Imagine a module uses a specialized list implemented in `Math.List`. The `alias` directive allows referring to `Math.List` just as `List` within the module definition:
-
-```elixir
-defmodule Stats do
-  alias Math.List, as: List
-  # In the remaining module definition List expands to Math.List.
-end
-```
-
-The original `List` can still be accessed within `Stats` by the fully-qualified name `Elixir.List`.
-
-> Note: All modules defined in Elixir are defined inside the main `Elixir` namespace, such as `Elixir.String`. However, for convenience, you can omit "Elixir." when referencing them.
-
-Aliases are frequently used to define shortcuts. In fact, calling `alias` without an `:as` option sets the alias automatically to the last part of the module name, for example:
-
-```elixir
-alias Math.List
-```
-
-Is the same as:
-
-```elixir
-alias Math.List, as: List
-```
-
-Note that `alias` is **lexically scoped**, which allows you to set aliases inside specific functions:
-
-```elixir
-defmodule Math do
-  def plus(a, b) do
-    alias Math.List
-    # ...
-  end
-
-  def minus(a, b) do
-    # ...
-  end
-end
-```
-
-In the example above, since we are invoking `alias` inside the function `plus/2`, the alias will be valid only inside the function `plus/2`. `minus/2` won't be affected at all.
-
-## require
-
-Elixir provides macros as a mechanism for meta-programming (writing code that generates code). Macros are expanded at compile time.
-
-Public functions in modules are globally available, but in order to use macros, you need to opt-in by requiring the module they are defined in.
-
-```elixir
-iex> Integer.is_odd(3)
-** (UndefinedFunctionError) function Integer.is_odd/1 is undefined or private. However, there is a macro with the same name and arity. Be sure to require Integer if you intend to invoke this macro
-    (elixir) Integer.is_odd(3)
-iex> require Integer
-Integer
-iex> Integer.is_odd(3)
-true
-```
-
-In Elixir, `Integer.is_odd/1` is defined as a macro so that it can be used as a guard. This means that, in order to invoke `Integer.is_odd/1`, we need to first require the `Integer` module.
-
-Note that like the `alias` directive, `require` is also lexically scoped. We will talk more about macros in a later chapter.
-
-## import
-
-We use `import` whenever we want to access functions or macros from other modules without using the fully-qualified name. Note we can only import public functions, as private functions are never accessible externally.
-
-For example, if we want to use the `duplicate/2` function from the `List` module several times, we can import it:
-
-```elixir
-iex> import List, only: [duplicate: 2]
-List
-iex> duplicate(:ok, 3)
-[:ok, :ok, :ok]
-```
-
-We imported only the function `duplicate` (with arity 2) from `List`. Although `:only` is optional, its usage is recommended in order to avoid importing all the functions of a given module inside the current scope. `:except` could also be given as an option in order to import everything in a module *except* a list of functions.
-
-Note that `import` is **lexically scoped** too. This means that we can import specific macros or functions inside function definitions:
-
-```elixir
-defmodule Math do
-  def some_function do
-    import List, only: [duplicate: 2]
-    duplicate(:ok, 10)
-  end
-end
-```
-
-In the example above, the imported `List.duplicate/2` is only visible within that specific function. `duplicate/2` won't be available in any other function in that module (or any other module for that matter).
-
-Note that `import`s are generally discouraged in the language. When working on your own code, prefer `alias` to `import`.
-
-## use
-
-The `use` macro is frequently used as an extension point. This means that, when you `use` a module `FooBar`, you allow that module to inject *any* code in the current module, such as importing itself or other modules, defining new functions, setting a module state, etc.
-
-For example, in order to write tests using the ExUnit framework, a developer should use the `ExUnit.Case` module:
-
-```elixir
-defmodule AssertionTest do
-  use ExUnit.Case, async: true
-
-  test "always pass" do
-    assert true
-  end
-end
-```
-
-Behind the scenes, `use` requires the given module and then calls the `__using__/1` callback on it allowing the module to inject some code into the current context. Some modules (for example, the above `ExUnit.Case`, but also `Supervisor` and `GenServer`) use this mechanism to populate your module with some basic behaviour, which your module is intended to override or complete.
-
-Generally speaking, the following module:
-
-```elixir
-defmodule Example do
-  use Feature, option: :value
-end
-```
-
-is compiled into
-
-```elixir
-defmodule Example do
-  require Feature
-  Feature.__using__(option: :value)
-end
-```
-
-Since `use` allows any code to run, we can't really know the side-effects of using a module without reading its documentation. Therefore use this function with care and only if strictly required. Don't use `use` where an `import` or `alias` would do.
-
-## Understanding Aliases
-
-At this point, you may be wondering: what exactly is an Elixir alias and how is it represented?
-
-An alias in Elixir is a capitalized identifier (like `String`, `Keyword`, etc) which is converted to an atom during compilation. For instance, the `String` alias translates by default to the atom `:"Elixir.String"`:
-
-```elixir
-iex> is_atom(String)
-true
-iex> to_string(String)
-"Elixir.String"
-iex> :"Elixir.String" == String
-true
-```
-
-By using the `alias/2` directive, we are changing the atom the alias expands to.
-
-Aliases expand to atoms because in the Erlang <abbr title="Virtual Machine">VM</abbr> (and consequently Elixir) modules are always represented by atoms:
-
-```elixir
-iex> List.flatten([1, [2], 3])
-[1, 2, 3]
-iex> :"Elixir.List".flatten([1, [2], 3])
-[1, 2, 3]
-```
-
-That's the mechanism we use to call Erlang modules:
-
-```elixir
-iex> :lists.flatten([1, [2], 3])
-[1, 2, 3]
-```
-
-## Module nesting
-
-Now that we have talked about aliases, we can talk about nesting and how it works in Elixir. Consider the following example:
-
-```elixir
-defmodule Foo do
-  defmodule Bar do
-  end
-end
-```
-
-The example above will define two modules: `Foo` and `Foo.Bar`. The second can be accessed as `Bar` inside `Foo` as long as they are in the same lexical scope.
-
-If, later, the `Bar` module is moved outside the `Foo` module definition, it must be referenced by its full name (`Foo.Bar`) or an alias must be set using the `alias` directive discussed above.
-
-**Note**: in Elixir, you don't have to define the `Foo` module before being able to define the `Foo.Bar` module, as they are effectively independent. The above could also be written as:
-
-```elixir
-defmodule Foo.Bar do
-end
-
-defmodule Foo do
-  alias Foo.Bar
-  # Can still access it as `Bar`
-end
-```
-
-Aliasing a nested module does not bring parent modules into scope. Consider the following example:
-
-```elixir
-defmodule Foo do
-  defmodule Bar do
-    defmodule Baz do
-    end
-  end
-end
-
-alias Foo.Bar.Baz
-# The module `Foo.Bar.Baz` is now available as `Baz`
-# However, the module `Foo.Bar` is *not* available as `Bar`
-```
-
-As we will see in later chapters, aliases also play a crucial role in macros, to guarantee they are hygienic.
-
-## Multi alias/import/require/use
-
-It is possible to `alias`, `import`, `require`, or `use` multiple modules at once. This is particularly useful once we start nesting modules, which is very common when building Elixir applications. For example, imagine you have an application where all modules are nested under `MyApp`, you can alias the modules `MyApp.Foo`, `MyApp.Bar` and `MyApp.Baz` at once as follows:
-
-```elixir
-alias MyApp.{Foo, Bar, Baz}
-```
-
-With this, we have finished our tour of Elixir modules. The next topic to cover is module attributes.
diff --git a/getting-started/basic-operators.markdown b/getting-started/basic-operators.markdown
index 217814092..459bdf53c 100644
--- a/getting-started/basic-operators.markdown
+++ b/getting-started/basic-operators.markdown
@@ -1,98 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Basic operators
+layout: redirect
+sitemap: false
+redirect_to: lists-and-tuples
 ---
-
-In the [previous chapter](/getting-started/basic-types.html), we saw Elixir provides `+`, `-`, `*`, `/` as arithmetic operators, plus the functions `div/2` and `rem/2` for integer division and remainder.
-
-Elixir also provides `++` and `--` to manipulate lists:
-
-```elixir
-iex> [1, 2, 3] ++ [4, 5, 6]
-[1, 2, 3, 4, 5, 6]
-iex> [1, 2, 3] -- [2]
-[1, 3]
-```
-
-String concatenation is done with `<>`:
-
-```elixir
-iex> "foo" <> "bar"
-"foobar"
-```
-
-Elixir also provides three boolean operators: `or`, `and` and `not`. These operators are strict in the sense that they expect something that evaluates to a boolean (`true` or `false`) as their first argument:
-
-```elixir
-iex> true and true
-true
-iex> false or is_atom(:example)
-true
-```
-
-Providing a non-boolean will raise an exception:
-
-```elixir
-iex> 1 and true
-** (BadBooleanError) expected a boolean on left-side of "and", got: 1
-```
-
-`or` and `and` are short-circuit operators. They only execute the right side if the left side is not enough to determine the result:
-
-```elixir
-iex> false and raise("This error will never be raised")
-false
-iex> true or raise("This error will never be raised")
-true
-```
-
-Besides these boolean operators, Elixir also provides `||`, `&&` and `!` which accept arguments of any type. For these operators, all values except `false` and `nil` will evaluate to true:
-
-```elixir
-# or
-iex> 1 || true
-1
-iex> false || 11
-11
-
-# and
-iex> nil && 13
-nil
-iex> true && 17
-17
-
-# not
-iex> !true
-false
-iex> !1
-false
-iex> !nil
-true
-```
-
-As a rule of thumb, use `and`, `or` and `not` when you are expecting booleans. If any of the arguments are non-boolean, use `&&`, `||` and `!`.
-
-Elixir also provides `==`, `!=`, `===`, `!==`, `<=`, `>=`, `<` and `>` as comparison operators:
-
-```elixir
-iex> 1 == 1
-true
-iex> 1 != 2
-true
-iex> 1 < 2
-true
-```
-
-The difference between `==` and `===` is that the latter is more strict when comparing integers and floats:
-
-```elixir
-iex> 1 == 1.0
-true
-iex> 1 === 1.0
-false
-```
-
-We say these operators perform _structural comparison_. For more information, you can read our documentation on [Structural vs Semantic comparisons](https://hexdocs.pm/elixir/Kernel.html#module-structural-comparison).
-
-In the next chapter, we are going to discuss pattern matching through the use of `=`, the match operator.
diff --git a/getting-started/basic-types.markdown b/getting-started/basic-types.markdown
index fa3f0be70..2ab92484a 100644
--- a/getting-started/basic-types.markdown
+++ b/getting-started/basic-types.markdown
@@ -1,459 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Basic types
+layout: redirect
+sitemap: false
+redirect_to: basic-types
 ---
-
-In this chapter we will learn more about Elixir basic types: integers, floats, booleans, atoms, strings, lists and tuples. Some basic types are:
-
-```elixir
-iex> 1          # integer
-iex> 0x1F       # integer
-iex> 1.0        # float
-iex> true       # boolean
-iex> :atom      # atom / symbol
-iex> "elixir"   # string
-iex> [1, 2, 3]  # list
-iex> {1, 2, 3}  # tuple
-```
-
-## Basic arithmetic
-
-Open up `iex` and type the following expressions:
-
-```elixir
-iex> 1 + 2
-3
-iex> 5 * 5
-25
-iex> 10 / 2
-5.0
-```
-
-Notice that `10 / 2` returned a float `5.0` instead of an integer `5`. This is expected. In Elixir, the operator `/` always returns a float. If you want to do integer division or get the division remainder, you can invoke the `div` and `rem` functions:
-
-```elixir
-iex> div(10, 2)
-5
-iex> div 10, 2
-5
-iex> rem 10, 3
-1
-```
-
-Notice that Elixir allows you to drop the parentheses when invoking named functions with at least one argument. This feature gives a cleaner syntax when writing declarations and control-flow constructs. However, Elixir developers generally prefer to use parentheses.
-
-Elixir also supports shortcut notations for entering binary, octal, and hexadecimal numbers:
-
-```elixir
-iex> 0b1010
-10
-iex> 0o777
-511
-iex> 0x1F
-31
-```
-
-Float numbers require a dot followed by at least one digit and also support `e` for scientific notation:
-
-```elixir
-iex> 1.0
-1.0
-iex> 1.0e-10
-1.0e-10
-```
-
-Floats in Elixir are 64-bit double precision.
-
-You can invoke the `round` function to get the closest integer to a given float, or the `trunc` function to get the integer part of a float.
-
-```elixir
-iex> round(3.58)
-4
-iex> trunc(3.58)
-3
-```
-
-## Identifying functions and documentation
-
-Functions in Elixir are identified by both their name and their arity. The arity of a function describes the number of arguments that the function takes. From this point on we will use both the function name and its arity to describe functions throughout the documentation. `trunc/1` identifies the function which is named `trunc` and takes `1` argument, whereas `trunc/2` identifies a different (nonexistent) function with the same name but with an arity of `2`.
-
-We can also use this syntax to access documentation. The Elixir shell defines the `h` function, which you can use to access documentation for any function. For example, typing `h trunc/1` is going to print the documentation for the `trunc/1` function:
-
-```elixir
-iex> h trunc/1
-                             def trunc()
-
-Returns the integer part of number.
-```
-
-`h trunc/1` works because it is defined in the `Kernel` module. All functions in the `Kernel` module are automatically imported into our namespace. Most often you will also include the module name when looking up for documentation for a given function:
-
-```elixir
-iex> h Kernel.trunc/1
-                             def trunc()
-
-Returns the integer part of number.
-```
-
-You can use the module+function to lookup for anything, including operators (try `h Kernel.+/2`). Invoking `h` without arguments displays the documentation for `IEx.Helpers`, which is where `h` and other functionality is defined.
-
-## Booleans
-
-Elixir supports `true` and `false` as booleans:
-
-```elixir
-iex> true
-true
-iex> true == false
-false
-```
-
-Elixir provides a bunch of predicate functions to check for a value type. For example, the `is_boolean/1` function can be used to check if a value is a boolean or not:
-
-```elixir
-iex> is_boolean(true)
-true
-iex> is_boolean(1)
-false
-```
-
-You can also use `is_integer/1`, `is_float/1` or `is_number/1` to check, respectively, if an argument is an integer, a float, or either.
-
-## Atoms
-
-An atom is a constant whose value is its own name. Some other languages call these symbols. They are often useful to enumerate over distinct values, such as:
-
-```elixir
-iex> :apple
-:apple
-iex> :orange
-:orange
-iex> :watermelon
-:watermelon
-```
-
-Atoms are equal if their names are equal.
-
-```elixir
-iex> :apple == :apple
-true
-iex> :apple == :orange
-false
-```
-
-Often they are used to express the state of an operation, by using values such as `:ok` and `:error`.
-
-The booleans `true` and `false` are also atoms:
-
-```elixir
-iex> true == :true
-true
-iex> is_atom(false)
-true
-iex> is_boolean(:false)
-true
-```
-
-Elixir allows you to skip the leading `:` for the atoms `false`, `true` and `nil`.
-
-
-Finally, Elixir has a construct called aliases which we will explore later. Aliases start in upper case and are also atoms:
-
-```elixir
-iex> is_atom(Hello)
-true
-```
-
-## Strings
-
-Strings in Elixir are delimited by double quotes, and they are encoded in UTF-8:
-
-```elixir
-iex> "hellö"
-"hellö"
-```
-
-> Note: if you are running on Windows, there is a chance your terminal does not use UTF-8 by default. You can change the encoding of your current session by running `chcp 65001` before entering IEx.
-
-Elixir also supports string interpolation:
-
-```elixir
-iex> string = :world
-iex> "hellö #{string}"
-"hellö world"
-```
-
-Strings can have line breaks in them. You can introduce them using escape sequences:
-
-```elixir
-iex> "hello
-...> world"
-"hello\nworld"
-iex> "hello\nworld"
-"hello\nworld"
-```
-
-You can print a string using the `IO.puts/1` function from the `IO` module:
-
-```elixir
-iex> IO.puts("hello\nworld")
-hello
-world
-:ok
-```
-
-Notice that the `IO.puts/1` function returns the atom `:ok` after printing.
-
-Strings in Elixir are represented internally by contiguous sequences of bytes known as binaries:
-
-```elixir
-iex> is_binary("hellö")
-true
-```
-
-We can also get the number of bytes in a string:
-
-```elixir
-iex> byte_size("hellö")
-6
-```
-
-Notice that the number of bytes in that string is 6, even though it has 5 graphemes. That's because the grapheme "ö" takes 2 bytes to be represented in UTF-8. We can get the actual length of the string, based on the number of graphemes, by using the `String.length/1` function:
-
-```elixir
-iex> String.length("hellö")
-5
-```
-
-The [String module](https://hexdocs.pm/elixir/String.html) contains a bunch of functions that operate on strings as defined in the Unicode standard:
-
-```elixir
-iex> String.upcase("hellö")
-"HELLÖ"
-```
-
-## Anonymous functions
-
-Elixir also provides anonymous functions. Anonymous functions allow us to store and pass executable code around as if it was an integer or a string. They are delimited by the keywords `fn` and `end`:
-
-```elixir
-iex> add = fn a, b -> a + b end
-#Function<12.71889879/2 in :erl_eval.expr/5>
-iex> add.(1, 2)
-3
-iex> is_function(add)
-true
-```
-
-In the example above, we defined an anonymous function that receives two arguments, `a` and `b`, and returns the result of `a + b`. The arguments are always on the left-hand side of `->` and the code to be executed on the right-hand side. The anonymous function is stored in the variable `add`.
-
-We can invoke anonymous functions by passing arguments to it. Note that a dot (`.`) between the variable and parentheses is required to invoke an anonymous function. The dot ensures there is no ambiguity between calling the anonymous function matched to a variable `add` and a named function `add/2`. We will write our own named functions when dealing with [Modules and Functions](/getting-started/modules-and-functions.html). For now, just remember that Elixir makes a clear distinction between anonymous functions and named functions.
-
-Anonymous functions in Elixir are also identified by the number of arguments they receive. We can check if a function is of any given arity by using `is_function/2`:
-
-```elixir
-# check if add is a function that expects exactly 2 arguments
-iex> is_function(add, 2)
-true
-# check if add is a function that expects exactly 1 argument
-iex> is_function(add, 1)
-false
-```
-
-Finally, anonymous functions can also access variables that are in scope when the function is defined. This is typically referred to as closures, as they close over their scope. Let's define a new anonymous function that uses the `add` anonymous function we have previously defined:
-
-```elixir
-iex> double = fn a -> add.(a, a) end
-#Function<6.71889879/1 in :erl_eval.expr/5>
-iex> double.(2)
-4
-```
-
-A variable assigned inside a function does not affect its surrounding environment:
-
-```elixir
-iex> x = 42
-42
-iex> (fn -> x = 0 end).()
-0
-iex> x
-42
-```
-
-## (Linked) Lists
-
-Elixir uses square brackets to specify a list of values. Values can be of any type:
-
-```elixir
-iex> [1, 2, true, 3]
-[1, 2, true, 3]
-iex> length [1, 2, 3]
-3
-```
-
-Two lists can be concatenated or subtracted using the `++/2` and `--/2` operators respectively:
-
-```elixir
-iex> [1, 2, 3] ++ [4, 5, 6]
-[1, 2, 3, 4, 5, 6]
-iex> [1, true, 2, false, 3, true] -- [true, false]
-[1, 2, 3, true]
-```
-
-List operators never modify the existing list. Concatenating to or removing elements from a list returns a new list. We say that Elixir data structures are *immutable*. One advantage of immutability is that it leads to clearer code. You can freely pass the data around with the guarantee no one will mutate it in memory - only transform it.
-
-Throughout the tutorial, we will talk a lot about the head and tail of a list. The head is the first element of a list and the tail is the remainder of the list. They can be retrieved with the functions `hd/1` and `tl/1`. Let's assign a list to a variable and retrieve its head and tail:
-
-```elixir
-iex> list = [1, 2, 3]
-iex> hd(list)
-1
-iex> tl(list)
-[2, 3]
-```
-
-Getting the head or the tail of an empty list throws an error:
-
-```elixir
-iex> hd([])
-** (ArgumentError) argument error
-```
-
-Sometimes you will create a list and it will return a quoted value preceded by `~c`. For example:
-
-```elixir
-iex> [11, 12, 13]
-~c"\v\f\r"
-iex> [104, 101, 108, 108, 111]
-~c"hello"
-```
-
-In Elixir versions before v1.15, this might be displayed as single quotes instead:
-
-```elixir
-iex> [104, 101, 108, 108, 111]
-'hello'
-```
-
-When Elixir sees a list of printable ASCII numbers, Elixir will print that as a charlist (literally a list of characters). Charlists are quite common when interfacing with existing Erlang code. Whenever you see a value in IEx and you are not quite sure what it is, you can use the `i/1` to retrieve information about it:
-
-```elixir
-iex> i ~c"hello"
-Term
-  i ~c"hello"
-Data type
-  List
-Description
-  ...
-Raw representation
-  [104, 101, 108, 108, 111]
-Reference modules
-  List
-Implemented protocols
-  ...
-```
-
-Keep in mind single-quoted and double-quoted representations are not equivalent in Elixir as they are represented by different types:
-
-```elixir
-iex> 'hello' == "hello"
-false
-iex> 'hello' == ~c"hello"
-true
-```
-
-Single quotes are charlists, double quotes are strings. We will talk more about them in the ["Binaries, strings and charlists"](/getting-started/binaries-strings-and-char-lists.html) chapter.
-
-## Tuples
-
-Elixir uses curly brackets to define tuples. Like lists, tuples can hold any value:
-
-```elixir
-iex> {:ok, "hello"}
-{:ok, "hello"}
-iex> tuple_size {:ok, "hello"}
-2
-```
-
-Tuples store elements contiguously in memory. This means accessing a tuple element by index or getting the tuple size is a fast operation. Indexes start from zero:
-
-```elixir
-iex> tuple = {:ok, "hello"}
-{:ok, "hello"}
-iex> elem(tuple, 1)
-"hello"
-iex> tuple_size(tuple)
-2
-```
-
-It is also possible to put an element at a particular index in a tuple with `put_elem/3`:
-
-```elixir
-iex> tuple = {:ok, "hello"}
-{:ok, "hello"}
-iex> put_elem(tuple, 1, "world")
-{:ok, "world"}
-iex> tuple
-{:ok, "hello"}
-```
-
-Notice that `put_elem/3` returned a new tuple. The original tuple stored in the `tuple` variable was not modified. Like lists, tuples are also immutable. Every operation on a tuple returns a new tuple, it never changes the given one.
-
-## Lists or tuples?
-
-What is the difference between lists and tuples?
-
-Lists are stored in memory as linked lists, meaning that each element in a list holds its value and points to the following element until the end of the list is reached. This means accessing the length of a list is a linear operation: we need to traverse the whole list in order to figure out its size.
-
-Similarly, the performance of list concatenation depends on the length of the left-hand list:
-
-```elixir
-iex> list = [1, 2, 3]
-[1, 2, 3]
-
-# This is fast as we only need to traverse `[0]` to prepend to `list`
-iex> [0] ++ list
-[0, 1, 2, 3]
-
-# This is slow as we need to traverse `list` to append 4
-iex> list ++ [4]
-[1, 2, 3, 4]
-```
-
-Tuples, on the other hand, are stored contiguously in memory. This means getting the tuple size or accessing an element by index is fast. However, updating or adding elements to tuples is expensive because it requires creating a new tuple in memory:
-
-```elixir
-iex> tuple = {:a, :b, :c, :d}
-{:a, :b, :c, :d}
-iex> put_elem(tuple, 2, :e)
-{:a, :b, :e, :d}
-```
-
-Note that this applies only to the tuple itself, not its contents. For instance, when you update a tuple, all entries are shared between the old and the new tuple, except for the entry that has been replaced. In other words, tuples and lists in Elixir are capable of sharing their contents. This reduces the amount of memory allocation the language needs to perform and is only possible thanks to the immutable semantics of the language.
-
-Those performance characteristics dictate the usage of those data structures. One very common use case for tuples is to use them to return extra information from a function. For example, `File.read/1` is a function that can be used to read file contents. It returns a tuple:
-
-```elixir
-iex> File.read("path/to/existing/file")
-{:ok, "... contents ..."}
-iex> File.read("path/to/unknown/file")
-{:error, :enoent}
-```
-
-If the path given to `File.read/1` exists, it returns a tuple with the atom `:ok` as the first element and the file contents as the second. Otherwise, it returns a tuple with `:error` and the error description.
-
-Most of the time, Elixir is going to guide you to do the right thing. For example, there is an `elem/2` function to access a tuple item but there is no built-in equivalent for lists:
-
-```elixir
-iex> tuple = {:ok, "hello"}
-{:ok, "hello"}
-iex> elem(tuple, 1)
-"hello"
-```
-
-When counting the elements in a data structure, Elixir also abides by a simple rule: the function is named `size` if the operation is in constant time (i.e. the value is pre-calculated) or `length` if the operation is linear (i.e. calculating the length gets slower as the input grows). As a mnemonic, both "length" and "linear" start with "l".
-
-For example, we have used 4 counting functions so far: `byte_size/1` (for the number of bytes in a string), `tuple_size/1` (for tuple size), `length/1` (for list length) and `String.length/1` (for the number of graphemes in a string). We use `byte_size` to get the number of bytes in a string -- a cheap operation. Retrieving the number of Unicode graphemes, on the other hand, uses `String.length`, and may be expensive as it relies on a traversal of the entire string.
-
-Elixir also provides `Port`, `Reference`, and `PID` as data types (usually used in process communication), and we will take a quick look at them when talking about processes. For now, let's take a look at some of the basic operators that go with our basic types.
diff --git a/getting-started/binaries-strings-and-char-lists.markdown b/getting-started/binaries-strings-and-char-lists.markdown
index a461056d9..1836f0b2e 100644
--- a/getting-started/binaries-strings-and-char-lists.markdown
+++ b/getting-started/binaries-strings-and-char-lists.markdown
@@ -1,310 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Binaries, strings, and charlists
+layout: redirect
+sitemap: false
+redirect_to: binaries-strings-and-charlists
 ---
-
-In "Basic types", we learned a little bit about strings and we used the `is_binary/1` function for checks:
-
-```elixir
-iex> string = "hello"
-"hello"
-iex> is_binary(string)
-true
-```
-
-In this chapter, we will gain clarity on what exactly binaries are, how they relate to strings, and what single-quoted values, `'like this'`, mean in Elixir. Although strings are one of the most common data types in computer languages, they are subtly complex and are often misunderstood. To understand strings in Elixir, we have to educate ourselves about [Unicode](https://en.wikipedia.org/wiki/Unicode) and character encodings, specifically the [UTF-8](https://en.wikipedia.org/wiki/UTF-8) encoding.
-
-## Unicode and Code Points
-
-In order to facilitate meaningful communication between computers across multiple languages, a standard is required so that the ones and zeros on one machine mean the same thing when they are transmitted to another. The [Unicode Standard](https://unicode.org/standard/standard.html) acts as an official registry of virtually all the characters we know: this includes characters from classical and historical texts, emoji, and formatting and control characters as well.
-
-Unicode organizes all of the characters in its repertoire into code charts, and each character is given a unique numerical index. This numerical index is known as a [Code Point](https://en.wikipedia.org/wiki/Code_point).
-
-In Elixir you can use a `?` in front of a character literal to reveal its code point:
-
-```elixir
-iex> ?a
-97
-iex> ?ł
-322
-```
-
-Note that most Unicode code charts will refer to a code point by its hexadecimal (hex) representation, e.g. `97` translates to `0061` in hex, and we can represent any Unicode character in an Elixir string by using the `\uXXXX` notation and the hex representation of its code point number:
-
-```elixir
-iex> "\u0061" == "a"
-true
-iex> 0x0061 = 97 = ?a
-97
-```
-
-The hex representation will also help you look up information about a code point, e.g. [https://codepoints.net/U+0061](https://codepoints.net/U+0061) has a data sheet all about the lower case `a`, a.k.a. code point 97.
-
-## UTF-8 and Encodings
-
-Now that we understand what the Unicode standard is and what code points are, we can finally talk about encodings. Whereas the code point is **what** we store, an encoding deals with **how** we store it: encoding is an implementation. In other words, we need a mechanism to convert the code point numbers into bytes so they can be stored in memory, written to disk, etc.
-
-Elixir uses UTF-8 to encode its strings, which means that code points are encoded as a series of 8-bit bytes. UTF-8 is a **variable width** character encoding that uses one to four bytes to store each code point. It is capable of encoding all valid Unicode code points. Let's see an example:
-
-```elixir
-iex> string = "héllo"
-"héllo"
-iex> String.length(string)
-5
-iex> byte_size(string)
-6
-```
-
-Although the string above has 5 characters, it uses 6 bytes, as two bytes are used to represent the character `é`.
-
-> Note: if you are running on Windows, there is a chance your terminal does not use UTF-8 by default. You can change the encoding of your current session by running `chcp 65001` before entering `iex` (`iex.bat`).
-
-Besides defining characters, UTF-8 also provides a notion of graphemes. Graphemes may consist of multiple characters that are often perceived as one. For example, the [woman firefighter emoji](https://emojipedia.org/woman-firefighter/) is represented as the combination of three characters: the woman emoji (👩), a hidden zero-width joiner, and the fire engine emoji (🚒):
-
-```elixir
-iex> String.codepoints("👩‍🚒")
-["👩", "‍", "🚒"]
-iex> String.graphemes("👩‍🚒")
-["👩‍🚒"]
-```
-
-However, Elixir is smart enough to know they are seen as a single character, and therefore the length is still one:
-
-```elixir
-iex> String.length("👩‍🚒")
-1
-```
-
-> Note: if you can't see the emoji above in your terminal, you need to make sure your terminal supports emoji and that you are using a font that can render them.
-
-Although these rules may sound complicated, UTF-8 encoded documents are everywhere. This page itself is encoded in UTF-8. The encoding information is given to your browser which then knows how to render all of the bytes, characters, and graphemes accordingly.
-
-If you want to see the exact bytes that a string would be stored in a file, a common trick is to concatenate the null byte `<<0>>` to it:
-
-```elixir
-iex> "hełło" <> <<0>>
-<<104, 101, 197, 130, 197, 130, 111, 0>>
-```
-
-Alternatively, you can view a string's binary representation by using [IO.inspect/2](https://hexdocs.pm/elixir/IO.html#inspect/2):
-
-```elixir
-iex> IO.inspect("hełło", binaries: :as_binaries)
-<<104, 101, 197, 130, 197, 130, 111>>
-```
-
-We are getting a little bit ahead of ourselves. Let's talk about bitstrings to learn about what exactly the `<<>>` constructor means.
-
-## Bitstrings
-
-Although we have covered code points and UTF-8 encoding, we still need to go a bit deeper into how exactly we store the encoded bytes, and this is where we introduce the **bitstring**. A bitstring is a fundamental data type in Elixir, denoted with the `<<>>` syntax. **A bitstring is a contiguous sequence of bits in memory.**
-
-A complete reference about the binary / bitstring constructor `<<>>` can be found [in the Elixir documentation](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#%3C%3C%3E%3E/1).
-
-By default, 8 bits (i.e. 1 byte) is used to store each number in a bitstring, but you can manually specify the number of bits via a `::n` modifier to denote the size in `n` bits, or you can use the more verbose declaration `::size(n)`:
-
-```elixir
-iex> <<42>> == <<42::8>>
-true
-iex> <<3::4>>
-<<3::size(4)>>
-```
-
-For example, the decimal number `3` when represented with 4 bits in base 2 would be `0011`, which is equivalent to the values `0`, `0`, `1`, `1`, each stored using 1 bit:
-
-```elixir
-iex> <<0::1, 0::1, 1::1, 1::1>> == <<3::4>>
-true
-```
-
-Any value that exceeds what can be stored by the number of bits provisioned is truncated:
-
-```elixir
-iex> <<1>> == <<257>>
-true
-```
-
-Here, 257 in base 2 would be represented as `100000001`, but since we have reserved only 8 bits for its representation (by default), the left-most bit is ignored and the value becomes truncated to `00000001`, or simply `1` in decimal.
-
-## Binaries
-
-**A binary is a bitstring where the number of bits is divisible by 8.** That means that every binary is a bitstring, but not every bitstring is a binary. We can use the `is_bitstring/1` and `is_binary/1` functions to demonstrate this.
-
-```elixir
-iex> is_bitstring(<<3::4>>)
-true
-iex> is_binary(<<3::4>>)
-false
-iex> is_bitstring(<<0, 255, 42>>)
-true
-iex> is_binary(<<0, 255, 42>>)
-true
-iex> is_binary(<<42::16>>)
-true
-```
-
-We can pattern match on binaries / bitstrings:
-
-```elixir
-iex> <<0, 1, x>> = <<0, 1, 2>>
-<<0, 1, 2>>
-iex> x
-2
-iex> <<0, 1, x>> = <<0, 1, 2, 3>>
-** (MatchError) no match of right hand side value: <<0, 1, 2, 3>>
-```
-
-Note that unless you explicitly use `::` modifiers, each entry in the binary pattern is expected to match a single byte (exactly 8 bits). If we want to match on a binary of unknown size, we can use the `binary` modifier at the end of the pattern:
-
-```elixir
-iex> <<0, 1, x::binary>> = <<0, 1, 2, 3>>
-<<0, 1, 2, 3>>
-iex> x
-<<2, 3>>
-```
-
-There are a couple other modifiers that can be useful when doing pattern matches on binaries. The `binary-size(n)` modifier will match `n` bytes in a binary:
-
-```elixir
-iex> <<head::binary-size(2), rest::binary>> = <<0, 1, 2, 3>>
-<<0, 1, 2, 3>>
-iex> head
-<<0, 1>>
-iex> rest
-<<2, 3>>
-```
-
-**A string is a UTF-8 encoded binary**, where the code point for each character is encoded using 1 to 4 bytes. Thus every string is a binary, but due to the UTF-8 standard encoding rules, not every binary is a valid string.
-
-```elixir
-iex> is_binary("hello")
-true
-iex> is_binary(<<239, 191, 19>>)
-true
-iex> String.valid?(<<239, 191, 19>>)
-false
-```
-
-The string concatenation operator `<>` is actually a binary concatenation operator:
-
-```elixir
-iex> "a" <> "ha"
-"aha"
-iex> <<0, 1>> <> <<2, 3>>
-<<0, 1, 2, 3>>
-```
-
-Given that strings are binaries, we can also pattern match on strings:
-
-```elixir
-iex> <<head, rest::binary>> = "banana"
-"banana"
-iex> head == ?b
-true
-iex> rest
-"anana"
-```
-
-However, remember that binary pattern matching works on *bytes*, so matching on the string like "über" with multibyte characters won't match on the _character_, it will match on the _first byte of that character_:
-
-```elixir
-iex> "ü" <> <<0>>
-<<195, 188, 0>>
-iex> <<x, rest::binary>> = "über"
-"über"
-iex> x == ?ü
-false
-iex> rest
-<<188, 98, 101, 114>>
-```
-
-Above, `x` matched on only the first byte of the multibyte `ü` character.
-
-Therefore, when pattern matching on strings, it is important to use the `utf8` modifier:
-
-```elixir
-iex> <<x::utf8, rest::binary>> = "über"
-"über"
-iex> x == ?ü
-true
-iex> rest
-"ber"
-```
-
-## Charlists
-
-Our tour of our bitstrings, binaries, and strings is nearly complete, but we have one more data type to explain: the charlist.
-
-**A charlist is a list of integers where all the integers are valid code points.** In practice, you will not come across them often, only in specific scenarios such as interfacing with older Erlang libraries that do not accept binaries as arguments.
-
-```elixir
-iex> ~c"hello"
-~c"hello"
-iex> [?h, ?e, ?l, ?l, ?o]
-~c"hello"
-```
-
-The `~c` sigil (we'll cover sigils later in the ["Sigils"](/getting-started/sigils.html) section)
-indicates the fact that we are dealing with a charlist and not a regular string.
-
-Whereas double-quotes creates strings, single-quotes create charlist literals.
-Charlists used to be represented with single quotes in Elixir <1.15:
-
-```elixir
-iex> 'hello'
-~c"hello"
-```
-
-The key takeaway is that `"hello"` is not the same as `'hello'`. Generally speaking, **double-quotes must always be used to represent strings in Elixir**. In any case, let's learn how charlists work.
-
-Instead of containing bytes, a charlist contains integer code points. However, the list is only printed in single-quotes if all code points are within the ASCII range:
-
-```elixir
-iex> ~c"hełło"
-[104, 101, 322, 322, 111]
-iex> is_list(~c"hełło")
-true
-```
-
-Interpreting integers as code points may lead to some surprising behavior. For example, if you are storing a list of integers that happen to range between 0 and 127, by default IEx will interpret this as a charlist and it will display the corresponding ASCII characters.
-
-```elixir
-iex> heartbeats_per_minute = [99, 97, 116]
-~c"cat"
-```
-
-You can convert a charlist to a string and back by using the `to_string/1` and `to_charlist/1` functions:
-
-```elixir
-iex> to_charlist("hełło")
-[104, 101, 322, 322, 111]
-iex> to_string(~c"hełło")
-"hełło"
-iex> to_string(:hello)
-"hello"
-iex> to_string(1)
-"1"
-```
-
-Note that those functions are polymorphic - not only do they convert charlists to strings, they also operate on integers, atoms, and so on.
-
-String (binary) concatenation uses the `<>` operator but charlists, being lists, use the list concatenation operator `++`:
-
-```elixir
-iex> ~c"this " <> ~c"fails"
-** (ArgumentError) expected binary argument in <> operator but got: ~c"this "
-    (elixir) lib/kernel.ex:1821: Kernel.wrap_concatenation/3
-    (elixir) lib/kernel.ex:1808: Kernel.extract_concatenations/2
-    (elixir) expanding macro: Kernel.<>/2
-    iex:1: (file)
-iex> ~c"this " ++ ~c"works"
-~c"this works"
-iex> "he" ++ "llo"
-** (ArgumentError) argument error
-    :erlang.++("he", "llo")
-iex> "he" <> "llo"
-"hello"
-```
-
-With binaries, strings, and charlists out of the way, it is time to talk about key-value data structures.
diff --git a/getting-started/case-cond-and-if.markdown b/getting-started/case-cond-and-if.markdown
index c93c5cbd9..98dd9f544 100644
--- a/getting-started/case-cond-and-if.markdown
+++ b/getting-started/case-cond-and-if.markdown
@@ -1,196 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: case, cond, and if
+layout: redirect
+sitemap: false
+redirect_to: case-cond-and-if
 ---
-
-In this chapter, we will learn about the `case`, `cond`, and `if` control flow structures.
-
-## `case`
-
-`case` allows us to compare a value against many patterns until we find a matching one:
-
-```elixir
-iex> case {1, 2, 3} do
-...>   {4, 5, 6} ->
-...>     "This clause won't match"
-...>   {1, x, 3} ->
-...>     "This clause will match and bind x to 2 in this clause"
-...>   _ ->
-...>     "This clause would match any value"
-...> end
-"This clause will match and bind x to 2 in this clause"
-```
-
-If you want to pattern match against an existing variable, you need to use the `^` operator:
-
-```elixir
-iex> x = 1
-1
-iex> case 10 do
-...>   ^x -> "Won't match"
-...>   _ -> "Will match"
-...> end
-"Will match"
-```
-
-Clauses also allow extra conditions to be specified via guards:
-
-```elixir
-iex> case {1, 2, 3} do
-...>   {1, x, 3} when x > 0 ->
-...>     "Will match"
-...>   _ ->
-...>     "Would match, if guard condition were not satisfied"
-...> end
-"Will match"
-```
-
-The first clause above will only match when `x` is positive.
-
-Keep in mind errors in guards do not leak but simply make the guard fail:
-
-```elixir
-iex> hd(1)
-** (ArgumentError) argument error
-iex> case 1 do
-...>   x when hd(x) -> "Won't match"
-...>   x -> "Got #{x}"
-...> end
-"Got 1"
-```
-
-If none of the clauses match, an error is raised:
-
-```elixir
-iex> case :ok do
-...>   :error -> "Won't match"
-...> end
-** (CaseClauseError) no case clause matching: :ok
-```
-
-Consult [the full documentation for guards](https://hexdocs.pm/elixir/patterns-and-guards.html#guards) for more information about guards, how they are used, and what expressions are allowed in them.
-
-Note anonymous functions can also have multiple clauses and guards:
-
-```elixir
-iex> f = fn
-...>   x, y when x > 0 -> x + y
-...>   x, y -> x * y
-...> end
-#Function<12.71889879/2 in :erl_eval.expr/5>
-iex> f.(1, 3)
-4
-iex> f.(-1, 3)
--3
-```
-
-The number of arguments in each anonymous function clause needs to be the same, otherwise an error is raised.
-
-```elixir
-iex> f2 = fn
-...>   x, y when x > 0 -> x + y
-...>   x, y, z -> x * y + z
-...> end
-** (CompileError) iex:1: cannot mix clauses with different arities in anonymous functions
-```
-
-## `cond`
-
-`case` is useful when you need to match against different values. However, in many circumstances, we want to check different conditions and find the first one that does not evaluate to `nil` or `false`. In such cases, one may use `cond`:
-
-```elixir
-iex> cond do
-...>   2 + 2 == 5 ->
-...>     "This will not be true"
-...>   2 * 2 == 3 ->
-...>     "Nor this"
-...>   1 + 1 == 2 ->
-...>     "But this will"
-...> end
-"But this will"
-```
-
-This is equivalent to `else if` clauses in many imperative languages - although used less frequently in Elixir.
-
-If all of the conditions return `nil` or `false`, an error (`CondClauseError`) is raised. For this reason, it may be necessary to add a final condition, equal to `true`, which will always match:
-
-```elixir
-iex> cond do
-...>   2 + 2 == 5 ->
-...>     "This is never true"
-...>   2 * 2 == 3 ->
-...>     "Nor this"
-...>   true ->
-...>     "This is always true (equivalent to else)"
-...> end
-"This is always true (equivalent to else)"
-```
-
-Finally, note `cond` considers any value besides `nil` and `false` to be true:
-
-```elixir
-iex> cond do
-...>   hd([1, 2, 3]) ->
-...>     "1 is considered as true"
-...> end
-"1 is considered as true"
-```
-
-## `if` and `unless`
-
-Besides `case` and `cond`, Elixir also provides `if/2` and `unless/2`, which are useful when you need to check for only one condition:
-
-```elixir
-iex> if true do
-...>   "This works!"
-...> end
-"This works!"
-iex> unless true do
-...>   "This will never be seen"
-...> end
-nil
-```
-
-If the condition given to `if/2` returns `false` or `nil`, the body given between `do`-`end` is not executed and instead it returns `nil`. The opposite happens with `unless/2`.
-
-They also support `else` blocks:
-
-```elixir
-iex> if nil do
-...>   "This won't be seen"
-...> else
-...>   "This will"
-...> end
-"This will"
-```
-
-This is also a good opportunity to talk about variable scoping in Elixir. If any variable is declared or changed inside `if`, `case`, and similar constructs, the declaration and change will only be visible inside the construct. For example:
-
-```elixir
-iex> x = 1
-1
-iex> if true do
-...>   x = x + 1
-...> end
-2
-iex> x
-1
-```
-
-In said cases, if you want to change a value, you must return the value from the `if`:
-
-```elixir
-iex> x = 1
-1
-iex> x = if true do
-...>   x + 1
-...> else
-...>   x
-...> end
-2
-```
-
-> Note: An interesting note regarding `if/2` and `unless/2` is that they are implemented as macros in the language; they aren't special language constructs as they would be in many languages. You can check the documentation and the source of `if/2` in [the `Kernel` module docs](https://hexdocs.pm/elixir/Kernel.html). The `Kernel` module is also where operators like `+/2` and functions like `is_function/2` are defined, all automatically imported and available in your code by default.
-
-We have concluded the introduction to the most fundamental control-flow constructs in Elixir. Now it is time to talk about "Binaries, strings, and char lists".
\ No newline at end of file
diff --git a/getting-started/comprehensions.markdown b/getting-started/comprehensions.markdown
index 97e1f4bf5..a1ddb4dd7 100644
--- a/getting-started/comprehensions.markdown
+++ b/getting-started/comprehensions.markdown
@@ -1,114 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Comprehensions
+layout: redirect
+sitemap: false
+redirect_to: comprehensions
 ---
-
-In Elixir, it is common to loop over an Enumerable, often filtering out some results and mapping values into another list. Comprehensions are syntactic sugar for such constructs: they group those common tasks into the `for` special form.
-
-For example, we can map a list of integers into their squared values:
-
-```elixir
-iex> for n <- [1, 2, 3, 4], do: n * n
-[1, 4, 9, 16]
-```
-
-A comprehension is made of three parts: generators, filters, and collectables.
-
-## Generators and filters
-
-In the expression above, `n <- [1, 2, 3, 4]` is the **generator**. It is literally generating values to be used in the comprehension. Any enumerable can be passed on the right-hand side of the generator expression:
-
-```elixir
-iex> for n <- 1..4, do: n * n
-[1, 4, 9, 16]
-```
-
-Generator expressions also support pattern matching on their left-hand side; all non-matching patterns are *ignored*. Imagine that, instead of a range, we have a keyword list where the key is the atom `:good` or `:bad` and we only want to compute the square of the `:good` values:
-
-```elixir
-iex> values = [good: 1, good: 2, bad: 3, good: 4]
-iex> for {:good, n} <- values, do: n * n
-[1, 4, 16]
-```
-
-Alternatively to pattern matching, filters can be used to select some particular elements. For example, we can select the multiples of 3 and discard all others:
-
-```elixir
-iex> for n <- 0..5, rem(n, 3) == 0, do: n * n
-[0, 9]
-```
-
-Comprehensions discard all elements for which the filter expression returns `false` or `nil`; all other values are selected.
-
-Comprehensions generally provide a much more concise representation than using the equivalent functions from the `Enum` and `Stream` modules. Furthermore, comprehensions also allow multiple generators and filters to be given. Here is an example that receives a list of directories and gets the size of each file in those directories:
-
-```elixir
-dirs = ["/home/mikey", "/home/james"]
-
-for dir <- dirs,
-    file <- File.ls!(dir),
-    path = Path.join(dir, file),
-    File.regular?(path) do
-  File.stat!(path).size
-end
-```
-
-Multiple generators can also be used to calculate the cartesian product of two lists:
-
-```elixir
-iex> for i <- [:a, :b, :c], j <- [1, 2], do:  {i, j}
-[a: 1, a: 2, b: 1, b: 2, c: 1, c: 2]
-```
-
-Finally, keep in mind that variable assignments inside the comprehension, be it in generators, filters or inside the block, are not reflected outside of the comprehension.
-
-## Bitstring generators
-
-Bitstring generators are also supported and are very useful when you need to comprehend over bitstring streams. The example below receives a list of pixels from a binary with their respective red, green and blue values and converts them into tuples of three elements each:
-
-```elixir
-iex> pixels = <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
-iex> for <<r::8, g::8, b::8 <- pixels>>, do: {r, g, b}
-[{213, 45, 132}, {64, 76, 32}, {76, 0, 0}, {234, 32, 15}]
-```
-
-A bitstring generator can be mixed with "regular" enumerable generators, and supports filters as well.
-
-## The `:into` option
-
-In the examples above, all the comprehensions returned lists as their result. However, the result of a comprehension can be inserted into different data structures by passing the `:into` option to the comprehension.
-
-For example, a bitstring generator can be used with the `:into` option in order to easily remove all spaces in a string:
-
-```elixir
-iex> for <<c <- " hello world ">>, c != ?\s, into: "", do: <<c>>
-"helloworld"
-```
-
-Sets, maps, and other dictionaries can also be given to the `:into` option. In general, `:into` accepts any structure that implements the [`Collectable`](https://hexdocs.pm/elixir/Collectable.html) protocol.
-
-A common use case of `:into` can be transforming values in a map:
-
-```elixir
-iex> for {key, val} <- %{"a" => 1, "b" => 2}, into: %{}, do: {key, val * val}
-%{"a" => 1, "b" => 4}
-```
-
-Let's make another example using streams. Since the `IO` module provides streams (that are both `Enumerable`s and `Collectable`s), an echo terminal that echoes back the upcased version of whatever is typed can be implemented using comprehensions:
-
-```elixir
-iex> stream = IO.stream(:stdio, :line)
-iex> for line <- stream, into: stream do
-...>   String.upcase(line) <> "\n"
-...> end
-```
-
-Now type any string into the terminal and you will see that the same value will be printed in upper-case. Unfortunately, this example also got your IEx shell stuck in the comprehension, so you will need to hit `Ctrl+C` twice to get out of it. :)
-
-## Other options
-
-Comprehensions support other options, such as `:reduce` and `:uniq`. Here are additional resources to learn more about comprehensions:
-
-  * [`for` official reference in Elixir documentation](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#for/1)
-  * [Mitchell Hanberg's comprehensive guide to Elixir's comprehensions](https://www.mitchellhanberg.com/the-comprehensive-guide-to-elixirs-for-comprehension/)
diff --git a/getting-started/debugging.markdown b/getting-started/debugging.markdown
index 12eb14861..c63f3e447 100644
--- a/getting-started/debugging.markdown
+++ b/getting-started/debugging.markdown
@@ -1,167 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Debugging
+layout: redirect
+sitemap: false
+redirect_to: debugging
 ---
-
-There are a number of ways to debug code in Elixir. In this chapter we will cover some of the more common ways of doing so.
-
-## IO.inspect/2
-
-What makes `IO.inspect(item, opts \\ [])` really useful in debugging is that it returns the `item` argument passed to it without affecting the behavior of the original code. Let's see an example.
-
-```elixir
-(1..10)
-|> IO.inspect
-|> Enum.map(fn x -> x * 2 end)
-|> IO.inspect
-|> Enum.sum
-|> IO.inspect
-```
-
-Prints:
-
-```elixir
-1..10
-[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
-110
-```
-
-As you can see `IO.inspect/2` makes it possible to "spy" on values almost anywhere in your code without altering the result, making it very helpful inside of a pipeline like in the above case.
-
-`IO.inspect/2` also provides the ability to decorate the output with a `label` option. The label will be printed before the inspected `item`:
-
-```elixir
-[1, 2, 3]
-|> IO.inspect(label: "before")
-|> Enum.map(&(&1 * 2))
-|> IO.inspect(label: "after")
-|> Enum.sum
-```
-
-Prints:
-
-```elixir
-before: [1, 2, 3]
-after: [2, 4, 6]
-```
-
-It is also very common to use `IO.inspect/2` with [`binding()`](https://hexdocs.pm/elixir/Kernel.html#binding/0), which returns all variable names and their values:
-
-```elixir
-def some_fun(a, b, c) do
-  IO.inspect binding()
-  ...
-end
-```
-
-When `some_fun/3` is invoked with `:foo`, `"bar"`, `:baz` it prints:
-
-```elixir
-[a: :foo, b: "bar", c: :baz]
-```
-
-Please see [IO.inspect/2](https://hexdocs.pm/elixir/IO.html#inspect/2) to read more about other ways in which one could use this function. Also, in order to find a full list of other formatting options that one can use alongside `IO.inspect/2`, see [Inspect.Opts](https://hexdocs.pm/elixir/Inspect.Opts.html).
-
-## `dbg`
-
-Elixir v1.14 introduced `dbg/2`. `dbg` is similar to `IO.inspect/2`, but specifically tailored for debugging. It prints the value passed to it and returns it (just like `IO.inspect/2`), but it also prints the code and location.
-
-```elixir
-# In my_file.exs
-feature = %{name: :dbg, inspiration: "Rust"}
-dbg(feature)
-dbg(Map.put(feature, :in_version, "1.14.0"))
-```
-
-The code above prints this:
-
-```shell
-[my_file.exs:2: (file)]
-feature #=> %{inspiration: "Rust", name: :dbg}
-[my_file.exs:3: (file)]
-Map.put(feature, :in_version, "1.14.0") #=> %{in_version: "1.14.0", inspiration: "Rust", name: :dbg}
-```
-
-When talking about `IO.inspect/2`, we mentioned its usefulness when placed between steps of `|>` pipelines. `dbg` does it better: it understands Elixir code, so it will print values at *every step of the pipeline*.
-
-```elixir
-# In dbg_pipes.exs
-__ENV__.file
-|> String.split("/", trim: true)
-|> List.last()
-|> File.exists?()
-|> dbg()
-```
-
-This code prints:
-
-```shell
-[dbg_pipes.exs:5: (file)]
-__ENV__.file #=> "/home/myuser/dbg_pipes.exs"
-|> String.split("/", trim: true) #=> ["home", "myuser", "dbg_pipes.exs"]
-|> List.last() #=> "dbg_pipes.exs"
-|> File.exists?() #=> true
-```
-
-Note `dbg` only supports stepping for pipelines (in other words, it can only step through the code it sees). For general stepping of functions, you will need to set breakpoints using `IEx.break!/4`.
-
-## Breakpoints
-
-When code calling `dbg` is executed via `iex`, IEx will ask you to "stop" the code execution where the `dbg` call is. If you accept, you'll be able to access all variables, as well as imports and aliases from the code, directly from IEx. This is called "prying". While the pry session is running, the code execution stops, until `continue` or `next` are called. Remember you can always run `iex` in the context of a project with `iex -S mix TASK`.
-
-<script id="asciicast-509509" src="https://asciinema.org/a/509509.js" async></script>
-
-`dbg` calls require us to change the code we intend to debug and has limited stepping functionality. Luckily IEx also provides a [`break!/2`](https://hexdocs.pm/iex/IEx.html#break!/2) function which allows you to set and manage breakpoints on any Elixir code without modifying its source:
-
-<script type="text/javascript" src="https://asciinema.org/a/0h3po0AmTcBAorc5GBNU97nrs.js" id="asciicast-0h3po0AmTcBAorc5GBNU97nrs" async></script><noscript><p><a href="https://asciinema.org/a/0h3po0AmTcBAorc5GBNU97nrs">See the example in asciinema</a></p></noscript>
-
-Similar to `dbg`, once a breakpoint is reached code execution stops until `continue` or `next` are invoked. However, `break!/2` does not have access to aliases and imports from the debugged code as it works on the compiled artifact rather than on source code.
-
-## Observer
-
-For debugging complex systems, jumping at the code is not enough. It is necessary to have an understanding of the whole virtual machine, processes, applications, as well as set up tracing mechanisms. Luckily this can be achieved in Erlang with `:observer`. In your application:
-
-```elixir
-$ iex
-iex> :observer.start()
-```
-
-> When running `iex` inside a project with `iex -S mix`, `observer` won't be available as a dependency from Elixir v1.15. To do so, you will need to call the following functions before:
->
-> ```elixir
-> iex> Mix.ensure_application!(:wx)
-> iex> Mix.ensure_application!(:runtime_tools)
-> iex> Mix.ensure_application!(:observer)
-> iex> :observer.start()
-> ```
->
-> If any of the calls above fail, here is what may have happened: some package managers default to installing a minimized Erlang without WX bindings for GUI support. In some package managers, you may be able to replace the headless Erlang with a more complete package (look for packages named `erlang` vs `erlang-nox` on Debian/Ubuntu/Arch). In others managers, you may need to install a separate `erlang-wx` (or similarly named) package.
->
-> There are conversations to improve this experience in future releases.
-
-The above will open another Graphical User Interface that provides many panes to fully understand and navigate the runtime and your project:
-
-<img src="/images/contents/kv-observer.png" width="640" alt="Observer GUI screenshot" />
-
-We explore the Observer in the context of an actual project [in the Dynamic Supervisor chapter of the Mix & OTP guide](/getting-started/mix-otp/dynamic-supervisor.html). This is one of the debugging techniques [the Phoenix framework used to achieve 2 million connections on a single machine](https://phoenixframework.org/blog/the-road-to-2-million-websocket-connections).
-
-If you are using the Phoenix web framework, it ships with the [Phoenix LiveDashboard](https://github.com/phoenixframework/phoenix_live_dashboard), a web dashboard for production nodes which provides similar features to Observer.
-
-Finally, remember you can also get a mini-overview of the runtime info by calling `runtime_info/0` directly in IEx.
-
-## Other tools and community
-
-We have just scratched the surface of what the Erlang VM has to offer, for example:
-
-  * Alongside the observer application, Erlang also includes a `:crashdump_viewer` to view crash dumps
-
-  * Integration with OS level tracers, such as [Linux Trace Toolkit,](http://www.erlang.org/doc/apps/runtime_tools/LTTng.html) [DTRACE,](http://www.erlang.org/doc/apps/runtime_tools/DTRACE.html) and [SystemTap](http://www.erlang.org/doc/apps/runtime_tools/SYSTEMTAP.html)
-
-  * [Microstate accounting](http://www.erlang.org/doc/man/msacc.html) measures how much time the runtime spends in several low-level tasks in a short time interval
-
-  * Mix ships with many tasks under the `profile` namespace, such as `cprof` and `fprof`
-
-  * For more advanced use cases, we recommend the excellent [Erlang in Anger](https://www.erlang-in-anger.com/), which is available as a free ebook
-
-Happy debugging!
diff --git a/getting-started/enumerables-and-streams.markdown b/getting-started/enumerables-and-streams.markdown
index 7e1b18d19..b6abedae7 100644
--- a/getting-started/enumerables-and-streams.markdown
+++ b/getting-started/enumerables-and-streams.markdown
@@ -1,126 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Enumerables and Streams
+layout: redirect
+sitemap: false
+redirect_to: enumerable-and-streams
 ---
-
-## Enumerables
-
-Elixir provides the concept of enumerables and [the `Enum` module](https://hexdocs.pm/elixir/Enum.html) to work with them. We have already learned two enumerables: lists and maps.
-
-```elixir
-iex> Enum.map([1, 2, 3], fn x -> x * 2 end)
-[2, 4, 6]
-iex> Enum.map(%{1 => 2, 3 => 4}, fn {k, v} -> k * v end)
-[2, 12]
-```
-
-The `Enum` module provides a huge range of functions to transform, sort, group, filter and retrieve items from enumerables. It is one of the modules developers use frequently in their Elixir code.
-
-Elixir also provides ranges:
-
-```elixir
-iex> Enum.map(1..3, fn x -> x * 2 end)
-[2, 4, 6]
-iex> Enum.reduce(1..3, 0, &+/2)
-6
-```
-
-The functions in the Enum module are limited to, as the name says, enumerating values in data structures. For specific operations, like inserting and updating particular elements, you may need to reach for modules specific to the data type. For example, if you want to insert an element at a given position in a list, you should use the `List.insert_at/3` function from [the `List` module](https://hexdocs.pm/elixir/List.html), as it would make little sense to insert a value into, for example, a range.
-
-We say the functions in the `Enum` module are polymorphic because they can work with diverse data types. In particular, the functions in the `Enum` module can work with any data type that implements [the `Enumerable` protocol](https://hexdocs.pm/elixir/Enumerable.html). We are going to discuss Protocols in a later chapter; for now we are going to move on to a specific kind of enumerable called a stream.
-
-## Eager vs Lazy
-
-All the functions in the `Enum` module are eager. Many functions expect an enumerable and return a list back:
-
-```elixir
-iex> odd? = &(rem(&1, 2) != 0)
-#Function<6.80484245/1 in :erl_eval.expr/5>
-iex> Enum.filter(1..3, odd?)
-[1, 3]
-```
-
-This means that when performing multiple operations with `Enum`, each operation is going to generate an intermediate list until we reach the result:
-
-```elixir
-iex> 1..100_000 |> Enum.map(&(&1 * 3)) |> Enum.filter(odd?) |> Enum.sum()
-7500000000
-```
-
-The example above has a pipeline of operations. We start with a range and then multiply each element in the range by 3. This first operation will now create and return a list with `100_000` items. Then we keep all odd elements from the list, generating a new list, now with `50_000` items, and then we sum all entries.
-
-## The pipe operator
-
-The `|>` symbol used in the snippet above is the **pipe operator**: it takes the output from the expression on its left side and passes it as the first argument to the function call on its right side. It's similar to the Unix `|` operator.  Its purpose is to highlight the data being transformed by a series of functions. To see how it can make the code cleaner, have a look at the example above rewritten without using the `|>` operator:
-
-```elixir
-iex> Enum.sum(Enum.filter(Enum.map(1..100_000, &(&1 * 3)), odd?))
-7500000000
-```
-
-Find more about the pipe operator [by reading its documentation](https://hexdocs.pm/elixir/Kernel.html#%7C%3E/2).
-
-## Streams
-
-As an alternative to `Enum`, Elixir provides [the `Stream` module](https://hexdocs.pm/elixir/Stream.html) which supports lazy operations:
-
-```elixir
-iex> 1..100_000 |> Stream.map(&(&1 * 3)) |> Stream.filter(odd?) |> Enum.sum
-7500000000
-```
-
-Streams are lazy, composable enumerables.
-
-In the example above, `1..100_000 |> Stream.map(&(&1 * 3))` returns a data type, an actual stream, that represents the `map` computation over the range `1..100_000`:
-
-```elixir
-iex> 1..100_000 |> Stream.map(&(&1 * 3))
-#Stream<[enum: 1..100000, funs: [#Function<34.16982430/1 in Stream.map/2>]]>
-```
-
-Furthermore, they are composable because we can pipe many stream operations:
-
-```elixir
-iex> 1..100_000 |> Stream.map(&(&1 * 3)) |> Stream.filter(odd?)
-#Stream<[enum: 1..100000, funs: [...]]>
-```
-
-Instead of generating intermediate lists, streams build a series of computations that are invoked only when we pass the underlying stream to the `Enum` module. Streams are useful when working with large, *possibly infinite*, collections.
-
-Many functions in the `Stream` module accept any enumerable as an argument and return a stream as a result. It also provides functions for creating streams. For example, `Stream.cycle/1` can be used to create a stream that cycles a given enumerable infinitely. Be careful to not call a function like `Enum.map/2` on such streams, as they would cycle forever:
-
-```elixir
-iex> stream = Stream.cycle([1, 2, 3])
-#Function<15.16982430/2 in Stream.unfold/2>
-iex> Enum.take(stream, 10)
-[1, 2, 3, 1, 2, 3, 1, 2, 3, 1]
-```
-
-On the other hand, `Stream.unfold/2` can be used to generate values from a given initial value:
-
-```elixir
-iex> stream = Stream.unfold("hełło", &String.next_codepoint/1)
-#Function<39.75994740/2 in Stream.unfold/2>
-iex> Enum.take(stream, 3)
-["h", "e", "ł"]
-```
-
-Another interesting function is `Stream.resource/3` which can be used to wrap around resources, guaranteeing they are opened right before enumeration and closed afterwards, even in the case of failures. For example, `File.stream!/1` builds on top of `Stream.resource/3` to stream files:
-
-```elixir
-iex> stream = File.stream!("path/to/file")
-%File.Stream{
-  line_or_bytes: :line,
-  modes: [:raw, :read_ahead, :binary],
-  path: "path/to/file",
-  raw: true
-}
-iex> Enum.take(stream, 10)
-```
-
-The example above will fetch the first 10 lines of the file you have selected. This means streams can be very useful for handling large files or even slow resources like network resources.
-
-The amount of functionality in the [`Enum`](https://hexdocs.pm/elixir/Enum.html) and [`Stream`](https://hexdocs.pm/elixir/Stream.html) modules can be daunting at first, but you will get familiar with them case by case. In particular, focus on the `Enum` module first and only move to `Stream` for the particular scenarios where laziness is required, to either deal with slow resources or large, possibly infinite, collections.
-
-Next, we'll look at a feature central to Elixir, Processes, which allows us to write concurrent, parallel and distributed programs in an easy and understandable way.
diff --git a/getting-started/erlang-libraries.markdown b/getting-started/erlang-libraries.markdown
index 5719d9175..8af923cc7 100644
--- a/getting-started/erlang-libraries.markdown
+++ b/getting-started/erlang-libraries.markdown
@@ -1,208 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Erlang libraries
+layout: redirect
+sitemap: false
+redirect_to: erlang-libraries
 ---
-
-Elixir provides excellent interoperability with Erlang libraries. In fact,
-Elixir discourages simply wrapping Erlang libraries in favor of directly
-interfacing with Erlang code. In this section, we will present some of the
-most common and useful Erlang functionality that is not found in Elixir.
-
-As you grow more proficient in Elixir, you may want to explore the Erlang
-[STDLIB Reference Manual](http://www.erlang.org/doc/apps/stdlib/index.html) in more
-detail.
-
-## The binary module
-
-The built-in Elixir String module handles binaries that are UTF-8 encoded.
-[The binary module](http://www.erlang.org/doc/man/binary.html) is useful when
-you are dealing with binary data that is not necessarily UTF-8 encoded.
-
-```elixir
-iex> String.to_charlist "Ø"
-[216]
-iex> :binary.bin_to_list "Ø"
-[195, 152]
-```
-
-The above example shows the difference; the `String` module returns Unicode
-codepoints, while `:binary` deals with raw data bytes.
-
-## Formatted text output
-
-Elixir does not contain a function similar to `printf` found in C and other
-languages. Luckily, the Erlang standard library functions `:io.format/2` and
-`:io_lib.format/2` may be used. The first formats to terminal output, while
-the second formats to an iolist. The format specifiers differ from `printf`,
-[refer to the Erlang documentation for details](http://www.erlang.org/doc/man/io.html#format-1).
-
-```elixir
-iex> :io.format("Pi is approximately given by:~10.3f~n", [:math.pi])
-Pi is approximately given by:     3.142
-:ok
-iex> to_string :io_lib.format("Pi is approximately given by:~10.3f~n", [:math.pi])
-"Pi is approximately given by:     3.142\n"
-```
-
-Also note that Erlang's formatting functions require special attention to
-Unicode handling.
-
-## The crypto module
-
-[The crypto module](http://www.erlang.org/doc/man/crypto.html) contains hashing
-functions, digital signatures, encryption and more:
-
-```elixir
-iex> Base.encode16(:crypto.hash(:sha256, "Elixir"))
-"3315715A7A3AD57428298676C5AE465DADA38D951BDFAC9348A8A31E9C7401CB"
-```
-
-The `:crypto` module is part of the `:crypto` application that ships with
-Erlang. This means you must list the `:crypto` application as an additional
-application in your project configuration. To do this, edit your `mix.exs`
-file to include:
-
-```elixir
-def application do
-  [extra_applications: [:crypto]]
-end
-```
-
-Any module that is not part of the `:kernel` or `:stdlib` Erlang applications
-must have their application explicitly listed in your `mix.exs`. You can find
-the application name of any Erlang module in the Erlang documentation, immediately
-below the Erlang logo in the sidebar.
-
-## The digraph module
-
-[The digraph module](http://www.erlang.org/doc/man/digraph.html) (as well as
-[digraph_utils](http://www.erlang.org/doc/man/digraph_utils.html)) contains
-functions for dealing with directed graphs built of vertices and edges.
-After constructing the graph, the algorithms in there will help find,
-for instance, the shortest path between two vertices, or loops in the graph.
-
-Given three vertices, find the shortest path from the first to the last.
-
-```elixir
-iex> digraph = :digraph.new()
-iex> coords = [{0.0, 0.0}, {1.0, 0.0}, {1.0, 1.0}]
-iex> [v0, v1, v2] = (for c <- coords, do: :digraph.add_vertex(digraph, c))
-iex> :digraph.add_edge(digraph, v0, v1)
-iex> :digraph.add_edge(digraph, v1, v2)
-iex> :digraph.get_short_path(digraph, v0, v2)
-[{0.0, 0.0}, {1.0, 0.0}, {1.0, 1.0}]
-```
-
-Note that the functions in `:digraph` alter the graph structure in-place, this
-is possible because they are implemented as ETS tables, explained next.
-
-## Erlang Term Storage
-
-The modules [`ets`](http://www.erlang.org/doc/man/ets.html) and
-[`dets`](http://www.erlang.org/doc/man/dets.html) handle storage of large
-data structures in memory or on disk respectively.
-
-ETS lets you create a table containing tuples. By default, ETS tables
-are protected, which means only the owner process may write to the table
-but any other process can read. ETS has some functionality to allow a
-table to be used as a simple database, a key-value store or as a cache
-mechanism.
-
-The functions in the `ets` module will modify the state of the table as a
-side-effect.
-
-```elixir
-iex> table = :ets.new(:ets_test, [])
-# Store as tuples with {name, population}
-iex> :ets.insert(table, {"China", 1_374_000_000})
-iex> :ets.insert(table, {"India", 1_284_000_000})
-iex> :ets.insert(table, {"USA", 322_000_000})
-iex> :ets.i(table)
-<1   > {<<"India">>,1284000000}
-<2   > {<<"USA">>,322000000}
-<3   > {<<"China">>,1374000000}
-```
-
-## The math module
-
-[The `math` module](http://www.erlang.org/doc/man/math.html) contains common
-mathematical operations covering trigonometry, exponential, and logarithmic
-functions.
-
-```elixir
-iex> angle_45_deg = :math.pi() * 45.0 / 180.0
-iex> :math.sin(angle_45_deg)
-0.7071067811865475
-iex> :math.exp(55.0)
-7.694785265142018e23
-iex> :math.log(7.694785265142018e23)
-55.0
-```
-
-## The queue module
-
-The [`queue` is a data structure](http://www.erlang.org/doc/man/queue.html)
-that implements (double-ended) FIFO (first-in first-out) queues efficiently:
-
-```elixir
-iex> q = :queue.new
-iex> q = :queue.in("A", q)
-iex> q = :queue.in("B", q)
-iex> {value, q} = :queue.out(q)
-iex> value
-{:value, "A"}
-iex> {value, q} = :queue.out(q)
-iex> value
-{:value, "B"}
-iex> {value, q} = :queue.out(q)
-iex> value
-:empty
-```
-
-## The rand module
-
-[`rand` has functions](http://www.erlang.org/doc/man/rand.html) for returning
-random values and setting the random seed.
-
-```elixir
-iex> :rand.uniform()
-0.8175669086010815
-iex> _ = :rand.seed(:exs1024, {123, 123534, 345345})
-iex> :rand.uniform()
-0.5820506340260994
-iex> :rand.uniform(6)
-6
-```
-
-## The zip and zlib modules
-
-[The `zip` module](http://www.erlang.org/doc/man/zip.html) lets you read and write
-ZIP files to and from disk or memory, as well as extracting file information.
-
-This code counts the number of files in a ZIP file:
-
-```elixir
-iex> :zip.foldl(fn _, _, _, acc -> acc + 1 end, 0, :binary.bin_to_list("file.zip"))
-{:ok, 633}
-```
-
-[The `zlib` module](http://www.erlang.org/doc/man/zlib.html) deals with data compression in zlib format, as found in the
-`gzip` command.
-
-```elixir
-iex> song = "
-...> Mary had a little lamb,
-...> His fleece was white as snow,
-...> And everywhere that Mary went,
-...> The lamb was sure to go."
-iex> compressed = :zlib.compress(song)
-iex> byte_size song
-110
-iex> byte_size compressed
-99
-iex> :zlib.uncompress(compressed)
-"\nMary had a little lamb,\nHis fleece was white as snow,\nAnd everywhere that Mary went,\nThe lamb was sure to go."
-```
-
-Now let's take a look at existing Elixir (and Erlang) libraries you might use while debugging.
\ No newline at end of file
diff --git a/getting-started/index.html b/getting-started/index.html
index a5a74f690..c50365d75 100644
--- a/getting-started/index.html
+++ b/getting-started/index.html
@@ -1,7 +1,5 @@
-<!DOCTYPE html>
-<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
-	<head>
-	  <title>Introduction - Elixir</title>
-    <meta http-equiv="refresh" content="0; url=/getting-started/introduction.html" />
-  </head>
-</html>
+---
+layout: redirect
+sitemap: false
+redirect_to: introduction
+---
diff --git a/getting-started/introduction.markdown b/getting-started/introduction.markdown
index 031c6b7e4..c50365d75 100644
--- a/getting-started/introduction.markdown
+++ b/getting-started/introduction.markdown
@@ -1,64 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Introduction
+layout: redirect
+sitemap: false
+redirect_to: introduction
 ---
-{% assign stable = site.data.elixir-versions[site.data.elixir-versions.stable] %}
-
-Welcome!
-
-In this tutorial, we are going to teach you about Elixir fundamentals - the language syntax, how to define modules, how to manipulate the characteristics of common data structures, and more. This chapter will focus on ensuring that Elixir is installed and that you can successfully run Elixir's Interactive Shell, called IEx.
-
-Our requirements are (see `elixir -v`):
-
-  * Elixir 1.11.0 onwards
-  * Erlang/OTP 22 onwards
-
-Let's get started!
-
-> If you find any errors in the tutorial or on the website, [please report a bug or send a pull request to our issue tracker](https://github.com/elixir-lang/elixir-lang.github.com).
-
-## Installation
-
-If you haven't yet installed Elixir, visit our [installation page](/install.html). Once you are done, you can run `elixir --version` to get the current Elixir version.
-
-## Interactive mode
-
-When you install Elixir, you will have three new executables: `iex`, `elixir` and `elixirc`. If you compiled Elixir from source or are using a packaged version, you can find these inside the `bin` directory.
-
-For now, let's start by running `iex` (or `iex.bat` if you are on Windows PowerShell, where `iex` is a PowerShell command) which stands for Interactive Elixir. In interactive mode, we can type any Elixir expression and get its result. Let's warm up with some basic expressions.
-
-Open up `iex` and type the following expressions:
-
-```elixir
-Erlang/OTP {{ stable.minimum_otp }} [64-bit] [smp:2:2] [...]
-
-Interactive Elixir ({{ stable.version }}) - press Ctrl+C to exit
-iex> 40 + 2
-42
-iex> "hello" <> " world"
-"hello world"
-```
-
-Please note that some details like version numbers may differ a bit in your session; that's not important. From now on `iex` sessions will be stripped down to focus on the code. To exit `iex` press `Ctrl+C` twice.
-
-It seems we are ready to go! We will use the interactive shell quite a lot in the next chapters to get a bit more familiar with the language constructs and basic types, starting in the next chapter.
-
-> Note: if you are on Windows and running on an Erlang/OTP version earlier than 26, you can also try `iex --werl` (`iex.bat --werl` on PowerShell) which may provide a better experience depending on which console you are using.
-
-## Running scripts
-
-After getting familiar with the basics of the language you may want to try writing simple programs. This can be accomplished by putting the following Elixir code into a file:
-
-```elixir
-IO.puts("Hello world from Elixir")
-```
-
-Save it as `simple.exs` and execute it with `elixir`:
-
-```console
-$ elixir simple.exs
-Hello world from Elixir
-```
-
-Later on we will learn how to compile Elixir code (in [Chapter 8](/getting-started/modules-and-functions.html)) and how to use the Mix build tool (in the [Mix & OTP guide](/getting-started/mix-otp/introduction-to-mix.html)). For now, let's move on to [Chapter 2](/getting-started/basic-types.html).
diff --git a/getting-started/io-and-the-file-system.markdown b/getting-started/io-and-the-file-system.markdown
index 3a02f35f2..17a6e7bef 100644
--- a/getting-started/io-and-the-file-system.markdown
+++ b/getting-started/io-and-the-file-system.markdown
@@ -1,223 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: IO and the file system
+layout: redirect
+sitemap: false
+redirect_to: io-and-the-file-system
 ---
-
-This chapter is an introduction to input/output mechanisms, file-system-related tasks, and related modules such as [`IO`](https://hexdocs.pm/elixir/IO.html), [`File`](https://hexdocs.pm/elixir/File.html), and [`Path`](https://hexdocs.pm/elixir/Path.html). The IO system provides a great opportunity to shed some light on some philosophies and curiosities of Elixir and the VM.
-
-## The `IO` module
-
-The [`IO`](https://hexdocs.pm/elixir/IO.html) module is the main mechanism in Elixir for reading and writing to standard input/output (`:stdio`), standard error (`:stderr`), files, and other IO devices. Usage of the module is pretty straightforward:
-
-```elixir
-iex> IO.puts("hello world")
-hello world
-:ok
-iex> IO.gets("yes or no? ")
-yes or no? yes
-"yes\n"
-```
-
-By default, functions in the `IO` module read from the standard input and write to the standard output. We can change that by passing, for example, `:stderr` as an argument (in order to write to the standard error device):
-
-```elixir
-iex> IO.puts(:stderr, "hello world")
-hello world
-:ok
-```
-
-## The `File` module
-
-The [`File`](https://hexdocs.pm/elixir/File.html) module contains functions that allow us to open files as IO devices. By default, files are opened in binary mode, which requires developers to use the specific `IO.binread/2` and `IO.binwrite/2` functions from the `IO` module:
-
-```elixir
-iex> {:ok, file} = File.open("path/to/file/hello", [:write])
-{:ok, #PID<0.47.0>}
-iex> IO.binwrite(file, "world")
-:ok
-iex> File.close(file)
-:ok
-iex> File.read("path/to/file/hello")
-{:ok, "world"}
-```
-
-A file can also be opened with `:utf8` encoding, which tells the `File` module to interpret the bytes read from the file as UTF-8-encoded bytes.
-
-Besides functions for opening, reading and writing files, the `File` module has many functions to work with the file system. Those functions are named after their UNIX equivalents. For example, `File.rm/1` can be used to remove files, `File.mkdir/1` to create directories, `File.mkdir_p/1` to create directories and all their parent chain. There are even `File.cp_r/2` and `File.rm_rf/1` to respectively copy and remove files and directories recursively (i.e., copying and removing the contents of the directories too).
-
-You will also notice that functions in the `File` module have two variants: one "regular" variant and another variant with a trailing bang (`!`). For example, when we read the `"hello"` file in the example above, we use `File.read/1`. Alternatively, we can use `File.read!/1`:
-
-```elixir
-iex> File.read("path/to/file/hello")
-{:ok, "world"}
-iex> File.read!("path/to/file/hello")
-"world"
-iex> File.read("path/to/file/unknown")
-{:error, :enoent}
-iex> File.read!("path/to/file/unknown")
-** (File.Error) could not read file "path/to/file/unknown": no such file or directory
-```
-
-Notice that the version with `!` returns the contents of the file instead of a tuple, and if anything goes wrong the function raises an error.
-
-The version without `!` is preferred when you want to handle different outcomes using pattern matching:
-
-```elixir
-case File.read("path/to/file/hello") do
-  {:ok, body} -> # do something with the `body`
-  {:error, reason} -> # handle the error caused by `reason`
-end
-```
-
-However, if you expect the file to be there, the bang variation is more useful as it raises a meaningful error message. Avoid writing:
-
-```elixir
-{:ok, body} = File.read("path/to/file/unknown")
-```
-
-as, in case of an error, `File.read/1` will return `{:error, reason}` and the pattern matching will fail. You will still get the desired result (a raised error), but the message will be about the pattern which doesn't match (thus being cryptic in respect to what the error actually is about).
-
-Therefore, if you don't want to handle the error outcomes, prefer to use the functions ending with an exclamation mark, such as `File.read!/1`.
-
-## The `Path` module
-
-The majority of the functions in the `File` module expect paths as arguments. Most commonly, those paths will be regular binaries. The [`Path`](https://hexdocs.pm/elixir/Path.html) module provides facilities for working with such paths:
-
-```elixir
-iex> Path.join("foo", "bar")
-"foo/bar"
-iex> Path.expand("~/hello")
-"/Users/jose/hello"
-```
-
-Using functions from the `Path` module as opposed to directly manipulating strings is preferred since the `Path` module takes care of different operating systems transparently. Finally, keep in mind that Elixir will automatically convert slashes (`/`) into backslashes (`\`) on Windows when performing file operations.
-
-With this, we have covered the main modules that Elixir provides for dealing with IO and interacting with the file system. In the next section, we will peek a bit under the covers and learn how the IO system is implemented in the <abbr title="Virtual Machine">VM</abbr>.
-
-## Processes
-
-You may have noticed that `File.open/2` returns a tuple like `{:ok, pid}`:
-
-```elixir
-iex> {:ok, file} = File.open("hello", [:write])
-{:ok, #PID<0.47.0>}
-```
-
-This happens because the `IO` module actually works with processes (see [chapter 11](/getting-started/processes.html)). Given a file is a process, when you write to a file that has been closed, you are actually sending a message to a process which has been terminated:
-
-```elixir
-iex> File.close(file)
-:ok
-iex> IO.write(file, "is anybody out there")
-** (ErlangError) Erlang error: :terminated:
-
-  * 1st argument: the device has terminated
-
-    (stdlib 5.0) io.erl:94: :io.put_chars(#PID<0.114.0>, "is anybody out there")
-    iex:4: (file)
-```
-
-Let's see in more detail what happens when you request `IO.write(pid, binary)`. The `IO` module sends a message to the process identified by `pid` with the desired operation. A small ad-hoc process can help us see it:
-
-```elixir
-iex> pid = spawn(fn ->
-...>  receive do: (msg -> IO.inspect msg)
-...> end)
-#PID<0.57.0>
-iex> IO.write(pid, "hello")
-{:io_request, #PID<0.41.0>, #Reference<0.0.8.91>,
- {:put_chars, :unicode, "hello"}}
-** (ErlangError) erlang error: :terminated
-```
-
-After `IO.write/2`, we can see the request sent by the `IO` module printed out (a four-elements tuple). Soon after that, we see that it fails since the `IO` module expected some kind of result, which we did not supply.
-
-By modeling IO devices with processes, the Erlang <abbr title="Virtual Machine">VM</abbr> allows IO messages to be routed between different nodes running Distributed Erlang or even exchange files to perform read/write operations across nodes. Neat!
-
-## `iodata` and `chardata`
-
-In all of the examples above, we used binaries when writing to files. However, most of the IO functions in Elixir also accept either "iodata" or "chardata".
-
-One of the main reasons for using "iodata" and "chardata" is for performance. For example,
-imagine you need to greet someone in your application:
-
-```elixir
-name = "Mary"
-IO.puts("Hello " <> name <> "!")
-```
-
-Given strings in Elixir are immutable, as most data structures, the example above will copy the string "Mary" into the new "Hello Mary!" string. While this is unlikely to matter for the short string as above, copying can be quite expensive for large strings! For this reason, the IO functions in Elixir allow you to pass instead a list of strings:
-
-```elixir
-name = "Mary"
-IO.puts(["Hello ", name, "!"])
-```
-
-In the example above, there is no copying. Instead we create a list that contains the original name. We call such lists either "iodata" or "chardata" and we will learn the precise difference between them soon.
-
-Those lists are very useful because it can actually simplify the processing strings in several scenarios. For example, imagine you have a list of values, such as `["apple", "banana", "lemon"]` that you want to write to disk separated by commas. How can you achieve this?
-
-One option is to use `Enum.join/2` and convert the values to a string:
-
-```elixir
-iex> Enum.join(["apple", "banana", "lemon"], ",")
-"apple,banana,lemon"
-```
-
-The above returns a new string by copying each value into the new string. However, with the knowledge in this section, we know that we can pass a list of strings to the IO/File functions. So instead we can do:
-
-```elixir
-iex> Enum.intersperse(["apple", "banana", "lemon"], ",")
-["apple", ",", "banana", ",", "lemon"]
-```
-
-"iodata" and "chardata" do not only contain strings, but they may contain arbitrary nested lists of strings too:
-
-```elixir
-iex> IO.puts(["apple", [",", "banana", [",", "lemon"]]])
-```
-
-"iodata" and "chardata" may also contain integers. For example, we could print our comma separated list of values by using `?,` as separator, which is the integer representing a comma (`44`):
-
-```elixir
-iex> IO.puts(["apple", ?,, "banana", ?,, "lemon"])
-```
-
-The difference between "iodata" and "chardata" is precisely what said integer represents. For iodata, the integers represent bytes. For chardata, the integers represent Unicode codepoints. For ASCII characters, the byte representation is the same as the codepoint representation, so it fits both classifications. However, the default IO device works with chardata, which means we can do:
-
-```elixir
-iex> IO.puts([?O, ?l, ?á, ?\s, "Mary", ?!])
-```
-
-Overall, integers in a list may represent either a bunch of bytes or a bunch of characters and which one to use depends on the encoding of the IO device. If the file is opened without encoding, the file is expected to be in raw mode, and the functions in the `IO` module starting with `bin*` must be used. Those functions expect an `iodata` as an argument, where integers in the list would represent bytes.
-
-On the other hand, the default IO device (`:stdio`) and files opened with `:utf8` encoding work with the remaining functions in the `IO` module. Those functions expect a `chardata` as an argument, where integers represent codepoints.
-
-Although this is a subtle difference, you only need to worry about these details if you intend to pass lists containing integers to those functions. If you pass binaries, or list of binaries, then there is no ambiguity.
-
-Finally, there is one last construct called charlist, which is a special case of chardata where we have a list in which all of its values are integers representing Unicode codepoints. They can be created with the `~c` sigil:
-
-```elixir
-iex> ~c"hello"
-~c"hello"
-```
-
-> Note: the above is printed as 'hello' in Elixir v1.14 and earlier, which is the deprecated syntax for charlists.
-
-They mostly show up when interfacing with Erlang, as some Erlang APIs use charlist as their representation for strings. For this reason, any list containing printable ASCII codepoints will be printed as a charlist:
-
-```elixir
-iex> [?a, ?b, ?c]
-~c"abc"
-```
-
-We packed a lot into this small section, so let's break it down:
-
-  * iodata and chardata are lists of binaries and integers. Those binaries and integers can be arbitrarily nested inside lists. Their goal is to give flexibility and performance when working with IO devices and files
-
-  * the choice between iodata and chardata depends on the encoding of the IO device. If the file is opened without encoding, the file expects iodata, and the functions in the `IO` module starting with `bin*` must be used. The default IO device (`:stdio`) and files opened with `:utf8` encoding expect chardata and work with the remaining functions in the `IO` module
-
-  * charlists are a special case of chardata, where it exclusively uses a list of integers Unicode codepoints. They can be created with the `~c` sigil. Lists of integers are automatically printed using the `~c` sigil if all integers in a list represent printable ASCII codepoints.
-
-This finishes our tour of IO devices and IO related functionality. We have learned about three Elixir modules - [`IO`](https://hexdocs.pm/elixir/IO.html), [`File`](https://hexdocs.pm/elixir/File.html), and [`Path`](https://hexdocs.pm/elixir/Path.html) - as well as how the <abbr title="Virtual Machine">VM</abbr> uses processes for the underlying IO mechanisms and how to use `chardata` and `iodata` for IO operations.
diff --git a/getting-started/keywords-and-maps.markdown b/getting-started/keywords-and-maps.markdown
index c41d7d16f..a7430b486 100644
--- a/getting-started/keywords-and-maps.markdown
+++ b/getting-started/keywords-and-maps.markdown
@@ -1,272 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Keyword lists and maps
-redirect_from: /getting-started/maps-and-dicts.html
+layout: redirect
+sitemap: false
+redirect_to: keywords-and-maps
 ---
-
-Now let's talk about associative data structures. Associative data structures are able to associate a key to a certain value. Different languages call these different names like dictionaries, hashes, associative arrays, etc.
-
-In Elixir, we have two main associative data structures: keyword lists and maps. It's time to learn more about them!
-
-## Keyword lists
-
-Keyword lists are a data-structure used to pass options to functions. Imagine you want to split a string of numbers. We can use `String.split/2`:
-
-```elixir
-iex> String.split("1 2 3", " ")
-["1", "2", "3"]
-```
-
-However, what happens if there is an additional space between the numbers:
-
-```elixir
-iex> String.split("1  2  3", " ")
-["1", "", "2", "", "3"]
-```
-
-As you can see, there are now empty strings in our results. Luckily, the `String.split/3` function allows the `trim` option to be set to true:
-
-```elixir
-iex> String.split("1  2  3", " ", [trim: true])
-["1", "2", "3"]
-```
-
-`[trim: true]` is a keyword list. Furthermore, when a keyword list is the last argument of a function, we can skip the brackets and write:
-
-```elixir
-iex> String.split("1  2  3", " ", trim: true)
-["1", "2", "3"]
-```
-
-As the name implies, keyword lists are simply lists. In particular, they are lists consisting of 2-item tuples where the first element (the key) is an atom and the second element can be any value. Both representations are the same:
-
-```elixir
-iex> [{:trim, true}] == [trim: true]
-true
-```
-
-Since keyword lists are lists, we can use all operations available to lists. For example, we can use `++` to add new values to a keyword list:
-
-```elixir
-iex> list = [a: 1, b: 2]
-[a: 1, b: 2]
-iex> list ++ [c: 3]
-[a: 1, b: 2, c: 3]
-iex> [a: 0] ++ list
-[a: 0, a: 1, b: 2]
-```
-
-You can read the value of a keyword list using the brackets syntax:
-
-```elixir
-iex> list[:a]
-1
-iex> list[:b]
-2
-```
-
-In case of duplicate keys, values added to the front are the ones fetched:
-
-```elixir
-iex> new_list = [a: 0] ++ list
-[a: 0, a: 1, b: 2]
-iex> new_list[:a]
-0
-```
-
-Keyword lists are important because they have three special characteristics:
-
-  * Keys must be atoms.
-  * Keys are ordered, as specified by the developer.
-  * Keys can be given more than once.
-
-For example, [the Ecto library](https://github.com/elixir-lang/ecto) makes use of these features to provide an elegant DSL for writing database queries:
-
-```elixir
-query =
-  from w in Weather,
-    where: w.prcp > 0,
-    where: w.temp < 20,
-    select: w
-```
-
-Although we can pattern match on keyword lists, it is rarely done in practice since pattern matching on lists requires the number of items and their order to match:
-
-```elixir
-iex> [a: a] = [a: 1]
-[a: 1]
-iex> a
-1
-iex> [a: a] = [a: 1, b: 2]
-** (MatchError) no match of right hand side value: [a: 1, b: 2]
-iex> [b: b, a: a] = [a: 1, b: 2]
-** (MatchError) no match of right hand side value: [a: 1, b: 2]
-```
-
-In order to manipulate keyword lists, Elixir provides [the `Keyword` module](https://hexdocs.pm/elixir/Keyword.html). Remember, though, keyword lists are simply lists, and as such they provide the same linear performance characteristics as them: the longer the list, the longer it will take to find a key, to count the number of items, and so on. For this reason, keyword lists are used in Elixir mainly for passing optional values. If you need to store many items or guarantee one-key associates with at maximum one-value, you should use maps instead.
-
-### `do`-blocks and keywords
-
-As we have seen, keywords are mostly used in the language to pass optional values. In fact, we have used keywords before in this guide. For example, we have seen:
-
-```elixir
-iex> if true do
-...>   "This will be seen"
-...> else
-...>   "This won't"
-...> end
-"This will be seen"
-```
-
-It happens that `do` blocks are nothing more than a syntax convenience on top of keywords. We can rewrite the above to:
-
-```elixir
-iex> if true, do: "This will be seen", else: "This won't"
-"This will be seen"
-```
-
-Pay close attention to both syntaxes. In the keyword list format, we separate each key-value pair with commas, and each key is followed by `:`. In the `do`-blocks, we get rid of the colons, the commas, and separate each keyword by a newline. They are useful exactly because they remove the verbosity when writing blocks of code. Most of the time, you will use the block syntax, but it is good to know they are equivalent.
-
-Note that only a handful of keyword lists can be converted to blocks: `do`, `else`, `catch`, `rescue`, and `after`. Those are all the keywords used by Elixir control-flow constructs. We have already learned some of them and we will learn others in the future.
-
-With this out of the way, let's see how we can work with nested data structures.
-
-## Maps as key-value pairs
-
-Whenever you need to store key-value pairs, maps are the "go to" data structure in Elixir. A map is created using the `%{}` syntax:
-
-```elixir
-iex> map = %{:a => 1, 2 => :b}
-%{2 => :b, :a => 1}
-iex> map[:a]
-1
-iex> map[2]
-:b
-iex> map[:c]
-nil
-```
-
-Compared to keyword lists, we can already see two differences:
-
-  * Maps allow any value as a key.
-  * Maps' keys do not follow any ordering.
-
-In contrast to keyword lists, maps are very useful with pattern matching. When a map is used in a pattern, it will always match on a subset of the given value:
-
-```elixir
-iex> %{} = %{:a => 1, 2 => :b}
-%{2 => :b, :a => 1}
-iex> %{:a => a} = %{:a => 1, 2 => :b}
-%{2 => :b, :a => 1}
-iex> a
-1
-iex> %{:c => c} = %{:a => 1, 2 => :b}
-** (MatchError) no match of right hand side value: %{2 => :b, :a => 1}
-```
-
-As shown above, a map matches as long as the keys in the pattern exist in the given map. Therefore, an empty map matches all maps.
-
-[The `Map` module](https://hexdocs.pm/elixir/Map.html) provides a very similar API to the `Keyword` module with convenience functions to add, remove, and update maps keys:
-
-```elixir
-iex> Map.get(%{:a => 1, 2 => :b}, :a)
-1
-iex> Map.put(%{:a => 1, 2 => :b}, :c, 3)
-%{2 => :b, :a => 1, :c => 3}
-iex> Map.to_list(%{:a => 1, 2 => :b})
-[{2, :b}, {:a, 1}]
-```
-
-## Maps of fixed keys
-
-In the previous section, we have used maps as a key-value data structure where keys can be added or removed at any time. However, it is also common to create maps with a pre-defined set of keys. Their values may be updated, but new keys are never added nor removed. This is useful when we know the shape of the data we are working with and, if we get a different key, it likely means a mistake
-was done elsewhere.
-
-We define such maps using the same syntax as in the previous section, except
-that all keys must be atoms:
-
-```elixir
-iex> map = %{:name => "John", :age => 23}
-%{name: "John", age: 23}
-```
-
-As you can see from the printed result above, Elixir also allows you to
-write maps of atom keys using the same `key: value` syntax as keyword lists.
-
-When the keys are atoms, we can also access them using the `map.key`
-syntax:
-
-```elixir
-iex> map = %{name: "John", age: 23}
-%{name: "John", age: 23}
-
-iex> map.name
-"John"
-iex> map.agee
-** (KeyError) key :agee not found in: %{name: "John", age: 23}
-```
-
-This syntax has one large benefit in that it raises an exception if the key does not exist in the map. Sometimes the Elixir compiler may even warn too. This makes it useful to get quick feedback and spot bugs and typos early on. This is also
-the syntax used to power another Elixir feature called "Structs".
-
-Elixir developers typically prefer to use the `map.key` syntax and pattern matching instead of the functions in the `Map` module when working with maps because they lead to an assertive style of programming. [This blog post by José Valim](https://dashbit.co/blog/writing-assertive-code-with-elixir) provides insight and examples on how you get more concise and faster software by writing assertive code in Elixir.
-
-## Nested data structures
-
-Often we will have maps inside maps, or even keywords lists inside maps, and so forth. Elixir provides conveniences for manipulating nested data structures via the `put_in/2`, `update_in/2` and other macros giving the same conveniences you would find in imperative languages while keeping the immutable properties of the language.
-
-Imagine you have the following structure:
-
-```elixir
-iex> users = [
-  john: %{name: "John", age: 27, languages: ["Erlang", "Ruby", "Elixir"]},
-  mary: %{name: "Mary", age: 29, languages: ["Elixir", "F#", "Clojure"]}
-]
-[
-  john: %{age: 27, languages: ["Erlang", "Ruby", "Elixir"], name: "John"},
-  mary: %{age: 29, languages: ["Elixir", "F#", "Clojure"], name: "Mary"}
-]
-```
-
-We have a keyword list of users where each value is a map containing the name, age and a list of programming languages each user likes. If we wanted to access the age for john, we could write:
-
-```elixir
-iex> users[:john].age
-27
-```
-
-It happens we can also use this same syntax for updating the value:
-
-```elixir
-iex> users = put_in users[:john].age, 31
-[
-  john: %{age: 31, languages: ["Erlang", "Ruby", "Elixir"], name: "John"},
-  mary: %{age: 29, languages: ["Elixir", "F#", "Clojure"], name: "Mary"}
-]
-```
-
-The `update_in/2` macro is similar but allows us to pass a function that controls how the value changes. For example, let's remove "Clojure" from Mary's list of languages:
-
-```elixir
-iex> users = update_in users[:mary].languages, fn languages -> List.delete(languages, "Clojure") end
-[
-  john: %{age: 31, languages: ["Erlang", "Ruby", "Elixir"], name: "John"},
-  mary: %{age: 29, languages: ["Elixir", "F#"], name: "Mary"}
-]
-```
-
-There is more to learn about `put_in/2` and `update_in/2`, including the `get_and_update_in/2` that allows us to extract a value and update the data structure at once. There are also `put_in/3`, `update_in/3` and `get_and_update_in/3` which allow dynamic access into the data structure. [Check their respective documentation in the `Kernel` module for more information](https://hexdocs.pm/elixir/Kernel.html). Between the Access
-module and pattern matching, Elixir developers have a rich set of tools
-for manipulating nested and complex data structures.
-
-## Summary
-
-This concludes our introduction to associative data structures in Elixir.
-As a summary, you should:
-
-  * Use keyword lists for passing optional values to functions
-
-  * Use maps for general key-value data structures and when working with known data (with fixed keys)
-
-Now we can move on to talk about modules and functions.
diff --git a/getting-started/meta/domain-specific-languages.markdown b/getting-started/meta/domain-specific-languages.markdown
index ba4f9ac22..96c2c5f2b 100644
--- a/getting-started/meta/domain-specific-languages.markdown
+++ b/getting-started/meta/domain-specific-languages.markdown
@@ -1,204 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Domain-specific languages
-category: Meta-programming in Elixir
+layout: redirect
+sitemap: false
+redirect_to: domain-specific-languages
 ---
-
-## Foreword
-
-[Domain-specific languages (DSL)](https://en.wikipedia.org/wiki/Domain-specific_language) allow developers to tailor their application to a particular domain. You don't need macros in order to have a DSL: every data structure and every function you define in your module is part of your Domain-specific language.
-
-For example, imagine we want to implement a Validator module which provides a data validation domain-specific language. We could implement it using data structures, functions or macros. Let's see what those different DSLs would look like:
-
-```elixir
-# 1. data structures
-import Validator
-validate user, name: [length: 1..100],
-               email: [matches: ~r/@/]
-
-# 2. functions
-import Validator
-user
-|> validate_length(:name, 1..100)
-|> validate_matches(:email, ~r/@/)
-
-# 3. macros + modules
-defmodule MyValidator do
-  use Validator
-  validate_length :name, 1..100
-  validate_matches :email, ~r/@/
-end
-
-MyValidator.validate(user)
-```
-
-Of all the approaches above, the first is definitely the most flexible. If our domain rules can be encoded with data structures, they are by far the easiest to compose and implement, as Elixir's standard library is filled with functions for manipulating different data types.
-
-The second approach uses function calls which better suits more complex APIs (for example, if you need to pass many options) and reads nicely in Elixir thanks to the pipe operator.
-
-The third approach uses macros, and is by far the most complex. It will take more lines of code to implement, it is hard and expensive to test (compared to testing simple functions), and it limits how the user may use the library since all validations need to be defined inside a module.
-
-To drive the point home, imagine you want to validate a certain attribute only if a given condition is met. We could easily achieve it with the first solution, by manipulating the data structure accordingly, or with the second solution by using conditionals (if/else) before invoking the function. However, it is impossible to do so with the macros approach unless its DSL is augmented.
-
-In other words:
-
-    data > functions > macros
-
-That said, there are still cases where using macros and modules to build domain-specific languages is useful. Since we have explored data structures and function definitions in the Getting Started guide, this chapter will explore how to use macros and module attributes to tackle more complex DSLs.
-
-## Building our own test case
-
-The goal in this chapter is to build a module named `TestCase` that allows us to write the following:
-
-```elixir
-defmodule MyTest do
-  use TestCase
-
-  test "arithmetic operations" do
-    4 = 2 + 2
-  end
-
-  test "list operations" do
-    [1, 2, 3] = [1, 2] ++ [3]
-  end
-end
-
-MyTest.run
-```
-
-In the example above, by using `TestCase`, we can write tests using the `test` macro, which defines a function named `run` to automatically run all tests for us. Our prototype will rely on the match operator (`=`) as a mechanism to do assertions.
-
-## The `test` macro
-
-Let's start by creating a module that defines and imports the `test` macro when used:
-
-```elixir
-defmodule TestCase do
-  # Callback invoked by `use`.
-  #
-  # For now it returns a quoted expression that
-  # imports the module itself into the user code.
-  @doc false
-  defmacro __using__(_opts) do
-    quote do
-      import TestCase
-    end
-  end
-
-  @doc """
-  Defines a test case with the given description.
-
-  ## Examples
-
-      test "arithmetic operations" do
-        4 = 2 + 2
-      end
-
-  """
-  defmacro test(description, do: block) do
-    function_name = String.to_atom("test " <> description)
-    quote do
-      def unquote(function_name)(), do: unquote(block)
-    end
-  end
-end
-```
-
-Assuming we defined `TestCase` in a file named `tests.exs`, we can open it up by running `iex tests.exs` and define our first tests:
-
-```elixir
-iex> defmodule MyTest do
-...>   use TestCase
-...>
-...>   test "hello" do
-...>     "hello" = "world"
-...>   end
-...> end
-```
-
-For now, we don't have a mechanism to run tests, but we know that a function named "test hello" was defined behind the scenes. When we invoke it, it should fail:
-
-```elixir
-iex> MyTest."test hello"()
-** (MatchError) no match of right hand side value: "world"
-```
-
-## Storing information with attributes
-
-In order to finish our `TestCase` implementation, we need to be able to access all defined test cases. One way of doing this is by retrieving the tests at runtime via `__MODULE__.__info__(:functions)`, which returns a list of all functions in a given module. However, considering that we may want to store more information about each test besides the test name, a more flexible approach is required.
-
-When discussing module attributes in earlier chapters, we mentioned how they can be used as temporary storage. That's exactly the property we will apply in this section.
-
-In the `__using__/1` implementation, we will initialize a module attribute named `@tests` to an empty list, then store the name of each defined test in this attribute so the tests can be invoked from the `run` function.
-
-Here is the updated code for the `TestCase` module:
-
-```elixir
-defmodule TestCase do
-  @doc false
-  defmacro __using__(_opts) do
-    quote do
-      import TestCase
-
-      # Initialize @tests to an empty list
-      @tests []
-
-      # Invoke TestCase.__before_compile__/1 before the module is compiled
-      @before_compile TestCase
-    end
-  end
-
-  @doc """
-  Defines a test case with the given description.
-
-  ## Examples
-
-      test "arithmetic operations" do
-        4 = 2 + 2
-      end
-
-  """
-  defmacro test(description, do: block) do
-    function_name = String.to_atom("test " <> description)
-    quote do
-      # Prepend the newly defined test to the list of tests
-      @tests [unquote(function_name) | @tests]
-      def unquote(function_name)(), do: unquote(block)
-    end
-  end
-
-  # This will be invoked right before the target module is compiled
-  # giving us the perfect opportunity to inject the `run/0` function
-  @doc false
-  defmacro __before_compile__(_env) do
-    quote do
-      def run do
-        Enum.each @tests, fn name ->
-          IO.puts "Running #{name}"
-          apply(__MODULE__, name, [])
-        end
-      end
-    end
-  end
-end
-```
-
-By starting a new IEx session, we can now define our tests and run them:
-
-```elixir
-iex> defmodule MyTest do
-...>   use TestCase
-...>
-...>   test "hello" do
-...>     "hello" = "world"
-...>   end
-...> end
-iex> MyTest.run
-Running test hello
-** (MatchError) no match of right hand side value: "world"
-```
-
-Although we have overlooked some details, this is the main idea behind creating domain-specific modules in Elixir. Macros enable us to return quoted expressions that are executed in the caller, which we can then use to transform code and store relevant information in the target module via module attributes. Finally, callbacks such as `@before_compile` allow us to inject code into the module when its definition is complete.
-
-Besides `@before_compile`, there are other useful module attributes like `@on_definition` and `@after_compile`, which you can read more about in [the docs for the `Module` module](https://hexdocs.pm/elixir/Module.html). You can also find useful information about macros and the compilation environment in the documentation for the [`Macro` module](https://hexdocs.pm/elixir/Macro.html) and [`Macro.Env`](https://hexdocs.pm/elixir/Macro.Env.html).
diff --git a/getting-started/meta/index.html b/getting-started/meta/index.html
index 262b2e711..70c16019b 100644
--- a/getting-started/meta/index.html
+++ b/getting-started/meta/index.html
@@ -1,7 +1,5 @@
-<!DOCTYPE html>
-<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
-	<head>
-	  <title>Quote and unquote - Elixir</title>
-    <meta http-equiv="refresh" content="0; url=/getting-started/meta/quote-and-unquote.html" />
-  </head>
-</html>
+---
+layout: redirect
+sitemap: false
+redirect_to: quote-and-unquote
+---
diff --git a/getting-started/meta/macros.markdown b/getting-started/meta/macros.markdown
index b522df71d..349aee294 100644
--- a/getting-started/meta/macros.markdown
+++ b/getting-started/meta/macros.markdown
@@ -1,295 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Macros
-category: Meta-programming in Elixir
+layout: redirect
+sitemap: false
+redirect_to: macros
 ---
-
-## Foreword
-
-Even though Elixir attempts its best to provide a safe environment for macros, the major responsibility of writing clean code with macros falls on developers. Macros are harder to write than ordinary Elixir functions and it's considered to be bad style to use them when they're not necessary. So write macros responsibly.
-
-Elixir already provides mechanisms to write your everyday code in a simple and readable fashion by using its data structures and functions. Macros should only be used as a last resort. Remember that **explicit is better than implicit**. **Clear code is better than concise code.**
-
-## Our first macro
-
-Macros in Elixir are defined via `defmacro/2`.
-
-> For this chapter, we will be using files instead of running code samples in IEx. That's because the code samples will span multiple lines of code and typing them all in IEx can be counter-productive. You should be able to run the code samples by saving them into a `macros.exs` file and running it with `elixir macros.exs` or `iex macros.exs`.
-
-In order to better understand how macros work, let's create a new module where we are going to implement `unless`, which does the opposite of `if`, as a macro and as a function:
-
-```elixir
-defmodule Unless do
-  def fun_unless(clause, do: expression) do
-    if(!clause, do: expression)
-  end
-
-  defmacro macro_unless(clause, do: expression) do
-    quote do
-      if(!unquote(clause), do: unquote(expression))
-    end
-  end
-end
-```
-
-The function receives the arguments and passes them to `if`. However, as we learned in the [previous chapter](/getting-started/meta/quote-and-unquote.html), the macro will receive quoted expressions, inject them into the quote, and finally return another quoted expression.
-
-Let's start `iex` with the module above:
-
-```console
-$ iex macros.exs
-```
-
-And play with those definitions:
-
-```elixir
-iex> require Unless
-iex> Unless.macro_unless true, do: IO.puts "this should never be printed"
-nil
-iex> Unless.fun_unless true, do: IO.puts "this should never be printed"
-"this should never be printed"
-nil
-```
-
-Note that in our macro implementation, the sentence was not printed, although it was printed in our function implementation. That's because the arguments to a function call are evaluated before calling the function. However, macros do not evaluate their arguments. Instead, they receive the arguments as quoted expressions which are then transformed into other quoted expressions. In this case, we have rewritten our `unless` macro to become an `if` behind the scenes.
-
-In other words, when invoked as:
-
-```elixir
-Unless.macro_unless true, do: IO.puts "this should never be printed"
-```
-
-Our `macro_unless` macro received the following:
-
-{% raw %}
-```elixir
-macro_unless(true, [do: {{:., [], [{:__aliases__, [alias: false], [:IO]}, :puts]}, [], ["this should never be printed"]}])
-```
-{% endraw %}
-
-And it then returned a quoted expression as follows:
-
-{% raw %}
-```elixir
-{:if, [],
- [{:!, [], [true]},
-  [do: {{:., [],
-     [{:__aliases__,
-       [], [:IO]},
-      :puts]}, [], ["this should never be printed"]}]]}
-```
-{% endraw %}
-
-We can actually verify that this is the case by using `Macro.expand_once/2`:
-
-```elixir
-iex> expr = quote do: Unless.macro_unless(true, do: IO.puts "this should never be printed")
-iex> res  = Macro.expand_once(expr, __ENV__)
-iex> IO.puts Macro.to_string(res)
-if(!true) do
-  IO.puts("this should never be printed")
-end
-:ok
-```
-
-`Macro.expand_once/2` receives a quoted expression and expands it according to the current environment. In this case, it expanded/invoked the `Unless.macro_unless/2` macro and returned its result. We then proceeded to convert the returned quoted expression to a string and print it (we will talk about `__ENV__` later in this chapter).
-
-That's what macros are all about. They are about receiving quoted expressions and transforming them into something else. In fact, `unless/2` in Elixir is implemented as a macro:
-
-```elixir
-defmacro unless(clause, do: expression) do
-  quote do
-    if(!unquote(clause), do: unquote(expression))
-  end
-end
-```
-
-Constructs such as `unless/2`, `defmacro/2`, `def/2`, `defprotocol/2`, and many others used throughout this getting started guide are implemented in pure Elixir, often as a macro. This means that the constructs being used to build the language can be used by developers to extend the language to the domains they are working on.
-
-We can define any function and macro we want, including ones that override the built-in definitions provided by Elixir. The only exceptions are Elixir special forms which are not implemented in Elixir and therefore cannot be overridden, [the full list of special forms is available in `Kernel.SpecialForms`](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#summary).
-
-## Macro hygiene
-
-Elixir macros have late resolution. This guarantees that a variable defined inside a quote won't conflict with a variable defined in the context where that macro is expanded. For example:
-
-```elixir
-defmodule Hygiene do
-  defmacro no_interference do
-    quote do: a = 1
-  end
-end
-
-defmodule HygieneTest do
-  def go do
-    require Hygiene
-    a = 13
-    Hygiene.no_interference()
-    a
-  end
-end
-
-HygieneTest.go
-# => 13
-```
-
-In the example above, even though the macro injects `a = 1`, it does not affect the variable `a` defined by the `go` function. If a macro wants to explicitly affect the context, it can use `var!`:
-
-```elixir
-defmodule Hygiene do
-  defmacro interference do
-    quote do: var!(a) = 1
-  end
-end
-
-defmodule HygieneTest do
-  def go do
-    require Hygiene
-    a = 13
-    Hygiene.interference()
-    a
-  end
-end
-
-HygieneTest.go
-# => 1
-```
-
-The code above will work but issue a warning: `variable "a" is unused`. The macro is overriding the original value and the original value is never used.
-
-Variable hygiene only works because Elixir annotates variables with their context. For example, a variable `x` defined on line 3 of a module would be represented as:
-
-```elixir
-{:x, [line: 3], nil}
-```
-
-However, a quoted variable is represented as:
-
-```elixir
-defmodule Sample do
-  def quoted do
-    quote do: x
-  end
-end
-
-Sample.quoted() #=> {:x, [line: 3], Sample}
-```
-
-Notice that the third element in the quoted variable is the atom `Sample`, instead of `nil`, which marks the variable as coming from the `Sample` module. Therefore, Elixir considers these two variables as coming from different contexts and handles them accordingly.
-
-Elixir provides similar mechanisms for imports and aliases too. This guarantees that a macro will behave as specified by its source module rather than conflicting with the target module where the macro is expanded. Hygiene can be bypassed under specific situations by using macros like `var!/2` and `alias!/1`, although one must be careful when using those as they directly change the user environment.
-
-Sometimes variable names might be dynamically created. In such cases, `Macro.var/2` can be used to define new variables:
-
-```elixir
-defmodule Sample do
-  defmacro initialize_to_char_count(variables) do
-    Enum.map(variables, fn name ->
-      var = Macro.var(name, nil)
-      length = name |> Atom.to_string |> String.length
-
-      quote do
-        unquote(var) = unquote(length)
-      end
-    end)
-  end
-
-  def run do
-    initialize_to_char_count [:red, :green, :yellow]
-    [red, green, yellow]
-  end
-end
-
-> Sample.run #=> [3, 5, 6]
-```
-
-Take note of the second argument to `Macro.var/2`. This is the context being used and will determine hygiene as described in the next section.
-
-## The environment
-
-When calling `Macro.expand_once/2` earlier in this chapter, we used the special form `__ENV__`.
-
-`__ENV__` returns an instance of the `Macro.Env` struct which contains useful information about the compilation environment, including the current module, file, and line, all variables defined in the current scope, as well as imports, requires and so on:
-
-```elixir
-iex> __ENV__.module
-nil
-iex> __ENV__.file
-"iex"
-iex> __ENV__.requires
-[IEx.Helpers, Kernel, Kernel.Typespec]
-iex> require Integer
-nil
-iex> __ENV__.requires
-[IEx.Helpers, Integer, Kernel, Kernel.Typespec]
-```
-
-Many of the functions in the `Macro` module expect an environment. You can read more about these functions in [the docs for the `Macro` module](https://hexdocs.pm/elixir/Macro.html) and learn more about the compilation environment in the [docs for `Macro.Env`](https://hexdocs.pm/elixir/Macro.Env.html).
-
-## Private macros
-
-Elixir also supports private macros via `defmacrop`. As private functions, these macros are only available inside the module that defines them, and only at compilation time.
-
-It is important that a macro is defined before its usage. Failing to define a macro before its invocation will raise a compilation error, since the macro won't be expanded and will be translated to a function call:
-
-```elixir
-iex> defmodule Sample do
-...>  def four, do: two + two
-...>  defmacrop two, do: 2
-...> end
-** (CompileError) iex:2: function two/0 undefined
-```
-
-## Write macros responsibly
-
-Macros are a powerful construct and Elixir provides many mechanisms to ensure they are used responsibly.
-
-* Macros are hygienic: by default, variables defined inside a macro are not going to affect the user code. Furthermore, function calls and aliases available in the macro context are not going to leak into the user context.
-
-* Macros are lexical: it is impossible to inject code or macros globally. In order to use a macro, you need to explicitly `require` or `import` the module that defines the macro.
-
-* Macros are explicit: it is impossible to run a macro without explicitly invoking it. For example, some languages allow developers to completely rewrite functions behind the scenes, often via parse transforms or via some reflection mechanisms. In Elixir, a macro must be explicitly invoked in the caller during compilation time.
-
-* Macros' language is clear: many languages provide syntax shortcuts for `quote` and `unquote`. In Elixir, we preferred to have them explicitly spelled out, in order to clearly delimit the boundaries of a macro definition and its quoted expressions.
-
-Even with such guarantees, the developer plays a big role when writing macros responsibly. If you are confident you need to resort to macros, remember that macros are not your API. Keep your macro definitions short, including their quoted contents. For example, instead of writing a macro like this:
-
-```elixir
-defmodule MyModule do
-  defmacro my_macro(a, b, c) do
-    quote do
-      do_this(unquote(a))
-      ...
-      do_that(unquote(b))
-      ...
-      and_that(unquote(c))
-    end
-  end
-end
-```
-
-write:
-
-```elixir
-defmodule MyModule do
-  defmacro my_macro(a, b, c) do
-    quote do
-      # Keep what you need to do here to a minimum
-      # and move everything else to a function
-      MyModule.do_this_that_and_that(unquote(a), unquote(b), unquote(c))
-    end
-  end
-
-  def do_this_that_and_that(a, b, c) do
-    do_this(a)
-    ...
-    do_that(b)
-    ...
-    and_that(c)
-  end
-end
-```
-
-This makes your code clearer and easier to test and maintain, as you can invoke and test `do_this_that_and_that/3` directly. It also helps you design an actual API for developers that do not want to rely on macros.
-
-With those lessons, we finish our introduction to macros. The next chapter is a brief discussion on DSLs that shows how we can mix macros and module attributes to annotate and extend modules and functions.
diff --git a/getting-started/meta/quote-and-unquote.markdown b/getting-started/meta/quote-and-unquote.markdown
index 1447ef509..70c16019b 100644
--- a/getting-started/meta/quote-and-unquote.markdown
+++ b/getting-started/meta/quote-and-unquote.markdown
@@ -1,155 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Quote and unquote
-category: Meta-programming in Elixir
+layout: redirect
+sitemap: false
+redirect_to: quote-and-unquote
 ---
-
-This guide aims to introduce the meta-programming techniques available in Elixir. The ability to represent an Elixir program by its own data structures is at the heart of meta-programming. This chapter starts by exploring those structures and the associated `quote` and `unquote` constructs, so we can take a look at macros in the next chapter and finally build our own domain specific language.
-
-## Quoting
-
-The building block of an Elixir program is a tuple with three elements. For example, the function call `sum(1, 2, 3)` is represented internally as:
-
-```elixir
-{:sum, [], [1, 2, 3]}
-```
-
-You can get the representation of any expression by using the `quote` macro:
-
-```elixir
-iex> quote do: sum(1, 2, 3)
-{:sum, [], [1, 2, 3]}
-```
-
-The first element is the function name, the second is a keyword list containing metadata and the third is the arguments list.
-
-Operators are also represented as such tuples:
-
-```elixir
-iex> quote do: 1 + 2
-{:+, [context: Elixir, import: Kernel], [1, 2]}
-```
-
-Even a map is represented as a call to `%{}`:
-
-```elixir
-iex> quote do: %{1 => 2}
-{:%{}, [], [{1, 2}]}
-```
-
-Variables are also represented using such triplets, except the last element is an atom, instead of a list:
-
-```elixir
-iex> quote do: x
-{:x, [], Elixir}
-```
-
-When quoting more complex expressions, we can see that the code is represented in such tuples, which are often nested inside each other in a structure resembling a tree. Many languages would call such representations an Abstract Syntax Tree (AST). Elixir calls them quoted expressions:
-
-```elixir
-iex> quote do: sum(1, 2 + 3, 4)
-{:sum, [], [1, {:+, [context: Elixir, import: Kernel], [2, 3]}, 4]}
-```
-
-Sometimes when working with quoted expressions, it may be useful to get the textual code representation back. This can be done with `Macro.to_string/1`:
-
-```elixir
-iex> Macro.to_string(quote do: sum(1, 2 + 3, 4))
-"sum(1, 2 + 3, 4)"
-```
-
-In general, the tuples above are structured according to the following format:
-
-```elixir
-{atom | tuple, list, list | atom}
-```
-
-* The first element is an atom or another tuple in the same representation;
-* The second element is a keyword list containing metadata, like numbers and contexts;
-* The third element is either a list of arguments for the function call or an atom. When this element is an atom, it means the tuple represents a variable.
-
-Besides the tuple defined above, there are five Elixir literals that, when quoted, return themselves (and not a tuple). They are:
-
-```elixir
-:sum         #=> Atoms
-1.0          #=> Numbers
-[1, 2]       #=> Lists
-"strings"    #=> Strings
-{key, value} #=> Tuples with two elements
-```
-
-Most Elixir code has a straight-forward translation to its underlying quoted expression. We recommend you try out different code samples and see what the results are. For example, what does `String.upcase("foo")` expand to? We have also learned that `if(true, do: :this, else: :that)` is the same as `if true do :this else :that end`. How does this affirmation hold with quoted expressions?
-
-## Unquoting
-
-Quote is about retrieving the inner representation of some particular chunk of code. However, sometimes it may be necessary to inject some other particular chunk of code inside the representation we want to retrieve.
-
-For example, imagine you have a variable `number` which contains the number you want to inject inside a quoted expression.
-
-```elixir
-iex> number = 13
-iex> Macro.to_string(quote do: 11 + number)
-"11 + number"
-```
-
-That's not what we wanted, since the value of the `number` variable has not been injected and `number` has been quoted in the expression. In order to inject the *value* of the `number` variable, `unquote` has to be used inside the quoted representation:
-
-```elixir
-iex> number = 13
-iex> Macro.to_string(quote do: 11 + unquote(number))
-"11 + 13"
-```
-
-`unquote` can even be used to inject function names:
-
-```elixir
-iex> fun = :hello
-iex> Macro.to_string(quote do: unquote(fun)(:world))
-"hello(:world)"
-```
-
-In some cases, it may be necessary to inject many values inside a list. For example, imagine you have a list containing `[1, 2, 6]` and we want to inject `[3, 4, 5]` into it. Using `unquote` won't yield the desired result:
-
-```elixir
-iex> inner = [3, 4, 5]
-iex> Macro.to_string(quote do: [1, 2, unquote(inner), 6])
-"[1, 2, [3, 4, 5], 6]"
-```
-
-That's when `unquote_splicing` becomes handy:
-
-```elixir
-iex> inner = [3, 4, 5]
-iex> Macro.to_string(quote do: [1, 2, unquote_splicing(inner), 6])
-"[1, 2, 3, 4, 5, 6]"
-```
-
-Unquoting is very useful when working with macros. When writing macros, developers are able to receive code chunks and inject them inside other code chunks, which can be used to transform code or write code that generates code during compilation.
-
-## Escaping
-
-As we saw at the beginning of this chapter, only some values are valid quoted expressions in Elixir. For example, a map is not a valid quoted expression. Neither is a tuple with four elements. However, such values *can* be expressed as a quoted expression:
-
-```elixir
-iex> quote do: %{1 => 2}
-{:%{}, [], [{1, 2}]}
-```
-
-In some cases, you may need to inject such *values* into *quoted expressions*. To do that, we need to first escape those values into quoted expressions with the help of `Macro.escape/1`:
-
-```elixir
-iex> map = %{hello: :world}
-iex> quote do: map
-{:map, [], Elixir}
-iex> Macro.escape(map)
-{:%{}, [], [hello: :world]}
-```
-
-Macros receive quoted expressions and must return quoted expressions. However, sometimes during the execution of a macro, you may need to work with values and making a distinction between values and quoted expressions will be required.
-
-In other words, it is important to make a distinction between a regular Elixir value (like a list, a map, a process, a reference, etc) and a quoted expression. Some values, such as integers, atoms, and strings, have a quoted expression equal to the value itself. Other values, like maps, need to be explicitly converted. Finally, values like functions and references cannot be converted to a quoted expression at all.
-
-You can read more about `quote` and `unquote` in the [`Kernel.SpecialForms` module](https://hexdocs.pm/elixir/Kernel.SpecialForms.html). Documentation for `Macro.escape/1` and other functions related to quoted expressions can be found in the [`Macro` module](https://hexdocs.pm/elixir/Macro.html).
-
-In this introduction, we have laid the groundwork to finally write our first macro, so let's move to the next chapter.
diff --git a/getting-started/mix-otp/agent.markdown b/getting-started/mix-otp/agent.markdown
index 603202eea..419cc43f7 100644
--- a/getting-started/mix-otp/agent.markdown
+++ b/getting-started/mix-otp/agent.markdown
@@ -1,219 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Agent
-category: Mix and OTP
+layout: redirect
+sitemap: false
+redirect_to: agents
 ---
-
-{% include mix-otp-preface.html %}
-
-In this chapter, we will learn how to keep and share state between multiple entities. If you have previous programming experience, you may think of globally shared variables, but the model we will learn here is quite different. The next chapters will generalize the concepts introduced here.
-
-If you have skipped the Getting Started guide or read it long ago, be sure to re-read the [Processes](/getting-started/processes.html) chapter. We will use it as a starting point.
-
-## The trouble with state
-
-Elixir is an immutable language where nothing is shared by default. If we want to share information, which can be read and modified from multiple places, we have two main options in Elixir:
-
-* Using Processes and message passing
-* [ETS (Erlang Term Storage)](http://www.erlang.org/doc/man/ets.html)
-
-We covered processes in the Getting Started guide. <abbr title="Erlang Term Storage">ETS</abbr> is a new topic that we will explore in later chapters. When it comes to processes though, we rarely hand-roll our own, instead we use the abstractions available in Elixir and  <abbr title="Open Telecom Platform">OTP</abbr>:
-
-* [Agent](https://hexdocs.pm/elixir/Agent.html) - Simple wrappers around state.
-* [GenServer](https://hexdocs.pm/elixir/GenServer.html) - "Generic servers" (processes) that encapsulate state, provide sync and async calls, support code reloading, and more.
-* [Task](https://hexdocs.pm/elixir/Task.html) - Asynchronous units of computation that allow spawning a process and potentially retrieving its result at a later time.
-
-We will explore most of these abstractions in this guide. Keep in mind that they are all implemented on top of processes using the basic features provided by the <abbr title="Virtual Machine">VM</abbr>, like `send`, `receive`, `spawn` and `link`.
-
-Here we will use Agents, and create a module named `KV.Bucket`, responsible for storing our key-value entries in a way that allows them to be read and modified by other processes.
-
-## Agents
-
-[Agents](https://hexdocs.pm/elixir/Agent.html) are simple wrappers around state. If all you want from a process is to keep state, agents are a great fit. Let's start an `iex` session inside the project with:
-
-```console
-$ iex -S mix
-```
-
-And play a bit with agents:
-
-```elixir
-iex> {:ok, agent} = Agent.start_link fn -> [] end
-{:ok, #PID<0.57.0>}
-iex> Agent.update(agent, fn list -> ["eggs" | list] end)
-:ok
-iex> Agent.get(agent, fn list -> list end)
-["eggs"]
-iex> Agent.stop(agent)
-:ok
-```
-
-We started an agent with an initial state of an empty list. We updated the agent's state, adding our new item to the head of the list. The second argument of [`Agent.update/3`](https://hexdocs.pm/elixir/Agent.html#update/3) is a function that takes the agent's current state as input and returns its desired new state. Finally, we retrieved the whole list. The second argument of [`Agent.get/3`](https://hexdocs.pm/elixir/Agent.html#get/3) is a function that takes the state as input and returns the value that [`Agent.get/3`](https://hexdocs.pm/elixir/Agent.html#get/3) itself will return. Once we are done with the agent, we can call [`Agent.stop/3`](https://hexdocs.pm/elixir/Agent.html#stop/3) to terminate the agent process.
-
-The `Agent.update/3` function accepts as a second argument any function that receives one argument and returns a value:
-
-```elixir
-iex> {:ok, agent} = Agent.start_link fn -> [] end
-{:ok, #PID<0.338.0>}
-iex> Agent.update(agent, fn _list -> 123 end)
-:ok
-iex> Agent.update(agent, fn content -> %{a: content} end)
-:ok
-iex> Agent.update(agent, fn content -> [12 | [content]] end)
-:ok
-iex> Agent.update(agent, fn list -> [:nop | list] end)
-:ok
-iex> Agent.get(agent, fn content -> content end)
-[:nop, 12, %{a: 123}]
-```
-
-As you can see, we can modify the agent state in any way we want. Therefore, we most likely don't want to access the Agent API throughout many different places in our code. Instead, we want to encapsulate all Agent-related functionality in a single module, which we will call `KV.Bucket`. Before we implement it, let's write some tests which will outline the API exposed by our module.
-
-Create a file at `test/kv/bucket_test.exs` (remember the `.exs` extension) with the following:
-
-```elixir
-defmodule KV.BucketTest do
-  use ExUnit.Case, async: true
-
-  test "stores values by key" do
-    {:ok, bucket} = KV.Bucket.start_link([])
-    assert KV.Bucket.get(bucket, "milk") == nil
-
-    KV.Bucket.put(bucket, "milk", 3)
-    assert KV.Bucket.get(bucket, "milk") == 3
-  end
-end
-```
-
-`use ExUnit.Case` is responsible for setting up our module for testing and imports many test-related functionality, such as the `test/2` macro.
-
-Our first test starts a new `KV.Bucket` by calling the `start_link/1` and passing an empty list of options. Then we perform some `get/2` and `put/3` operations on it, asserting the result.
-
-Also note the `async: true` option passed to `ExUnit.Case`. This option makes the test case run in parallel with other `:async` test cases by using multiple cores in our machine. This is extremely useful to speed up our test suite. However, `:async` must *only* be set if the test case does not rely on or change any global values. For example, if the test requires writing to the filesystem or access a database, keep it synchronous (omit the `:async` option) to avoid race conditions between tests.
-
-Async or not, our new test should obviously fail, as none of the functionality is implemented in the module being tested:
-
-```
-** (UndefinedFunctionError) function KV.Bucket.start_link/1 is undefined (module KV.Bucket is not available)
-```
-
-In order to fix the failing test, let's create a file at `lib/kv/bucket.ex` with the contents below. Feel free to give a try at implementing the `KV.Bucket` module yourself using agents before peeking at the implementation below.
-
-```elixir
-defmodule KV.Bucket do
-  use Agent
-
-  @doc """
-  Starts a new bucket.
-  """
-  def start_link(_opts) do
-    Agent.start_link(fn -> %{} end)
-  end
-
-  @doc """
-  Gets a value from the `bucket` by `key`.
-  """
-  def get(bucket, key) do
-    Agent.get(bucket, &Map.get(&1, key))
-  end
-
-  @doc """
-  Puts the `value` for the given `key` in the `bucket`.
-  """
-  def put(bucket, key, value) do
-    Agent.update(bucket, &Map.put(&1, key, value))
-  end
-end
-```
-
-The first step in our implementation is to call `use Agent`. Most of the functionality we will learn in this guide, such as `GenServer` and `Supervisor`, follow this pattern. For all of them, calling `use` generates a `child_spec` function with default configuration, which will be handy when we start supervising processes in chapter 4.
-
-Then we define a `start_link/1` function, which will effectively start the agent. It is a convention to define a `start_link/1` function that always accepts a list of options. We don't plan on using any options right now, but we might later on. We then proceed to call `Agent.start_link/1`, which receives an anonymous function that returns the Agent's initial state.
-
-We are keeping a map inside the agent to store our keys and values. Getting and putting values on the map is done with the Agent API  and the capture operator `&`, introduced in [the Getting Started guide](/getting-started/modules-and-functions.html#function-capturing). The agent passes its state to the anonymous function via the `&1` argument when `Agent.get/2` and `Agent.update/2` are called.
-
-Now that the `KV.Bucket` module has been defined, our test should pass! You can try it yourself by running: `mix test`.
-
-## Test setup with ExUnit callbacks
-
-Before moving on and adding more features to `KV.Bucket`, let's talk about ExUnit callbacks. As you may expect, all `KV.Bucket` tests will require a bucket agent to be up and running. Luckily, ExUnit supports callbacks that allow us to skip such repetitive tasks.
-
-Let's rewrite the test case to use callbacks:
-
-```elixir
-defmodule KV.BucketTest do
-  use ExUnit.Case, async: true
-
-  setup do
-    {:ok, bucket} = KV.Bucket.start_link([])
-    %{bucket: bucket}
-  end
-
-  test "stores values by key", %{bucket: bucket} do
-    assert KV.Bucket.get(bucket, "milk") == nil
-
-    KV.Bucket.put(bucket, "milk", 3)
-    assert KV.Bucket.get(bucket, "milk") == 3
-  end
-end
-```
-
-We have first defined a setup callback with the help of the `setup/1` macro. The `setup/1` macro defines a callback that is run before every test, in the same process as the test itself.
-
-Note that we need a mechanism to pass the `bucket` pid from the callback to the test. We do so by using the *test context*. When we return `%{bucket: bucket}` from the callback, ExUnit will merge this map into the test context. Since the test context is a map itself, we can pattern match the bucket out of it, providing access to the bucket inside the test:
-
-```elixir
-test "stores values by key", %{bucket: bucket} do
-  # `bucket` is now the bucket from the setup block
-end
-```
-
-You can read more about ExUnit cases in the [`ExUnit.Case` module documentation](https://hexdocs.pm/ex_unit/ExUnit.Case.html) and more about callbacks in [`ExUnit.Callbacks` docs](https://hexdocs.pm/ex_unit/ExUnit.Callbacks.html).
-
-## Other agent actions
-
-Besides getting a value and updating the agent state, agents allow us to get a value and update the agent state in one function call via `Agent.get_and_update/2`. Let's implement a `KV.Bucket.delete/2` function that deletes a key from the bucket, returning its current value:
-
-```elixir
-@doc """
-Deletes `key` from `bucket`.
-
-Returns the current value of `key`, if `key` exists.
-"""
-def delete(bucket, key) do
-  Agent.get_and_update(bucket, &Map.pop(&1, key))
-end
-```
-
-Now it is your turn to write a test for the functionality above! Also, be sure to explore [the documentation for the `Agent` module](https://hexdocs.pm/elixir/Agent.html) to learn more about them.
-
-## Client/Server in agents
-
-Before we move on to the next chapter, let's discuss the client/server dichotomy in agents. Let's expand the `delete/2` function we have just implemented:
-
-```elixir
-def delete(bucket, key) do
-  Agent.get_and_update(bucket, fn dict ->
-    Map.pop(dict, key)
-  end)
-end
-```
-
-Everything that is inside the function we passed to the agent happens in the agent process. In this case, since the agent process is the one receiving and responding to our messages, we say the agent process is the server. Everything outside the function is happening in the client.
-
-This distinction is important. If there are expensive actions to be done, you must consider if it will be better to perform these actions on the client or on the server. For example:
-
-```elixir
-def delete(bucket, key) do
-  Process.sleep(1000) # puts client to sleep
-  Agent.get_and_update(bucket, fn dict ->
-    Process.sleep(1000) # puts server to sleep
-    Map.pop(dict, key)
-  end)
-end
-```
-
-When a long action is performed on the server, all other requests to that particular server will wait until the action is done, which may cause some clients to timeout.
-
-In the next chapter, we will explore GenServers, where the segregation between clients and servers is made more apparent.
diff --git a/getting-started/mix-otp/config-and-releases.markdown b/getting-started/mix-otp/config-and-releases.markdown
index d62265632..6a141bef9 100644
--- a/getting-started/mix-otp/config-and-releases.markdown
+++ b/getting-started/mix-otp/config-and-releases.markdown
@@ -1,422 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Configuration and releases
-category: Mix and OTP
+layout: redirect
+sitemap: false
+redirect_to: config-and-releases
 ---
-
-{% include mix-otp-preface.html %}
-
-In this last chapter, we will make the routing table for our distributed key-value store configurable, and then finally package the software for production.
-
-Let's do this.
-
-## Application environment
-
-So far we have hardcoded the routing table into the `KV.Router` module. However, we would like to make the table dynamic. This allows us not only to configure development/test/production, but also to allow different nodes to run with different entries in the routing table. There is a feature of <abbr title="Open Telecom Platform">OTP</abbr> that does exactly that: the application environment.
-
-Each application has an environment that stores the application's specific configuration by key. For example, we could store the routing table in the `:kv` application environment, giving it a default value and allowing other applications to change the table as needed.
-
-Open up `apps/kv/mix.exs` and change the `application/0` function to return the following:
-
-```elixir
-def application do
-  [
-    extra_applications: [:logger],
-    env: [routing_table: []],
-    mod: {KV, []}
-  ]
-end
-```
-
-We have added a new `:env` key to the application. It returns the application default environment, which has an entry of key `:routing_table` and value of an empty list. It makes sense for the application environment to ship with an empty table, as the specific routing table depends on the testing/deployment structure.
-
-In order to use the application environment in our code, we need to replace `KV.Router.table/0` with the definition below:
-
-```elixir
-@doc """
-The routing table.
-"""
-def table do
-  Application.fetch_env!(:kv, :routing_table)
-end
-```
-
-We use `Application.fetch_env!/2` to read the entry for `:routing_table` in `:kv`'s environment. You can find more information and other functions to manipulate the app environment in the [Application module](https://hexdocs.pm/elixir/Application.html).
-
-Since our routing table is now empty, our distributed tests should fail. Restart the apps and re-run tests to see the failure:
-
-```console
-$ iex --sname bar -S mix
-$ elixir --sname foo -S mix test --only distributed
-```
-
-We need a way to configure the application environment. That's when we use configuration files.
-
-## Configuration
-
-Configuration files provide a mechanism for us to configure the environment of any application. Elixir provides two configuration entry points:
-
-  * `config/config.exs` - this file is read at build time, before we compile our application and before we even load our dependencies. This means we can't access the code in our application nor in our dependencies. However, it means we can control how they are compiled
-
-  * `config/runtime.exs` - this file is read after our application and dependencies are compiled and therefore it can configure how our application works at runtime. If you want to read system environment variables (via `System.get_env/1`) or any sort of external configuration, this is the appropriate place to do so
-
-For example, we can configure IEx default prompt to another value. Let's create the `config/runtime.exs` file with the following content:
-
-```elixir
-import Config
-config :iex, default_prompt: ">>>"
-```
-
-Start IEx with `iex -S mix` and you can see that the IEx prompt has changed.
-
-This means we can also configure our `:routing_table` directly in the `config/runtime.exs` file. However, which configuration value should we use?
-
-Currently we have two tests tagged with `@tag :distributed`. The "server interaction" test in `KVServerTest`, and the "route requests across nodes" in `KV.RouterTest`. Both tests are failing since they require a routing table, which is currently empty.
-
-For simplicity, we will define a routing table that always points to the current node. That's the table we will use for development and most of our tests. Back in `config/runtime.exs`, add this line:
-
-```elixir
-config :kv, :routing_table, [{?a..?z, node()}]
-```
-
-With such a simple table available, we can now remove `@tag :distributed` from the test in `test/kv_server_test.exs`. If you run the complete suite, the test should now pass.
-
-However, for the tests in `KV.RouterTest`, we effectively need two nodes in our routing table. To do so, we will write a setup block that runs before all tests in that file. The setup block will change the application environment and revert it back once we are done, like this:
-
-```elixir
-defmodule KV.RouterTest do
-  use ExUnit.Case
-
-  setup_all do
-    current = Application.get_env(:kv, :routing_table)
-
-    Application.put_env(:kv, :routing_table, [
-      {?a..?m, :"foo@computer-name"},
-      {?n..?z, :"bar@computer-name"}
-    ])
-
-    on_exit fn -> Application.put_env(:kv, :routing_table, current) end
-  end
-
-  @tag :distributed
-  test "route requests across nodes" do
-```
-
-Note we removed `async: true` from `use ExUnit.Case`. Since the application environment is a global storage, tests that modify it cannot run concurrently. With all changes in place, all tests should pass, including the distributed one.
-
-Details of other configuration strategies are beyond the scope of this document, but you should be aware that other sources of runtime configuration data can be specified as configuration providers in `mix.exs`. For more details see the documentation for the [Config.Provider module](https://hexdocs.pm/elixir/main/Config.Provider.html#content). Excellent libraries for many types of config providers can be found on [Hex](https://hex.pm). These can ease the use of environment variables and configuration files of various formats, such as TOML, YAML, INI, and JSON.
-
-## Releases
-
-Now that our application runs distributed, you may be wondering how we can package our application to run in production. After all, all of our code so far depends on Erlang and Elixir versions that are installed in your current system. To achieve this goal, Elixir provides releases.
-
-A release is a self-contained directory that consists of your application code, all of its dependencies, plus the whole Erlang Virtual Machine (VM) and runtime. Once a release is assembled, it can be packaged and deployed to a target as long as the target runs on the same operating system (OS) distribution and version as the machine that assembled the release.
-
-In a regular project, we can assemble a release by simply running `mix release`. However, we have an umbrella project, and in such cases Elixir requires some extra input from us. Let's see what is necessary:
-
-    $ MIX_ENV=prod mix release
-    ** (Mix) Umbrella projects require releases to be explicitly defined with a non-empty applications key that chooses which umbrella children should be part of the releases:
-
-    releases: [
-      foo: [
-        applications: [child_app_foo: :permanent]
-      ],
-      bar: [
-        applications: [child_app_bar: :permanent]
-      ]
-    ]
-
-    Alternatively you can perform the release from the children applications
-
-That's because an umbrella project gives us plenty of options when deploying the software. We can:
-
-  * deploy all applications in the umbrella to a node that will work as both TCP server and key-value storage
-
-  * deploy the `:kv_server` application to work only as a TCP server as long as the routing table points only to other nodes
-
-  * deploy only the `:kv` application when we want a node to work only as storage (no TCP access)
-
-As a starting point, let's define a release that includes both `:kv_server` and `:kv` applications. We will also add a version to it. Open up the `mix.exs` in the umbrella root and add inside `def project`:
-
-```elixir
-releases: [
-  foo: [
-    version: "0.0.1",
-    applications: [kv_server: :permanent, kv: :permanent]
-  ]
-]
-```
-
-
-That defines a release named `foo` with both `kv_server` and `kv` applications. Their mode is set to `:permanent`, which means that, if those applications crash, the whole node terminates. That's reasonable since those applications are essential to our system.
-
-Before we assemble the release, let's also define our routing table for production. Given we expect to have two nodes, we need to update `config/runtime.exs` to look like this:
-
-```elixir
-import Config
-    
-config :kv, :routing_table, [{?a..?z, node()}]
-
-if config_env() == :prod do
-  config :kv, :routing_table, [
-    {?a..?m, :"foo@computer-name"},
-    {?n..?z, :"bar@computer-name"}
-  ]
-end
-```
-
-We have hardcoded the table and node names, which is good enough for our example, but you would likely move it to an external configuration system in an actual production setup. We have also wrapped it in a `config_env() == :prod` check, so this configuration does not apply to other environments. 
-
-With the configuration in place, let's give assembling the release another try:
-
-    $ MIX_ENV=prod mix release foo
-    * assembling foo-0.0.1 on MIX_ENV=prod
-    * skipping runtime configuration (config/runtime.exs not found)
-
-    Release created at _build/prod/rel/foo
-
-        # To start your system
-        _build/prod/rel/foo/bin/foo start
-
-    Once the release is running:
-
-        # To connect to it remotely
-        _build/prod/rel/foo/bin/foo remote
-
-        # To stop it gracefully (you may also send SIGINT/SIGTERM)
-        _build/prod/rel/foo/bin/foo stop
-
-    To list all commands:
-
-        _build/prod/rel/foo/bin/foo
-
-Excellent! A release was assembled in `_build/prod/rel/foo`. Inside the release, there will be a `bin/foo` file which is the entry point to your system. It supports multiple commands, such as:
-
-  * `bin/foo start`, `bin/foo start_iex`, `bin/foo restart`, and `bin/foo stop` - for general management of the release
-
-  * `bin/foo rpc COMMAND` and `bin/foo remote` - for running commands on the running system or to connect to the running system
-
-  * `bin/foo eval COMMAND` - to start a fresh system that runs a single command and then shuts down
-
-  * `bin/foo daemon` and `bin/foo daemon_iex` - to start the system as a daemon on Unix-like systems
-
-  * `bin/foo install` - to install the system as a service on Windows machines
-
-If you run `bin/foo start`, it will start the system using a short name (`--sname`) equal to the release name, which in this case is `foo`. The next step is to start a system named `bar`, so we can connect `foo` and `bar` together, like we did in the previous chapter. But before we achieve this, let's talk a bit about the benefits of releases.
-
-## Why releases?
-
-Releases allow developers to precompile and package all of their code and the runtime into a single unit. The benefits of releases are:
-
-  * Code preloading. The VM has two mechanisms for loading code: interactive and embedded. By default, it runs in the interactive mode which dynamically loads modules when they are used for the first time. The first time your application calls `Enum.map/2`, the VM will find the `Enum` module and load it. There's a downside. When you start a new server in production, it may need to load many other modules, causing the first requests to have an unusual spike in response time. Releases run in embedded mode, which loads all available modules upfront, guaranteeing your system is ready to handle requests after booting.
-
-  * Configuration and customization. Releases give developers fine grained control over system configuration and the VM flags used to start the system.
-
-  * Self-contained. A release does not require the source code to be included in your production artifacts. All of the code is precompiled and packaged. Releases do not even require Erlang or Elixir on your servers, as they include the Erlang VM and its runtime by default. Furthermore, both Erlang and Elixir standard libraries are stripped to bring only the parts you are actually using.
-
-  * Multiple releases. You can assemble different releases with different configuration per application or even with different applications altogether.
-
-We have written extensive documentation on releases, so [please check the official docs for more information](https://hexdocs.pm/mix/Mix.Tasks.Release.html). For now, we will continue exploring some of the features outlined above.
-
-## Assembling multiple releases
-
-So far, we have assembled a release named `foo`, but our routing table contains information for both `foo` and `bar`. Let's start `foo`:
-
-    $ _build/prod/rel/foo/bin/foo start
-    16:58:58.508 [info]  Accepting connections on port 4040
-
-And let's connect to it and issue a request in another terminal:
-
-    $ telnet 127.0.0.1 4040
-    Trying 127.0.0.1...
-    Connected to localhost.
-    Escape character is '^]'.
-    CREATE bitsandpieces
-    OK
-    PUT bitsandpieces sword 1
-    OK
-    GET bitsandpieces sword
-    1
-    OK
-    GET shopping foo
-    Connection closed by foreign host.
-
-Our application works already when we operate on the bucket named "bitsandpieces". But since the "shopping" bucket would be stored on `bar`, the request fails as `bar` is not available. If you go back to the terminal running `foo`, you will see:
-
-    17:16:19.555 [error] Task #PID<0.622.0> started from #PID<0.620.0> terminating
-    ** (stop) exited in: GenServer.call({KV.RouterTasks, :"bar@computer-name"}, {:start_task, [{:"foo@josemac-2", #PID<0.622.0>, #PID<0.622.0>}, [#PID<0.622.0>, #PID<0.620.0>, #PID<0.618.0>], :monitor, {KV.Router, :route, ["shopping", KV.Registry, :lookup, [KV.Registry, "shopping"]]}], :temporary, nil}, :infinity)
-        ** (EXIT) no connection to bar@computer-name
-        (elixir) lib/gen_server.ex:1010: GenServer.call/3
-        (elixir) lib/task/supervisor.ex:454: Task.Supervisor.async/6
-        (kv) lib/kv/router.ex:21: KV.Router.route/4
-        (kv_server) lib/kv_server/command.ex:74: KVServer.Command.lookup/2
-        (kv_server) lib/kv_server.ex:29: KVServer.serve/1
-        (elixir) lib/task/supervised.ex:90: Task.Supervised.invoke_mfa/2
-        (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
-    Function: #Function<0.128611034/0 in KVServer.loop_acceptor/1>
-        Args: []
-
-Let's now define a release for `:bar`. One first step could be to define a release exactly like `foo` inside `mix.exs`. Additionally we will set the `cookie` option on both releases to `weknoweachother` in order for them to allow connections from each other. See the [Distributed Erlang Documentation](http://www.erlang.org/doc/reference_manual/distributed.html) for further information on this topic:
-
-```elixir
-releases: [
-  foo: [
-    version: "0.0.1",
-    applications: [kv_server: :permanent, kv: :permanent],
-    cookie: "weknoweachother"
-  ],
-  bar: [
-    version: "0.0.1",
-    applications: [kv_server: :permanent, kv: :permanent],
-    cookie: "weknoweachother"
-  ]
-]
-```
-
-And now let's assemble both releases:
-
-    $ MIX_ENV=prod mix release foo
-    $ MIX_ENV=prod mix release bar
-
-Stop `foo` if it's still running and re-start it to load the `cookie`:
-
-    $ _build/prod/rel/foo/bin/foo start
-
-And start `bar` in another terminal:
-
-    $ _build/prod/rel/bar/bin/bar start
-
-You should see an error like the error below happen 5 times, before the application finally shuts down:
-
-    17:21:57.567 [error] Task #PID<0.620.0> started from KVServer.Supervisor terminating
-    ** (MatchError) no match of right hand side value: {:error, :eaddrinuse}
-        (kv_server) lib/kv_server.ex:12: KVServer.accept/1
-        (elixir) lib/task/supervised.ex:90: Task.Supervised.invoke_mfa/2
-        (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
-    Function: #Function<0.98032413/0 in KVServer.Application.start/2>
-        Args: []
-
-That's happening because the release `foo` is already listening on port `4040` and `bar` is trying to do the same! One option could be to move the `:port` configuration to the application environment, like we did for the routing table, and setup different ports per node.
-
-But let's try something else. Let's make it so the `bar` release contains only the `:kv` application. So it works as a storage but it won't have a front-end. Change the `:bar` information to this:
-
-```elixir
-releases: [
-  foo: [
-    version: "0.0.1",
-    applications: [kv_server: :permanent, kv: :permanent],
-    cookie: "weknoweachother"
-  ],
-  bar: [
-    version: "0.0.1",
-    applications: [kv: :permanent],
-    cookie: "weknoweachother"
-  ]
-]
-```
-
-And now let's assemble `bar` once more:
-
-    $ MIX_ENV=prod mix release bar
-
-And finally successfully boot it:
-
-    $ _build/prod/rel/bar/bin/bar start
-
-If you connect to localhost once again and perform another request, now everything should work, as long as the routing table contains the correct node names. Outstanding!
-
-With releases, we were able to "cut different slices" of our project and prepared them to run in production, all packaged into a single directory.
-
-## Configuring releases
-
-Releases also provide built-in hooks for configuring almost every need of the production system:
-
-  * `config/config.exs` - provides build-time application configuration, which is executed before our application compiles. This file often imports configuration files based on the environment, such as `config/dev.exs` and `config/prod.exs`
-
-  * `config/runtime.exs` - provides runtime application configuration. It is executed every time the release boots and is further extensible via config providers
-
-  * `rel/env.sh.eex` and `rel/env.bat.eex` - template files that are copied into every release and executed on every command to set up environment variables, including ones specific to the VM, and the general environment
-
-  * `rel/vm.args.eex` - a template file that is copied into every release and provides static configuration of the Erlang Virtual Machine and other runtime flags
-
-As we have seen, `config/config.exs` and `config/runtime.exs` are loaded during releases and regular Mix commands. On the other hand, `rel/env.sh.eex` and `rel/vm.args.eex` are specific to releases. Let's take a look.
-
-### Operating System environment configuration
-
-Every release contains an environment file, named `env.sh` on Unix-like systems and `env.bat` on Windows machines, that executes before the Elixir system starts. In this file, you can execute any OS-level code, such as invoke other applications, set environment variables and so on. Some of those environment variables can even configure how the release itself runs.
-
-For instance, releases run using short-names (`--sname`). However, if you want to actually run a distributed key-value store in production, you will need multiple nodes and start the release with the `--name` option. We can achieve this by setting the `RELEASE_DISTRIBUTION` environment variable inside the `env.sh` and `env.bat` files. Mix already has a template for said files which we can customize, so let's ask Mix to copy them to our application:
-
-    $ mix release.init
-    * creating rel/vm.args.eex
-    * creating rel/remote.vm.args.eex
-    * creating rel/env.sh.eex
-    * creating rel/env.bat.eex
-
-If you open up `rel/env.sh.eex`, you will see:
-
-```shell
-#!/bin/sh
-
-# # Sets and enables heart (recommended only in daemon mode)
-# case $RELEASE_COMMAND in
-#   daemon*)
-#     HEART_COMMAND="$RELEASE_ROOT/bin/$RELEASE_NAME $RELEASE_COMMAND"
-#     export HEART_COMMAND
-#     export ELIXIR_ERL_OPTIONS="-heart"
-#     ;;
-#   *)
-#     ;;
-# esac
-
-# # Set the release to load code on demand (interactive) instead of preloading (embedded).
-# export RELEASE_MODE=interactive
-
-# # Set the release to work across nodes.
-# # RELEASE_DISTRIBUTION must be "sname" (local), "name" (distributed) or "none".
-# export RELEASE_DISTRIBUTION=name
-# export RELEASE_NODE=<%= @release.name %>
-```
-
-The steps necessary to work across nodes is already commented out as an example. You can enable full distribution by uncommenting the last two lines by removing the leading  `# `.
-
-If you are on Windows, you will have to open up `rel/env.bat.eex`, where you will find this:
-
-```bat
-@echo off
-rem Set the release to load code on demand (interactive) instead of preloading (embedded).
-rem set RELEASE_MODE=interactive
-
-rem Set the release to work across nodes.
-rem RELEASE_DISTRIBUTION must be "sname" (local), "name" (distributed) or "none".
-rem set RELEASE_DISTRIBUTION=name
-rem set RELEASE_NODE=<%= @release.name %>
-```
-
-Once again, uncomment the last two lines by removing the leading `rem ` to enable full distribution. And that's all!
-
-### VM args
-
-The `rel/vm.args.eex` allows you to specify low-level flags that control how the Erlang VM and its runtime operate. You specify entries as if you were specifying arguments in the command line with code comments also supported. Here is the default generated file:
-
-    ## Customize flags given to the VM: https://www.erlang.org/doc/man/erl.html
-    ## -mode/-name/-sname/-setcookie are configured via env vars, do not set them here
-
-    ## Increase number of concurrent ports/sockets
-    ##+Q 65536
-
-    ## Tweak GC to run more often
-    ##-env ERL_FULLSWEEP_AFTER 10
-
-You can see [a complete list of VM args and flags in the Erlang documentation](http://www.erlang.org/doc/man/erl.html).
-
-## Summing up
-
-Throughout the guide, we have built a very simple distributed key-value store as an opportunity to explore many constructs like generic servers, supervisors, tasks, agents, applications and more. Not only that, we have written tests for the whole application, got familiar with ExUnit, and learned how to use the Mix build tool to accomplish a wide range of tasks.
-
-If you are looking for a distributed key-value store to use in production, you should definitely look into [Riak](http://basho.com/products/riak-kv/), which also runs in the Erlang <abbr title="Virtual Machine">VM</abbr>. In Riak, the buckets are replicated, to avoid data loss, and instead of a router, they use [consistent hashing](https://en.wikipedia.org/wiki/Consistent_hashing) to map a bucket to a node. A consistent hashing algorithm helps reduce the amount of data that needs to be migrated when new storage nodes are added to your live system.
-
-Of course, Elixir can be used for much more than distributed key-value stores. Embedded systems, data-processing and data-ingestion, web applications, audio/video streaming systems, and others are many of the different domains Elixir excels at. We hope this guide has prepared you to explore any of those domains or any future domain you may desire to bring Elixir into.
-
-Happy coding!
diff --git a/getting-started/mix-otp/dependencies-and-umbrella-apps.markdown b/getting-started/mix-otp/dependencies-and-umbrella-apps.markdown
new file mode 100644
index 000000000..946955ce2
--- /dev/null
+++ b/getting-started/mix-otp/dependencies-and-umbrella-apps.markdown
@@ -0,0 +1,5 @@
+---
+layout: redirect
+sitemap: false
+redirect_to: dependencies-and-umbrella-projects
+---
diff --git a/getting-started/mix-otp/dependencies-and-umbrella-projects.markdown b/getting-started/mix-otp/dependencies-and-umbrella-projects.markdown
index 6ffcedc29..946955ce2 100644
--- a/getting-started/mix-otp/dependencies-and-umbrella-projects.markdown
+++ b/getting-started/mix-otp/dependencies-and-umbrella-projects.markdown
@@ -1,310 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Dependencies and umbrella projects
-redirect_from: /getting-started/mix-otp/dependencies-and-umbrella-apps.html
-category: Mix and OTP
+layout: redirect
+sitemap: false
+redirect_to: dependencies-and-umbrella-projects
 ---
-
-{% include mix-otp-preface.html %}
-
-In this chapter, we will discuss how to manage dependencies in Mix.
-
-Our `kv` application is complete, so it's time to implement the server that will handle the requests we defined in the first chapter:
-
-```
-CREATE shopping
-OK
-
-PUT shopping milk 1
-OK
-
-PUT shopping eggs 3
-OK
-
-GET shopping milk
-1
-OK
-
-DELETE shopping eggs
-OK
-```
-
-However, instead of adding more code to the `kv` application, we are going to build the TCP server as another application that is a client of the `kv` application. Since the whole runtime and Elixir ecosystem are geared towards applications, it makes sense to break our projects into smaller applications that work together rather than building a big, monolithic app.
-
-Before creating our new application, we must discuss how Mix handles dependencies. In practice, there are two kinds of dependencies we usually work with: internal and external dependencies. Mix supports mechanisms to work with both of them.
-
-## External dependencies
-
-External dependencies are the ones not tied to your business domain. For example, if you need an HTTP API for your distributed KV application, you can use the [Plug](https://github.com/elixir-lang/plug) project as an external dependency.
-
-Installing external dependencies is simple. Most commonly, we use the [Hex Package Manager](https://hex.pm), by listing the dependency inside the deps function in our `mix.exs` file:
-
-```elixir
-def deps do
-  [{:plug, "~> 1.0"}]
-end
-```
-
-This dependency refers to the latest version of Plug in the 1.x.x version series that has been pushed to Hex. This is indicated by the `~>` preceding the version number. For more information on specifying version requirements, see the [documentation for the Version module](https://hexdocs.pm/elixir/Version.html).
-
-Typically, stable releases are pushed to Hex. If you want to depend on an external dependency still in development, Mix is able to manage Git dependencies too:
-
-```elixir
-def deps do
-  [{:plug, git: "https://github.com/elixir-lang/plug.git"}]
-end
-```
-
-You will notice that when you add a dependency to your project, Mix generates a `mix.lock` file that guarantees *repeatable builds*. The lock file must be checked in to your version control system, to guarantee that everyone who uses the project will use the same dependency versions as you.
-
-Mix provides many tasks for working with dependencies, which can be seen in `mix help`:
-
-```console
-$ mix help
-mix deps              # Lists dependencies and their status
-mix deps.clean        # Deletes the given dependencies' files
-mix deps.compile      # Compiles dependencies
-mix deps.get          # Gets all out of date dependencies
-mix deps.tree         # Prints the dependency tree
-mix deps.unlock       # Unlocks the given dependencies
-mix deps.update       # Updates the given dependencies
-```
-
-The most common tasks are `mix deps.get` and `mix deps.update`. Once fetched, dependencies are automatically compiled for you. You can read more about deps by typing `mix help deps`, and in the [documentation for the Mix.Tasks.Deps module](https://hexdocs.pm/mix/Mix.Tasks.Deps.html).
-
-## Internal dependencies
-
-Internal dependencies are the ones that are specific to your project. They usually don't make sense outside the scope of your project/company/organization. Most of the time, you want to keep them private, whether due to technical, economic or business reasons.
-
-If you have an internal dependency, Mix supports two methods to work with them: Git repositories or umbrella projects.
-
-For example, if you push the `kv` project to a Git repository, you'll need to list it in your deps code in order to use it:
-
-```elixir
-def deps do
-  [{:kv, git: "https://github.com/YOUR_ACCOUNT/kv.git"}]
-end
-```
-
-If the repository is private though, you may need to specify the private URL `git@github.com:YOUR_ACCOUNT/kv.git`. In any case, Mix will be able to fetch it for you as long as you have the proper credentials.
-
-Using Git repositories for internal dependencies is somewhat discouraged in Elixir. Remember that the runtime and the Elixir ecosystem already provide the concept of applications. As such, we expect you to frequently break your code into applications that can be organized logically, even within a single project.
-
-However, if you push every application as a separate project to a Git repository, your projects may become very hard to maintain as you will spend a lot of time managing those Git repositories rather than writing your code.
-
-For this reason, Mix supports "umbrella projects". Umbrella projects are used to build applications that run together in a single repository. That is exactly the style we are going to explore in the next sections.
-
-Let's create a new Mix project. We are going to creatively name it `kv_umbrella`, and this new project will have both the existing `kv` application and the new `kv_server` application inside. The directory structure will look like this:
-
-    + kv_umbrella
-      + apps
-        + kv
-        + kv_server
-
-The interesting thing about this approach is that Mix has many conveniences for working with such projects, such as the ability to compile and test all applications inside `apps` with a single command. However, even though they are all listed together inside `apps`, they are still decoupled from each other, so you can build, test and deploy each application in isolation if you want to.
-
-So let's get started!
-
-## Umbrella projects
-
-Let's start a new project using `mix new`. This new project will be named `kv_umbrella` and we need to pass the `--umbrella` option when creating it. Do not create this new project inside the existing `kv` project!
-
-```console
-$ mix new kv_umbrella --umbrella
-* creating README.md
-* creating .formatter.exs
-* creating .gitignore
-* creating mix.exs
-* creating apps
-* creating config
-* creating config/config.exs
-```
-
-From the printed information, we can see far fewer files are generated. The generated `mix.exs` file is different too. Let's take a look (comments have been removed):
-
-```elixir
-defmodule KvUmbrella.MixProject do
-  use Mix.Project
-
-  def project do
-    [
-      apps_path: "apps",
-      start_permanent: Mix.env() == :prod,
-      deps: deps()
-    ]
-  end
-
-  defp deps do
-    []
-  end
-end
-```
-
-What makes this project different from the previous one is the `apps_path: "apps"` entry in the project definition. This means this project will act as an umbrella. Such projects do not have source files nor tests, although they can have their own dependencies. Each child application must be defined inside the `apps` directory.
-
-Let's move inside the apps directory and start building `kv_server`. This time, we are going to pass the `--sup` flag, which will tell Mix to generate a supervision tree automatically for us, instead of building one manually as we did in previous chapters:
-
-```console
-$ cd kv_umbrella/apps
-$ mix new kv_server --module KVServer --sup
-```
-
-The generated files are similar to the ones we first generated for `kv`, with a few differences. Let's open up `mix.exs`:
-
-```elixir
-defmodule KVServer.MixProject do
-  use Mix.Project
-
-  def project do
-    [
-      app: :kv_server,
-      version: "0.1.0",
-      build_path: "../../_build",
-      config_path: "../../config/config.exs",
-      deps_path: "../../deps",
-      lockfile: "../../mix.lock",
-      elixir: "~> 1.14",
-      start_permanent: Mix.env() == :prod,
-      deps: deps()
-    ]
-  end
-
-  # Run "mix help compile.app" to learn about applications
-  def application do
-    [
-      extra_applications: [:logger],
-      mod: {KVServer.Application, []}
-    ]
-  end
-
-  # Run "mix help deps" to learn about dependencies
-  defp deps do
-    [
-      # {:dep_from_hexpm, "~> 0.3.0"},
-      # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"},
-      # {:sibling_app_in_umbrella, in_umbrella: true},
-    ]
-  end
-end
-```
-
-First of all, since we generated this project inside `kv_umbrella/apps`, Mix automatically detected the umbrella structure and added four lines to the project definition:
-
-```elixir
-build_path: "../../_build",
-config_path: "../../config/config.exs",
-deps_path: "../../deps",
-lockfile: "../../mix.lock",
-```
-
-Those options mean all dependencies will be checked out to `kv_umbrella/deps`, and they will share the same build, config, and lock files. We haven't talked about configuration yet, but keep in mind all configuration and dependencies are shared across all projects in an umbrella, and it is not per application.
-
-The second change is in the `application` function inside `mix.exs`:
-
-```elixir
-def application do
-  [
-    extra_applications: [:logger],
-    mod: {KVServer.Application, []}
-  ]
-end
-```
-
-Because we passed the `--sup` flag, Mix automatically added `mod: {KVServer.Application, []}`, specifying that `KVServer.Application` is our application callback module. `KVServer.Application` will start our application supervision tree.
-
-In fact, let's open up `lib/kv_server/application.ex`:
-
-```elixir
-defmodule KVServer.Application do
-  # See https://hexdocs.pm/elixir/Application.html
-  # for more information on OTP Applications
-  @moduledoc false
-
-  use Application
-
-  @impl true
-  def start(_type, _args) do
-    # List all child processes to be supervised
-    children = [
-      # Starts a worker by calling: KVServer.Worker.start_link(arg)
-      # {KVServer.Worker, arg},
-    ]
-
-    # See https://hexdocs.pm/elixir/Supervisor.html
-    # for other strategies and supported options
-    opts = [strategy: :one_for_one, name: KVServer.Supervisor]
-    Supervisor.start_link(children, opts)
-  end
-end
-```
-
-Notice that it defines the application callback function, `start/2`, and instead of defining a supervisor named `KVServer.Supervisor` that uses the `Supervisor` module, it conveniently defined the supervisor inline! You can read more about such supervisors by reading [the Supervisor module documentation](https://hexdocs.pm/elixir/Supervisor.html).
-
-We can already try out our first umbrella child. We could run tests inside the `apps/kv_server` directory, but that wouldn't be much fun. Instead, go to the root of the umbrella project and run `mix test`:
-
-```console
-$ mix test
-```
-
-And it works!
-
-Since we want `kv_server` to eventually use the functionality we defined in `kv`, we need to add `kv` as a dependency to our application.
-
-## Dependencies within an umbrella project
-
-Dependencies between applications in an umbrella project must still be explicitly defined and Mix makes it easy to do so. Open up `apps/kv_server/mix.exs` and change the `deps/0` function to the following:
-
-```elixir
-defp deps do
-  [{:kv, in_umbrella: true}]
-end
-```
-
-The line above makes `:kv` available as a dependency inside `:kv_server` and automatically starts the `:kv` application before the server starts.
-
-Finally, copy the `kv` application we have built so far to the `apps` directory in our new umbrella project. The final directory structure should match the structure we mentioned earlier:
-
-    + kv_umbrella
-      + apps
-        + kv
-        + kv_server
-
-We now need to modify `apps/kv/mix.exs` to contain the umbrella entries we have seen in `apps/kv_server/mix.exs`. Open up `apps/kv/mix.exs` and add to the `project/0` function:
-
-```elixir
-build_path: "../../_build",
-config_path: "../../config/config.exs",
-deps_path: "../../deps",
-lockfile: "../../mix.lock",
-```
-
-Now you can run tests for both projects from the umbrella root with `mix test`. Sweet!
-
-## Don't drink the kool aid
-
-Umbrella projects are a convenience to help you organize and manage multiple applications. While it provides a degree of separation between applications, those applications are not fully decoupled, as they share the same configuration and the same dependencies.
-
-The pattern of keeping multiple applications in the same repository is known as "mono-repo". Umbrella projects maximize this pattern by providing conveniences to compile, test and run multiple applications at once.
-
-If you find yourself in a position where you want to use different configurations in each application for the same dependency or use different dependency versions, then it is likely your codebase has grown beyond what umbrellas can provide.
-
-The good news is that breaking an umbrella apart is quite straightforward, as you simply need to move applications outside of the umbrella project's `apps/` directory and update the project's mix.exs file to no longer set the `build_path`, `config_path`, `deps_path`, and `lockfile` configuration. You can depend on private projects outside of the umbrella in multiple ways:
-
-  1. Move it to a separate folder within the same repository and point to it using a path dependency (the mono-repo pattern)
-  2. Move the repository to a separate Git repository and depend on it
-  3. Publish the project to a private [Hex.pm](https://hex.pm/) organization
-
-## Summing up
-
-In this chapter, we have learned more about Mix dependencies and umbrella projects. While we may run `kv` without a server, our `kv_server` depends directly on `kv`. By breaking them into separate applications, we gain more control in how they are developed and tested.
-
-When using umbrella applications, it is important to have a clear boundary between them. Our upcoming `kv_server` must only access public APIs defined in `kv`. Think of your umbrella apps as any other dependency or even Elixir itself: you can only access what is public and documented. Reaching into private functionality in your dependencies is a poor practice that will eventually cause your code to break when a new version is up.
-
-Umbrella applications can also be used as a stepping stone for eventually extracting an application from your codebase. For example, imagine a web application that has to send "push notifications" to its users. The whole "push notifications system" can be developed as a separate application in the umbrella, with its own supervision tree and APIs. If you ever run into a situation where another project needs the push notifications system, the system can be moved to a private repository or a Hex package.
-
-Developers may also use umbrella projects to break large business domains apart. The caution here is to make sure the domains don't depend on each other (also known as cyclic dependencies). If you run into such situations, it means those applications are not as isolated from each other as you originally thought, and you have architectural and design issues to solve.
-
-Finally, keep in mind that applications in an umbrella project all share the same configurations and dependencies. If two applications in your umbrella need to configure the same dependency in drastically different ways or even use different versions, you have probably outgrown the benefits brought by umbrellas. Remember you can break the umbrella and still leverage the benefits behind "mono-repos".
-
-With our umbrella project up and running, it is time to start writing our server.
diff --git a/getting-started/mix-otp/distributed-tasks.markdown b/getting-started/mix-otp/distributed-tasks.markdown
index 400e6b74b..a75f95d9a 100644
--- a/getting-started/mix-otp/distributed-tasks.markdown
+++ b/getting-started/mix-otp/distributed-tasks.markdown
@@ -1,361 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Distributed tasks and tags
-category: Mix and OTP
+layout: redirect
+sitemap: false
+redirect_to: distributed-tasks
 ---
-
-{% include mix-otp-preface.html %}
-
-In this chapter, we will go back to the `:kv` application and add a routing layer that will allow us to distribute requests between nodes based on the bucket name.
-
-The routing layer will receive a routing table of the following format:
-
-```elixir
-[
-  {?a..?m, :"foo@computer-name"},
-  {?n..?z, :"bar@computer-name"}
-]
-```
-
-The router will check the first byte of the bucket name against the table and dispatch to the appropriate node based on that. For example, a bucket starting with the letter "a" (`?a` represents the Unicode codepoint of the letter "a") will be dispatched to node `foo@computer-name`.
-
-If the matching entry points to the node evaluating the request, then we've finished routing, and this node will perform the requested operation. If the matching entry points to a different node, we'll pass the request to said node, which will look at its own routing table (which may be different from the one in the first node) and act accordingly. If no entry matches, an error will be raised.
-
-> Note: we will be using two nodes in the same machine throughout this chapter. You are free to use two (or more) different machines on the same network but you need to do some prep work. First of all, you need to ensure all machines have a `~/.erlang.cookie` file with exactly the same value. Then you need to guarantee [epmd](http://www.erlang.org/doc/man/epmd.html) is running on a port that is not blocked (you can run `epmd -d` for debug info).
-
-## Our first distributed code
-
-Elixir ships with facilities to connect nodes and exchange information between them. In fact, we use the same concepts of processes, message passing and receiving messages when working in a distributed environment because Elixir processes are *location transparent*. This means that when sending a message, it doesn't matter if the recipient process is on the same node or on another node, the <abbr title="Virtual Machine">VM</abbr> will be able to deliver the message in both cases.
-
-In order to run distributed code, we need to start the <abbr title="Virtual Machine">VM</abbr> with a name. The name can be short (when in the same network) or long (requires the full computer address). Let's start a new IEx session:
-
-```console
-$ iex --sname foo
-```
-
-You can see now the prompt is slightly different and shows the node name followed by the computer name:
-
-    Interactive Elixir - press Ctrl+C to exit (type h() ENTER for help)
-    iex(foo@jv)1>
-
-My computer is named `jv`, so I see `foo@jv` in the example above, but you will get a different result. We will use `foo@computer-name` in the following examples and you should update them accordingly when trying out the code.
-
-Let's define a module named `Hello` in this shell:
-
-```elixir
-iex> defmodule Hello do
-...>   def world, do: IO.puts "hello world"
-...> end
-```
-
-If you have another computer on the same network with both Erlang and Elixir installed, you can start another shell on it. If you don't, you can start another IEx session in another terminal. In either case, give it the short name of `bar`:
-
-```console
-$ iex --sname bar
-```
-
-Note that inside this new IEx session, we cannot access `Hello.world/0`:
-
-```elixir
-iex> Hello.world
-** (UndefinedFunctionError) function Hello.world/0 is undefined (module Hello is not available)
-    Hello.world()
-```
-
-However, we can spawn a new process on `foo@computer-name` from `bar@computer-name`! Let's give it a try (where `@computer-name` is the one you see locally):
-
-```elixir
-iex> Node.spawn_link(:"foo@computer-name", fn -> Hello.world() end)
-#PID<9014.59.0>
-hello world
-```
-
-Elixir spawned a process on another node and returned its pid. The code then executed on the other node where the `Hello.world/0` function exists and invoked that function. Note that the result of "hello world" was printed on the current node `bar` and not on `foo`. In other words, the message to be printed was sent back from `foo` to `bar`. This happens because the process spawned on the other node (`foo`) knows all of the output should be sent back to the original node!
-
-We can send and receive messages from the pid returned by `Node.spawn_link/2` as usual. Let's try a quick ping-pong example:
-
-```elixir
-iex> pid = Node.spawn_link(:"foo@computer-name", fn ->
-...>   receive do
-...>     {:ping, client} -> send(client, :pong)
-...>   end
-...> end)
-#PID<9014.59.0>
-iex> send(pid, {:ping, self()})
-{:ping, #PID<0.73.0>}
-iex> flush()
-:pong
-:ok
-```
-
-From our quick exploration, we could conclude that we should use `Node.spawn_link/2` to spawn processes on a remote node every time we need to do a distributed computation. However, we have learned throughout this guide that spawning processes outside of supervision trees should be avoided if possible, so we need to look for other options.
-
-There are three better alternatives to `Node.spawn_link/2` that we could use in our implementation:
-
-1. We could use Erlang's [:erpc](http://www.erlang.org/doc/man/erpc.html) module to execute functions on a remote node. Inside the `bar@computer-name` shell above, you can call `:erpc.call(:"foo@computer-name", Hello, :world, [])` and it will print "hello world"
-
-2. We could have a server running on the other node and send requests to that node via the [GenServer](https://hexdocs.pm/elixir/GenServer.html) API. For example, you can call a server on a remote node by using `GenServer.call({name, node}, arg)` or passing the remote process PID as the first argument
-
-3. We could use [tasks](https://hexdocs.pm/elixir/Task.html), which we have learned about in [a previous chapter](/getting-started/mix-otp/task-and-gen-tcp.html), as they can be spawned on both local and remote nodes
-
-The options above have different properties. The GenServer would serialize your requests on a single server, while tasks are effectively running asynchronously on the remote node, with the only serialization point being the spawning done by the supervisor.
-
-For our routing layer, we are going to use tasks, but feel free to explore the other alternatives too.
-
-## async/await
-
-So far we have explored tasks that are started and run in isolation, without regard to their return value. However, sometimes it is useful to run a task to compute a value and read its result later on. For this, tasks also provide the `async/await` pattern:
-
-```elixir
-task = Task.async(fn -> compute_something_expensive() end)
-res  = compute_something_else()
-res + Task.await(task)
-```
-
-`async/await` provides a very simple mechanism to compute values concurrently. Not only that, `async/await` can also be used with the same [`Task.Supervisor`](https://hexdocs.pm/elixir/Task.Supervisor.html) we have used in previous chapters. We just need to call `Task.Supervisor.async/2` instead of `Task.Supervisor.start_child/2` and use `Task.await/2` to read the result later on.
-
-## Distributed tasks
-
-Distributed tasks are exactly the same as supervised tasks. The only difference is that we pass the node name when spawning the task on the supervisor. Open up `lib/kv/supervisor.ex` from the `:kv` application. Let's add a task supervisor as the last child of the tree:
-
-```elixir
-{Task.Supervisor, name: KV.RouterTasks},
-```
-
-Now, let's start two named nodes again, but inside the `:kv` application:
-
-```console
-$ iex --sname foo -S mix
-$ iex --sname bar -S mix
-```
-
-From inside `bar@computer-name`, we can now spawn a task directly on the other node via the supervisor:
-
-```elixir
-iex> task = Task.Supervisor.async({KV.RouterTasks, :"foo@computer-name"}, fn ->
-...>   {:ok, node()}
-...> end)
-%Task{
-  mfa: {:erlang, :apply, 2},
-  owner: #PID<0.122.0>,
-  pid: #PID<12467.88.0>,
-  ref: #Reference<0.0.0.400>
-}
-iex> Task.await(task)
-{:ok, :"foo@computer-name"}
-```
-
-Our first distributed task retrieves the name of the node the task is running on. Notice we have given an anonymous function to `Task.Supervisor.async/2` but, in distributed cases, it is preferable to give the module, function, and arguments explicitly:
-
-```elixir
-iex> task = Task.Supervisor.async({KV.RouterTasks, :"foo@computer-name"}, Kernel, :node, [])
-%Task{
-  mfa: {Kernel, :node, 0},
-  owner: #PID<0.122.0>,
-  pid: #PID<12467.89.0>,
-  ref: #Reference<0.0.0.404>
-}
-iex> Task.await(task)
-:"foo@computer-name"
-```
-
-The difference is that anonymous functions require the target node to have exactly the same code version as the caller. Using module, function, and arguments is more robust because you only need to find a function with matching arity in the given module.
-
-With this knowledge in hand, let's finally write the routing code.
-
-## Routing layer
-
-Create a file at `lib/kv/router.ex` with the following contents:
-
-```elixir
-defmodule KV.Router do
-  @doc """
-  Dispatch the given `mod`, `fun`, `args` request
-  to the appropriate node based on the `bucket`.
-  """
-  def route(bucket, mod, fun, args) do
-    # Get the first byte of the binary
-    first = :binary.first(bucket)
-
-    # Try to find an entry in the table() or raise
-    entry =
-      Enum.find(table(), fn {enum, _node} ->
-        first in enum
-      end) || no_entry_error(bucket)
-
-    # If the entry node is the current node
-    if elem(entry, 1) == node() do
-      apply(mod, fun, args)
-    else
-      {KV.RouterTasks, elem(entry, 1)}
-      |> Task.Supervisor.async(KV.Router, :route, [bucket, mod, fun, args])
-      |> Task.await()
-    end
-  end
-
-  defp no_entry_error(bucket) do
-    raise "could not find entry for #{inspect bucket} in table #{inspect table()}"
-  end
-
-  @doc """
-  The routing table.
-  """
-  def table do
-    # Replace computer-name with your local machine name
-    [{?a..?m, :"foo@computer-name"}, {?n..?z, :"bar@computer-name"}]
-  end
-end
-```
-
-Let's write a test to verify our router works. Create a file named `test/kv/router_test.exs` containing:
-
-```elixir
-defmodule KV.RouterTest do
-  use ExUnit.Case, async: true
-
-  test "route requests across nodes" do
-    assert KV.Router.route("hello", Kernel, :node, []) ==
-             :"foo@computer-name"
-    assert KV.Router.route("world", Kernel, :node, []) ==
-             :"bar@computer-name"
-  end
-
-  test "raises on unknown entries" do
-    assert_raise RuntimeError, ~r/could not find entry/, fn ->
-      KV.Router.route(<<0>>, Kernel, :node, [])
-    end
-  end
-end
-```
-
-The first test invokes `Kernel.node/0`, which returns the name of the current node, based on the bucket names "hello" and "world". According to our routing table so far, we should get `foo@computer-name` and `bar@computer-name` as responses, respectively.
-
-The second test checks that the code raises for unknown entries.
-
-In order to run the first test, we need to have two nodes running. Move into `apps/kv` and let's restart the node named `bar` which is going to be used by tests.
-
-```console
-$ iex --sname bar -S mix
-```
-
-And now run tests with:
-
-```console
-$ elixir --sname foo -S mix test
-```
-
-The test should pass.
-
-## Test filters and tags
-
-Although our tests pass, our testing structure is getting more complex. In particular, running tests with only `mix test` causes failures in our suite, since our test requires a connection to another node.
-
-Luckily, ExUnit ships with a facility to tag tests, allowing us to run specific callbacks or even filter tests altogether based on those tags. We have already used the `:capture_log` tag in the previous chapter, which has its semantics specified by ExUnit itself.
-
-This time let's add a `:distributed` tag to `test/kv/router_test.exs`:
-
-```elixir
-@tag :distributed
-test "route requests across nodes" do
-```
-
-Writing `@tag :distributed` is equivalent to writing `@tag distributed: true`.
-
-With the test properly tagged, we can now check if the node is alive on the network and, if not, we can exclude all distributed tests. Open up `test/test_helper.exs` inside the `:kv` application and add the following:
-
-```elixir
-exclude =
-  if Node.alive?(), do: [], else: [distributed: true]
-
-ExUnit.start(exclude: exclude)
-```
-
-Now run tests with `mix test`:
-
-```console
-$ mix test
-Excluding tags: [distributed: true]
-
-.......
-
-Finished in 0.05 seconds
-9 tests, 0 failures, 1 excluded
-```
-
-This time all tests passed and ExUnit warned us that distributed tests were being excluded. If you run tests with `$ elixir --sname foo -S mix test`, one extra test should run and successfully pass as long as the `bar@computer-name` node is available.
-
-The `mix test` command also allows us to dynamically include and exclude tags. For example, we can run `$ mix test --include distributed` to run distributed tests regardless of the value set in `test/test_helper.exs`. We could also pass `--exclude` to exclude a particular tag from the command line. Finally, `--only` can be used to run only tests with a particular tag:
-
-```console
-$ elixir --sname foo -S mix test --only distributed
-```
-
-You can read more about filters, tags and the default tags in [`ExUnit.Case` module documentation](https://hexdocs.pm/ex_unit/ExUnit.Case.html).
-
-## Wiring it all up
-
-Now with our routing system in place, let's change `KVServer` to use the router. Replace the `lookup/2` function in `KVServer.Command` from this:
-
-```elixir
-defp lookup(bucket, callback) do
-  case KV.Registry.lookup(KV.Registry, bucket) do
-    {:ok, pid} -> callback.(pid)
-    :error -> {:error, :not_found}
-  end
-end
-```
-
-by this:
-
-```elixir
-defp lookup(bucket, callback) do
-  case KV.Router.route(bucket, KV.Registry, :lookup, [KV.Registry, bucket]) do
-    {:ok, pid} -> callback.(pid)
-    :error -> {:error, :not_found}
-  end
-end
-```
-
-Instead of directly looking up the registry, we are using the router instead to match a specific node. Then we get a `pid` that can be from any process in our cluster. From now on, `GET`, `PUT` and `DELETE` requests are all routed to the appropriate node.
-
-Let's also make sure that when a new bucket is created it ends up on the correct node. Replace the `run/1` function in `KVServer.Command`, the one that matches the `:create` command, with the following:
-
-```elixir
-def run({:create, bucket}) do
-  case KV.Router.route(bucket, KV.Registry, :create, [KV.Registry, bucket]) do
-    pid when is_pid(pid) -> {:ok, "OK\r\n"}
-    _ -> {:error, "FAILED TO CREATE BUCKET"}
-  end
-end
-```
-
-Now if you run the tests, you will see that an existing test that checks the server interaction will fail, as it will attempt to use the routing table. To address this failure, change the `test_helper.exs` for `:kv_server` application as we did for `:kv` and add `@tag :distributed` to this test too:
-
-```elixir
-@tag :distributed
-test "server interaction", %{socket: socket} do
-```
-
-However, keep in mind that by making the test distributed, we will likely run it less frequently, since we may not do the distributed setup on every test run. We will learn how to address this in the next chapter, by effectively learning how to make the routing table configurable.
-
-## Summing up
-
-We have only scratched the surface of what is possible when it comes to distribution.
-
-In all of our examples, we relied on Erlang's ability to automatically connect nodes whenever there is a request. For example, when we invoked `Node.spawn_link(:"foo@computer-name", fn -> Hello.world() end)`, Erlang automatically connected to said node and started a new process. However, you may also want to take a more explicit approach to connections, by using [`Node.connect/1`](https://hexdocs.pm/elixir/Node.html#connect/1) and [`Node.disconnect/1`](https://hexdocs.pm/elixir/Node.html#disconnect/1).
-
-By default, Erlang establishes a fully meshed network, which means all nodes are connected to each other. Under this topology, the Erlang distribution is known to scale to several dozens of nodes in the same cluster. Erlang also has the concept of hidden nodes, which can allow developers to assemble custom topologies as seen in projects such as [Partisan](https://github.com/lasp-lang/partisan).
-
-In production, you may have nodes connecting and disconnecting at any time. In such scenarios, you need to provide _node discoverability_. Libraries such as [libcluster](https://github.com/bitwalker/libcluster/) and [peerage](https://github.com/mrluc/peerage) provide several strategies for node discoverability using DNS, Kubernetes, etc.
-
-Distributed key-value stores, used in real-life, need to consider the fact nodes may go up and down at any time and also migrate the bucket across nodes. Even further, buckets often need to be duplicated between nodes, so a failure in a node does not lead to the whole bucket being lost. This process is called *replication*. Our implementation won't attempt to tackle such problems. Instead, we assume there is a fixed number of nodes and therefore use a fixed routing table.
-
-These topics can be daunting at first but remember that most Elixir frameworks abstract those concerns for you. For example, when using [the Phoenix web framework](https://phoenixframework.org), its plug-and-play abstractions take care of sending messages and tracking how users join and leave a cluster. However, if you are interested in distributed systems after all, there is much to explore. Here are some additional references:
-
-  * [The excellent Distribunomicon chapter from Learn You Some Erlang](http://learnyousomeerlang.com/distribunomicon)
-  * [Erlang's global module](https://www.erlang.org/doc/man/global.html), which can provide global names and global locks, allowing unique names and unique locks in a whole cluster of machines
-  * [Erlang's pg module](https://www.erlang.org/doc/man/pg.html), which allows process to join different groups shared across the whole cluster
-  * [Phoenix PubSub project](https://github.com/phoenixframework/phoenix_pubsub), which provides a distributed messaging system and a distributed presence system for tracking users and processes in a cluster
-
-You will also find many libraries for building distributed systems within the overall Erlang ecosystem. For now, it is time to go back to our simple distributed key-value store and learn how to configure and package it for production.
diff --git a/getting-started/mix-otp/docs-tests-and-with.markdown b/getting-started/mix-otp/docs-tests-and-with.markdown
index 95153c9c5..dbeb73254 100644
--- a/getting-started/mix-otp/docs-tests-and-with.markdown
+++ b/getting-started/mix-otp/docs-tests-and-with.markdown
@@ -1,455 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Doctests, patterns and with
-redirect_from: /getting-started/mix_otp/docs-tests-and-pipelines.html
-category: Mix and OTP
+layout: redirect
+sitemap: false
+redirect_to: docs-tests-and-with
 ---
-
-{% include mix-otp-preface.html %}
-
-In this chapter, we will implement the code that parses the commands we described in the first chapter:
-
-```
-CREATE shopping
-OK
-
-PUT shopping milk 1
-OK
-
-PUT shopping eggs 3
-OK
-
-GET shopping milk
-1
-OK
-
-DELETE shopping eggs
-OK
-```
-
-After the parsing is done, we will update our server to dispatch the parsed commands to the `:kv` application we built previously.
-
-## Doctests
-
-On the language homepage, we mention that Elixir makes documentation a first-class citizen in the language. We have explored this concept many times throughout this guide, be it via `mix help` or by typing `h Enum` or another module in an IEx console.
-
-In this section, we will implement the parsing functionality, document it and make sure our documentation is up to date with doctests. This helps us provide documentation with accurate code samples.
-
-We need two steps to achieve this: first we write the documentation and then we instruct ExUnit to extract and run the examples in it by calling [`ExUnit.DocTest.doctest/1`](https://hexdocs.pm/ex_unit/ExUnit.DocTest.html#doctest/1).
-
-Let's start by creating an empty definition of the parsing function with documentation at `lib/kv_server/command.ex`:
-
-```elixir
-defmodule KVServer.Command do
-  @doc ~S"""
-  Parses the given `line` into a command.
-
-  ## Examples
-
-      iex> KVServer.Command.parse("CREATE shopping\r\n")
-      {:ok, {:create, "shopping"}}
-
-  """
-  def parse(_line) do
-    :not_implemented
-  end
-end
-```
-
-Doctests are specified by an indentation of four spaces followed by the `iex>` prompt in a documentation string. If a command spans multiple lines, you can use `...>`, as in IEx. The expected result should start at the next line after `iex>` or `...>` line(s) and is terminated either by a newline or a new `iex>` prefix.
-
-Also, note that we started the documentation string using `@doc ~S"""`. The `~S` prevents the `\r\n` characters from being converted to a carriage return and line feed until they are evaluated in the test.
-
-To run our doctests, we'll create a file at `test/kv_server/command_test.exs` and call `doctest KVServer.Command` in the test case:
-
-```elixir
-defmodule KVServer.CommandTest do
-  use ExUnit.Case, async: true
-  doctest KVServer.Command
-end
-```
-
-Run the test suite and the doctest should fail:
-
-```
-  1) doctest KVServer.Command.parse/1 (1) (KVServer.CommandTest)
-     test/kv_server/command_test.exs:3
-     Doctest failed
-     doctest:
-       iex> KVServer.Command.parse("CREATE shopping\r\n")
-       {:ok, {:create, "shopping"}}
-     code: KVServer.Command.parse "CREATE shopping\r\n" === {:ok, {:create, "shopping"}}
-     left:  :not_implemented
-     right: {:ok, {:create, "shopping"}}
-     stacktrace:
-       lib/kv_server/command.ex:7: KVServer.Command (module)
-```
-
-Excellent!
-
-Now let's make the doctest pass. Let's implement the `parse/1` function:
-
-```elixir
-def parse(line) do
-  case String.split(line) do
-    ["CREATE", bucket] -> {:ok, {:create, bucket}}
-  end
-end
-```
-
-Our implementation splits the line on whitespace and then matches the command against a list. Using `String.split/1` means our commands will be whitespace-insensitive. Leading and trailing whitespace won't matter, nor will consecutive spaces between words. Let's add some new doctests to test this behaviour along with the other commands:
-
-```elixir
-@doc ~S"""
-Parses the given `line` into a command.
-
-## Examples
-
-    iex> KVServer.Command.parse "CREATE shopping\r\n"
-    {:ok, {:create, "shopping"}}
-
-    iex> KVServer.Command.parse "CREATE  shopping  \r\n"
-    {:ok, {:create, "shopping"}}
-
-    iex> KVServer.Command.parse "PUT shopping milk 1\r\n"
-    {:ok, {:put, "shopping", "milk", "1"}}
-
-    iex> KVServer.Command.parse "GET shopping milk\r\n"
-    {:ok, {:get, "shopping", "milk"}}
-
-    iex> KVServer.Command.parse "DELETE shopping eggs\r\n"
-    {:ok, {:delete, "shopping", "eggs"}}
-
-Unknown commands or commands with the wrong number of
-arguments return an error:
-
-    iex> KVServer.Command.parse "UNKNOWN shopping eggs\r\n"
-    {:error, :unknown_command}
-
-    iex> KVServer.Command.parse "GET shopping\r\n"
-    {:error, :unknown_command}
-
-"""
-```
-
-With doctests at hand, it is your turn to make tests pass! Once you're ready, you can compare your work with our solution below:
-
-```elixir
-def parse(line) do
-  case String.split(line) do
-    ["CREATE", bucket] -> {:ok, {:create, bucket}}
-    ["GET", bucket, key] -> {:ok, {:get, bucket, key}}
-    ["PUT", bucket, key, value] -> {:ok, {:put, bucket, key, value}}
-    ["DELETE", bucket, key] -> {:ok, {:delete, bucket, key}}
-    _ -> {:error, :unknown_command}
-  end
-end
-```
-
-Notice how we were able to elegantly parse the commands without adding a bunch of `if/else` clauses that check the command name and number of arguments!
-
-Finally, you may have observed that each doctest corresponds to a different test in our suite, which now reports a total of 7 doctests. That is because ExUnit considers the following to define two different doctests:
-
-```elixir
-iex> KVServer.Command.parse("UNKNOWN shopping eggs\r\n")
-{:error, :unknown_command}
-
-iex> KVServer.Command.parse("GET shopping\r\n")
-{:error, :unknown_command}
-```
-
-Without new lines, as seen below, ExUnit compiles it into a single doctest:
-
-```elixir
-iex> KVServer.Command.parse("UNKNOWN shopping eggs\r\n")
-{:error, :unknown_command}
-iex> KVServer.Command.parse("GET shopping\r\n")
-{:error, :unknown_command}
-```
-
-As the name says, doctest is documentation first and a test later. Their goal is not to replace tests but to provide up to date documentation. You can read more about doctests in [the `ExUnit.DocTest` docs](https://hexdocs.pm/ex_unit/ExUnit.DocTest.html).
-
-## with
-
-As we are now able to parse commands, we can finally start implementing the logic that runs the commands. Let's add a stub definition for this function for now:
-
-```elixir
-defmodule KVServer.Command do
-  @doc """
-  Runs the given command.
-  """
-  def run(command) do
-    {:ok, "OK\r\n"}
-  end
-end
-```
-
-Before we implement this function, let's change our server to start using our new `parse/1` and `run/1` functions. Remember, our `read_line/1` function was also crashing when the client closed the socket, so let's take the opportunity to fix it, too. Open up `lib/kv_server.ex` and replace the existing server definition:
-
-```elixir
-defp serve(socket) do
-  socket
-  |> read_line()
-  |> write_line(socket)
-
-  serve(socket)
-end
-
-defp read_line(socket) do
-  {:ok, data} = :gen_tcp.recv(socket, 0)
-  data
-end
-
-defp write_line(line, socket) do
-  :gen_tcp.send(socket, line)
-end
-```
-
-by the following:
-
-```elixir
-defp serve(socket) do
-  msg =
-    case read_line(socket) do
-      {:ok, data} ->
-        case KVServer.Command.parse(data) do
-          {:ok, command} ->
-            KVServer.Command.run(command)
-          {:error, _} = err ->
-            err
-        end
-      {:error, _} = err ->
-        err
-    end
-
-  write_line(socket, msg)
-  serve(socket)
-end
-
-defp read_line(socket) do
-  :gen_tcp.recv(socket, 0)
-end
-
-defp write_line(socket, {:ok, text}) do
-  :gen_tcp.send(socket, text)
-end
-
-defp write_line(socket, {:error, :unknown_command}) do
-  # Known error; write to the client
-  :gen_tcp.send(socket, "UNKNOWN COMMAND\r\n")
-end
-
-defp write_line(_socket, {:error, :closed}) do
-  # The connection was closed, exit politely
-  exit(:shutdown)
-end
-
-defp write_line(socket, {:error, error}) do
-  # Unknown error; write to the client and exit
-  :gen_tcp.send(socket, "ERROR\r\n")
-  exit(error)
-end
-```
-
-If we start our server, we can now send commands to it. For now, we will get two different responses: "OK" when the command is known and "UNKNOWN COMMAND" otherwise:
-
-```console
-$ telnet 127.0.0.1 4040
-Trying 127.0.0.1...
-Connected to localhost.
-Escape character is '^]'.
-CREATE shopping
-OK
-HELLO
-UNKNOWN COMMAND
-```
-
-This means our implementation is going in the correct direction, but it doesn't look very elegant, does it?
-
-The previous implementation used pipelines which made the logic straightforward to follow. However, now that we need to handle different error codes along the way, our server logic is nested inside many `case` calls.
-
-Thankfully, Elixir v1.2 introduced the `with` construct, which allows you to simplify code like the above, replacing nested `case` calls with a chain of matching clauses. Let's rewrite the `serve/1` function to use `with`:
-
-```elixir
-defp serve(socket) do
-  msg =
-    with {:ok, data} <- read_line(socket),
-         {:ok, command} <- KVServer.Command.parse(data),
-         do: KVServer.Command.run(command)
-
-  write_line(socket, msg)
-  serve(socket)
-end
-```
-
-Much better! `with` will retrieve the value returned by the right-side of `<-` and match it against the pattern on the left side. If the value matches the pattern, `with` moves on to the next expression. In case there is no match, the non-matching value is returned.
-
-In other words, we converted each expression given to `case/2` as a step in `with`. As soon as any of the steps return something that does not match `{:ok, x}`, `with` aborts, and returns the non-matching value.
-
-You can read more about [`with` in our documentation](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#with/1).
-
-## Running commands
-
-The last step is to implement `KVServer.Command.run/1`, to run the parsed commands against the `:kv` application. Its implementation is shown below:
-
-```elixir
-@doc """
-Runs the given command.
-"""
-def run(command)
-
-def run({:create, bucket}) do
-  KV.Registry.create(KV.Registry, bucket)
-  {:ok, "OK\r\n"}
-end
-
-def run({:get, bucket, key}) do
-  lookup(bucket, fn pid ->
-    value = KV.Bucket.get(pid, key)
-    {:ok, "#{value}\r\nOK\r\n"}
-  end)
-end
-
-def run({:put, bucket, key, value}) do
-  lookup(bucket, fn pid ->
-    KV.Bucket.put(pid, key, value)
-    {:ok, "OK\r\n"}
-  end)
-end
-
-def run({:delete, bucket, key}) do
-  lookup(bucket, fn pid ->
-    KV.Bucket.delete(pid, key)
-    {:ok, "OK\r\n"}
-  end)
-end
-
-defp lookup(bucket, callback) do
-  case KV.Registry.lookup(KV.Registry, bucket) do
-    {:ok, pid} -> callback.(pid)
-    :error -> {:error, :not_found}
-  end
-end
-```
-
-Every function clause dispatches the appropriate command to the `KV.Registry` server that we registered during the `:kv` application startup. Since our `:kv_server` depends on the `:kv` application, it is completely fine to depend on the services it provides.
-
-You might have noticed we have a function head, `def run(command)`, without a body. In the [Modules and Functions](/getting-started/modules-and-functions#default-arguments) chapter, we learned that a bodiless function can be used to declare default arguments for a multi-clause function. Here is another use case where we use a function without a body to document what the arguments are.
-
-Note that we have also defined a private function named `lookup/2` to help with the common functionality of looking up a bucket and returning its `pid` if it exists, `{:error, :not_found}` otherwise.
-
-By the way, since we are now returning `{:error, :not_found}`, we should amend the `write_line/2` function in `KVServer` to print such error as well:
-
-```elixir
-defp write_line(socket, {:error, :not_found}) do
-  :gen_tcp.send(socket, "NOT FOUND\r\n")
-end
-```
-
-Our server functionality is almost complete. Only tests are missing. This time, we have left tests for last because there are some important considerations to be made.
-
-`KVServer.Command.run/1`'s implementation is sending commands directly to the server named `KV.Registry`, which is registered by the `:kv` application. This means this server is global and if we have two tests sending messages to it at the same time, our tests will conflict with each other (and likely fail). We need to decide between having unit tests that are isolated and can run asynchronously, or writing integration tests that work on top of the global state, but exercise our application's full stack as it is meant to be exercised in production.
-
-So far we have only written unit tests, typically testing a single module directly. However, in order to make `KVServer.Command.run/1` testable as a unit we would need to change its implementation to not send commands directly to the `KV.Registry` process but instead pass a server as an argument. For example, we would need to change `run`'s signature to `def run(command, pid)` and then change all clauses accordingly:
-
-```elixir
-def run({:create, bucket}, pid) do
-  KV.Registry.create(pid, bucket)
-  {:ok, "OK\r\n"}
-end
-
-# ... other run clauses ...
-```
-
-Feel free to go ahead and do the changes above and write some unit tests. The idea is that your tests will start an instance of the `KV.Registry` and pass it as an argument to `run/2` instead of relying on the global `KV.Registry`. This has the advantage of keeping our tests asynchronous as there is no shared state.
-
-But let's also try something different. Let's write integration tests that rely on the global server names to exercise the whole stack from the TCP server to the bucket. Our integration tests will rely on global state and must be synchronous. With integration tests, we get coverage on how the components in our application work together at the cost of test performance. They are typically used to test the main flows in your application. For example, we should avoid using integration tests to test an edge case in our command parsing implementation.
-
-Our integration test will use a TCP client that sends commands to our server and assert we are getting the desired responses.
-
-Let's implement the integration test in `test/kv_server_test.exs` as shown below:
-
-```elixir
-defmodule KVServerTest do
-  use ExUnit.Case
-
-  setup do
-    Application.stop(:kv)
-    :ok = Application.start(:kv)
-  end
-
-  setup do
-    opts = [:binary, packet: :line, active: false]
-    {:ok, socket} = :gen_tcp.connect('localhost', 4040, opts)
-    %{socket: socket}
-  end
-
-  test "server interaction", %{socket: socket} do
-    assert send_and_recv(socket, "UNKNOWN shopping\r\n") ==
-           "UNKNOWN COMMAND\r\n"
-
-    assert send_and_recv(socket, "GET shopping eggs\r\n") ==
-           "NOT FOUND\r\n"
-
-    assert send_and_recv(socket, "CREATE shopping\r\n") ==
-           "OK\r\n"
-
-    assert send_and_recv(socket, "PUT shopping eggs 3\r\n") ==
-           "OK\r\n"
-
-    # GET returns two lines
-    assert send_and_recv(socket, "GET shopping eggs\r\n") == "3\r\n"
-    assert send_and_recv(socket, "") == "OK\r\n"
-
-    assert send_and_recv(socket, "DELETE shopping eggs\r\n") ==
-           "OK\r\n"
-
-    # GET returns two lines
-    assert send_and_recv(socket, "GET shopping eggs\r\n") == "\r\n"
-    assert send_and_recv(socket, "") == "OK\r\n"
-  end
-
-  defp send_and_recv(socket, command) do
-    :ok = :gen_tcp.send(socket, command)
-    {:ok, data} = :gen_tcp.recv(socket, 0, 1000)
-    data
-  end
-end
-```
-
-Our integration test checks all server interaction, including unknown commands and not found errors. It is worth noting that, as with <abbr title="Erlang Term Storage">ETS</abbr> tables and linked processes, there is no need to close the socket. Once the test process exits, the socket is automatically closed.
-
-This time, since our test relies on global data, we have not given `async: true` to `use ExUnit.Case`. Furthermore, in order to guarantee our test is always in a clean state, we stop and start the `:kv` application before each test. In fact, stopping the `:kv` application even prints a warning on the terminal:
-
-```
-18:12:10.698 [info] Application kv exited: :stopped
-```
-
-To avoid printing log messages during tests, ExUnit provides a neat feature called `:capture_log`. By setting `@tag :capture_log` before each test or `@moduletag :capture_log` for the whole test module, ExUnit will automatically capture anything that is logged while the test runs. In case our test fails, the captured logs will be printed alongside the ExUnit report.
-
-Between `use ExUnit.Case` and setup, add the following call:
-
-```elixir
-@moduletag :capture_log
-```
-
-In case the test crashes, you will see a report as follows:
-
-```
-  1) test server interaction (KVServerTest)
-     test/kv_server_test.exs:17
-     ** (RuntimeError) oops
-     stacktrace:
-       test/kv_server_test.exs:29
-
-     The following output was logged:
-
-     13:44:10.035 [notice] Application kv exited: :stopped
-```
-
-With this simple integration test, we start to see why integration tests may be slow. Not only can this test not run asynchronously, but it also requires the expensive setup of stopping and starting the `:kv` application. In fact, your test suite may even fail and run into timeouts. If that's the case, you can tweak the `:gen_tcp.recv(socket, 0)` call to pass a third argument, which is the timeout in milliseconds. In the next chapter we will learn about application configuration, which we could use to make the timeout configurable, if desired.
-
-At the end of the day, it is up to you and your team to figure out the best testing strategy for your applications. You need to balance code quality, confidence, and test suite runtime. For example, we may start with testing the server only with integration tests, but if the server continues to grow in future releases, or it becomes a part of the application with frequent bugs, it is important to consider breaking it apart and writing more intensive unit tests that don't have the weight of an integration test.
-
-Let's move to the next chapter. We will finally make our system distributed by adding a bucket routing mechanism. We will use this opportunity to also improve our testing chops.
diff --git a/getting-started/mix-otp/dynamic-supervisor.markdown b/getting-started/mix-otp/dynamic-supervisor.markdown
index bb0d7c8a4..9dfcd0300 100644
--- a/getting-started/mix-otp/dynamic-supervisor.markdown
+++ b/getting-started/mix-otp/dynamic-supervisor.markdown
@@ -1,207 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Dynamic supervisors
-category: Mix and OTP
+layout: redirect
+sitemap: false
+redirect_to: dynamic-supervisor
 ---
-
-{% include mix-otp-preface.html %}
-
-We have now successfully defined our supervisor which is automatically started (and stopped) as part of our application lifecycle.
-
-Remember, however, that our `KV.Registry` is both linking (via `start_link`) and monitoring (via `monitor`) bucket processes in the `handle_cast/2` callback:
-
-```elixir
-{:ok, bucket} = KV.Bucket.start_link([])
-ref = Process.monitor(bucket)
-```
-
-Links are bidirectional, which implies that a crash in a bucket will crash the registry. Although we now have the supervisor, which guarantees the registry will be back up and running, crashing the registry still means we lose all data associating bucket names to their respective processes.
-
-In other words, we want the registry to keep on running even if a bucket crashes. Let's write a new registry test:
-
-```elixir
-test "removes bucket on crash", %{registry: registry} do
-  KV.Registry.create(registry, "shopping")
-  {:ok, bucket} = KV.Registry.lookup(registry, "shopping")
-
-  # Stop the bucket with non-normal reason
-  Agent.stop(bucket, :shutdown)
-  assert KV.Registry.lookup(registry, "shopping") == :error
-end
-```
-
-The test is similar to "removes bucket on exit" except that we are being a bit more harsh by sending `:shutdown` as the exit reason instead of `:normal`. If a process terminates with a reason different than `:normal`, all linked processes receive an EXIT signal, causing the linked process to also terminate unless it is trapping exits.
-
-Since the bucket terminated, the registry also stopped, and our test fails when trying to `GenServer.call/3` it:
-
-```
-  1) test removes bucket on crash (KV.RegistryTest)
-     test/kv/registry_test.exs:26
-     ** (exit) exited in: GenServer.call(#PID<0.148.0>, {:lookup, "shopping"}, 5000)
-         ** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started
-     code: assert KV.Registry.lookup(registry, "shopping") == :error
-     stacktrace:
-       (elixir) lib/gen_server.ex:770: GenServer.call/3
-       test/kv/registry_test.exs:33: (test)
-```
-
-We are going to solve this issue by defining a new supervisor that will spawn and supervise all buckets. Opposite to the previous Supervisor we defined, the children are not known upfront, but they are rather started dynamically. For those situations, we use a supervisor optimized to such use cases called `DynamicSupervisor`. The `DynamicSupervisor` does not expect a list of children during initialization; instead each child is started manually via `DynamicSupervisor.start_child/2`.
-
-## The bucket supervisor
-
-Since a `DynamicSupervisor` does not define any children during initialization, the `DynamicSupervisor` also allows us to skip the work of defining a whole separate module with the usual `start_link` function and the `init` callback. Instead, we can define a `DynamicSupervisor` directly in the supervision tree, by giving it a name and a strategy.
-
-Open up `lib/kv/supervisor.ex` and add the dynamic supervisor as a child as follows:
-
-
-```elixir
-  def init(:ok) do
-    children = [
-      {KV.Registry, name: KV.Registry},
-      {DynamicSupervisor, name: KV.BucketSupervisor, strategy: :one_for_one}
-    ]
-
-    Supervisor.init(children, strategy: :one_for_one)
-  end
-```
-
-Remember that the name of a process can be any atom. So far, we have named processes with the same name as the modules that define their implementation. For example, the process defined by `KV.Registry` was given a process name of `KV.Registry`. This is simply a convention: If later there is an error in your system that says, "process named KV.Registry crashed with reason", we know exactly where to investigate.
-
-In this case, there is no module, so we picked the name `KV.BucketSupervisor`. It could have been any other name. We also chose the `:one_for_one` strategy, which is currently the only available strategy for dynamic supervisors.
-
-Run `iex -S mix` so we can give our dynamic supervisor a try:
-
-```elixir
-iex> {:ok, bucket} = DynamicSupervisor.start_child(KV.BucketSupervisor, KV.Bucket)
-{:ok, #PID<0.72.0>}
-iex> KV.Bucket.put(bucket, "eggs", 3)
-:ok
-iex> KV.Bucket.get(bucket, "eggs")
-3
-```
-
-`DynamicSupervisor.start_child/2` expects the name of the supervisor and the child specification of the child to be started.
-
-The last step is to change the registry to use the dynamic supervisor:
-
-```elixir
-  def handle_cast({:create, name}, {names, refs}) do
-    if Map.has_key?(names, name) do
-      {:noreply, {names, refs}}
-    else
-      {:ok, pid} = DynamicSupervisor.start_child(KV.BucketSupervisor, KV.Bucket)
-      ref = Process.monitor(pid)
-      refs = Map.put(refs, ref, name)
-      names = Map.put(names, name, pid)
-      {:noreply, {names, refs}}
-    end
-  end
-```
-
-That's enough for our tests to pass but there is a resource leakage in our application. When a bucket terminates, the supervisor will start a new bucket in its place. After all, that's the role of the supervisor!
-
-However, when the supervisor restarts the new bucket, the registry does not know about it. So we will have an empty bucket in the supervisor that nobody can access! To solve this, we want to say that buckets are actually temporary. If they crash, regardless of the reason, they should not be restarted.
-
-We can do this by passing the `restart: :temporary` option to `use Agent` in `KV.Bucket`:
-
-```elixir
-defmodule KV.Bucket do
-  use Agent, restart: :temporary
-```
-
-Let's also add a test to `test/kv/bucket_test.exs` that guarantees the bucket is temporary:
-
-```elixir
-  test "are temporary workers" do
-    assert Supervisor.child_spec(KV.Bucket, []).restart == :temporary
-  end
-```
-
-Our test uses the `Supervisor.child_spec/2` function to retrieve the child specification out of a module and then assert its restart value is `:temporary`. At this point, you may be wondering why use a supervisor if it never restarts its children. It happens that supervisors provide more than restarts, they are also responsible for guaranteeing proper startup and shutdown, especially in case of crashes in a supervision tree.
-
-## Supervision trees
-
-When we added `KV.BucketSupervisor` as a child of `KV.Supervisor`, we began to have supervisors that supervise other supervisors, forming so-called "supervision trees".
-
-Every time you add a new child to a supervisor, it is important to evaluate if the supervisor strategy is correct as well as the order of child processes. In this case, we are using `:one_for_one` and the `KV.Registry` is started before `KV.BucketSupervisor`.
-
-One flaw that shows up right away is the ordering issue. Since `KV.Registry` invokes `KV.BucketSupervisor`, then the `KV.BucketSupervisor` must be started before `KV.Registry`. Otherwise, it may happen that the registry attempts to reach the bucket supervisor before it has started.
-
-The second flaw is related to the supervision strategy. If `KV.Registry` dies, all information linking `KV.Bucket` names to bucket processes is lost. Therefore the `KV.BucketSupervisor` and all children must terminate too - otherwise we will have orphan processes.
-
-In light of this observation, we should consider moving to another supervision strategy. The two other candidates are `:one_for_all` and `:rest_for_one`. A supervisor using the `:rest_for_one` strategy will kill and restart child processes which were started *after* the crashed child. In this case, we would want `KV.BucketSupervisor` to terminate if `KV.Registry` terminates. This would require the bucket supervisor to be placed after the registry which violates the ordering constraints we have established two paragraphs above.
-
-So our last option is to go all in and pick the `:one_for_all` strategy: the supervisor will kill and restart all of its children processes whenever any one of them dies. This is a completely reasonable approach for our application, since the registry can't work without the bucket supervisor, and the bucket supervisor should terminate without the registry. Let's reimplement `init/1` in `KV.Supervisor` to encode those properties:
-
-```elixir
-  def init(:ok) do
-    children = [
-      {DynamicSupervisor, name: KV.BucketSupervisor, strategy: :one_for_one},
-      {KV.Registry, name: KV.Registry}
-    ]
-
-    Supervisor.init(children, strategy: :one_for_all)
-  end
-```
-
-There are two topics left before we move on to the next chapter.
-
-## Shared state in tests
-
-So far we have been starting one registry per test to ensure they are isolated:
-
-```elixir
-setup do
-  registry = start_supervised!(KV.Registry)
-  %{registry: registry}
-end
-```
-
-Since we have changed our registry to use `KV.BucketSupervisor`, our tests are now relying on this shared supervisor even though each test has its own registry. The question is: should we?
-
-It depends. It is ok to rely on shared state as long as we depend only on a non-shared partition of this state. Although multiple registries may start buckets on the shared bucket supervisor, those buckets and registries are isolated from each other. We would only run into concurrency issues if we used a function like `DynamicSupervisor.count_children(KV.BucketSupervisor)` which would count all buckets from all registries, potentially giving different results when tests run concurrently.
-
-Since we have relied only on a non-shared partition of the bucket supervisor so far, we don't need to worry about concurrency issues in our test suite. In case it ever becomes a problem, we can start a supervisor per test and pass it as an argument to the registry `start_link` function.
-
-## Observer
-
-Now that we have defined our supervision tree, it is a great opportunity to introduce the Observer tool that ships with Erlang. Start your application with `iex -S mix` and key this in:
-
-```elixir
-iex> :observer.start()
-```
-
-> ### Missing dependencies
->
-> When running `iex` inside a project with `iex -S mix`, `observer` won't be available as a dependency. To do so, you will need to call the following functions before:
->
-> ```elixir
-> iex> Mix.ensure_application!(:wx)
-> iex> Mix.ensure_application!(:runtime_tools)
-> iex> Mix.ensure_application!(:observer)
-> iex> :observer.start()
-> ```
->
-> If any of the calls above fail, here is what may have happened: some package managers default to installing a minimized Erlang without WX bindings for GUI support. In some package managers, you may be able to replace the headless Erlang with a more complete package (look for packages named `erlang` vs `erlang-nox` on Debian/Ubuntu/Arch). In others managers, you may need to install a separate `erlang-wx` (or similarly named) package.
->
-> There are conversations to improve this experience in future releases.
-
-A GUI should pop-up containing all sorts of information about our system, from general statistics to load charts as well as a list of all running processes and applications.
-
-In the Applications tab, you will see all applications currently running in your system alongside their supervision tree. You can select the `kv` application to explore it further:
-
-<img src="/images/contents/kv-observer.png" width="640" alt="Observer GUI screenshot" />
-
-Not only that, as you create new buckets on the terminal, you should see new processes spawned in the supervision tree shown in Observer:
-
-```elixir
-iex> KV.Registry.create(KV.Registry, "shopping")
-:ok
-```
-
-We will leave it up to you to further explore what Observer provides. Note you can double click any process in the supervision tree to retrieve more information about it, as well as right-click a process to send "a kill signal", a perfect way to emulate failures and see if your supervisor reacts as expected.
-
-At the end of the day, tools like Observer are one of the reasons you want to always start processes inside supervision trees, even if they are temporary, to ensure they are always reachable and introspectable.
-
-Now that our buckets are properly linked and supervised, let's see how we can speed things up.
diff --git a/getting-started/mix-otp/ets.markdown b/getting-started/mix-otp/ets.markdown
index 06cabbe22..22e0a0978 100644
--- a/getting-started/mix-otp/ets.markdown
+++ b/getting-started/mix-otp/ets.markdown
@@ -1,290 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: ETS
-category: Mix and OTP
+layout: redirect
+sitemap: false
+redirect_to: erlang-term-storage
 ---
-
-{% include mix-otp-preface.html %}
-
-Every time we need to look up a bucket, we need to send a message to the registry. In case our registry is being accessed concurrently by multiple processes, the registry may become a bottleneck!
-
-In this chapter, we will learn about ETS (Erlang Term Storage) and how to use it as a cache mechanism.
-
-> Warning! Don't use ETS as a cache prematurely! Log and analyze your application performance and identify which parts are bottlenecks, so you know *whether* you should cache, and *what* you should cache. This chapter is merely an example of how ETS can be used, once you've determined the need.
-
-## ETS as a cache
-
-ETS allows us to store any Elixir term in an in-memory table. Working with ETS tables is done via [Erlang's `:ets` module](http://www.erlang.org/doc/man/ets.html):
-
-```elixir
-iex> table = :ets.new(:buckets_registry, [:set, :protected])
-#Reference<0.1885502827.460455937.234656>
-iex> :ets.insert(table, {"foo", self()})
-true
-iex> :ets.lookup(table, "foo")
-[{"foo", #PID<0.41.0>}]
-```
-
-When creating an ETS table, two arguments are required: the table name and a set of options. From the available options, we passed the table type and its access rules. We have chosen the `:set` type, which means that keys cannot be duplicated. We've also set the table's access to `:protected`, meaning only the process that created the table can write to it, but all processes can read from it. The possible access controls:
-
-  `:public` — Read/Write available to all processes.
-
-  `:protected` — Read available to all processes. Only writable by owner process. This is the default.
-
-  `:private` — Read/Write limited to owner process.
-
-Be aware that if your Read/Write call violates the access control, the operation will raise `ArgumentError`. Finally, since `:set` and `:protected` are the default values, we will skip them from now on.
-
-ETS tables can also be named, allowing us to access them by a given name:
-
-```elixir
-iex> :ets.new(:buckets_registry, [:named_table])
-:buckets_registry
-iex> :ets.insert(:buckets_registry, {"foo", self()})
-true
-iex> :ets.lookup(:buckets_registry, "foo")
-[{"foo", #PID<0.41.0>}]
-```
-
-Let's change the `KV.Registry` to use ETS tables. The first change is to modify our registry to require a name argument, we will use it to name the ETS table and the registry process itself. ETS names and process names are stored in different locations, so there is no chance of conflicts.
-
-Open up `lib/kv/registry.ex`, and let's change its implementation. We've added comments to the source code to highlight the changes we've made:
-
-```elixir
-defmodule KV.Registry do
-  use GenServer
-
-  ## Client API
-
-  @doc """
-  Starts the registry with the given options.
-
-  `:name` is always required.
-  """
-  def start_link(opts) do
-    # 1. Pass the name to GenServer's init
-    server = Keyword.fetch!(opts, :name)
-    GenServer.start_link(__MODULE__, server, opts)
-  end
-
-  @doc """
-  Looks up the bucket pid for `name` stored in `server`.
-
-  Returns `{:ok, pid}` if the bucket exists, `:error` otherwise.
-  """
-  def lookup(server, name) do
-    # 2. Lookup is now done directly in ETS, without accessing the server
-    case :ets.lookup(server, name) do
-      [{^name, pid}] -> {:ok, pid}
-      [] -> :error
-    end
-  end
-
-  @doc """
-  Ensures there is a bucket associated with the given `name` in `server`.
-  """
-  def create(server, name) do
-    GenServer.cast(server, {:create, name})
-  end
-
-  ## Server callbacks
-
-  @impl true
-  def init(table) do
-    # 3. We have replaced the names map by the ETS table
-    names = :ets.new(table, [:named_table, read_concurrency: true])
-    refs  = %{}
-    {:ok, {names, refs}}
-  end
-
-  # 4. The previous handle_call callback for lookup was removed
-
-  @impl true
-  def handle_cast({:create, name}, {names, refs}) do
-    # 5. Read and write to the ETS table instead of the map
-    case lookup(names, name) do
-      {:ok, _pid} ->
-        {:noreply, {names, refs}}
-      :error ->
-        {:ok, pid} = DynamicSupervisor.start_child(KV.BucketSupervisor, KV.Bucket)
-        ref = Process.monitor(pid)
-        refs = Map.put(refs, ref, name)
-        :ets.insert(names, {name, pid})
-        {:noreply, {names, refs}}
-    end
-  end
-
-  @impl true
-  def handle_info({:DOWN, ref, :process, _pid, _reason}, {names, refs}) do
-    # 6. Delete from the ETS table instead of the map
-    {name, refs} = Map.pop(refs, ref)
-    :ets.delete(names, name)
-    {:noreply, {names, refs}}
-  end
-
-  @impl true
-  def handle_info(_msg, state) do
-    {:noreply, state}
-  end
-end
-```
-
-Notice that before our changes `KV.Registry.lookup/2` sent requests to the server, but now it reads directly from the ETS table, which is shared across all processes. That's the main idea behind the cache mechanism we are implementing.
-
-In order for the cache mechanism to work, the created ETS table needs to have access `:protected` (the default), so all clients can read from it, while only the `KV.Registry` process writes to it. We have also set `read_concurrency: true` when starting the table, optimizing the table for the common scenario of concurrent read operations.
-
-The changes we have performed above have broken our tests because the registry requires the `:name` option when starting up. Furthermore, some registry operations such as `lookup/2` require the name to be given as an argument, instead of a PID, so we can do the ETS table lookup. Let's change the setup function in `test/kv/registry_test.exs` to fix both issues:
-
-```elixir
-  setup context do
-    _ = start_supervised!({KV.Registry, name: context.test})
-    %{registry: context.test}
-  end
-```
-
-Since each test has a unique name, we use the test name to name our registries. This way, we no longer need to pass the registry PID around, instead we identify it by the test name. Also note we assigned the result of `start_supervised!` to underscore (`_`). This idiom is often used to signal that we are not interested in the result of `start_supervised!`.
-
-Once we change `setup`, some tests will continue to fail. You may even notice tests pass and fail inconsistently between runs. For example, the "spawns buckets" test:
-
-```elixir
-test "spawns buckets", %{registry: registry} do
-  assert KV.Registry.lookup(registry, "shopping") == :error
-
-  KV.Registry.create(registry, "shopping")
-  assert {:ok, bucket} = KV.Registry.lookup(registry, "shopping")
-
-  KV.Bucket.put(bucket, "milk", 1)
-  assert KV.Bucket.get(bucket, "milk") == 1
-end
-```
-
-may be failing on this line:
-
-```elixir
-{:ok, bucket} = KV.Registry.lookup(registry, "shopping")
-```
-
-How can this line fail if we just created the bucket in the previous line?
-
-The reason those failures are happening is because, for didactic purposes, we have made two mistakes:
-
-  1. We are prematurely optimizing (by adding this cache layer)
-  2. We are using `cast/2` (while we should be using `call/2`)
-
-## Race conditions?
-
-Developing in Elixir does not make your code free of race conditions. However, Elixir's abstractions where nothing is shared by default make it easier to spot a race condition's root cause.
-
-What is happening in our tests is that there is a delay in between an operation and the time we can observe this change in the ETS table. Here is what we were expecting to happen:
-
-1. We invoke `KV.Registry.create(registry, "shopping")`
-2. The registry creates the bucket and updates the cache table
-3. We access the information from the table with `KV.Registry.lookup(registry, "shopping")`
-4. The command above returns `{:ok, bucket}`
-
-However, since `KV.Registry.create/2` is a cast operation, the command will return before we actually write to the table! In other words, this is happening:
-
-1. We invoke `KV.Registry.create(registry, "shopping")`
-2. We access the information from the table with `KV.Registry.lookup(registry, "shopping")`
-3. The command above returns `:error`
-4. The registry creates the bucket and updates the cache table
-
-To fix the failure we need to make `KV.Registry.create/2` synchronous by using `call/2` rather than `cast/2`. This will guarantee that the client will only continue after changes have been made to the table. Let's go back to `lib/kv/registry.ex` and change the function and its callback as follows:
-
-```elixir
-def create(server, name) do
-  GenServer.call(server, {:create, name})
-end
-```
-```elixir
-@impl true
-def handle_call({:create, name}, _from, {names, refs}) do
-  case lookup(names, name) do
-    {:ok, pid} ->
-      {:reply, pid, {names, refs}}
-    :error ->
-      {:ok, pid} = DynamicSupervisor.start_child(KV.BucketSupervisor, KV.Bucket)
-      ref = Process.monitor(pid)
-      refs = Map.put(refs, ref, name)
-      :ets.insert(names, {name, pid})
-      {:reply, pid, {names, refs}}
-  end
-end
-```
-
-We changed the callback from `handle_cast/2` to `handle_call/3` and changed it to reply with the pid of the created bucket. Generally speaking, Elixir developers prefer to use `call/2` instead of `cast/2` as it also provides back-pressure - you block until you get a reply. Using `cast/2` when not necessary can also be considered a premature optimization.
-
-Let's run the tests once again. This time though, we will pass the `--trace` option:
-
-```console
-$ mix test --trace
-```
-
-The `--trace` option is useful when your tests are deadlocking or there are race conditions, as it runs all tests synchronously (`async: true` has no effect) and shows detailed information about each test. If you run the tests multiple times you may see this intermittent failure:
-
-```
-  1) test removes buckets on exit (KV.RegistryTest)
-     test/kv/registry_test.exs:19
-     Assertion with == failed
-     code:  assert KV.Registry.lookup(registry, "shopping") == :error
-     left:  {:ok, #PID<0.109.0>}
-     right: :error
-     stacktrace:
-       test/kv/registry_test.exs:23
-```
-
-According to the failure message, we are expecting that the bucket no longer exists on the table, but it still does! This problem is the opposite of the one we have just solved: while previously there was a delay between the command to create a bucket and updating the table, now there is a delay between the bucket process dying and its entry being removed from the table. Since this is a race condition, you may not be able to reproduce it on your machine, but it is there.
-
-Last time we fixed the race condition by replacing the asynchronous operation, a `cast`, by a `call`, which is synchronous. Unfortunately, the `handle_info/2` callback we are using to receive the `:DOWN` message and delete the entry from the ETS table does not have a synchronous equivalent. This time, we need to find a way to guarantee the registry has processed the `:DOWN` notification sent when the bucket process terminated.
-
-An easy way to do so is by sending a synchronous request to the registry before we do the bucket lookup. The `Agent.stop/2` operation is synchronous and only returns after the bucket process terminates and all `:DOWN` messages are delivered. Therefore, once `Agent.stop/2` returns, the registry has already received the `:DOWN` message but it may not have processed it yet. In order to guarantee the processing of the `:DOWN` message, we can do a synchronous request. Since messages are processed in order, once the registry replies to the synchronous request, then the `:DOWN` message will definitely have been processed.
-
-Let's do so by creating a "bogus" bucket, which is a synchronous request, after `Agent.stop/2` in both "remove" tests at `test/kv/registry_test.exs`:
-
-```elixir
-  test "removes buckets on exit", %{registry: registry} do
-    KV.Registry.create(registry, "shopping")
-    {:ok, bucket} = KV.Registry.lookup(registry, "shopping")
-    Agent.stop(bucket)
-
-    # Do a call to ensure the registry processed the DOWN message
-    _ = KV.Registry.create(registry, "bogus")
-    assert KV.Registry.lookup(registry, "shopping") == :error
-  end
-
-  test "removes bucket on crash", %{registry: registry} do
-    KV.Registry.create(registry, "shopping")
-    {:ok, bucket} = KV.Registry.lookup(registry, "shopping")
-
-    # Stop the bucket with non-normal reason
-    Agent.stop(bucket, :shutdown)
-
-    # Do a call to ensure the registry processed the DOWN message
-    _ = KV.Registry.create(registry, "bogus")
-    assert KV.Registry.lookup(registry, "shopping") == :error
-  end
-```
-
-Our tests should now (always) pass!
-
-Note that the purpose of the test is to check whether the registry processes the bucket's shutdown message correctly. The fact that the `KV.Registry.lookup/2` sends us a valid bucket does not mean that the bucket is still alive by the time you call it. For example, it might have crashed for some reason. The following test depicts this situation:
-
-```elixir
-  test "bucket can crash at any time", %{registry: registry} do
-    KV.Registry.create(registry, "shopping")
-    {:ok, bucket} = KV.Registry.lookup(registry, "shopping")
-
-    # Simulate a bucket crash by explicitly and synchronously shutting it down
-    Agent.stop(bucket, :shutdown)
-
-    # Now trying to call the dead process causes a :noproc exit
-    catch_exit KV.Bucket.put(bucket, "milk", 3)
-  end
-```
-
-This concludes our optimization chapter. We have used ETS as a cache mechanism where reads can happen from any processes but writes are still serialized through a single process. More importantly, we have also learned that once data can be read asynchronously, we need to be aware of the race conditions it might introduce.
-
-In practice, if you find yourself in a position where you need a process registry for dynamic processes, you should use [the `Registry` module](https://hexdocs.pm/elixir/Registry.html) provided as part of Elixir. It provides functionality similar to the one we have built using a GenServer + `:ets` while also being able to perform both writes and reads concurrently. [It has been benchmarked to scale across all cores even on machines with 40 cores](https://elixir-lang.org/blog/2017/01/05/elixir-v1-4-0-released/).
-
-Next, let's discuss external and internal dependencies and how Mix helps us manage large codebases.
diff --git a/getting-started/mix-otp/genserver.markdown b/getting-started/mix-otp/genserver.markdown
index 9e6ff7652..0c548b6bb 100644
--- a/getting-started/mix-otp/genserver.markdown
+++ b/getting-started/mix-otp/genserver.markdown
@@ -1,345 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: GenServer
-category: Mix and OTP
+layout: redirect
+sitemap: false
+redirect_to: genservers
 ---
-
-{% include mix-otp-preface.html %}
-
-In the [previous chapter](/getting-started/mix-otp/agent.html), we used agents to represent our buckets. In the [introduction to mix](/getting-started/mix-otp/introduction-to-mix.html), we specified we would like to name each bucket so we can do the following:
-
-```elixir
-CREATE shopping
-OK
-
-PUT shopping milk 1
-OK
-
-GET shopping milk
-1
-OK
-```
-
-In the session above we interacted with the "shopping" bucket.
-
-Since agents are processes, each bucket has a process identifier (pid), but buckets do not have a name. Back [in the Process chapter](/getting-started/processes.html), we have learned that we can register processes in Elixir by giving them atom names:
-
-```elixir
-iex> Agent.start_link(fn -> %{} end, name: :shopping)
-{:ok, #PID<0.43.0>}
-iex> KV.Bucket.put(:shopping, "milk", 1)
-:ok
-iex> KV.Bucket.get(:shopping, "milk")
-1
-```
-
-However, naming dynamic processes with atoms is a terrible idea! If we use atoms, we would need to convert the bucket name (often received from an external client) to atoms, and **we should never convert user input to atoms**. This is because atoms are not garbage collected. Once an atom is created, it is never reclaimed. Generating atoms from user input would mean the user can inject enough different names to exhaust our system memory!
-
-In practice, it is more likely you will reach the Erlang <abbr title="Virtual Machine">VM</abbr> limit for the maximum number of atoms before you run out of memory, which will bring your system down regardless.
-
-Instead of abusing the built-in name facility, we will create our own *process registry* that associates the bucket name to the bucket process.
-
-The registry needs to guarantee that it is always up to date. For example, if one of the bucket processes crashes due to a bug, the registry must notice this change and avoid serving stale entries. In Elixir, we say the registry needs to *monitor* each bucket. Because our *registry* needs to be able to receive and handle ad-hoc messages from the system, the `Agent` API is not enough.
-
-We will use a [GenServer](https://hexdocs.pm/elixir/GenServer.html) to create a registry process that can monitor the bucket processes. GenServer provides industrial strength functionality for building servers in both Elixir and  <abbr title="Open Telecom Platform">OTP</abbr>.
-
-Please read [the GenServer module documentation](https://hexdocs.pm/elixir/GenServer.html) for an overview if you haven't yet. Once you do so, we are ready to proceed.
-
-## GenServer callbacks
-
-A GenServer is a process that invokes a limited set of functions under specific conditions. When we used an `Agent`, we would keep both the client code and the server code side by side, like this:
-
-```elixir
-def put(bucket, key, value) do
-  Agent.update(bucket, &Map.put(&1, key, value))
-end
-```
-
-Let's break that code apart a bit:
-
-```elixir
-def put(bucket, key, value) do
-  # Here is the client code
-  Agent.update(bucket, fn state ->
-    # Here is the server code
-    Map.put(state, key, value)
-  end)
-  # Back to the client code
-end
-```
-
-In the code above, we have a process, which we call "the client" sending a request to an agent, "the server". The request contains an anonymous function, which must be executed by the server.
-
-In a GenServer, the code above would be two separate functions, roughly like this:
-
-```elixir
-def put(bucket, key, value) do
-  # Send the server a :put "instruction"
-  GenServer.call(bucket, {:put, key, value})
-end
-
-# Server callback
-
-def handle_call({:put, key, value}, _from, state) do
-  {:reply, :ok, Map.put(state, key, value)}
-end
-```
-
-There is quite a bit more ceremony in the GenServer code but, as we will see, it brings some benefits too.
-
-For now, we will write only the server callbacks for our bucket registering logic, without providing a proper API, which we will do later.
-
-Create a new file at `lib/kv/registry.ex` with the following contents:
-
-```elixir
-defmodule KV.Registry do
-  use GenServer
-
-  ## Missing Client API - will add this later
-
-  ## Defining GenServer Callbacks
-
-  @impl true
-  def init(:ok) do
-    {:ok, %{}}
-  end
-
-  @impl true
-  def handle_call({:lookup, name}, _from, names) do
-    {:reply, Map.fetch(names, name), names}
-  end
-
-  @impl true
-  def handle_cast({:create, name}, names) do
-    if Map.has_key?(names, name) do
-      {:noreply, names}
-    else
-      {:ok, bucket} = KV.Bucket.start_link([])
-      {:noreply, Map.put(names, name, bucket)}
-    end
-  end
-end
-```
-
-There are two types of requests you can send to a GenServer: calls and casts. Calls are synchronous and the server **must** send a response back to such requests. While the server computes the response, the client is **waiting**. Casts are asynchronous: the server won't send a response back and therefore the client won't wait for one. Both requests are messages sent to the server, and will be handled in sequence. In the above implementation, we pattern-match on the `:create` messages, to be handled as cast, and on the `:lookup` messages, to be handled as call.
-
-In order to invoke the callbacks above, we need to go through the corresponding `GenServer` functions. Let's start a registry, create a named bucket, and then look it up:
-
-```elixir
-iex> {:ok, registry} = GenServer.start_link(KV.Registry, :ok)
-{:ok, #PID<0.136.0>}
-iex> GenServer.cast(registry, {:create, "shopping"})
-:ok
-iex> {:ok, bk} = GenServer.call(registry, {:lookup, "shopping"})
-{:ok, #PID<0.174.0>}
-```
-
-Our `KV.Registry` process received a cast with `{:create, "shopping"}` and a call with `{:lookup, "shopping"}`, in this sequence. `GenServer.cast` will immediately return, as soon as the message is sent to the `registry`. The `GenServer.call` on the other hand, is where we would be waiting for an answer, provided by the above `KV.Registry.handle_call` callback.
-
-You may also have noticed that we have added `@impl true` before each callback. The `@impl true` informs the compiler that our intention for the subsequent function definition is to define a callback. If by any chance we make a mistake in the function name or in the number of arguments, like we define a `handle_call/2`, the compiler would warn us there isn't any `handle_call/2` to define, and would give us the complete list of known callbacks for the `GenServer` module.
-
-This is all good and well, but we still want to offer our users an API that allows us to hide our implementation details.
-
-## The Client API
-
-A GenServer is implemented in two parts: the client API and the server callbacks. You can either combine both parts into a single module or you can separate them into a client module and a server module. The client is any process that invokes the client function. The server is always the process identifier or process name that we will explicitly pass as argument to the client API. Here we'll use a single module for both the server callbacks and the client API.
-
-Edit the file at `lib/kv/registry.ex`, filling in the blanks for the client API:
-
-```elixir
-  ## Client API
-
-  @doc """
-  Starts the registry.
-  """
-  def start_link(opts) do
-    GenServer.start_link(__MODULE__, :ok, opts)
-  end
-
-  @doc """
-  Looks up the bucket pid for `name` stored in `server`.
-
-  Returns `{:ok, pid}` if the bucket exists, `:error` otherwise.
-  """
-  def lookup(server, name) do
-    GenServer.call(server, {:lookup, name})
-  end
-
-  @doc """
-  Ensures there is a bucket associated with the given `name` in `server`.
-  """
-  def create(server, name) do
-    GenServer.cast(server, {:create, name})
-  end
-```
-
-The first function is `start_link/1`, which starts a new GenServer passing a list of options. `start_link/1` calls out to `GenServer.start_link/3`, which takes three arguments:
-
-1. The module where the server callbacks are implemented, in this case `__MODULE__` (meaning the current module)
-
-2. The initialization arguments, in this case the atom `:ok`
-
-3. A list of options which can be used to specify things like the name of the server. For now, we forward the list of options that we receive on `start_link/1` to `GenServer.start_link/3`
-
-The next two functions, `lookup/2` and `create/2`, are responsible for sending these requests to the server.  In this case, we have used `{:lookup, name}` and `{:create, name}` respectively.  Requests are often specified as tuples, like this, in order to provide more than one "argument" in that first argument slot. It's common to specify the action being requested as the first element of a tuple, and arguments for that action in the remaining elements. Note that the requests must match the first argument to `handle_call/3` or `handle_cast/2`.
-
-That's it for the client API. On the server side, we can implement a variety of callbacks to guarantee the server initialization, termination, and handling of requests. Those callbacks are optional and for now, we have only implemented the ones we care about. Let's recap.
-
-The first is the `init/1` callback, that receives the second argument given to `GenServer.start_link/3` and returns `{:ok, state}`, where state is a new map. We can already notice how the `GenServer` API makes the client/server segregation more apparent. `start_link/3` happens in the client, while `init/1` is the respective callback that runs on the server.
-
-For `call/2` requests, we  implement a `handle_call/3` callback that receives the `request`, the process from which we received the request (`_from`), and the current server state (`names`). The `handle_call/3` callback returns a tuple in the format `{:reply, reply, new_state}`. The first element of the tuple, `:reply`,  indicates that the server should send a reply back to the client. The second element, `reply`, is what will be sent to the client while the third, `new_state` is the new server state.
-
-For `cast/2` requests, we implement a `handle_cast/2` callback that receives the `request` and the current server state (`names`). The `handle_cast/2` callback returns a tuple in the format `{:noreply, new_state}`. Note that in a real application we would have probably implemented the callback for `:create` with a synchronous call instead of an asynchronous cast. We are doing it this way to illustrate how to implement a cast callback.
-
-There are other tuple formats both `handle_call/3` and `handle_cast/2` callbacks may return. There are also other callbacks like `terminate/2` and `code_change/3` that we could implement. You are welcome to explore the [full GenServer documentation](https://hexdocs.pm/elixir/GenServer.html) to learn more about those.
-
-For now, let's write some tests to guarantee our GenServer works as expected.
-
-## Testing a GenServer
-
-Testing a GenServer is not much different from testing an agent. We will spawn the server on a setup callback and use it throughout our tests. Create a file at `test/kv/registry_test.exs` with the following:
-
-```elixir
-defmodule KV.RegistryTest do
-  use ExUnit.Case, async: true
-
-  setup do
-    registry = start_supervised!(KV.Registry)
-    %{registry: registry}
-  end
-
-  test "spawns buckets", %{registry: registry} do
-    assert KV.Registry.lookup(registry, "shopping") == :error
-
-    KV.Registry.create(registry, "shopping")
-    assert {:ok, bucket} = KV.Registry.lookup(registry, "shopping")
-
-    KV.Bucket.put(bucket, "milk", 1)
-    assert KV.Bucket.get(bucket, "milk") == 1
-  end
-end
-```
-
-Our test case first asserts there's no buckets in our registry, creates a named bucket, looks it up, and asserts it behaves as a bucket.
-
-There is one important difference between the `setup` block we wrote for `KV.Registry` and the one we wrote for `KV.Bucket`. Instead of starting the registry by hand by calling `KV.Registry.start_link/1`, we instead called [the `start_supervised!/2` function](https://hexdocs.pm/ex_unit/ExUnit.Callbacks.html#start_supervised/2), passing the `KV.Registry` module.
-
-The `start_supervised!` function was injected into our test module by `use ExUnit.Case`. It does the job of starting the `KV.Registry` process, by calling its `start_link/1` function. The advantage of using `start_supervised!` is that ExUnit will guarantee that the registry process will be shutdown **before** the next test starts. In other words, it helps guarantee that the state of one test is not going to interfere with the next one in case they depend on shared resources.
-
-When starting processes during your tests, we should always prefer to use `start_supervised!`. We recommend you to change the `setup` block in `bucket_test.exs` to use `start_supervised!` too.
-
-Run the tests and they should all pass!
-
-## The need for monitoring
-
-Everything we have done so far could have been implemented with an `Agent`. In this section, we will see one of many things that we can achieve with a GenServer that is not possible with an Agent.
-
-Let's start with a test that describes how we want the registry to behave if a bucket stops or crashes:
-
-```elixir
-test "removes buckets on exit", %{registry: registry} do
-  KV.Registry.create(registry, "shopping")
-  {:ok, bucket} = KV.Registry.lookup(registry, "shopping")
-  Agent.stop(bucket)
-  assert KV.Registry.lookup(registry, "shopping") == :error
-end
-```
-
-The test above will fail on the last assertion as the bucket name remains in the registry even after we stop the bucket process.
-
-In order to fix this bug, we need the registry to monitor every bucket it spawns. Once we set up a monitor, the registry will receive a notification every time a bucket process exits, allowing us to clean the registry up.
-
-Let's first play with monitors by starting a new console with `iex -S mix`:
-
-```elixir
-iex> {:ok, pid} = KV.Bucket.start_link([])
-{:ok, #PID<0.66.0>}
-iex> Process.monitor(pid)
-#Reference<0.0.0.551>
-iex> Agent.stop(pid)
-:ok
-iex> flush()
-{:DOWN, #Reference<0.0.0.551>, :process, #PID<0.66.0>, :normal}
-```
-
-Note `Process.monitor(pid)` returns a unique reference that allows us to match upcoming messages to that monitoring reference. After we stop the agent, we can `flush/0` all messages and notice a `:DOWN` message arrived, with the exact reference returned by `monitor`, notifying that the bucket process exited with reason `:normal`.
-
-Let's reimplement the server callbacks to fix the bug and make the test pass. First, we will modify the GenServer state to two dictionaries: one that contains `name -> pid` and another that holds `ref -> name`. Then we need to monitor the buckets on `handle_cast/2` as well as implement a `handle_info/2` callback to handle the monitoring messages. The full server callbacks implementation is shown below:
-
-```elixir
-## Server callbacks
-
-@impl true
-def init(:ok) do
-  names = %{}
-  refs = %{}
-  {:ok, {names, refs}}
-end
-
-@impl true
-def handle_call({:lookup, name}, _from, state) do
-  {names, _} = state
-  {:reply, Map.fetch(names, name), state}
-end
-
-@impl true
-def handle_cast({:create, name}, {names, refs}) do
-  if Map.has_key?(names, name) do
-    {:noreply, {names, refs}}
-  else
-    {:ok, bucket} = KV.Bucket.start_link([])
-    ref = Process.monitor(bucket)
-    refs = Map.put(refs, ref, name)
-    names = Map.put(names, name, bucket)
-    {:noreply, {names, refs}}
-  end
-end
-
-@impl true
-def handle_info({:DOWN, ref, :process, _pid, _reason}, {names, refs}) do
-  {name, refs} = Map.pop(refs, ref)
-  names = Map.delete(names, name)
-  {:noreply, {names, refs}}
-end
-
-@impl true
-def handle_info(msg, state) do
-  require Logger
-  Logger.debug("Unexpected message in KV.Registry: #{inspect(msg)}")
-  {:noreply, state}
-end
-```
-
-Observe that we were able to considerably change the server implementation without changing any of the client API. That's one of the benefits of explicitly segregating the server and the client.
-
-Finally, different from the other callbacks, we have defined a "catch-all" clause for `handle_info/2` that discards and logs any unknown message. To understand why, let's move on to the next section.
-
-## `call`, `cast` or `info`?
-
-So far we have used three callbacks: `handle_call/3`, `handle_cast/2` and `handle_info/2`. Here is what we should consider when deciding when to use each:
-
-1. `handle_call/3` must be used for synchronous requests. This should be the default choice as waiting for the server reply is a useful backpressure mechanism.
-
-2. `handle_cast/2` must be used for asynchronous requests, when you don't care about a reply. A cast does not guarantee the server has received the message and, for this reason, should be used sparingly. For example, the `create/2` function we have defined in this chapter should have used `call/2`. We have used `cast/2` for didactic purposes.
-
-3. `handle_info/2` must be used for all other messages a server may receive that are not sent via `GenServer.call/2` or `GenServer.cast/2`, including regular messages sent with `send/2`. The monitoring `:DOWN` messages are an example of this.
-
-Since any message, including the ones sent via `send/2`, go to `handle_info/2`, there is a chance unexpected messages will arrive to the server. Therefore, if we don't define the catch-all clause, those messages could cause our registry to crash, because no clause would match. We don't need to worry about such cases for `handle_call/3` and `handle_cast/2` though. Calls and casts are only done via the `GenServer` API, so an unknown message is quite likely a developer mistake.
-
-To help developers remember the differences between call, cast and info, the supported return values and more, we have a tiny [GenServer cheat sheet](/downloads/cheatsheets/gen-server.pdf).
-
-## Monitors or links?
-
-We have previously learned about links in the [Process chapter](/getting-started/processes.html). Now, with the registry complete, you may be wondering: when should we use monitors and when should we use links?
-
-Links are bi-directional. If you link two processes and one of them crashes, the other side will crash too (unless it is trapping exits). A monitor is uni-directional: only the monitoring process will receive notifications about the monitored one. In other words: use links when you want linked crashes, and monitors when you just want to be informed of crashes, exits, and so on.
-
-Returning to our `handle_cast/2` implementation, you can see the registry is both linking and monitoring the buckets:
-
-```elixir
-{:ok, bucket} = KV.Bucket.start_link([])
-ref = Process.monitor(bucket)
-```
-
-This is a bad idea, as we don't want the registry to crash when a bucket crashes. The proper fix is to actually not link the bucket to the registry. Instead, we will link each bucket to a special type of process called Supervisors, which are explicitly designed to handle failures and crashes. We will learn more about them in the next chapter.
diff --git a/getting-started/mix-otp/index.html b/getting-started/mix-otp/index.html
index b2f271a12..6406e2fed 100644
--- a/getting-started/mix-otp/index.html
+++ b/getting-started/mix-otp/index.html
@@ -1,7 +1,5 @@
-<!DOCTYPE html>
-<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
-	<head>
-		<title>Introduction to Mix - Elixir</title>
-    <meta http-equiv="refresh" content="0; url=/getting-started/mix-otp/introduction-to-mix.html" />
-  </head>
-</html>
+---
+layout: redirect
+sitemap: false
+redirect_to: introduction-to-mix
+---
diff --git a/getting-started/mix-otp/introduction-to-mix.markdown b/getting-started/mix-otp/introduction-to-mix.markdown
index 820ddb545..6406e2fed 100644
--- a/getting-started/mix-otp/introduction-to-mix.markdown
+++ b/getting-started/mix-otp/introduction-to-mix.markdown
@@ -1,317 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Introduction to Mix
-category: Mix and OTP
+layout: redirect
+sitemap: false
+redirect_to: introduction-to-mix
 ---
-
-In this guide, we will learn how to build a complete Elixir application, with its own supervision tree, configuration, tests and more.
-
-The requirements for this guide are (see `elixir -v`):
-
-  * Elixir 1.11.0 onwards
-  * Erlang/OTP 22 onwards
-
-The application works as a distributed key-value store. We are going to organize key-value pairs into buckets and distribute those buckets across multiple nodes. We will also build a simple client that allows us to connect to any of those nodes and send requests such as:
-
-```
-CREATE shopping
-OK
-
-PUT shopping milk 1
-OK
-
-PUT shopping eggs 3
-OK
-
-GET shopping milk
-1
-OK
-
-DELETE shopping eggs
-OK
-```
-
-In order to build our key-value application, we are going to use three main tools:
-
-* ***OTP*** _(Open Telecom Platform)_ is a set of libraries that ships with Erlang. Erlang developers use OTP to build robust, fault-tolerant applications. In this chapter we will explore how many aspects from OTP integrate with Elixir, including supervision trees, event managers and more;
-
-* ***[Mix](https://hexdocs.pm/mix/)*** is a build tool that ships with Elixir that provides tasks for creating, compiling, testing your application, managing its dependencies and much more;
-
-* ***[ExUnit](https://hexdocs.pm/ex_unit/)*** is a test-unit based framework that ships with Elixir;
-
-In this chapter, we will create our first project using Mix and explore different features in  <abbr title="Open Telecom Platform">OTP</abbr>, Mix and ExUnit as we go.
-
-> If you have any questions or improvements to the guide, please reach discussion channels such as the [Elixir Forum](https://elixirforum.com) or the [issues tracker](https://github.com/elixir-lang/elixir-lang.github.com/issues). Your input is really important to help us guarantee the guides are accessible and up to date!
->
-> The final code for the application built in this guide is in [this repository](https://github.com/josevalim/kv_umbrella) and can be used as a reference.
-
-## Our first project
-
-When you install Elixir, besides getting the `elixir`, `elixirc` and `iex` executables, you also get an executable Elixir script named `mix`.
-
-Let's create our first project by invoking `mix new` from the command line. We'll pass the project path as the argument (`kv`, in this case). By default the application name and module name will be retrieved from the path. So we tell Mix that our main module should be the all-uppercase `KV`, instead of the default, which would have been `Kv`:
-
-```console
-$ mix new kv --module KV
-```
-
-Mix will create a directory named `kv` with a few files in it:
-
-    * creating README.md
-    * creating .formatter.exs
-    * creating .gitignore
-    * creating mix.exs
-    * creating lib
-    * creating lib/kv.ex
-    * creating test
-    * creating test/test_helper.exs
-    * creating test/kv_test.exs
-
-Let's take a brief look at those generated files.
-
-> Note: Mix is an Elixir executable. This means that in order to run `mix`, you need to have both `mix` and `elixir` executables in your PATH. That's what happens when you install Elixir.
-
-## Project compilation
-
-A file named `mix.exs` was generated inside our new project folder (`kv`) and its main responsibility is to configure our project. Let's take a look at it:
-
-```elixir
-defmodule KV.MixProject do
-  use Mix.Project
-
-  def project do
-    [
-      app: :kv,
-      version: "0.1.0",
-      elixir: "~> 1.11",
-      start_permanent: Mix.env() == :prod,
-      deps: deps()
-    ]
-  end
-
-  # Run "mix help compile.app" to learn about applications
-  def application do
-    [
-      extra_applications: [:logger]
-    ]
-  end
-
-  # Run "mix help deps" to learn about dependencies
-  defp deps do
-    [
-      # {:dep_from_hexpm, "~> 0.3.0"},
-      # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"},
-    ]
-  end
-end
-```
-
-Our `mix.exs` defines two public functions: `project`, which returns project configuration like the project name and version, and `application`, which is used to generate an application file.
-
-There is also a private function named `deps`, which is invoked from the `project` function, that defines our project dependencies. Defining `deps` as a separate function is not required, but it helps keep the project configuration tidy.
-
-Mix also generates a file at `lib/kv.ex` with a module containing exactly one function, called `hello`:
-
-```elixir
-defmodule KV do
-  @moduledoc """
-  Documentation for KV.
-  """
-
-  @doc """
-  Hello world.
-
-  ## Examples
-
-      iex> KV.hello()
-      :world
-
-  """
-  def hello do
-    :world
-  end
-end
-
-```
-
-This structure is enough to compile our project:
-
-```console
-$ cd kv
-$ mix compile
-```
-
-Will output:
-
-    Compiling 1 file (.ex)
-    Generated kv app
-
-The `lib/kv.ex` file was compiled, an application manifest named `kv.app` was generated. All compilation artifacts are placed inside the `_build` directory using the options defined in the `mix.exs` file.
-
-Once the project is compiled, you can start an `iex` session inside the project by running the command below. The `-S mix` is necessary to load the project in the interactive shell:
-
-```console
-$ iex -S mix
-```
-
-We are going to work on this `kv` project, making modifications and trying out the latest changes from an `iex` session. While you may start a new session whenever there are changes to the project source code, you can also recompile the project from within `iex` with the `recompile` helper, like this:
-
-```elixir
-iex> recompile()
-Compiling 1 file (.ex)
-:ok
-iex> recompile()
-:noop
-```
-
-If anything had to be compiled, you see some informative text, and get the `:ok` atom back, otherwise the function is silent, and returns `:noop`.
-
-## Running tests
-
-Mix also generated the appropriate structure for running our project tests. Mix projects usually follow the convention of having a `<filename>_test.exs` file in the `test` directory for each file in the `lib` directory. For this reason, we can already find a `test/kv_test.exs` corresponding to our `lib/kv.ex` file. It doesn't do much at this point:
-
-```elixir
-defmodule KVTest do
-  use ExUnit.Case
-  doctest KV
-
-  test "greets the world" do
-    assert KV.hello() == :world
-  end
-end
-```
-
-It is important to note a couple of things:
-
-1. the test file is an Elixir script file (`.exs`). This is convenient because we don't need to compile test files before running them;
-
-2. we define a test module named `KVTest`, in which we [`use ExUnit.Case`](https://hexdocs.pm/ex_unit/ExUnit.Case.html) to inject the testing API;
-
-3. we use one of the imported macros, [`doctest/1`](https://hexdocs.pm/ex_unit/ExUnit.DocTest.html#doctest/1), to indicate that the `KV` module contains doctests (we will discuss those in a later chapter);
-
-4. we use the [`test/2`](https://hexdocs.pm/ex_unit/ExUnit.Case.html#test/2) macro to define a simple test;
-
-Mix also generated a file named `test/test_helper.exs` which is responsible for setting up the test framework:
-
-```elixir
-ExUnit.start()
-```
-
-This file will be required by Mix every time before we run our tests. We can run tests with:
-
-```console
-$ mix test
-Compiled lib/kv.ex
-Generated kv app
-..
-
-Finished in 0.04 seconds
-1 doctest, 1 test, 0 failures
-
-Randomized with seed 540224
-```
-
-Notice that by running `mix test`, Mix has compiled the source files and generated the application manifest once again. This happens because Mix supports multiple environments, which we will discuss later in this chapter.
-
-Furthermore, you can see that ExUnit prints a dot for each successful test and automatically randomizes tests too. Let's make the test fail on purpose and see what happens.
-
-Change the assertion in `test/kv_test.exs` to the following:
-
-```elixir
-assert KV.hello() == :oops
-```
-
-Now run `mix test` again (notice this time there will be no compilation):
-
-```
-  1) test greets the world (KVTest)
-     test/kv_test.exs:5
-     Assertion with == failed
-     code:  assert KV.hello() == :oops
-     left:  :world
-     right: :oops
-     stacktrace:
-       test/kv_test.exs:6: (test)
-
-.
-
-Finished in 0.05 seconds
-1 doctest, 1 test, 1 failure
-```
-
-For each failure, ExUnit prints a detailed report, containing the test name with the test case, the code that failed and the values for the left side and right side (rhs) of the `==` operator.
-
-In the second line of the failure, right below the test name, there is the location where the test was defined. If you copy the test location in full, including the file and line number, and append it to `mix test`, Mix will load and run just that particular test:
-
-```console
-$ mix test test/kv_test.exs:5
-```
-
-This shortcut will be extremely useful as we build our project, allowing us to quickly iterate by running a single test.
-
-Finally, the stacktrace relates to the failure itself, giving information about the test and often the place the failure was generated from within the source files.
-
-## Automatic code formatting
-
-One of the files generated by `mix new` is the `.formatter.exs`. Elixir ships with a code formatter that is capable of automatically formatting our codebase according to a consistent style. The formatter is triggered with the `mix format` task. The generated `.formatter.exs` file configures which files should be formatted when `mix format` runs.
-
-To give the formatter a try, change a file in the `lib` or `test` directories to include extra spaces or extra newlines, such as `def  hello  do`, and then run `mix format`.
-
-Most editors provide built-in integration with the formatter, allowing a file to be formatted on save or via a chosen keybinding. If you are learning Elixir, editor integration gives you useful and quick feedback when learning the Elixir syntax.
-
-For companies and teams, we recommend developers to run `mix format --check-formatted` on their continuous integration servers, ensuring all current and future code follows the standard.
-
-You can learn more about the code formatter by checking [the format task documentation](https://hexdocs.pm/mix/Mix.Tasks.Format.html) or by reading [the release announcement for Elixir v1.6](https://elixir-lang.org/blog/2018/01/17/elixir-v1-6-0-released/), the first version to include the formatter.
-
-## Environments
-
-Mix provides the concept of "environments". They allow a developer to customize compilation and other options for specific scenarios. By default, Mix understands three environments:
-
-* `:dev` - the one in which Mix tasks (like `compile`) run by default
-* `:test` - used by `mix test`
-* `:prod` - the one you will use to run your project in production
-
-The environment applies only to the current project. As we will see in future chapters, any dependency you add to your project will by default run in the `:prod` environment.
-
-Customization per environment can be done by accessing [the `Mix.env` function](https://hexdocs.pm/mix/Mix.html#env/0) in your `mix.exs` file, which returns the current environment as an atom. That's what we have used in the `:start_permanent` options:
-
-```elixir
-def project do
-  [
-    ...,
-    start_permanent: Mix.env() == :prod,
-    ...
-  ]
-end
-```
-
-When true, the `:start_permanent` option starts your application in permanent mode, which means the Erlang VM will crash if your application's supervision tree shuts down. Notice we don't want this behaviour in dev and test because it is useful to keep the VM instance running in those environments for troubleshooting purposes.
-
-Mix will default to the `:dev` environment, except for the `test` task that will default to the `:test` environment. The environment can be changed via the `MIX_ENV` environment variable:
-
-```console
-$ MIX_ENV=prod mix compile
-```
-
-Or on Windows:
-
-```batch
-> set "MIX_ENV=prod" && mix compile
-```
-
-> Mix is a build tool and, as such, it is not expected to be available in production. Therefore, it is recommended to access `Mix.env` only in configuration files and inside `mix.exs`, never in your application code (`lib`).
-
-## Exploring
-
-There is much more to Mix, and we will continue to explore it as we build our project. A [general overview is available on the Mix documentation](https://hexdocs.pm/mix/). Read [the Mix source code here](https://github.com/elixir-lang/elixir/tree/main/lib/mix).
-
-Keep in mind that you can always invoke the help task to list all available tasks:
-
-```console
-$ mix help
-```
-
-You can get further information about a particular task by invoking `mix help TASK`.
-
-Let's write some code!
diff --git a/getting-started/mix-otp/supervisor-and-application.markdown b/getting-started/mix-otp/supervisor-and-application.markdown
index 60a9b41d4..2d073b41b 100644
--- a/getting-started/mix-otp/supervisor-and-application.markdown
+++ b/getting-started/mix-otp/supervisor-and-application.markdown
@@ -1,273 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Supervisor and Application
-category: Mix and OTP
+layout: redirect
+sitemap: false
+redirect_to: supervisor-and-application
 ---
-
-{% include mix-otp-preface.html %}
-
-In the previous chapter about `GenServer`, we implemented `KV.Registry` to manage buckets. At some point, we started monitoring buckets so we were able to take action whenever a `KV.Bucket` crashed. Although the change was relatively small, it introduced a question which is frequently asked by Elixir developers: what happens when something fails?
-
-Before we added monitoring, if a bucket crashed, the registry would forever point to a bucket that no longer exists. If a user tried to read or write to the crashed bucket, it would fail. Any attempt at creating a new bucket with the same name would just return the PID of the crashed bucket. In other words, that registry entry for that bucket would forever be in a bad state. Once we added monitoring, the registry automatically removes the entry for the crashed bucket. Trying to lookup the crashed bucket now (correctly) says the bucket does not exist and a user of the system can successfully create a new one if desired.
-
-In practice, we are not expecting the processes working as buckets to fail. But, if it does happen, for whatever reason, we can rest assured that our system will continue to work as intended.
-
-If you have prior programming experience, you may be wondering: "could we just guarantee the bucket does not crash in the first place?". As we will see, Elixir developers tend to refer to those practices as "defensive programming". That's because a live production system has dozens of different reasons why something can go wrong. The disk can fail, memory can be corrupted, bugs, the network may stop working for a second, etc. If we were to write software that attempted to protect or circumvent all of those errors, we would spend more time handling failures than writing our own software!
-
-Therefore, an Elixir developer prefers to "let it crash" or "fail fast". And one of the most common ways we can recover from a failure is by restarting whatever part of the system crashed.
-
-For example, imagine your computer, router, printer, or whatever device is not working properly. How often do you fix it by restarting it? Once we restart the device, we reset the device back to its initial state, which is well-tested and guaranteed to work. In Elixir, we apply this same approach to software: whenever a process crashes, we start a new process to perform the same job as the crashed process.
-
-In Elixir, this is done by a Supervisor. A Supervisor is a process that supervises other processes and restarts them whenever they crash. To do so, Supervisors manage the whole life-cycle of any supervised processes, including startup and shutdown.
-
-In this chapter, we will learn how to put those concepts into practice by supervising the `KV.Registry` process. After all, if something goes wrong with the registry, the whole registry is lost and no bucket could ever be found! To address this, we will define a `KV.Supervisor` module that guarantees that our `KV.Registry` is up and running at any given moment.
-
-At the end of the chapter, we will also talk about Applications. As we will see, Mix has been packaging all of our code into an application, and we will learn how to customize our application to guarantee that our Supervisor and the Registry are up and running whenever our system starts.
-
-## Our first supervisor
-
-A supervisor is a process which supervises other processes, which we refer to as child processes. The act of supervising a process includes three distinct responsibilities. The first one is to start child processes. Once a child process is running, the supervisor may restart a child process, either because it terminated abnormally or because a certain condition was reached. For example, a supervisor may restart all children if any child dies. Finally, a supervisor is also responsible for shutting down the child processes when the system is shutting down. Please see the [Supervisor](https://hexdocs.pm/elixir/Supervisor.html) module for a more in-depth discussion.
-
-Creating a supervisor is not much different from creating a GenServer. We are going to define a module named `KV.Supervisor`, which will use the Supervisor behaviour, inside the `lib/kv/supervisor.ex` file:
-
-```elixir
-defmodule KV.Supervisor do
-  use Supervisor
-
-  def start_link(opts) do
-    Supervisor.start_link(__MODULE__, :ok, opts)
-  end
-
-  @impl true
-  def init(:ok) do
-    children = [
-      KV.Registry
-    ]
-
-    Supervisor.init(children, strategy: :one_for_one)
-  end
-end
-```
-
-Our supervisor has a single child so far: `KV.Registry`. After we define a list of children, we call `Supervisor.init/2`, passing the children and the supervision strategy.
-
-The supervision strategy dictates what happens when one of the children crashes. `:one_for_one` means that if a child dies, it will be the only one restarted. Since we have only one child now, that's all we need. The `Supervisor` behaviour supports many different strategies and we will discuss them in this chapter.
-
-Once the supervisor starts, it will traverse the list of children and it will invoke the `child_spec/1` function on each module.
-
-The `child_spec/1` function returns the child specification which describes how to start the process, if the process is a worker or a supervisor, if the process is temporary, transient or permanent and so on. The `child_spec/1` function is automatically defined when we `use Agent`, `use GenServer`, `use Supervisor`, etc. Let's give it a try in the terminal with `iex -S mix`:
-
-```elixir
-iex> KV.Registry.child_spec([])
-%{id: KV.Registry, start: {KV.Registry, :start_link, [[]]}}
-```
-
-We will learn those details as we move forward on this guide. If you would rather peek ahead, check the [Supervisor](https://hexdocs.pm/elixir/Supervisor.html) docs.
-
-After the supervisor retrieves all child specifications, it proceeds to start its children one by one, in the order they were defined, using the information in the `:start` key in the child specification. For our current specification, it will call `KV.Registry.start_link([])`.
-
-Let's take the supervisor for a spin:
-
-```elixir
-iex> {:ok, sup} = KV.Supervisor.start_link([])
-{:ok, #PID<0.148.0>}
-iex> Supervisor.which_children(sup)
-[{KV.Registry, #PID<0.150.0>, :worker, [KV.Registry]}]
-```
-
-So far we have started the supervisor and listed its children. Once the supervisor started, it also started all of its children.
-
-What happens if we intentionally crash the registry started by the supervisor? Let's do so by sending it a bad input on `call`:
-
-```elixir
-iex> [{_, registry, _, _}] = Supervisor.which_children(sup)
-[{KV.Registry, #PID<0.150.0>, :worker, [KV.Registry]}]
-iex> GenServer.call(registry, :bad_input)
-08:52:57.311 [error] GenServer #PID<0.150.0> terminating
-** (FunctionClauseError) no function clause matching in KV.Registry.handle_call/3
-iex> Supervisor.which_children(sup)
-[{KV.Registry, #PID<0.157.0>, :worker, [KV.Registry]}]
-```
-
-Notice how the supervisor automatically started a new registry, with a new PID, in place of the first one once we caused it to crash due to a bad input.
-
-In the previous chapters, we have always started processes directly. For example, we would call `KV.Registry.start_link([])`, which would return `{:ok, pid}`, and that would allow us to interact with the registry via its `pid`. Now that processes are started by the supervisor, we have to directly ask the supervisor who its children are, and fetch the pid from the returned list of children. In practice, doing so every time would be very expensive. To address this, we often give names to processes, allowing them to be uniquely identified in a single machine from anywhere in our code.
-
-Let's learn how to do that.
-
-## Naming processes
-
-While our application will have many buckets, it will only have a single registry. Therefore, whenever we start the registry, we want to give it a unique name so we can reach out to it from anywhere. We do so by passing a `:name` option to `KV.Registry.start_link/1`.
-
-Let's slightly change our children definition (in `KV.Supervisor.init/1`) to be a list of tuples instead of a list of atoms:
-
-```elixir
-  def init(:ok) do
-    children = [
-      {KV.Registry, name: KV.Registry}
-    ]
-```
-
-With this in place, the supervisor will now start `KV.Registry` by calling `KV.Registry.start_link(name: KV.Registry)`.
-
-If you revisit the `KV.Registry.start_link/1` implementation, you will remember it simply passes the options to GenServer:
-
-```elixir
-  def start_link(opts) do
-    GenServer.start_link(__MODULE__, :ok, opts)
-  end
-```
-
-which in turn will register the process with the given name. The `:name` option expects an atom for locally named processes (locally named means it is available to this machine - there are other options, which we won't discuss here). Since module identifiers are atoms (try `i(KV.Registry)` in IEx), we can name a process after the module that implements it, provided there is only one process for that name. This helps when debugging and introspecting the system.
-
-Let's give the updated supervisor a try inside `iex -S mix`:
-
-```elixir
-iex> KV.Supervisor.start_link([])
-{:ok, #PID<0.66.0>}
-iex> KV.Registry.create(KV.Registry, "shopping")
-:ok
-iex> KV.Registry.lookup(KV.Registry, "shopping")
-{:ok, #PID<0.70.0>}
-```
-
-This time the supervisor started a named registry, allowing us to create buckets without having to explicitly fetch the PID from the supervisor. You should also know how to make the registry crash again, without looking up its PID: give it a try.
-
-> At this point, you may be wondering: should you also locally name bucket processes? Remember buckets are started dynamically based on user input. Since local names MUST be atoms, we would have to dynamically create atoms, which is a bad idea since once an atom is defined, it is never erased nor garbage collected. This means that, if we create atoms dynamically based on user input, we will eventually run out of memory (or to be more precise, the VM will crash because it imposes a hard limit on the number of atoms). This limitation is precisely why we created our own registry (or why one would use Elixir's built-in [`Registry`](https://hexdocs.pm/elixir/Registry.html) module).
-
-We are getting closer and closer to a fully working system. The supervisor automatically starts the registry. But how can we automatically start the supervisor whenever our system starts? To answer this question, let's talk about applications.
-
-## Understanding applications
-
-We have been working inside an application this entire time. Every time we changed a file and ran `mix compile`, we could see a `Generated kv app` message in the compilation output.
-
-We can find the generated `.app` file at `_build/dev/lib/kv/ebin/kv.app`. Let's have a look at its contents:
-
-```erlang
-{application,kv,
-             [{applications,[kernel,stdlib,elixir,logger]},
-              {description,"kv"},
-              {modules,['Elixir.KV','Elixir.KV.Bucket','Elixir.KV.Registry',
-                        'Elixir.KV.Supervisor']},
-              {registered,[]},
-              {vsn,"0.1.0"}]}.
-```
-
-This file contains Erlang terms (written using Erlang syntax). Even though we are not familiar with Erlang, it is easy to guess this file holds our application definition. It contains our application `version`, all the modules defined by it, as well as a list of applications we depend on, like Erlang's `kernel`, `elixir` itself, and `logger`.
-
-> The `logger` application ships as part of Elixir. We stated that our application needs it by specifying it in the `:extra_applications` list in `mix.exs`. See the [official docs](https://hexdocs.pm/logger) for more information.
-
-In a nutshell, an application consists of all of the modules defined in the `.app` file, including the `.app` file itself. An application has generally only two directories: `ebin`, for Elixir artefacts, such as `.beam` and `.app` files, and `priv`, with any other artefact or asset you may need in your application.
-
-Although Mix generates and maintains the `.app` file for us, we can customize its contents by adding new entries to the `application/0` function inside the `mix.exs` project file. We are going to do our first customization soon.
-
-### Starting applications
-
-Each application in our system can be started and stopped. The rules for starting and stopping an application are also defined in the `.app` file. When we invoke `iex -S mix`, Mix compiles our application and then starts it.
-
-Let's see this in practice. Start a console with `iex -S mix` and try:
-
-```elixir
-iex> Application.start(:kv)
-{:error, {:already_started, :kv}}
-```
-
-Oops, it's already started. Mix starts the current application and all of its dependencies automatically. This is also true for `mix test` and many other Mix commands.
-
-You can change this behaviour by giving the `--no-start` flag to Mix. It is rarely used in practice but it allows us to understand the underlying mechanisms better. Let's give it a try.
-
-Invoking `mix` is the same as `mix run`. Therefore, if you want to pass a flag to `mix` or `iex -S mix`, we just need to add the task name and the desired flags. For example, run `iex -S mix run --no-start`:
-
-```elixir
-iex> Application.start(:kv)
-:ok
-```
-
-We can stop our `:kv` application as well as the `:logger` application, which is started by default with Elixir:
-
-```elixir
-iex> Application.stop(:kv)
-:ok
-iex> Application.stop(:logger)
-:ok
-```
-
-And let's try to start our application again:
-
-```elixir
-iex> Application.start(:kv)
-{:error, {:not_started, :logger}}
-```
-
-Now we get an error because an application that `:kv` depends on (`:logger` in this case) isn't started. We need to either start each application manually in the correct order or call `Application.ensure_all_started` as follows:
-
-```elixir
-iex> Application.ensure_all_started(:kv)
-{:ok, [:logger, :kv]}
-```
-
-In practice, our tools always start our applications for us, but there is an API available if you need fine-grained control.
-
-## The application callback
-
-Whenever we invoke `iex -S mix`, Mix automatically starts our application by calling `Application.start(:kv)`. But can we customize what happens when our application starts? As a matter of fact, we can! To do so, we define an application callback.
-
-The first step is to tell our application definition (i.e. our `.app` file) which module is going to implement the application callback. Let's do so by opening  `mix.exs` and changing `def application` to the following:
-
-```elixir
-  def application do
-    [
-      extra_applications: [:logger],
-      mod: {KV, []}
-    ]
-  end
-```
-
-The `:mod` option specifies the "application callback module", followed by the arguments to be passed on application start. The application callback module can be any module that implements the [Application](https://hexdocs.pm/elixir/Application.html) behaviour.
-
-To implement the `Application` behaviour, we have to `use Application` and define a `start/2` function. The goal of `start/2` is to start a supervisor, which will then start any child services or execute any other code our application may need. Let's use this opportunity to start the `KV.Supervisor` we have implemented earlier in this chapter.
-
-Since we have specified `KV` as the module callback, let's change the `KV` module defined in `lib/kv.ex` to implement a `start/2` function:
-
-```elixir
-defmodule KV do
-  use Application
-
-  @impl true
-  def start(_type, _args) do
-    # Although we don't use the supervisor name below directly,
-    # it can be useful when debugging or introspecting the system.
-    KV.Supervisor.start_link(name: KV.Supervisor)
-  end
-end
-```
-
-> Please note that by doing this, we are breaking the boilerplate test case which tested the `hello` function in `KV`. You can simply remove that test case.
-
-When we `use Application`, we may define a couple of functions, similar to when we used `Supervisor` or `GenServer`. This time we only had to define a `start/2` function. The `Application` behaviour also has a `stop/1` callback, but it is rarely used in practice. You can check the documentation for more information.
-
-Now that you have defined an application callback which starts our supervisor, we expect the `KV.Registry` process to be up and running as soon as we start `iex -S mix`. Let's give it another try:
-
-```elixir
-iex> KV.Registry.create(KV.Registry, "shopping")
-:ok
-iex> KV.Registry.lookup(KV.Registry, "shopping")
-{:ok, #PID<0.88.0>}
-```
-
-Let's recap what is happening. Whenever we invoke `iex -S mix`, it automatically starts our application by calling `Application.start(:kv)`, which then invokes the application callback. The application callback's job is to start a **supervision tree**. Right now, our supervisor has a single child named `KV.Registry`, started with name `KV.Registry`. Our supervisor could have other children, and some of these children could be their own supervisors with their own children, leading to the so-called supervision trees.
-
-## Projects or applications?
-
-Mix makes a distinction between projects and applications. Based on the contents of our `mix.exs` file, we would say we have a Mix project that defines the `:kv` application. As we will see in later chapters, there are projects that don't define any application.
-
-When we say "project" you should think about Mix. Mix is the tool that manages your project. It knows how to compile your project, test your project and more. It also knows how to compile and start the application relevant to your project.
-
-When we talk about applications, we talk about <abbr title="Open Telecom Platform">OTP</abbr>. Applications are the entities that are started and stopped as a whole by the runtime. You can learn more about applications and how they relate to booting and shutting down of your system as a whole in the [docs for the Application module](https://hexdocs.pm/elixir/Application.html).
-
-## Next steps
-
-Although this chapter was the first time we implemented a supervisor, it was not the first time we used one! In the previous chapter, when we used `start_supervised!` to start the registry during our tests, `ExUnit` started the registry under a supervisor managed by the ExUnit framework itself. By defining our own supervisor, we provide more structure on how we initialize, shutdown and supervise processes in our applications, aligning our production code and tests with best practices.
-
-But we are not done yet. So far we are supervising the registry but our application is also starting buckets. Since buckets are started dynamically, we can use a special type of supervisor called `DynamicSupervisor`, which is optimized to handle such scenarios. Let's explore it next.
diff --git a/getting-started/mix-otp/task-and-gen-tcp.markdown b/getting-started/mix-otp/task-and-gen-tcp.markdown
index a90bca993..a278081ed 100644
--- a/getting-started/mix-otp/task-and-gen-tcp.markdown
+++ b/getting-started/mix-otp/task-and-gen-tcp.markdown
@@ -1,312 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Task and gen_tcp
-category: Mix and OTP
+layout: redirect
+sitemap: false
+redirect_to: task-and-gen-tcp
 ---
-
-{% include mix-otp-preface.html %}
-
-In this chapter, we are going to learn how to use [Erlang's `:gen_tcp` module](http://www.erlang.org/doc/man/gen_tcp.html) to serve requests. This provides a great opportunity to explore Elixir's `Task` module. In future chapters, we will expand our server so it can actually serve the commands.
-
-## Echo server
-
-We will start our TCP server by first implementing an echo server. It will send a response with the text it received in the request. We will slowly improve our server until it is supervised and ready to handle multiple connections.
-
-A TCP server, in broad strokes, performs the following steps:
-
-  1. Listens to a port until the port is available and it gets hold of the socket
-  2. Waits for a client connection on that port and accepts it
-  3. Reads the client request and writes a response back
-
-Let's implement those steps. Move to the `apps/kv_server` application, open up `lib/kv_server.ex`, and add the following functions:
-
-```elixir
-defmodule KVServer do
-  require Logger
-
-  def accept(port) do
-    # The options below mean:
-    #
-    # 1. `:binary` - receives data as binaries (instead of lists)
-    # 2. `packet: :line` - receives data line by line
-    # 3. `active: false` - blocks on `:gen_tcp.recv/2` until data is available
-    # 4. `reuseaddr: true` - allows us to reuse the address if the listener crashes
-    #
-    {:ok, socket} =
-      :gen_tcp.listen(port, [:binary, packet: :line, active: false, reuseaddr: true])
-    Logger.info("Accepting connections on port #{port}")
-    loop_acceptor(socket)
-  end
-
-  defp loop_acceptor(socket) do
-    {:ok, client} = :gen_tcp.accept(socket)
-    serve(client)
-    loop_acceptor(socket)
-  end
-
-  defp serve(socket) do
-    socket
-    |> read_line()
-    |> write_line(socket)
-
-    serve(socket)
-  end
-
-  defp read_line(socket) do
-    {:ok, data} = :gen_tcp.recv(socket, 0)
-    data
-  end
-
-  defp write_line(line, socket) do
-    :gen_tcp.send(socket, line)
-  end
-end
-```
-
-We are going to start our server by calling `KVServer.accept(4040)`, where 4040 is the port. The first step in `accept/1` is to listen to the port until the socket becomes available and then call `loop_acceptor/1`. `loop_acceptor/1` is a loop accepting client connections. For each accepted connection, we call `serve/1`.
-
-`serve/1` is another loop that reads a line from the socket and writes those lines back to the socket. Note that the `serve/1` function uses [the pipe operator `|>`](https://hexdocs.pm/elixir/Kernel.html#%7C%3E/2) to express this flow of operations. The pipe operator evaluates the left side and passes its result as the first argument to the function on the right side. The example above:
-
-```elixir
-socket |> read_line() |> write_line(socket)
-```
-
-is equivalent to:
-
-```elixir
-write_line(read_line(socket), socket)
-```
-
-The `read_line/1` implementation receives data from the socket using `:gen_tcp.recv/2` and `write_line/2` writes to the socket using `:gen_tcp.send/2`.
-
-Note that `serve/1` is an infinite loop called sequentially inside `loop_acceptor/1`, so the tail call to `loop_acceptor/1` is never reached and could be avoided. However, as we shall see, we will need to execute `serve/1` in a separate process, so we will need that tail call soon.
-
-This is pretty much all we need to implement our echo server. Let's give it a try!
-
-Start an IEx session inside the `kv_server` application with `iex -S mix`. Inside IEx, run:
-
-```elixir
-iex> KVServer.accept(4040)
-```
-
-The server is now running, and you will even notice the console is blocked. Let's use [a `telnet` client](https://en.wikipedia.org/wiki/Telnet) to access our server. There are clients available on most operating systems, and their command lines are generally similar:
-
-```console
-$ telnet 127.0.0.1 4040
-Trying 127.0.0.1...
-Connected to localhost.
-Escape character is '^]'.
-hello
-hello
-is it me
-is it me
-you are looking for?
-you are looking for?
-```
-
-Type "hello", press enter, and you will get "hello" back. Excellent!
-
-My particular telnet client can be exited by typing `ctrl + ]`, typing `quit`, and pressing `<Enter>`, but your client may require different steps.
-
-Once you exit the telnet client, you will likely see an error in the IEx session:
-
-    ** (MatchError) no match of right hand side value: {:error, :closed}
-        (kv_server) lib/kv_server.ex:45: KVServer.read_line/1
-        (kv_server) lib/kv_server.ex:37: KVServer.serve/1
-        (kv_server) lib/kv_server.ex:30: KVServer.loop_acceptor/1
-
-That's because we were expecting data from `:gen_tcp.recv/2` but the client closed the connection. We need to handle such cases better in future revisions of our server.
-
-For now, there is a more important bug we need to fix: what happens if our TCP acceptor crashes? Since there is no supervision, the server dies and we won't be able to serve more requests, because it won't be restarted. That's why we must move our server to a supervision tree.
-
-## Tasks
-
-We have learned about agents, generic servers, and supervisors. They are all meant to work with multiple messages or manage state. But what do we use when we only need to execute some task and that is it?
-
-[The Task module](https://hexdocs.pm/elixir/Task.html) provides this functionality exactly. For example, it has a `start_link/1` function that receives an anonymous function and executes it inside a new process that will be part of a supervision tree.
-
-Let's give it a try. Open up `lib/kv_server/application.ex`, and let's change the supervisor in the `start/2` function to the following:
-
-```elixir
-  def start(_type, _args) do
-    children = [
-      {Task, fn -> KVServer.accept(4040) end}
-    ]
-
-    opts = [strategy: :one_for_one, name: KVServer.Supervisor]
-    Supervisor.start_link(children, opts)
-  end
-```
-
-As usual, we've passed a two-element tuple as a child specification, which in turn will invoke `Task.start_link/1`.
-
-With this change, we are saying that we want to run `KVServer.accept(4040)` as a task. We are hardcoding the port for now but this could be changed in a few ways, for example, by reading the port out of the system environment when starting the application:
-
-```elixir
-port = String.to_integer(System.get_env("PORT") || "4040")
-# ...
-{Task, fn -> KVServer.accept(port) end}
-```
-
-Insert these changes in your code and now you may start your application using the following command `PORT=4321 mix run --no-halt`, notice how we are passing the port as a variable, but still defaults to 4040 if none is given.
-
-Now that the server is part of the supervision tree, it should start automatically when we run the application. Start your server, now passing the port, and once again use the `telnet` client to make sure that everything still works:
-
-```console
-$ telnet 127.0.0.1 4321
-Trying 127.0.0.1...
-Connected to localhost.
-Escape character is '^]'.
-say you
-say you
-say me
-say me
-```
-
-Yes, it works! However, does it *scale*?
-
-Try to connect two telnet clients at the same time. When you do so, you will notice that the second client doesn't echo:
-
-```console
-$ telnet 127.0.0.1 4321
-Trying 127.0.0.1...
-Connected to localhost.
-Escape character is '^]'.
-hello
-hello?
-HELLOOOOOO?
-```
-
-It doesn't seem to work at all. That's because we are serving requests in the same process that are accepting connections. When one client is connected, we can't accept another client.
-
-## Task supervisor
-
-In order to make our server handle simultaneous connections, we need to have one process working as an acceptor that spawns other processes to serve requests. One solution would be to change:
-
-```elixir
-defp loop_acceptor(socket) do
-  {:ok, client} = :gen_tcp.accept(socket)
-  serve(client)
-  loop_acceptor(socket)
-end
-```
-
-to also use `Task.start_link/1`:
-
-```elixir
-defp loop_acceptor(socket) do
-  {:ok, client} = :gen_tcp.accept(socket)
-  Task.start_link(fn -> serve(client) end)
-  loop_acceptor(socket)
-end
-```
-
-We are starting a linked Task directly from the acceptor process. But we've already made this mistake once. Do you remember?
-
-This is similar to the mistake we made when we called `KV.Bucket.start_link/1` straight from the registry. That meant a failure in any bucket would bring the whole registry down.
-
-The code above would have the same flaw: if we link the `serve(client)` task to the acceptor, a crash when serving a request would bring the acceptor, and consequently all other connections, down.
-
-We fixed the issue for the registry by using a simple one for one supervisor. We are going to use the same tactic here, except that this pattern is so common with tasks that `Task` already comes with a solution: a simple one for one supervisor that starts temporary tasks as part of our supervision tree.
-
-Let's change `start/2` once again, to add a supervisor to our tree:
-
-```elixir
-  def start(_type, _args) do
-    port = String.to_integer(System.get_env("PORT") || "4040")
-
-    children = [
-      {Task.Supervisor, name: KVServer.TaskSupervisor},
-      {Task, fn -> KVServer.accept(port) end}
-    ]
-
-    opts = [strategy: :one_for_one, name: KVServer.Supervisor]
-    Supervisor.start_link(children, opts)
-  end
-```
-
-We'll now start a [`Task.Supervisor`](https://hexdocs.pm/elixir/Task.Supervisor.html) process with name `KVServer.TaskSupervisor`. Remember, since the acceptor task depends on this supervisor, the supervisor must be started first.
-
-Now we need to change `loop_acceptor/1` to use `Task.Supervisor` to serve each request:
-
-```elixir
-defp loop_acceptor(socket) do
-  {:ok, client} = :gen_tcp.accept(socket)
-  {:ok, pid} = Task.Supervisor.start_child(KVServer.TaskSupervisor, fn -> serve(client) end)
-  :ok = :gen_tcp.controlling_process(client, pid)
-  loop_acceptor(socket)
-end
-```
-
-You might notice that we added a line, `:ok = :gen_tcp.controlling_process(client, pid)`. This makes the child process the "controlling process" of the `client` socket. If we didn't do this, the acceptor would bring down all the clients if it crashed because sockets would be tied to the process that accepted them (which is the default behaviour).
-
-Start a new server with `PORT=4040 mix run --no-halt` and we can now open up many concurrent telnet clients. You will also notice that quitting a client does not bring the acceptor down. Excellent!
-
-Here is the full echo server implementation:
-
-```elixir
-defmodule KVServer do
-  require Logger
-
-  @doc """
-  Starts accepting connections on the given `port`.
-  """
-  def accept(port) do
-    {:ok, socket} = :gen_tcp.listen(port,
-                      [:binary, packet: :line, active: false, reuseaddr: true])
-    Logger.info "Accepting connections on port #{port}"
-    loop_acceptor(socket)
-  end
-
-  defp loop_acceptor(socket) do
-    {:ok, client} = :gen_tcp.accept(socket)
-    {:ok, pid} = Task.Supervisor.start_child(KVServer.TaskSupervisor, fn -> serve(client) end)
-    :ok = :gen_tcp.controlling_process(client, pid)
-    loop_acceptor(socket)
-  end
-
-  defp serve(socket) do
-    socket
-    |> read_line()
-    |> write_line(socket)
-
-    serve(socket)
-  end
-
-  defp read_line(socket) do
-    {:ok, data} = :gen_tcp.recv(socket, 0)
-    data
-  end
-
-  defp write_line(line, socket) do
-    :gen_tcp.send(socket, line)
-  end
-end
-```
-
-Since we have changed the supervisor specification, we need to ask: is our supervision strategy still correct?
-
-In this case, the answer is yes: if the acceptor crashes, there is no need to crash the existing connections. On the other hand, if the task supervisor crashes, there is no need to crash the acceptor too.
-
-However, there is still one concern left, which are the restart strategies. Tasks, by default, have the `:restart` value set to `:temporary`, which means they are not restarted. This is an excellent default for the connections started via the `Task.Supervisor`, as it makes no sense to restart a failed connection, but it is a bad choice for the acceptor. If the acceptor crashes, we want to bring the acceptor up and running again.
-
-We could fix this by defining our own module that calls `use Task, restart: :permanent` and invokes a `start_link` function responsible for restarting the task, quite similar to `Agent` and `GenServer`. However, let's take a different approach here. When integrating with someone else's library, we won't be able to change how their agents, tasks, and servers are defined. Instead, we need to be able to customize their child specification dynamically. This can be done by using `Supervisor.child_spec/2`, a function that we happen to know from previous chapters. Let's rewrite `start/2` in `KVServer.Application` once more:
-
-```elixir
-  def start(_type, _args) do
-    port = String.to_integer(System.get_env("PORT") || "4040")
-
-    children = [
-      {Task.Supervisor, name: KVServer.TaskSupervisor},
-      Supervisor.child_spec({Task, fn -> KVServer.accept(port) end}, restart: :permanent)
-    ]
-
-    opts = [strategy: :one_for_one, name: KVServer.Supervisor]
-    Supervisor.start_link(children, opts)
-  end
-```
-
-`Supervisor.child_spec/2` is capable of building a child specification from a given module and/or tuple, and it also accepts values that override the underlying child specification. Now we have an always running acceptor that starts temporary task processes under an always running task supervisor.
-
-In the next chapter, we will start parsing the client requests and sending responses, finishing our server.
diff --git a/getting-started/module-attributes.markdown b/getting-started/module-attributes.markdown
index 5a72cdc1b..026b62136 100644
--- a/getting-started/module-attributes.markdown
+++ b/getting-started/module-attributes.markdown
@@ -1,190 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Module attributes
+layout: redirect
+sitemap: false
+redirect_to: module-attributes
 ---
-
-Module attributes in Elixir serve three purposes:
-
-1. They serve to annotate the module, often with information to be used by the user or the <abbr title="Virtual Machine">VM</abbr>.
-2. They work as constants.
-3. They work as a temporary module storage to be used during compilation.
-
-Let's check each case, one by one.
-
-## As annotations
-
-Elixir brings the concept of module attributes from Erlang. For example:
-
-```elixir
-defmodule MyServer do
-  @moduledoc "My server code."
-end
-```
-
-In the example above, we are defining the module documentation by using the module attribute syntax. Elixir has a handful of reserved attributes. Here are a few of them, the most commonly used ones:
-
-* `@moduledoc` - provides documentation for the current module.
-* `@doc` - provides documentation for the function or macro that follows the attribute.
-* `@spec` - provides a typespec for the function that follows the attribute.
-* `@behaviour` - (notice the British spelling) used for specifying an <abbr title="Open Telecom Platform">OTP</abbr> or user-defined behaviour.
-
-`@moduledoc` and `@doc` are by far the most used attributes, and we expect you to use them a lot. Elixir treats documentation as first-class and provides many functions to access documentation. You can read more about [writing documentation in Elixir in our official documentation](https://hexdocs.pm/elixir/writing-documentation.html).
-
-Let's go back to the `Math` module defined in the previous chapters, add some documentation and save it to the `math.ex` file:
-
-```elixir
-defmodule Math do
-  @moduledoc """
-  Provides math-related functions.
-
-  ## Examples
-
-      iex> Math.sum(1, 2)
-      3
-
-  """
-
-  @doc """
-  Calculates the sum of two numbers.
-  """
-  def sum(a, b), do: a + b
-end
-```
-
-Elixir promotes the use of Markdown with heredocs to write readable documentation. Heredocs are multi-line strings, they start and end with triple double-quotes, keeping the formatting of the inner text. We can access the documentation of any compiled module directly from IEx:
-
-```console
-$ elixirc math.ex
-$ iex
-```
-
-```elixir
-iex> h Math # Access the docs for the module Math
-...
-iex> h Math.sum # Access the docs for the sum function
-...
-```
-
-We also provide a tool called [ExDoc](https://github.com/elixir-lang/ex_doc) which is used to generate HTML pages from the documentation.
-
-You can take a look at the docs for [Module](https://hexdocs.pm/elixir/Module.html) for a complete list of supported attributes. Elixir also uses attributes to define [typespecs](/getting-started/typespecs-and-behaviours.html).
-
-This section covers built-in attributes. However, attributes can also be used by developers or extended by libraries to support custom behaviour.
-
-## As "constants"
-
-Elixir developers often use module attributes when they wish to make a value more visible or reusable:
-
-```elixir
-defmodule MyServer do
-  @initial_state %{host: "127.0.0.1", port: 3456}
-  IO.inspect @initial_state
-end
-```
-
-Trying to access an attribute that was not defined will print a warning:
-
-```elixir
-defmodule MyServer do
-  @unknown
-end
-warning: undefined module attribute @unknown, please remove access to @unknown or explicitly set it before access
-```
-
-Attributes can also be read inside functions:
-
-```elixir
-defmodule MyServer do
-  @my_data 14
-  def first_data, do: @my_data
-  @my_data 13
-  def second_data, do: @my_data
-end
-
-MyServer.first_data #=> 14
-MyServer.second_data #=> 13
-```
-
-> Note: do not add a newline between the attribute and its value, otherwise Elixir will assume you are reading the value, rather than setting it.
-
-Functions may be called when defining a module attribute:
-
-```elixir
-defmodule MyApp.Status do
-  @service URI.parse("https://example.com")
-  def status(email) do
-    SomeHttpClient.get(@service)
-  end
-end
-```
-
-The function above will be called at compilation time and its *return value*, not the function call itself, is what will be substituted in for the attribute. So the above will effectively compile to this:
-
-```elixir
-defmodule MyApp.Status do
-  def status(email) do
-    SomeHttpClient.get(%URI{
-      authority: "example.com",
-      host: "example.com",
-      port: 443,
-      scheme: "https"
-    })
-  end
-end
-```
-
-This can be useful for pre-computing constant values, but it can also cause problems if you're expecting the function to be called at runtime. For example, if you are reading a value from a database or an environment variable inside an attribute, be aware that it will read that value only at compilation time. Be careful, however: *functions defined in the same module as the attribute itself cannot be called* because they have not yet been compiled when the attribute is being defined.
-
-Every time an attribute is read inside a function, Elixir takes a snapshot of its current value. Therefore if you read the same attribute multiple times inside multiple functions, you may end-up making multiple copies of it. That's usually not an issue, but if you are using functions to compute large module attributes, that can slow down compilation. The solution is to move the attribute to shared function. For example, instead of this:
-
-```elixir
-def some_function, do: do_something_with(@example)
-def another_function, do: do_something_else_with(@example)
-```
-
-Prefer this:
-
-```elixir
-def some_function, do: do_something_with(example())
-def another_function, do: do_something_else_with(example())
-defp example, do: @example
-```
-
-If `@example` is cheap to compute, it may be even better to skip the module attribute altogether, and compute its value inside the function.
-
-### Accumulating attributes
-
-Normally, repeating a module attribute will cause its value to be reassigned, but there are circumstances where you may want to [configure the module attribute](https://hexdocs.pm/elixir/Module.html#register_attribute/3) so that its values are accumulated:
-
-```elixir
-defmodule Foo do
-  Module.register_attribute __MODULE__, :param, accumulate: true
-
-  @param :foo
-  @param :bar
-  # here @param == [:bar, :foo]
-end
-```
-
-## As temporary storage
-
-To see an example of using module attributes as storage, look no further than Elixir's unit test framework called [ExUnit](https://hexdocs.pm/ex_unit/). ExUnit uses module attributes for multiple different purposes:
-
-```elixir
-defmodule MyTest do
-  use ExUnit.Case, async: true
-
-  @tag :external
-  @tag os: :unix
-  test "contacts external service" do
-    # ...
-  end
-end
-```
-
-In the example above, `ExUnit` stores the value of `async: true` in a module attribute to change how the module is compiled. Tags are also defined as `accumulate: true` attributes, and they store tags that can be used to setup and filter tests. For example, you can avoid running external tests on your machine because they are slow and dependent on other services, while they can still be enabled in your build system.
-
-In order to understand the underlying code, we'd need macros, so we will revisit this pattern in the meta-programming guide and learn how to use module attributes as storage to allow developers to create Domain Specific Languages (DSLs).
-
-In the next chapters, we'll explore structs and protocols before moving to exception handling and other constructs like sigils and comprehensions.
diff --git a/getting-started/modules-and-functions.markdown b/getting-started/modules-and-functions.markdown
index b561e95e7..263315f14 100644
--- a/getting-started/modules-and-functions.markdown
+++ b/getting-started/modules-and-functions.markdown
@@ -1,294 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Modules and functions
-redirect_from: /getting-started/modules.html
+layout: redirect
+sitemap: false
+redirect_to: modules-and-functions
 ---
-
-In Elixir we group several functions into modules. We've already used many different modules in the previous chapters such as [the `String` module](https://hexdocs.pm/elixir/String.html):
-
-```elixir
-iex> String.length("hello")
-5
-```
-
-In order to create our own modules in Elixir, we use the `defmodule` macro. The first letter of the module must be in uppercase. We use the `def` macro to define functions in that module. The first letter of every function must be in lowercase (or underscore):
-
-```elixir
-iex> defmodule Math do
-...>   def sum(a, b) do
-...>     a + b
-...>   end
-...> end
-
-iex> Math.sum(1, 2)
-3
-```
-
-In the following sections, our examples are going to get longer in size, and it can be tricky to type them all in the shell. It's about time for us to learn how to compile Elixir code and also how to run Elixir scripts.
-
-## Compilation
-
-Most of the time it is convenient to write modules into files so they can be compiled and reused. Let's assume we have a file named `math.ex` with the following contents:
-
-```elixir
-defmodule Math do
-  def sum(a, b) do
-    a + b
-  end
-end
-```
-
-This file can be compiled using `elixirc`:
-
-```console
-$ elixirc math.ex
-```
-
-This will generate a file named `Elixir.Math.beam` containing the bytecode for the defined module. If we start `iex` again, our module definition will be available (provided that `iex` is started in the same directory the bytecode file is in):
-
-```elixir
-iex> Math.sum(1, 2)
-3
-```
-
-Elixir projects are usually organized into three directories:
-
-* `_build` - contains compilation artifacts
-* `lib` - contains Elixir code (usually `.ex` files)
-* `test` - contains tests (usually `.exs` files)
-
-When working on actual projects, the build tool called `mix` will be responsible for compiling and setting up the proper paths for you. For learning and convenience purposes, Elixir also supports a scripted mode which is more flexible and does not generate any compiled artifacts.
-
-## Scripted mode
-
-In addition to the Elixir file extension `.ex`, Elixir also supports `.exs` files for scripting. Elixir treats both files exactly the same way, the only difference is in intention. `.ex` files are meant to be compiled while `.exs` files are used for scripting. This convention is followed by projects like `mix`.
-
-For instance, we can create a file called `math.exs`:
-
-```elixir
-defmodule Math do
-  def sum(a, b) do
-    a + b
-  end
-end
-
-IO.puts Math.sum(1, 2)
-```
-
-And execute it as:
-
-```console
-$ elixir math.exs
-```
-
-Because we used `elixir` instead of `elixirc`, the module was compiled and loaded into memory, but no `.beam` file was written to disk. In the following examples, we recommend you write your code into script files and execute them as shown above.
-
-## Named functions
-
-Inside a module, we can define functions with `def/2` and private functions with `defp/2`. A function defined with `def/2` can be invoked from other modules while a private function can only be invoked locally.
-
-```elixir
-defmodule Math do
-  def sum(a, b) do
-    do_sum(a, b)
-  end
-
-  defp do_sum(a, b) do
-    a + b
-  end
-end
-
-IO.puts Math.sum(1, 2)    #=> 3
-IO.puts Math.do_sum(1, 2) #=> ** (UndefinedFunctionError)
-```
-
-Function declarations also support guards and multiple clauses. If a function has several clauses, Elixir will try each clause until it finds one that matches. Here is an implementation of a function that checks if the given number is zero or not:
-
-```elixir
-defmodule Math do
-  def zero?(0) do
-    true
-  end
-
-  def zero?(x) when is_integer(x) do
-    false
-  end
-end
-
-IO.puts Math.zero?(0)         #=> true
-IO.puts Math.zero?(1)         #=> false
-IO.puts Math.zero?([1, 2, 3]) #=> ** (FunctionClauseError)
-IO.puts Math.zero?(0.0)       #=> ** (FunctionClauseError)
-```
-
-The trailing question mark in `zero?` means that this function returns a boolean. To learn more about the naming conventions for modules, function names, variables and more in Elixir, see [Naming Conventions](https://hexdocs.pm/elixir/naming-conventions.html).
-
-Giving an argument that does not match any of the clauses raises an error.
-
-Similar to constructs like `if`, named functions support both `do:` and `do`-block syntax, as [we learned in the previous chapter](/getting-started/keywords-and-maps.html#do-blocks-and-keywords). For example, we can edit `math.exs` to look like this:
-
-```elixir
-defmodule Math do
-  def zero?(0), do: true
-  def zero?(x) when is_integer(x), do: false
-end
-```
-
-And it will provide the same behaviour. You may use `do:` for one-liners but always use `do`-blocks for functions spanning multiple lines. If you prefer to be consistent, you can use `do`-blocks throughout your codebase.
-
-## Function capturing
-
-Throughout this tutorial, we have been using the notation `name/arity` to refer to functions. It happens that this notation can actually be used to retrieve a named function as a function type. Start `iex`, running the `math.exs` file defined above:
-
-```console
-$ iex math.exs
-```
-
-```elixir
-iex> Math.zero?(0)
-true
-iex> fun = &Math.zero?/1
-&Math.zero?/1
-iex> is_function(fun)
-true
-iex> fun.(0)
-true
-```
-
-Remember Elixir makes a distinction between anonymous functions and named functions, where the former must be invoked with a dot (`.`) between the variable name and parentheses. The capture operator (`&`) bridges this gap by allowing named functions to be assigned to variables and passed as arguments in the same way we assign, invoke and pass anonymous functions.
-
-Local or imported functions, like `is_function/1`, can be captured without the module:
-
-```elixir
-iex> &is_function/1
-&:erlang.is_function/1
-iex> (&is_function/1).(fun)
-true
-```
-
-You can also capture operators:
-
-```elixir
-iex> add = &+/2
-&:erlang.+/2
-iex> add.(1, 2)
-3
-```
-
-Note the capture syntax can also be used as a shortcut for creating functions:
-
-```elixir
-iex> fun = &(&1 + 1)
-#Function<6.71889879/1 in :erl_eval.expr/5>
-iex> fun.(1)
-2
-
-iex> fun2 = &"Good #{&1}"
-#Function<6.127694169/1 in :erl_eval.expr/5>
-iex> fun2.("morning")
-"Good morning"
-```
-
-The `&1` represents the first argument passed into the function. `&(&1 + 1)` above is exactly the same as `fn x -> x + 1 end`. The syntax above is useful for short function definitions.
-
-You can read more about the capture operator `&` in [the `Kernel.SpecialForms` documentation](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#&/1).
-
-## Default arguments
-
-Named functions in Elixir also support default arguments:
-
-```elixir
-defmodule Concat do
-  def join(a, b, sep \\ " ") do
-    a <> sep <> b
-  end
-end
-
-IO.puts Concat.join("Hello", "world")      #=> Hello world
-IO.puts Concat.join("Hello", "world", "_") #=> Hello_world
-```
-
-Any expression is allowed to serve as a default value, but it won't be evaluated during the function definition. Every time the function is invoked and any of its default values have to be used, the expression for that default value will be evaluated:
-
-```elixir
-defmodule DefaultTest do
-  def dowork(x \\ "hello") do
-    x
-  end
-end
-```
-
-```elixir
-iex> DefaultTest.dowork
-"hello"
-iex> DefaultTest.dowork 123
-123
-iex> DefaultTest.dowork
-"hello"
-```
-
-If a function with default values has multiple clauses, it is required to create a function head (a function definition without a body) for declaring defaults:
-
-```elixir
-defmodule Concat do
-  # A function head declaring defaults
-  def join(a, b \\ nil, sep \\ " ")
-
-  def join(a, b, _sep) when is_nil(b) do
-    a
-  end
-
-  def join(a, b, sep) do
-    a <> sep <> b
-  end
-end
-
-IO.puts Concat.join("Hello", "world")      #=> Hello world
-IO.puts Concat.join("Hello", "world", "_") #=> Hello_world
-IO.puts Concat.join("Hello")               #=> Hello
-```
-
-When a variable is not used by a function or a clause, we add a leading underscore (`_`) to its name to signal this intent. This rule is also covered in our [Naming Conventions](https://hexdocs.pm/elixir/main/naming-conventions.html#underscore-_foo) document.
-
-When using default values, one must be careful to avoid overlapping function definitions. Consider the following example:
-
-```elixir
-defmodule Concat do
-  def join(a, b) do
-    IO.puts "***First join"
-    a <> b
-  end
-
-  def join(a, b, sep \\ " ") do
-    IO.puts "***Second join"
-    a <> sep <> b
-  end
-end
-```
-
-Elixir will emit the following warning:
-
-    concat.ex:7: warning: this clause cannot match because a previous clause at line 2 always matches
-
-The compiler is telling us that invoking the `join` function with two arguments will always choose the first definition of `join` whereas the second one will only be invoked when three arguments are passed:
-
-```console
-$ iex concat.ex
-```
-
-```elixir
-iex> Concat.join "Hello", "world"
-***First join
-"Helloworld"
-```
-
-```elixir
-iex> Concat.join "Hello", "world", "_"
-***Second join
-"Hello_world"
-```
-
-Removing the default argument in this case will fix the warning.
-
-This finishes our short introduction to modules. In the next chapters, we will learn how to use named functions for recursion, explore Elixir lexical directives that can be used for importing functions from other modules and discuss module attributes.
diff --git a/getting-started/modules.markdown b/getting-started/modules.markdown
new file mode 100644
index 000000000..263315f14
--- /dev/null
+++ b/getting-started/modules.markdown
@@ -0,0 +1,5 @@
+---
+layout: redirect
+sitemap: false
+redirect_to: modules-and-functions
+---
diff --git a/getting-started/optional-syntax.markdown b/getting-started/optional-syntax.markdown
index 88160157b..9231aebf5 100644
--- a/getting-started/optional-syntax.markdown
+++ b/getting-started/optional-syntax.markdown
@@ -1,98 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Optional syntax sheet
+layout: redirect
+sitemap: false
+redirect_to: optional-syntax
 ---
-
-In this guide so far, we learned that the Elixir syntax allows developers to omit delimiters in a few occasions to make code more readable. For example, we learned that parentheses are optional:
-
-```elixir
-iex> length([1, 2, 3]) == length [1, 2, 3]
-true
-```
-
-and that `do`-`end` blocks are equivalent to keyword lists:
-
-```elixir
-# do-end blocks
-iex> if true do
-...>   :this
-...> else
-...>   :that
-...> end
-:this
-
-# keyword lists
-iex> if true, do: :this, else: :that
-:this
-```
-
-Keyword lists use Elixir's regular notation for separating arguments, where we separate each key-value pair with commas, and each key is followed by `:`. In the `do`-blocks, we get rid of the colons, the commas, and separate each keyword by a newline. They are useful exactly because they remove the verbosity when writing blocks of code. Most of the time, we use the block syntax, but it is good to know they are equivalent.
-
-Those conveniences, which we call here "optional syntax", allow the language syntax core to be small, without sacrificing the readability and expressiveness of your code.  In this brief chapter, we will review the four rules provided by the language, using a short snippet as playground.
-
-## Walk-through
-
-Take the following code:
-
-```elixir
-if variable? do
-  Call.this()
-else
-  Call.that()
-end
-```
-
-Now let's remove the conveniences one by one:
-
-1. `do`-`end` blocks are equivalent to keywords:
-
-   ```elixir
-   if variable?, do: Call.this(), else: Call.that()
-   ```
-
-2. Keyword lists as last argument do not require square brackets, but let's add them:
-
-   ```elixir
-   if variable?, [do: Call.this(), else: Call.that()]
-   ```
-
-3. Keyword lists are the same as lists of two-element tuples:
-
-   ```elixir
-   if variable?, [{:do, Call.this()}, {:else, Call.that()}]
-   ```
-
-4. Finally, parentheses are optional on function calls, but let's add them:
-
-   ```elixir
-   if(variable?, [{:do, Call.this()}, {:else, Call.that()}])
-   ```
-
-That's it! Those four rules outline the optional syntax available in Elixir.
-
-To understand why these rules matter, we can briefly compare Elixir with many other programming languages. Most programming languages have several keywords for defining methods, functions, conditionals, loops, and so forth. Each of those keywords have their own syntax rules attached to them.
-
-However, in Elixir, none of these language features require special "keywords", instead they all build from this small set of rules. The other benefit is that developers can also extend the language in a way that is consistent with the language itself, since the constructs for designing and extending the language are the same. We further explore this topic in [the Meta-programming in Elixir guide](/getting-started/meta/quote-and-unquote.html).
-
-At the end of the day, those rules are what enables us to write:
-
-```elixir
-defmodule Math do
-  def add(a, b) do
-    a + b
-  end
-end
-```
-
-instead of:
-
-```elixir
-defmodule(Math, [
-  {:do, def(add(a, b), [{:do, a + b}])}
-])
-```
-
-Whenever you have any questions, this quick walk-through has you covered.
-
-Finally, if you are concerned about when to apply these rules, it's worth noting that the Elixir formatter handles those concerns for you. Most Elixir developers use the [`mix format`](https://hexdocs.pm/mix/Mix.Tasks.Format.html) task to format their codebases according to a well-defined set of rules defined by the Elixir team and the community. For instance, `mix format` will always add parentheses to function calls unless explicitly configured not to do so. This helps to maintain consistency across all codebases within organizations and the wider community.
diff --git a/getting-started/pattern-matching.markdown b/getting-started/pattern-matching.markdown
index 82c759119..bfa53ced1 100644
--- a/getting-started/pattern-matching.markdown
+++ b/getting-started/pattern-matching.markdown
@@ -1,201 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Pattern matching
+layout: redirect
+sitemap: false
+redirect_to: pattern-matching
 ---
-
-In this chapter, we will show how the `=` operator in Elixir is actually a match operator and how to use it to pattern match inside data structures. Finally, we will learn about the pin operator `^` used to access previously bound values.
-
-## The match operator
-
-We have used the `=` operator a couple times to assign variables in Elixir:
-
-```elixir
-iex> x = 1
-1
-iex> x
-1
-```
-
-In Elixir, the `=` operator is actually called *the match operator*. Let's see why:
-
-```elixir
-iex> x = 1
-1
-iex> 1 = x
-1
-iex> 2 = x
-** (MatchError) no match of right hand side value: 1
-```
-
-Notice that `1 = x` is a valid expression, and it matched because both the left and right side are equal to 1. When the sides do not match, a `MatchError` is raised.
-
-A variable can only be assigned on the left side of `=`:
-
-```elixir
-iex> 1 = unknown
-** (CompileError) iex:1: undefined variable "unknown"
-```
-
-## Pattern matching
-
-The match operator is not only used to match against simple values, but it is also useful for destructuring more complex data types. For example, we can pattern match on tuples:
-
-```elixir
-iex> {a, b, c} = {:hello, "world", 42}
-{:hello, "world", 42}
-iex> a
-:hello
-iex> b
-"world"
-```
-
-A pattern match error will occur if the sides can't be matched, for example if the tuples have different sizes:
-
-```elixir
-iex> {a, b, c} = {:hello, "world"}
-** (MatchError) no match of right hand side value: {:hello, "world"}
-```
-
-And also when comparing different types, for example if matching a tuple on the left side with a list on the right side:
-
-```elixir
-iex> {a, b, c} = [:hello, "world", 42]
-** (MatchError) no match of right hand side value: [:hello, "world", 42]
-```
-
-More interestingly, we can match on specific values. The example below asserts that the left side will only match the right side when the right side is a tuple that starts with the atom `:ok`:
-
-```elixir
-iex> {:ok, result} = {:ok, 13}
-{:ok, 13}
-iex> result
-13
-
-iex> {:ok, result} = {:error, :oops}
-** (MatchError) no match of right hand side value: {:error, :oops}
-```
-
-We can pattern match on lists:
-
-```elixir
-iex> [a, b, c] = [1, 2, 3]
-[1, 2, 3]
-iex> a
-1
-```
-
-A list also supports matching on its own head and tail:
-
-```elixir
-iex> [head | tail] = [1, 2, 3]
-[1, 2, 3]
-iex> head
-1
-iex> tail
-[2, 3]
-```
-
-Similar to the `hd/1` and `tl/1` functions, we can't match an empty list with a head and tail pattern:
-
-```elixir
-iex> [head | tail] = []
-** (MatchError) no match of right hand side value: []
-```
-
-The `[head | tail]` format is not only used on pattern matching but also for prepending items to a list:
-
-```elixir
-iex> list = [1, 2, 3]
-[1, 2, 3]
-iex> [0 | list]
-[0, 1, 2, 3]
-```
-
-Pattern matching allows developers to easily destructure data types such as tuples and lists. As we will see in the following chapters, it is one of the foundations of recursion in Elixir and applies to other types as well, like maps and binaries.
-
-## The pin operator
-
-Variables in Elixir can be rebound:
-
-```elixir
-iex> x = 1
-1
-iex> x = 2
-2
-```
-However, there are times when we don't want variables to be rebound.
-
-Use the pin operator `^` when you want to pattern match against a variable's _existing value_ rather than rebinding the variable.
-
-```elixir
-iex> x = 1
-1
-iex> ^x = 2
-** (MatchError) no match of right hand side value: 2
-```
-
-Because we have pinned `x` when it was bound to the value of `1`, it is equivalent to the following:
-
-```elixir
-iex> 1 = 2
-** (MatchError) no match of right hand side value: 2
-```
-
-Notice that we even see the exact same error message.
-
-We can use the pin operator inside other pattern matches, such as tuples or lists:
-
-```elixir
-iex> x = 1
-1
-iex> [^x, 2, 3] = [1, 2, 3]
-[1, 2, 3]
-iex> {y, ^x} = {2, 1}
-{2, 1}
-iex> y
-2
-iex> {y, ^x} = {2, 2}
-** (MatchError) no match of right hand side value: {2, 2}
-```
-
-Because `x` was bound to the value of `1` when it was pinned, this last example could have been written as:
-
-```elixir
-iex> {y, 1} = {2, 2}
-** (MatchError) no match of right hand side value: {2, 2}
-```
-
-If a variable is mentioned more than once in a pattern, all references should bind to the same value:
-
-```elixir
-iex> {x, x} = {1, 1}
-{1, 1}
-iex> {x, x} = {1, 2}
-** (MatchError) no match of right hand side value: {1, 2}
-```
-
-In some cases, you don't care about a particular value in a pattern. It is a common practice to bind those values to the underscore, `_`. For example, if only the head of the list matters to us, we can assign the tail to underscore:
-
-```elixir
-iex> [head | _] = [1, 2, 3]
-[1, 2, 3]
-iex> head
-1
-```
-
-The variable `_` is special in that it can never be read from. Trying to read from it gives a compile error:
-
-```elixir
-iex> _
-** (CompileError) iex:1: invalid use of _. "_" represents a value to be ignored in a pattern and cannot be used in expressions
-```
-
-Although pattern matching allows us to build powerful constructs, its usage is limited. For instance, you cannot make function calls on the left side of a match. The following example is invalid:
-
-```elixir
-iex> length([1, [2], 3]) = 3
-** (CompileError) iex:1: cannot invoke remote function :erlang.length/1 inside match
-```
-
-This finishes our introduction to pattern matching. As we will see in the next chapter, pattern matching is very common in many language constructs.
diff --git a/getting-started/processes.markdown b/getting-started/processes.markdown
index 6da747bb7..1435024b8 100644
--- a/getting-started/processes.markdown
+++ b/getting-started/processes.markdown
@@ -1,239 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Processes
+layout: redirect
+sitemap: false
+redirect_to: processes
 ---
-
-In Elixir, all code runs inside processes. Processes are isolated from each other, run concurrent to one another and communicate via message passing. Processes are not only the basis for concurrency in Elixir, but they also provide the means for building distributed and fault-tolerant programs.
-
-Elixir's processes should not be confused with operating system processes. Processes in Elixir are extremely lightweight in terms of memory and CPU (even compared to threads as used in many other programming languages). Because of this, it is not uncommon to have tens or even hundreds of thousands of processes running simultaneously.
-
-In this chapter, we will learn about the basic constructs for spawning new processes, as well as sending and receiving messages between processes.
-
-## `spawn`
-
-The basic mechanism for spawning new processes is the auto-imported `spawn/1` function:
-
-```elixir
-iex> spawn(fn -> 1 + 2 end)
-#PID<0.43.0>
-```
-
-`spawn/1` takes a function which it will execute in another process.
-
-Notice `spawn/1` returns a PID (process identifier). At this point, the process you spawned is very likely dead. The spawned process will execute the given function and exit after the function is done:
-
-```elixir
-iex> pid = spawn(fn -> 1 + 2 end)
-#PID<0.44.0>
-iex> Process.alive?(pid)
-false
-```
-
-> Note: you will likely get different process identifiers than the ones we are getting in this guide.
-
-We can retrieve the PID of the current process by calling `self/0`:
-
-```elixir
-iex> self()
-#PID<0.41.0>
-iex> Process.alive?(self())
-true
-```
-
-Processes get much more interesting when we are able to send and receive messages.
-
-## `send` and `receive`
-
-We can send messages to a process with `send/2` and receive them with `receive/1`:
-
-```elixir
-iex> send(self(), {:hello, "world"})
-{:hello, "world"}
-iex> receive do
-...>   {:hello, msg} -> msg
-...>   {:world, _msg} -> "won't match"
-...> end
-"world"
-```
-
-When a message is sent to a process, the message is stored in the process mailbox. The `receive/1` block goes through the current process mailbox searching for a message that matches any of the given patterns. `receive/1` supports guards and many clauses, such as `case/2`.
-
-The process that sends the message does not block on `send/2`, it puts the message in the recipient's mailbox and continues. In particular, a process can send messages to itself.
-
-If there is no message in the mailbox matching any of the patterns, the current process will wait until a matching message arrives. A timeout can also be specified:
-
-```elixir
-iex> receive do
-...>   {:hello, msg}  -> msg
-...> after
-...>   1_000 -> "nothing after 1s"
-...> end
-"nothing after 1s"
-```
-
-A timeout of 0 can be given when you already expect the message to be in the mailbox.
-
-Let's put it all together and send messages between processes:
-
-```elixir
-iex> parent = self()
-#PID<0.41.0>
-iex> spawn(fn -> send(parent, {:hello, self()}) end)
-#PID<0.48.0>
-iex> receive do
-...>   {:hello, pid} -> "Got hello from #{inspect pid}"
-...> end
-"Got hello from #PID<0.48.0>"
-```
-
-The `inspect/1` function is used to convert a data structure's internal representation into a string, typically for printing. Notice that when the `receive` block gets executed the sender process we have spawned may already be dead, as its only instruction was to send a message.
-
-While in the shell, you may find the helper `flush/0` quite useful. It flushes and prints all the messages in the mailbox.
-
-```elixir
-iex> send(self(), :hello)
-:hello
-iex> flush()
-:hello
-:ok
-```
-
-## Links
-
-The majority of times we spawn processes in Elixir, we spawn them as linked processes. Before we show an example with `spawn_link/1`, let's see what happens when a process started with `spawn/1` fails:
-
-```elixir
-iex> spawn(fn -> raise "oops" end)
-#PID<0.58.0>
-
-[error] Process #PID<0.58.00> raised an exception
-** (RuntimeError) oops
-    (stdlib) erl_eval.erl:668: :erl_eval.do_apply/6
-```
-
-It merely logged an error but the parent process is still running. That's because processes are isolated. If we want the failure in one process to propagate to another one, we should link them. This can be done with `spawn_link/1`:
-
-```elixir
-iex> self()
-#PID<0.41.0>
-iex> spawn_link(fn -> raise "oops" end)
-
-** (EXIT from #PID<0.41.0>) evaluator process exited with reason: an exception was raised:
-    ** (RuntimeError) oops
-        (stdlib) erl_eval.erl:668: :erl_eval.do_apply/6
-
-[error] Process #PID<0.289.0> raised an exception
-** (RuntimeError) oops
-    (stdlib) erl_eval.erl:668: :erl_eval.do_apply/6
-```
-
-Because processes are linked, we now see a message saying the parent process, which is the shell process, has received an EXIT signal from another process causing the shell to terminate. IEx detects this situation and starts a new shell session.
-
-Linking can also be done manually by calling `Process.link/1`. We recommend that you take a look at [the `Process` module](https://hexdocs.pm/elixir/Process.html) for other functionality provided by processes.
-
-Processes and links play an important role when building fault-tolerant systems. Elixir processes are isolated and don't share anything by default. Therefore, a failure in a process will never crash or corrupt the state of another process. Links, however, allow processes to establish a relationship in case of failure. We often link our processes to supervisors which will detect when a process dies and start a new process in its place.
-
-While other languages would require us to catch/handle exceptions, in Elixir we are actually fine with letting processes fail because we expect supervisors to properly restart our systems. "Failing fast" (sometimes referred as "let it crash") is a common philosophy when writing Elixir software!
-
-`spawn/1` and `spawn_link/1` are the basic primitives for creating processes in Elixir. Although we have used them exclusively so far, most of the time we are going to use abstractions that build on top of them. Let's see the most common one, called tasks.
-
-## Tasks
-
-Tasks build on top of the spawn functions to provide better error reports and introspection:
-
-```elixir
-iex> Task.start(fn -> raise "oops" end)
-{:ok, #PID<0.55.0>}
-
-15:22:33.046 [error] Task #PID<0.55.0> started from #PID<0.53.0> terminating
-** (RuntimeError) oops
-    (stdlib) erl_eval.erl:668: :erl_eval.do_apply/6
-    (elixir) lib/task/supervised.ex:85: Task.Supervised.do_apply/2
-    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
-Function: #Function<20.99386804/0 in :erl_eval.expr/5>
-    Args: []
-```
-
-Instead of `spawn/1` and `spawn_link/1`, we use `Task.start/1` and `Task.start_link/1` which return `{:ok, pid}` rather than just the PID. This is what enables tasks to be used in supervision trees. Furthermore, `Task` provides convenience functions, like `Task.async/1` and `Task.await/1`, and functionality to ease distribution.
-
-We will explore those functionalities in the ***Mix and OTP guide***, for now it is enough to remember to use `Task` to get better error reports.
-
-## State
-
-We haven't talked about state so far in this guide. If you are building an application that requires state, for example, to keep your application configuration, or you need to parse a file and keep it in memory, where would you store it?
-
-Processes are the most common answer to this question. We can write processes that loop infinitely, maintain state, and send and receive messages. As an example, let's write a module that starts new processes that work as a key-value store in a file named `kv.exs`:
-
-```elixir
-defmodule KV do
-  def start_link do
-    Task.start_link(fn -> loop(%{}) end)
-  end
-
-  defp loop(map) do
-    receive do
-      {:get, key, caller} ->
-        send caller, Map.get(map, key)
-        loop(map)
-      {:put, key, value} ->
-        loop(Map.put(map, key, value))
-    end
-  end
-end
-```
-
-Note that the `start_link` function starts a new process that runs the `loop/1` function, starting with an empty map. The `loop/1` (private) function then waits for messages and performs the appropriate action for each message. We made `loop/1` private by using `defp` instead of `def`. In the case of a `:get` message, it sends a message back to the caller and calls `loop/1` again, to wait for a new message. While the `:put` message actually invokes `loop/1` with a new version of the map, with the given `key` and `value` stored.
-
-Let's give it a try by running `iex kv.exs`:
-
-```elixir
-iex> {:ok, pid} = KV.start_link()
-{:ok, #PID<0.62.0>}
-iex> send(pid, {:get, :hello, self()})
-{:get, :hello, #PID<0.41.0>}
-iex> flush()
-nil
-:ok
-```
-
-At first, the process map has no keys, so sending a `:get` message and then flushing the current process inbox returns `nil`. Let's send a `:put` message and try it again:
-
-```elixir
-iex> send(pid, {:put, :hello, :world})
-{:put, :hello, :world}
-iex> send(pid, {:get, :hello, self()})
-{:get, :hello, #PID<0.41.0>}
-iex> flush()
-:world
-:ok
-```
-
-Notice how the process is keeping a state and we can get and update this state by sending the process messages. In fact, any process that knows the `pid` above will be able to send it messages and manipulate the state.
-
-It is also possible to register the `pid`, giving it a name, and allowing everyone that knows the name to send it messages:
-
-```elixir
-iex> Process.register(pid, :kv)
-true
-iex> send(:kv, {:get, :hello, self()})
-{:get, :hello, #PID<0.41.0>}
-iex> flush()
-:world
-:ok
-```
-
-Using processes to maintain state and name registration are very common patterns in Elixir applications. However, most of the time, we won't implement those patterns manually as above, but by using one of the many abstractions that ship with Elixir. For example, Elixir provides [agents](https://hexdocs.pm/elixir/Agent.html), which are simple abstractions around state:
-
-```elixir
-iex> {:ok, pid} = Agent.start_link(fn -> %{} end)
-{:ok, #PID<0.72.0>}
-iex> Agent.update(pid, fn map -> Map.put(map, :hello, :world) end)
-:ok
-iex> Agent.get(pid, fn map -> Map.get(map, :hello) end)
-:world
-```
-
-A `:name` option could also be given to `Agent.start_link/2` and it would be automatically registered. Besides agents, Elixir provides an API for building generic servers (called `GenServer`), tasks, and more, all powered by processes underneath. Those, along with supervision trees, will be explored with more detail in the ***Mix and OTP guide*** which will build a complete Elixir application from start to finish.
-
-For now, let's move on and explore the world of I/O in Elixir.
diff --git a/getting-started/protocols.markdown b/getting-started/protocols.markdown
index 29193e918..a44082f4e 100644
--- a/getting-started/protocols.markdown
+++ b/getting-started/protocols.markdown
@@ -1,260 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Protocols
+layout: redirect
+sitemap: false
+redirect_to: protocols
 ---
-
-Protocols are a mechanism to achieve polymorphism in Elixir when you want behaviour to vary depending on the data type. We are already familiar with one way of solving this type of problem: via pattern matching and guard clauses. Consider a simple utility module that would tell us the type of input variable:
-
-```elixir
-defmodule Utility do
-  def type(value) when is_binary(value), do: "string"
-  def type(value) when is_integer(value), do: "integer"
-  # ... other implementations ...
-end
-```
-
-If the use of this module were confined to your own project, you would be able to keep defining new `type/1` functions for each new data type. However, this code could be problematic if it was shared as a dependency by multiple apps because there would be no easy way to extend its functionality.
-
-This is where protocols can help us: protocols allow us to extend the original behaviour for as many data types as we need. That's because **dispatching on a protocol is available to any data type that has implemented the protocol** and a protocol can be implemented by anyone, at any time.
-
-Here's how we could write the same `Utility.type/1` functionality as a protocol:
-
-```elixir
-defprotocol Utility do
-  @spec type(t) :: String.t()
-  def type(value)
-end
-
-defimpl Utility, for: BitString do
-  def type(_value), do: "string"
-end
-
-defimpl Utility, for: Integer do
-  def type(_value), do: "integer"
-end
-```
-
-We define the protocol using `defprotocol` - its functions and specs may look similar to interfaces or abstract base classes in other languages. We can add as many implementations as we like using `defimpl`. The output is exactly the same as if we had a single module with multiple functions:
-
-```elixir
-iex> Utility.type("foo")
-"string"
-iex> Utility.type(123)
-"integer"
-```
-
-With protocols, however, we are no longer stuck having to continuously modify the same module to support more and more data types. For example, we could get the `defimpl` calls above and spread them over multiple files and Elixir will dispatch the execution to the appropriate implementation based on the data type. Functions defined in a protocol may have more than one input, but the **dispatching will always be based on the data type of the first input**.
-
-One of the most common protocols you may encounter is the [`String.Chars`](https://hexdocs.pm/elixir/String.Chars.html) protocol: implementing its `to_string/1` function for your custom structs will tell the Elixir kernel how to represent them as strings. We will explore all built-in protocols later. For now, let's implement our own.
-
-## Example
-
-Now that you have seen an example of the type of problem protocols help solve and how they solve them, let's look at a more in-depth example.
-
-In Elixir, we have two idioms for checking how many items there are in a data structure: `length` and `size`. `length` means the information must be computed. For example, `length(list)` needs to traverse the whole list to calculate its length. On the other hand, `tuple_size(tuple)` and `byte_size(binary)` do not depend on the tuple and binary size as the size information is pre-computed in the data structure.
-
-Even if we have type-specific functions for getting the size built into Elixir (such as `tuple_size/1`), we could implement a generic `Size` protocol that all data structures for which size is pre-computed would implement.
-
-The protocol definition would look like this:
-
-```elixir
-defprotocol Size do
-  @doc "Calculates the size (and not the length!) of a data structure"
-  def size(data)
-end
-```
-
-The `Size` protocol expects a function called `size` that receives one argument (the data structure we want to know the size of) to be implemented. We can now implement this protocol for the data structures that would have a compliant implementation:
-
-```elixir
-defimpl Size, for: BitString do
-  def size(string), do: byte_size(string)
-end
-
-defimpl Size, for: Map do
-  def size(map), do: map_size(map)
-end
-
-defimpl Size, for: Tuple do
-  def size(tuple), do: tuple_size(tuple)
-end
-```
-
-We didn't implement the `Size` protocol for lists as there is no "size" information pre-computed for lists, and the length of a list has to be computed (with `length/1`).
-
-Now with the protocol defined and implementations in hand, we can start using it:
-
-```elixir
-iex> Size.size("foo")
-3
-iex> Size.size({:ok, "hello"})
-2
-iex> Size.size(%{label: "some label"})
-1
-```
-
-Passing a data type that doesn't implement the protocol raises an error:
-
-```elixir
-iex> Size.size([1, 2, 3])
-** (Protocol.UndefinedError) protocol Size not implemented for [1, 2, 3] of type List
-```
-
-It's possible to implement protocols for all Elixir data types:
-
-* `Atom`
-* `BitString`
-* `Float`
-* `Function`
-* `Integer`
-* `List`
-* `Map`
-* `PID`
-* `Port`
-* `Reference`
-* `Tuple`
-
-## Protocols and structs
-
-The power of Elixir's extensibility comes when protocols and structs are used together.
-
-In the [previous chapter](/getting-started/structs.html), we have learned that although structs are maps, they do not share protocol implementations with maps. For example, [`MapSet`](https://hexdocs.pm/elixir/MapSet.html)s (sets based on maps) are implemented as structs. Let's try to use the `Size` protocol with a `MapSet`:
-
-```elixir
-iex> Size.size(%{})
-0
-iex> set = %MapSet{} = MapSet.new
-MapSet.new([])
-iex> Size.size(set)
-** (Protocol.UndefinedError) protocol Size not implemented for MapSet.new([]) of type MapSet (a struct)
-```
-
-Instead of sharing protocol implementation with maps, structs require their own protocol implementation. Since a `MapSet` has its size precomputed and accessible through `MapSet.size/1`, we can define a `Size` implementation for it:
-
-```elixir
-defimpl Size, for: MapSet do
-  def size(set), do: MapSet.size(set)
-end
-```
-
-If desired, you could come up with your own semantics for the size of your struct. Not only that, you could use structs to build more robust data types, like queues, and implement all relevant protocols, such as `Enumerable` and possibly `Size`, for this data type.
-
-```elixir
-defmodule User do
-  defstruct [:name, :age]
-end
-
-defimpl Size, for: User do
-  def size(_user), do: 2
-end
-```
-
-## Implementing `Any`
-
-Manually implementing protocols for all types can quickly become repetitive and tedious. In such cases, Elixir provides two options: we can explicitly derive the protocol implementation for our types or automatically implement the protocol for all types. In both cases, we need to implement the protocol for `Any`.
-
-### Deriving
-
-Elixir allows us to derive a protocol implementation based on the `Any` implementation. Let's first implement `Any` as follows:
-
-```elixir
-defimpl Size, for: Any do
-  def size(_), do: 0
-end
-```
-
-The implementation above is arguably not a reasonable one. For example, it makes no sense to say that the size of a `PID` or an `Integer` is `0`.
-
-However, we should be fine with the implementation for `Any`, in order to use such implementation we would need to tell our struct to explicitly derive the `Size` protocol:
-
-```elixir
-defmodule OtherUser do
-  @derive [Size]
-  defstruct [:name, :age]
-end
-```
-
-When deriving, Elixir will implement the `Size` protocol for `OtherUser` based on the implementation provided for `Any`.
-
-### Fallback to `Any`
-
-Another alternative to `@derive` is to explicitly tell the protocol to fallback to `Any` when an implementation cannot be found. This can be achieved by setting `@fallback_to_any` to `true` in the protocol definition:
-
-```elixir
-defprotocol Size do
-  @fallback_to_any true
-  def size(data)
-end
-```
-
-As we said in the previous section, the implementation of `Size` for `Any` is not one that can apply to any data type. That's one of the reasons why `@fallback_to_any` is an opt-in behaviour. For the majority of protocols, raising an error when a protocol is not implemented is the proper behaviour. That said, assuming we have implemented `Any` as in the previous section:
-
-```elixir
-defimpl Size, for: Any do
-  def size(_), do: 0
-end
-```
-
-Now all data types (including structs) that have not implemented the `Size` protocol will be considered to have a size of `0`.
-
-Which technique is best between deriving and falling back to `Any` depends on the use case but, given Elixir developers prefer explicit over implicit, you may see many libraries pushing towards the `@derive` approach.
-
-## Built-in protocols
-
-Elixir ships with some built-in protocols. In previous chapters, we have discussed the `Enum` module which provides many functions that work with any data structure that implements the `Enumerable` protocol:
-
-```elixir
-iex> Enum.map([1, 2, 3], fn x -> x * 2 end)
-[2, 4, 6]
-iex> Enum.reduce(1..3, 0, fn x, acc -> x + acc end)
-6
-```
-
-Another useful example is the `String.Chars` protocol, which specifies how to convert a data structure to its human representation as a string. It's exposed via the `to_string` function:
-
-```elixir
-iex> to_string :hello
-"hello"
-```
-
-Notice that string interpolation in Elixir calls the `to_string` function:
-
-```elixir
-iex> "age: #{25}"
-"age: 25"
-```
-
-The snippet above only works because numbers implement the `String.Chars` protocol. Passing a tuple, for example, will lead to an error:
-
-```elixir
-iex> tuple = {1, 2, 3}
-{1, 2, 3}
-iex> "tuple: #{tuple}"
-** (Protocol.UndefinedError) protocol String.Chars not implemented for {1, 2, 3} of type Tuple
-```
-
-When there is a need to "print" a more complex data structure, one can use the `inspect` function, based on the `Inspect` protocol:
-
-```elixir
-iex> "tuple: #{inspect tuple}"
-"tuple: {1, 2, 3}"
-```
-
-The `Inspect` protocol is the protocol used to transform any data structure into a readable textual representation. This is what tools like IEx use to print results:
-
-```elixir
-iex> {1, 2, 3}
-{1, 2, 3}
-iex> %User{}
-%User{name: "john", age: 27}
-```
-
-Keep in mind that, by convention, whenever the inspected value starts with `#`, it is representing a data structure in non-valid Elixir syntax. This means the inspect protocol is not reversible as information may be lost along the way:
-
-```elixir
-iex> inspect &(&1+2)
-"#Function<6.71889879/1 in :erl_eval.expr/5>"
-```
-
-There are other protocols in Elixir but this covers the most common ones. You can learn more about protocols and implementations in the [`Protocol`](https://hexdocs.pm/elixir/Protocol.html) module.
diff --git a/getting-started/recursion.markdown b/getting-started/recursion.markdown
index 95d797ee1..ed7c1c2c9 100644
--- a/getting-started/recursion.markdown
+++ b/getting-started/recursion.markdown
@@ -1,142 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Recursion
+layout: redirect
+sitemap: false
+redirect_to: recursion
 ---
-
-## Loops through recursion
-
-Due to immutability, loops in Elixir (as in any functional programming language) are written differently from imperative languages. For example, in an imperative language like C, one would write:
-
-```c
-for(i = 0; i < sizeof(array); i++) {
-  array[i] = array[i] * 2;
-}
-```
-
-In the example above, we are mutating both the array and the variable `i`. However, data structures in Elixir are immutable. For this reason, functional languages rely on recursion: a function is called recursively until a condition is reached that stops the recursive action from continuing. No data is mutated in this process. Consider the example below that prints a string an arbitrary number of times:
-
-```elixir
-defmodule Recursion do
-  def print_multiple_times(msg, n) when n > 0 do
-    IO.puts(msg)
-    print_multiple_times(msg, n - 1)
-  end
-
-  def print_multiple_times(_msg, 0) do
-    :ok
-  end
-end
-
-Recursion.print_multiple_times("Hello!", 3)
-# Hello!
-# Hello!
-# Hello!
-:ok
-```
-
-Similar to `case`, a function may have many clauses. A particular clause is executed when the arguments passed to the function match the clause's argument patterns and its guards evaluate to `true`.
-
-When `print_multiple_times/2` is initially called in the example above, the argument `n` is equal to `3`.
-
-The first clause has a guard which says "use this definition if and only if `n` is more than `0`". Since this is the case, it prints the `msg` and then calls itself passing `n - 1` (`2`) as the second argument.
-
-Now we execute the same function again, starting from the first clause. Given the second argument, `n`, is still more than 0, we print the message and call ourselves once more, now with the second argument set to `1`. Then we print the message one last time and call `print_multiple_times("Hello!", 0)`, starting from the top once again.
-
-When the second argument is zero, the guard `n > 0` evaluates to false, and the first function clause won't execute. Elixir then proceeds to try the next function clause, which explicitly matches on the case where `n` is `0`. This clause, also known as the termination clause, ignores the message argument by assigning it to the `_msg` variable and returns the atom `:ok`.
-
-Finally, if you pass an argument that does not match any clause, Elixir raises a `FunctionClauseError`:
-
-```elixir
-iex> Recursion.print_multiple_times "Hello!", -1
-** (FunctionClauseError) no function clause matching in Recursion.print_multiple_times/2
-
-    The following arguments were given to Recursion.print_multiple_times/2:
-
-        # 1
-        "Hello!"
-
-        # 2
-        -1
-
-    iex:1: Recursion.print_multiple_times/2
-```
-
-## Reduce and map algorithms
-
-Let's now see how we can use the power of recursion to sum a list of numbers:
-
-```elixir
-defmodule Math do
-  def sum_list([head | tail], accumulator) do
-    sum_list(tail, head + accumulator)
-  end
-
-  def sum_list([], accumulator) do
-    accumulator
-  end
-end
-
-IO.puts Math.sum_list([1, 2, 3], 0) #=> 6
-```
-
-We invoke `sum_list` with the list `[1, 2, 3]` and the initial value `0` as arguments. We will try each clause until we find one that matches according to the pattern matching rules. In this case, the list `[1, 2, 3]` matches against `[head | tail]` which binds `head` to `1` and `tail` to `[2, 3]`; `accumulator` is set to `0`.
-
-Then, we add the head of the list to the accumulator `head + accumulator` and call `sum_list` again, recursively, passing the tail of the list as its first argument. The tail will once again match `[head | tail]` until the list is empty, as seen below:
-
-```elixir
-sum_list [1, 2, 3], 0
-sum_list [2, 3], 1
-sum_list [3], 3
-sum_list [], 6
-```
-
-When the list is empty, it will match the final clause which returns the final result of `6`.
-
-The process of taking a list and _reducing_ it down to one value is known as a _reduce algorithm_ and is central to functional programming.
-
-What if we instead want to double all of the values in our list?
-
-```elixir
-defmodule Math do
-  def double_each([head | tail]) do
-    [head * 2 | double_each(tail)]
-  end
-
-  def double_each([]) do
-    []
-  end
-end
-```
-
-```console
-$ iex math.exs
-```
-
-```elixir
-iex> Math.double_each([1, 2, 3]) #=> [2, 4, 6]
-```
-
-Here we have used recursion to traverse a list, doubling each element and returning a new list. The process of taking a list and _mapping_ over it is known as a _map algorithm_.
-
-Recursion and [tail call](https://en.wikipedia.org/wiki/Tail_call) optimization are an important part of Elixir and are commonly used to create loops. However, when programming in Elixir you will rarely use recursion as above to manipulate lists.
-
-The [`Enum` module](https://hexdocs.pm/elixir/Enum.html), which we're going to see in the next chapter, already provides many conveniences for working with lists. For instance, the examples above could be written as:
-
-```elixir
-iex> Enum.reduce([1, 2, 3], 0, fn(x, acc) -> x + acc end)
-6
-iex> Enum.map([1, 2, 3], fn(x) -> x * 2 end)
-[2, 4, 6]
-```
-
-Or, using the capture syntax:
-
-```elixir
-iex> Enum.reduce([1, 2, 3], 0, &+/2)
-6
-iex> Enum.map([1, 2, 3], &(&1 * 2))
-[2, 4, 6]
-```
-
-Let's take a deeper look at `Enumerable` and, while we're at it, its lazy counterpart, `Stream`.
diff --git a/getting-started/sigils.markdown b/getting-started/sigils.markdown
index 69c834223..0f929e472 100644
--- a/getting-started/sigils.markdown
+++ b/getting-started/sigils.markdown
@@ -1,244 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Sigils
+layout: redirect
+sitemap: false
+redirect_to: sigils
 ---
-
-We have already learned that Elixir provides double-quoted strings and single-quoted char lists. However, this only covers the surface of structures that have textual representation in the language. Atoms, for example, are mostly created via the `:atom` representation.
-
-One of Elixir's goals is extensibility: developers should be able to extend the language to fit any particular domain. Computer science has become such a wide field that it is impossible for a language to tackle all aspects of it as part of its core. Instead, Elixir aims to make itself extensible so developers, companies, and communities can extend the language to their relevant domains.
-
-In this chapter, we are going to explore sigils, which are one of the mechanisms provided by the language for working with textual representations. Sigils start with the tilde (`~`) character which is followed by a letter (which identifies the sigil) and then a delimiter; optionally, modifiers can be added after the final delimiter.
-
-## Regular expressions
-
-The most common sigil in Elixir is `~r`, which is used to create [regular expressions](https://en.wikipedia.org/wiki/Regular_Expressions):
-
-```elixir
-# A regular expression that matches strings which contain "foo" or "bar":
-iex> regex = ~r/foo|bar/
-~r/foo|bar/
-iex> "foo" =~ regex
-true
-iex> "bat" =~ regex
-false
-```
-
-Elixir provides Perl-compatible regular expressions (regexes), as implemented by the [PCRE](http://www.pcre.org/) library. Regexes also support modifiers. For example, the `i` modifier makes a regular expression case insensitive:
-
-```elixir
-iex> "HELLO" =~ ~r/hello/
-false
-iex> "HELLO" =~ ~r/hello/i
-true
-```
-
-Check out the [`Regex` module](https://hexdocs.pm/elixir/Regex.html) for more information on other modifiers and the supported operations with regular expressions.
-
-So far, all examples have used `/` to delimit a regular expression. However, sigils support 8 different delimiters:
-
-```
-~r/hello/
-~r|hello|
-~r"hello"
-~r'hello'
-~r(hello)
-~r[hello]
-~r{hello}
-~r<hello>
-```
-
-The reason behind supporting different delimiters is to provide a way to write literals without escaped delimiters. For example, a regular expression with forward slashes like `~r(^https?://)` reads arguably better than `~r/^https?:\/\//`. Similarly, if the regular expression has forward slashes and capturing groups (that use `()`), you may then choose double quotes instead of parentheses.
-
-## Strings, char lists, and word lists sigils
-
-Besides regular expressions, Elixir ships with three other sigils.
-
-### Strings
-
-The `~s` sigil is used to generate strings, like double quotes are. The `~s` sigil is useful when a string contains double quotes:
-
-```elixir
-iex> ~s(this is a string with "double" quotes, not 'single' ones)
-"this is a string with \"double\" quotes, not 'single' ones"
-```
-
-### Char lists
-
-The `~c` sigil is the regular way to represent charlists.
-
-```elixir
-iex> [?c, ?a, ?t]
-~c"cat"
-iex> ~c(this is a char list containing "double quotes")
-~c"this is a char list containing \"double quotes\""
-```
-
-### Word lists
-
-The `~w` sigil is used to generate lists of words (*words* are just regular strings). Inside the `~w` sigil, words are separated by whitespace.
-
-```elixir
-iex> ~w(foo bar bat)
-["foo", "bar", "bat"]
-```
-
-The `~w` sigil also accepts the `c`, `s` and `a` modifiers (for char lists, strings, and atoms, respectively), which specify the data type of the elements of the resulting list:
-
-```elixir
-iex> ~w(foo bar bat)a
-[:foo, :bar, :bat]
-```
-
-## Interpolation and escaping in string sigils
-
-Elixir supports some sigil variants to deal with escaping characters and interpolation. In particular, uppercase letters sigils do not perform interpolation nor escaping. For example, although both `~s` and `~S` will return strings, the former allows escape codes and interpolation while the latter does not:
-
-```elixir
-iex> ~s(String with escape codes \x26 #{"inter" <> "polation"})
-"String with escape codes & interpolation"
-iex> ~S(String without escape codes \x26 without #{interpolation})
-"String without escape codes \\x26 without \#{interpolation}"
-```
-
-The following escape codes can be used in strings and char lists:
-
-* `\\` – single backslash
-* `\a` – bell/alert
-* `\b` – backspace
-* `\d` - delete
-* `\e` - escape
-* `\f` - form feed
-* `\n` – newline
-* `\r` – carriage return
-* `\s` – space
-* `\t` – tab
-* `\v` – vertical tab
-* `\0` - null byte
-* `\xDD` - represents a single byte in hexadecimal (such as `\x13`)
-* `\uDDDD` and `\u{D...}` - represents a Unicode codepoint in hexadecimal (such as `\u{1F600}`)
-
-In addition to those, a double quote inside a double-quoted string needs to be escaped as `\"`, and, analogously, a single quote inside a single-quoted char list needs to be escaped as `\'`. Nevertheless, it is better style to change delimiters as seen above than to escape them.
-
-Sigils also support heredocs, that is, three double-quotes or single-quotes as separators:
-
-```elixir
-iex> ~s"""
-...> this is
-...> a heredoc string
-...> """
-```
-
-The most common use case for heredoc sigils is when writing documentation. For example, writing escape characters in the documentation would soon become error prone because of the need to double-escape some characters:
-
-```elixir
-@doc """
-Converts double-quotes to single-quotes.
-
-## Examples
-
-    iex> convert("\\\"foo\\\"")
-    "'foo'"
-
-"""
-def convert(...)
-```
-
-By using `~S`, this problem can be avoided altogether:
-
-```elixir
-@doc ~S"""
-Converts double-quotes to single-quotes.
-
-## Examples
-
-    iex> convert("\"foo\"")
-    "'foo'"
-
-"""
-def convert(...)
-```
-
-## Calendar sigils
-
-Elixir offers several sigils to deal with various flavors of times and dates.
-
-### Date
-
-A [%Date{}](https://hexdocs.pm/elixir/Date.html) struct contains the fields `year`, `month`, `day`, and `calendar`. You can create one using the `~D` sigil:
-
-```elixir
-iex> d = ~D[2019-10-31]
-~D[2019-10-31]
-iex> d.day
-31
-```
-
-### Time
-
-The [%Time{}](https://hexdocs.pm/elixir/Time.html) struct contains the fields `hour`, `minute`, `second`, `microsecond`, and `calendar`. You can create one using the `~T` sigil:
-
-```elixir
-iex> t = ~T[23:00:07.0]
-~T[23:00:07.0]
-iex> t.second
-7
-```
-
-### NaiveDateTime
-
-The [%NaiveDateTime{}](https://hexdocs.pm/elixir/NaiveDateTime.html) struct contains fields from both `Date` and `Time`. You can create one using the `~N` sigil:
-
-```elixir
-iex> ndt = ~N[2019-10-31 23:00:07]
-~N[2019-10-31 23:00:07]
-```
-
-Why is it called naive? Because it does not contain timezone information. Therefore, the given datetime may not exist at all or it may exist twice in certain timezones - for example, when we move the clock back and forward for daylight saving time.
-
-### UTC DateTime
-
-A [%DateTime{}](https://hexdocs.pm/elixir/DateTime.html) struct contains the same fields as a `NaiveDateTime` with the addition of fields to track timezones. The `~U` sigil allows developers to create a DateTime in the UTC timezone:
-
-```elixir
-iex> dt = ~U[2019-10-31 19:59:03Z]
-~U[2019-10-31 19:59:03Z]
-iex> %DateTime{minute: minute, time_zone: time_zone} = dt
-~U[2019-10-31 19:59:03Z]
-iex> minute
-59
-iex> time_zone
-"Etc/UTC"
-```
-
-## Custom sigils
-
-As hinted at the beginning of this chapter, sigils in Elixir are extensible. In fact, using the sigil `~r/foo/i` is equivalent to calling `sigil_r` with a binary and a char list as the argument:
-
-```elixir
-iex> sigil_r(<<"foo">>, ~c"i")
-~r"foo"i
-```
-
-We can access the documentation for the `~r` sigil via `sigil_r`:
-
-```elixir
-iex> h sigil_r
-...
-```
-
-We can also provide our own sigils by implementing functions that follow the `sigil_{character}` pattern. For example, let's implement the `~i` sigil that returns an integer (with the optional `n` modifier to make it negative):
-
-```elixir
-iex> defmodule MySigils do
-...>   def sigil_i(string, []), do: String.to_integer(string)
-...>   def sigil_i(string, [?n]), do: -String.to_integer(string)
-...> end
-iex> import MySigils
-iex> ~i(13)
-13
-iex> ~i(42)n
--42
-```
-
-Sigils can also be used to do compile-time work with the help of macros. For example, regular expressions in Elixir are compiled into an efficient representation during compilation of the source code, therefore skipping this step at runtime. If you're interested in the subject, we recommend you learn more about macros and check out how sigils are implemented in the `Kernel` module (where the `sigil_*` functions are defined).
diff --git a/getting-started/structs.markdown b/getting-started/structs.markdown
index f45868d28..2a92104e6 100644
--- a/getting-started/structs.markdown
+++ b/getting-started/structs.markdown
@@ -1,160 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Structs
-redirect_from: /getting-started/struct.html
+layout: redirect
+sitemap: false
+redirect_to: structs
 ---
-
-In [chapter 7](/getting-started/keywords-and-maps.html) we learned about maps:
-
-```elixir
-iex> map = %{a: 1, b: 2}
-%{a: 1, b: 2}
-iex> map[:a]
-1
-iex> %{map | a: 3}
-%{a: 3, b: 2}
-```
-
-Structs are extensions built on top of maps that provide compile-time checks and default values.
-
-## Defining structs
-
-To define a struct, the `defstruct` construct is used:
-
-```elixir
-iex> defmodule User do
-...>   defstruct name: "John", age: 27
-...> end
-```
-
-The keyword list used with `defstruct` defines what fields the struct will have along with their default values.
-
-Structs take the name of the module they're defined in. In the example above, we defined a struct named `User`.
-
-We can now create `User` structs by using a syntax similar to the one used to create maps:
-
-```elixir
-iex> %User{}
-%User{age: 27, name: "John"}
-iex> %User{name: "Jane"}
-%User{age: 27, name: "Jane"}
-```
-
-> Note: If you have defined the struct in a separate file, you can compile the file inside IEx before proceeding by running `c "file.exs"`. Be aware you may get an error saying `the struct was not yet defined` if you try the example above in a file directly due to when definitions are resolved.
-
-Structs provide *compile-time* guarantees that only the fields defined through `defstruct` will be allowed to exist in a struct:
-
-```elixir
-iex> %User{oops: :field}
-** (KeyError) key :oops not found expanding struct: User.__struct__/1
-```
-
-## Accessing and updating structs
-
-When we discussed maps, we showed how we can access and update the fields of a map. The same techniques (and the same syntax) apply to structs as well:
-
-```elixir
-iex> john = %User{}
-%User{age: 27, name: "John"}
-iex> john.name
-"John"
-iex> jane = %{john | name: "Jane"}
-%User{age: 27, name: "Jane"}
-iex> %{jane | oops: :field}
-** (KeyError) key :oops not found in: %User{age: 27, name: "Jane"}
-```
-
-When using the update syntax (`|`), the <abbr title="Virtual Machine">VM</abbr> is aware that no new keys will be added to the struct, allowing the maps underneath to share their structure in memory. In the example above, both `john` and `jane` share the same key structure in memory.
-
-Structs can also be used in pattern matching, both for matching on the value of specific keys as well as for ensuring that the matching value is a struct of the same type as the matched value.
-
-```elixir
-iex> %User{name: name} = john
-%User{age: 27, name: "John"}
-iex> name
-"John"
-iex> %User{} = %{}
-** (MatchError) no match of right hand side value: %{}
-```
-
-## Structs are bare maps underneath
-
-In the example above, pattern matching works because underneath structs are bare maps with a fixed set of fields. As maps, structs store a "special" field named `__struct__` that holds the name of the struct:
-
-```elixir
-iex> is_map(john)
-true
-iex> john.__struct__
-User
-```
-
-Notice that we referred to structs as **bare** maps because none of the protocols implemented for maps are available for structs. For example, you can neither enumerate nor access a struct:
-
-```elixir
-iex> john = %User{}
-%User{age: 27, name: "John"}
-iex> john[:name]
-** (UndefinedFunctionError) function User.fetch/2 is undefined (User does not implement the Access behaviour)
-             User.fetch(%User{age: 27, name: "John"}, :name)
-iex> Enum.each(john, fn {field, value} -> IO.puts(value) end)
-** (Protocol.UndefinedError) protocol Enumerable not implemented for %User{age: 27, name: "John"} of type User (a struct)
-```
-
-However, since structs are just maps, they work with the functions from the `Map` module:
-
-```elixir
-iex> jane = Map.put(%User{}, :name, "Jane")
-%User{age: 27, name: "Jane"}
-iex> Map.merge(jane, %User{name: "John"})
-%User{age: 27, name: "John"}
-iex> Map.keys(jane)
-[:__struct__, :age, :name]
-```
-
-Structs alongside protocols provide one of the most important features for Elixir developers: data polymorphism. That's what we will explore in the next chapter.
-
-## Default values and required keys
-
-If you don't specify a default key value when defining a struct, `nil` will be assumed:
-
-```elixir
-iex> defmodule Product do
-...>   defstruct [:name]
-...> end
-iex> %Product{}
-%Product{name: nil}
-```
-
-You can define a structure combining both fields with explicit default values, and implicit `nil` values. In this case you must first specify the fields which implicitly default to nil:
-
-```elixir
-iex> defmodule User do
-...>   defstruct [:email, name: "John", age: 27]
-...> end
-iex> %User{}
-%User{age: 27, email: nil, name: "John"}
-```
-
-Doing it in reverse order will raise a syntax error:
-
-```elixir
-iex> defmodule User do
-...>   defstruct [name: "John", age: 27, :email]
-...> end
-** (SyntaxError) iex:107: unexpected expression after keyword list. Keyword lists must always come last in lists and maps.
-```
-
-You can also enforce that certain keys have to be specified when creating the struct via the `@enforce_keys` module attribute:
-
-```elixir
-iex> defmodule Car do
-...>   @enforce_keys [:make]
-...>   defstruct [:model, :make]
-...> end
-iex> %Car{}
-** (ArgumentError) the following keys must also be given when building struct Car: [:make]
-    expanding struct: Car.__struct__/1
-```
-
-Enforcing keys provides a simple compile-time guarantee to aid developers when building structs. It is not enforced on updates and it does not provide any sort of value-validation.
diff --git a/getting-started/try-catch-and-rescue.markdown b/getting-started/try-catch-and-rescue.markdown
index e1a6d393d..158dc94ce 100644
--- a/getting-started/try-catch-and-rescue.markdown
+++ b/getting-started/try-catch-and-rescue.markdown
@@ -1,284 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: try, catch, and rescue
+layout: redirect
+sitemap: false
+redirect_to: try-catch-and-rescue
 ---
-
-Elixir has three error mechanisms: errors, throws, and exits. In this chapter, we will explore each of them and include remarks about when each should be used.
-
-## Errors
-
-Errors (or *exceptions*) are used when exceptional things happen in the code. A sample error can be retrieved by trying to add a number to an atom:
-
-```elixir
-iex> :foo + 1
-** (ArithmeticError) bad argument in arithmetic expression
-     :erlang.+(:foo, 1)
-```
-
-A runtime error can be raised any time by using `raise/1`:
-
-```elixir
-iex> raise "oops"
-** (RuntimeError) oops
-```
-
-Other errors can be raised with `raise/2` passing the error name and a list of keyword arguments:
-
-```elixir
-iex> raise ArgumentError, message: "invalid argument foo"
-** (ArgumentError) invalid argument foo
-```
-
-You can also define your own errors by creating a module and using the `defexception` construct inside it. This way, you'll create an error with the same name as the module it's defined in. The most common case is to define a custom exception with a message field:
-
-```elixir
-iex> defmodule MyError do
-iex>   defexception message: "default message"
-iex> end
-iex> raise MyError
-** (MyError) default message
-iex> raise MyError, message: "custom message"
-** (MyError) custom message
-```
-
-Errors can be **rescued** using the `try/rescue` construct:
-
-```elixir
-iex> try do
-...>   raise "oops"
-...> rescue
-...>   e in RuntimeError -> e
-...> end
-%RuntimeError{message: "oops"}
-```
-
-The example above rescues the runtime error and returns the exception itself, which is then printed in the `iex` session.
-
-If you don't have any use for the exception, you don't have to pass a variable to `rescue`:
-
-```elixir
-iex> try do
-...>   raise "oops"
-...> rescue
-...>   RuntimeError -> "Error!"
-...> end
-"Error!"
-```
-
-In practice, Elixir developers rarely use the `try/rescue` construct. For example, many languages would force you to rescue an error when a file cannot be opened successfully. Elixir instead provides a `File.read/1` function which returns a tuple containing information about whether the file was opened successfully:
-
-```elixir
-iex> File.read("hello")
-{:error, :enoent}
-iex> File.write("hello", "world")
-:ok
-iex> File.read("hello")
-{:ok, "world"}
-```
-
-There is no `try/rescue` here. In case you want to handle multiple outcomes of opening a file, you can use pattern matching using the `case` construct:
-
-```elixir
-iex> case File.read("hello") do
-...>   {:ok, body} -> IO.puts("Success: #{body}")
-...>   {:error, reason} -> IO.puts("Error: #{reason}")
-...> end
-```
-
-For the cases where you do expect a file to exist (and the lack of that file is truly an *error*) you may use `File.read!/1`:
-
-```elixir
-iex> File.read!("unknown")
-** (File.Error) could not read file "unknown": no such file or directory
-    (elixir) lib/file.ex:272: File.read!/1
-```
-
-At the end of the day, it's up to your application to decide if an error while opening a file is exceptional or not. That's why Elixir doesn't impose exceptions on `File.read/1` and many other functions. Instead, it leaves it up to the developer to choose the best way to proceed.
-
-Many functions in the standard library follow the pattern of having a counterpart that raises an exception instead of returning tuples to match against. The convention is to create a function (`foo`) which returns `{:ok, result}` or `{:error, reason}` tuples and another function (`foo!`, same name but with a trailing `!`) that takes the same arguments as `foo` but which raises an exception if there's an error. `foo!` should return the result (not wrapped in a tuple) if everything goes fine. The [`File` module](https://hexdocs.pm/elixir/File.html) is a good example of this convention.
-
-### Fail fast / Let it crash
-
-One saying that is common in the Erlang community, as well as Elixir's, is "fail fast" / "let it crash". The idea behind let it crash is that, in case something _unexpected_ happens, it is best to let the exception happen, without rescuing it.
-
-It is important to emphasize the word _unexpected_. For example, imagine you are building a script to process files. Your script receives filenames as inputs. It is expected that users may make mistakes and provide unknown filenames. In this scenario, while you could use `File.read!/1` to read files and let it crash in case of invalid filenames, it probably makes more sense to use `File.read/1` and provide users of your script with a clear and precise feedback of what went wrong.
-
-Other times, you may fully expect a certain file to exist, and in case it does not, it means something terribly wrong has happened elsewhere. In such cases, `File.read!/1` is all you need.
-
-The second approach also works because, as discussed in the [Processes](/getting-started/processes.html) chapter, all Elixir code runs inside processes that are isolated and don't share anything by default. Therefore, an unhandled exception in a process will never crash or corrupt the state of another process. This allows us to define supervisor processes, which are meant to observe when a process terminates unexpectedly, and start a new one in its place.
-
-At the end of the day, "fail fast" / "let it crash" is a way of saying that, when something _unexpected_ happens, it is best to start from scratch within a new process, freshly started by a supervisor, rather than blindly trying to rescue all possible error cases without the full context of when and how they can happen.
-
-### Reraise
-
-While we generally avoid using `try/rescue` in Elixir, one situation where we may want to use such constructs is for observability/monitoring. Imagine you want to log that something went wrong, you could do:
-
-```elixir
-try do
-  ... some code ...
-rescue
-  e ->
-    Logger.error(Exception.format(:error, e, __STACKTRACE__))
-    reraise e, __STACKTRACE__
-end
-```
-
-In the example above, we rescued the exception, logged it, and then re-raised it. We use the `__STACKTRACE__` construct both when formatting the exception and when re-raising. This ensures we reraise the exception as is, without changing value or its origin.
-
-Generally speaking, we take errors in Elixir literally: they are reserved for unexpected and/or exceptional situations, never for controlling the flow of our code. In case you actually need flow control constructs, *throws* should be used. That's what we are going to see next.
-
-## Throws
-
-In Elixir, a value can be thrown and later be caught. `throw` and `catch` are reserved for situations where it is not possible to retrieve a value unless by using `throw` and `catch`.
-
-Those situations are quite uncommon in practice except when interfacing with libraries that do not provide a proper API. For example, let's imagine the `Enum` module did not provide any API for finding a value and that we needed to find the first multiple of 13 in a list of numbers:
-
-```elixir
-iex> try do
-...>   Enum.each(-50..50, fn x ->
-...>     if rem(x, 13) == 0, do: throw(x)
-...>   end)
-...>   "Got nothing"
-...> catch
-...>   x -> "Got #{x}"
-...> end
-"Got -39"
-```
-
-Since `Enum` *does* provide a proper API, in practice `Enum.find/2` is the way to go:
-
-```elixir
-iex> Enum.find(-50..50, &(rem(&1, 13) == 0))
--39
-```
-
-## Exits
-
-All Elixir code runs inside processes that communicate with each other. When a process dies of "natural causes" (e.g., unhandled exceptions), it sends an `exit` signal. A process can also die by explicitly sending an `exit` signal:
-
-```elixir
-iex> spawn_link(fn -> exit(1) end)
-** (EXIT from #PID<0.56.0>) shell process exited with reason: 1
-```
-
-In the example above, the linked process died by sending an `exit` signal with a value of 1. The Elixir shell automatically handles those messages and prints them to the terminal.
-
-`exit` can also be "caught" using `try/catch`:
-
-```elixir
-iex> try do
-...>   exit("I am exiting")
-...> catch
-...>   :exit, _ -> "not really"
-...> end
-"not really"
-```
-
-Using `try/catch` is already uncommon and using it to catch exits is even rarer.
-
-`exit` signals are an important part of the fault tolerant system provided by the Erlang <abbr title="Virtual Machine">VM</abbr>. Processes usually run under supervision trees which are themselves processes that listen to `exit` signals from the supervised processes. Once an `exit` signal is received, the supervision strategy kicks in and the supervised process is restarted.
-
-It is exactly this supervision system that makes constructs like `try/catch` and `try/rescue` so uncommon in Elixir. Instead of rescuing an error, we'd rather "fail fast" since the supervision tree will guarantee our application will go back to a known initial state after the error.
-
-## After
-
-Sometimes it's necessary to ensure that a resource is cleaned up after some action that could potentially raise an error. The `try/after` construct allows you to do that. For example, we can open a file and use an `after` clause to close it -- even if something goes wrong:
-
-```elixir
-iex> {:ok, file} = File.open("sample", [:utf8, :write])
-iex> try do
-...>   IO.write(file, "olá")
-...>   raise "oops, something went wrong"
-...> after
-...>   File.close(file)
-...> end
-** (RuntimeError) oops, something went wrong
-```
-
-The `after` clause will be executed regardless of whether or not the tried block succeeds. Note, however, that if a linked process exits,
-this process will exit and the `after` clause will not get run. Thus `after` provides only a soft guarantee. Luckily, files in Elixir are also linked to the current processes and therefore they will always get closed if the current process crashes, independent of the
-`after` clause. You will find the same to be true for other resources like ETS tables, sockets, ports and more.
-
-Sometimes you may want to wrap the entire body of a function in a `try` construct, often to guarantee some code will be executed afterwards. In such cases, Elixir allows you to omit the `try` line:
-
-```elixir
-iex> defmodule RunAfter do
-...>   def without_even_trying do
-...>     raise "oops"
-...>   after
-...>     IO.puts "cleaning up!"
-...>   end
-...> end
-iex> RunAfter.without_even_trying
-cleaning up!
-** (RuntimeError) oops
-```
-
-Elixir will automatically wrap the function body in a `try` whenever one of `after`, `rescue` or `catch` is specified.
-
-## Else
-
-If an `else` block is present, it will match on the results of the `try` block whenever the `try` block finishes without a throw or an error.
-
-```elixir
-iex> x = 2
-2
-iex> try do
-...>   1 / x
-...> rescue
-...>   ArithmeticError ->
-...>     :infinity
-...> else
-...>   y when y < 1 and y > -1 ->
-...>     :small
-...>   _ ->
-...>     :large
-...> end
-:small
-```
-
-Exceptions in the `else` block are not caught. If no pattern inside the `else` block matches, an exception will be raised; this exception is not caught by the current `try/catch/rescue/after` block.
-
-## Variables scope
-
-Similar to `case`, `cond`, `if` and other constructs in Elixir, variables defined inside `try/catch/rescue/after` blocks do not leak to the outer context. In other words, this code is invalid:
-
-```elixir
-iex> try do
-...>   raise "fail"
-...>   what_happened = :did_not_raise
-...> rescue
-...>   _ -> what_happened = :rescued
-...> end
-iex> what_happened
-** (CompileError) undefined variable "what_happened"
-```
-
-Instead, you should return the value of the `try` expression:
-
-```elixir
-iex> what_happened =
-...>   try do
-...>     raise "fail"
-...>     :did_not_raise
-...>   rescue
-...>     _ -> :rescued
-...>   end
-iex> what_happened
-:rescued
-```
-
-Furthermore, variables defined in the do-block of `try` are not available inside `rescue/after/else` either. This is because the `try` block may fail at any moment and therefore the variables may have never been bound in the first place. So this also isn't valid:
-
-```elixir
-iex> try do
-...>   raise "fail"
-...>   another_what_happened = :did_not_raise
-...> rescue
-...>   _ -> another_what_happened
-...> end
-** (CompileError) undefined variable "another_what_happened"
-```
-
-This finishes our introduction to `try`, `catch`, and `rescue`. You will find they are used less frequently in Elixir than in other languages.
diff --git a/getting-started/typespecs-and-behaviours.markdown b/getting-started/typespecs-and-behaviours.markdown
index c931ba592..af6ce2592 100644
--- a/getting-started/typespecs-and-behaviours.markdown
+++ b/getting-started/typespecs-and-behaviours.markdown
@@ -1,225 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Typespecs and behaviours
+layout: redirect
+sitemap: false
+redirect_to: typespecs
 ---
-
-## Types and specs
-
-Elixir is a dynamically typed language, so all types in Elixir are checked at runtime. Nonetheless, Elixir comes with **typespecs**, which are a notation used for:
-
-1. declaring typed function signatures (also called specifications);
-2. declaring custom types.
-
-Typespecs are useful for code clarity and static code analysis (for example, Erlang's [Dialyzer](http://www.erlang.org/doc/man/dialyzer.html) tool).
-
-### Function specifications
-
-Elixir provides many [built-in types](https://hexdocs.pm/elixir/typespecs.html#built-in-types), such as `integer` or `pid`, that can be used to document function signatures.  For example, the `round/1` function, which rounds a number to its nearest integer. As you can see [in its documentation](https://hexdocs.pm/elixir/Kernel.html#round/1), `round/1`'s typed signature is written as:
-
-```elixir
-round(number()) :: integer()
-```
-
-The syntax is to put the function and its input on the left side of the `::` and the return value's type on the right side. Be aware that types *may* omit parentheses.
-
-In code, function specs are written with the `@spec` attribute, typically placed immediately before the function definition. Specs can describe both public and private functions. The function name and the number of arguments used in the `@spec` attribute must match the function it describes.
-
-Elixir supports compound types as well. For example, a list of integers has type `[integer]`, or maps that define keys and types (see the example below).
-
-You can see all the built-in types provided by Elixir [in the typespecs docs](https://hexdocs.pm/elixir/typespecs.html).
-
-### Defining custom types
-
-Defining custom types can help communicate the intention of your code and increase its readability. Custom types can be defined within modules via the `@type` attribute.
-
-A simple example of a custom type implementation is to provide a more descriptive alias of an existing type. For example, defining `year` as a type makes your function specs more descriptive than if they had simply used `integer`:
-
-```elixir
-defmodule Person do
-   @typedoc """
-   A 4 digit year, e.g. 1984
-   """
-   @type year :: integer
-
-   @spec current_age(year) :: integer
-   def current_age(year_of_birth), do: # implementation
-end
-```
-
-The `@typedoc` attribute, similar to the `@doc` and `@moduledoc` attributes, is used to document custom types.
-
-You may define compound custom types, e.g. maps:
-
-```elixir
-@type error_map :: %{
-   message: String.t,
-   line_number: integer
-}
-```
-
-[Structs](https://elixir-lang.org/getting-started/structs.html) offer similar functionality.
-
-Let's look at another example to understand how to define more complex types. Say we have a `LousyCalculator` module, which performs the usual arithmetic operations (sum, product, and so on) but, instead of returning numbers, it returns tuples with the result of an operation as the first element and a random remark as the second element.
-
-```elixir
-defmodule LousyCalculator do
-  @spec add(number, number) :: {number, String.t}
-  def add(x, y), do: {x + y, "You need a calculator to do that?!"}
-
-  @spec multiply(number, number) :: {number, String.t}
-  def multiply(x, y), do: {x * y, "Jeez, come on!"}
-end
-```
-
-Tuples are a compound type and each tuple is identified by the types inside it (in this case, a number and a string). To understand why `String.t` is not written as `string`, have another look at the [typespecs docs](https://hexdocs.pm/elixir/typespecs.html#the-string-type).
-
-Defining function specs this way works, but we end up repeating the type `{number, String.t}` over and over. We can use the `@type` attribute to declare our own custom type and cut down on the repetition.
-
-```elixir
-defmodule LousyCalculator do
-  @typedoc """
-  Just a number followed by a string.
-  """
-  @type number_with_remark :: {number, String.t}
-
-  @spec add(number, number) :: number_with_remark
-  def add(x, y), do: {x + y, "You need a calculator to do that?"}
-
-  @spec multiply(number, number) :: number_with_remark
-  def multiply(x, y), do: {x * y, "It is like addition on steroids."}
-end
-```
-
-Custom types defined through `@type` are exported and are available outside the module they're defined in:
-
-```elixir
-defmodule QuietCalculator do
-  @spec add(number, number) :: number
-  def add(x, y), do: make_quiet(LousyCalculator.add(x, y))
-
-  @spec make_quiet(LousyCalculator.number_with_remark) :: number
-  defp make_quiet({num, _remark}), do: num
-end
-```
-
-If you want to keep a custom type private, you can use the `@typep` attribute instead of `@type`. The visibility also affects whether or not documentation will be generated by tools like [ExDoc](https://hexdocs.pm/ex_doc/readme.html), Elixir's documentation generator.
-
-### Static code analysis
-
-Typespecs are not only useful to developers as additional documentation. The Erlang tool [Dialyzer](http://www.erlang.org/doc/man/dialyzer.html), for example, uses typespecs in order to perform static analysis of code. That's why, in the `QuietCalculator` example, we wrote a spec for the `make_quiet/1` function even though it was defined as a private function.
-
-## Behaviours
-
-Many modules share the same public API. Take a look at [Plug](https://github.com/elixir-lang/plug), which, as its description states, is a **specification** for composable modules in web applications. Each *plug* is a module which **has to** implement at least two public functions: `init/1` and `call/2`.
-
-Behaviours provide a way to:
-
-* define a set of functions that have to be implemented by a module;
-* ensure that a module implements all the functions in that set.
-
-If you have to, you can think of behaviours like interfaces in object oriented languages like Java: a set of function signatures that a module has to implement. Unlike Protocols, behaviours are independent of the type/data.
-
-### Defining behaviours
-
-Say we want to implement a bunch of parsers, each parsing structured data: for example, a JSON parser and a MessagePack parser. Each of these two parsers will *behave* the same way: both will provide a `parse/1` function and an `extensions/0` function. The `parse/1` function will return an Elixir representation of the structured data, while the `extensions/0` function will return a list of file extensions that can be used for each type of data (e.g., `.json` for JSON files).
-
-We can create a `Parser` behaviour:
-
-```elixir
-defmodule Parser do
-  @doc """
-  Parses a string.
-  """
-  @callback parse(String.t) :: {:ok, term} | {:error, atom}
-
-  @doc """
-  Lists all supported file extensions.
-  """
-  @callback extensions() :: [String.t]
-end
-```
-
-Modules adopting the `Parser` behaviour will have to implement all the functions defined with the `@callback` attribute. As you can see, `@callback` expects a function name but also a function specification like the ones used with the `@spec` attribute we saw above. Also note that the `term` type is used to represent the parsed value. In Elixir, the `term` type is a shortcut to represent any type.
-
-### Implementing behaviours
-
-Implementing a behaviour is straightforward:
-
-```elixir
-defmodule JSONParser do
-  @behaviour Parser
-
-  @impl Parser
-  def parse(str), do: {:ok, "some json " <> str} # ... parse JSON
-
-  @impl Parser
-  def extensions, do: [".json"]
-end
-```
-
-```elixir
-defmodule CSVParser do
-  @behaviour Parser
-
-  @impl Parser
-  def parse(str), do: {:ok, "some csv " <> str} # ... parse CSV
-
-  @impl Parser
-  def extensions, do: [".csv"]
-end
-```
-
-If a module adopting a given behaviour doesn't implement one of the callbacks required by that behaviour, a compile-time warning will be generated.
-
-Furthermore, with `@impl` you can also make sure that you are implementing the **correct** callbacks from the given behaviour in an explicit manner. For example, the following parser implements both `parse` and `extensions`. However, thanks to a typo, `BADParser` is implementing `parse/0` instead of `parse/1`.
-
-```elixir
-defmodule BADParser do
-  @behaviour Parser
-
-  @impl Parser
-  def parse, do: {:ok, "something bad"}
-
-  @impl Parser
-  def extensions, do: ["bad"]
-end
-```
-
-This code generates a warning letting you know that you are mistakenly implementing `parse/0` instead of `parse/1`.
-You can read more about `@impl` in the [module documentation](https://hexdocs.pm/elixir/main/Module.html#module-impl).
-
-### Using behaviours
-
-Behaviours are useful because you can pass modules around as arguments and you can then _call back_ to any of the functions specified in the behaviour. For example, we can have a function that receives a filename, several parsers, and parses the file based on its extension:
-
-```elixir
-@spec parse_path(Path.t(), [module()]) :: {:ok, term} | {:error, atom}
-def parse_path(filename, parsers) do
-  with {:ok, ext} <- parse_extension(filename),
-       {:ok, parser} <- find_parser(ext, parsers),
-       {:ok, contents} <- File.read(filename) do
-    parser.parse(contents)
-  end
-end
-
-defp parse_extension(filename) do
-  if ext = Path.extname(filename) do
-    {:ok, ext}
-  else
-    {:error, :no_extension}
-  end
-end
-
-defp find_parser(ext, parsers) do
-  if parser = Enum.find(parsers, fn parser -> ext in parser.extensions() end) do
-    {:ok, parser}
-  else
-    {:error, :no_matching_parser}
-  end
-end
-```
-
-Of course, you could also invoke any parser directly: `CSVParser.parse(...)`.
-
-Note you don't need to define a behaviour in order to dynamically dispatch on a module, but those features often go hand in hand.
diff --git a/getting-started/where-to-go-next.markdown b/getting-started/where-to-go-next.markdown
index 2a62b0acc..c50365d75 100644
--- a/getting-started/where-to-go-next.markdown
+++ b/getting-started/where-to-go-next.markdown
@@ -1,43 +1,5 @@
 ---
-section: getting-started
-layout: getting-started
-title: Where to go next
+layout: redirect
+sitemap: false
+redirect_to: introduction
 ---
-
-Eager to learn more? Keep reading!
-
-## Build your first Elixir project
-
-In order to get your first project started, Elixir ships with a build tool called Mix. You can get your new project started by running:
-
-```console
-$ mix new path/to/new/project
-```
-
-We have written a guide that covers how to build an Elixir application, with its own supervision tree, configuration, tests, and more. The application works as a distributed key-value store where we organize key-value pairs into buckets and distribute those buckets across multiple nodes:
-
-* [Mix and OTP](/getting-started/mix-otp/introduction-to-mix.html)
-
-If you are planning to write your first library for other developers to use, don't forget to read our [Library Guidelines](https://hexdocs.pm/elixir/library-guidelines.html).
-
-## Meta-programming
-
-Elixir is an extensible and very customizable programming language thanks to its meta-programming support. Most meta-programming in Elixir is done through macros, which are very useful in several situations, especially for writing DSLs. We have written a short guide that explains the basic mechanisms behind macros, shows how to write macros, and how to use macros to create DSLs:
-
-* [Meta-programming in Elixir](/getting-started/meta/quote-and-unquote.html)
-
-## Community and other resources
-
-We have a [Learning](/learning.html) section that suggests books, screencasts, and other resources for learning Elixir and exploring the ecosystem. There are also plenty of Elixir resources out there, like conference talks, open source projects, and other learning material produced by the community.
-
-Don't forget that you can also check the [source code of Elixir itself](https://github.com/elixir-lang/elixir), which is mostly written in Elixir (mainly the `lib` directory), or [explore Elixir's documentation](/docs.html).
-
-## A byte of Erlang
-
-Elixir runs on the Erlang Virtual Machine and, sooner or later, an Elixir developer will want to interface with existing Erlang libraries. Here's a list of online resources that cover Erlang's fundamentals and its more advanced features:
-
-* This [Erlang Syntax: A Crash Course](/crash-course.html) provides a concise intro to Erlang's syntax. Each code snippet is accompanied by equivalent code in Elixir. This is an opportunity for you to not only get some exposure to Erlang's syntax but also review some of the things you have learned in this guide.
-
-* Erlang's official website has a short [tutorial](https://www.erlang.org/course). There is a chapter with pictures briefly describing Erlang's primitives for [concurrent programming](https://www.erlang.org/course/concurrent_programming.html).
-
-* [Learn You Some Erlang for Great Good!](http://learnyousomeerlang.com/) is an excellent introduction to Erlang, its design principles, standard library, best practices, and much more. Once you have read through the crash course mentioned above, you'll be able to safely skip the first couple of chapters in the book that mostly deal with the syntax. When you reach [The Hitchhiker's Guide to Concurrency](http://learnyousomeerlang.com/the-hitchhikers-guide-to-concurrency) chapter, that's where the real fun starts.
diff --git a/images/cases/bg/cyanview-1.jpg b/images/cases/bg/cyanview-1.jpg
new file mode 100644
index 000000000..2e0b9ffcf
Binary files /dev/null and b/images/cases/bg/cyanview-1.jpg differ
diff --git a/images/cases/bg/cyanview-2.jpg b/images/cases/bg/cyanview-2.jpg
new file mode 100644
index 000000000..a6e7796e6
Binary files /dev/null and b/images/cases/bg/cyanview-2.jpg differ
diff --git a/images/cases/bg/cyanview-3.jpg b/images/cases/bg/cyanview-3.jpg
new file mode 100644
index 000000000..fbe3515f3
Binary files /dev/null and b/images/cases/bg/cyanview-3.jpg differ
diff --git a/images/cases/bg/cyanview-4.jpg b/images/cases/bg/cyanview-4.jpg
new file mode 100644
index 000000000..c14baed64
Binary files /dev/null and b/images/cases/bg/cyanview-4.jpg differ
diff --git a/images/cases/bg/remote.png b/images/cases/bg/remote.png
new file mode 100644
index 000000000..a4285ad4e
Binary files /dev/null and b/images/cases/bg/remote.png differ
diff --git a/images/cases/logos/cyanview.png b/images/cases/logos/cyanview.png
new file mode 100644
index 000000000..4fac3bf69
Binary files /dev/null and b/images/cases/logos/cyanview.png differ
diff --git a/images/cases/logos/remote.png b/images/cases/logos/remote.png
new file mode 100644
index 000000000..6e8db442f
Binary files /dev/null and b/images/cases/logos/remote.png differ
diff --git a/images/cases/logos/veeps.svg b/images/cases/logos/veeps.svg
new file mode 100755
index 000000000..8e9ce4fa5
--- /dev/null
+++ b/images/cases/logos/veeps.svg
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 27.6.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 1269.97 366.13" style="enable-background:new 0 0 1269.97 366.13;" xml:space="preserve">
+<g>
+	<polygon points="200.19,216.79 155.71,68.96 68.96,68.96 153.05,297.17 245.97,297.17 319.22,68.96 240.14,68.96 	"/>
+	<polygon points="543.57,297.17 737.45,297.17 737.45,232.5 611.99,232.5 611.99,210.95 735.8,210.95 735.8,151.74 611.99,151.74 
+		611.99,131.62 737.45,131.62 737.45,68.96 543.57,68.96 	"/>
+	<path d="M1114.28,151.74h-53.47c-5.74,0-10.42-2.87-10.42-10.06c0-7.18,4.67-10.06,10.42-10.06h50.74c5.74,0,8.21,2.87,8.21,10.06
+		h74.98c0-46.85-30.65-72.72-85.65-72.72h-48.29c-60.47,0-84.55,20.7-84.55,72.72c0,45.42,26.81,69.27,77.99,69.27h59.22
+		c5.74,0,10.42,3.16,10.42,10.63c0,7.76-4.4,10.92-10.15,10.92h-54.02c-5.74,0-8.21-3.16-8.21-10.92h-74.43
+		c0,54.04,24.08,75.59,84.56,75.59h42.26c67.05,0,97.13-21.56,97.13-75.59C1201.01,175.59,1169.01,151.74,1114.28,151.74z"/>
+	<polygon points="330.8,297.17 524.96,297.17 524.96,232.5 399.22,232.5 399.22,210.95 523.31,210.95 523.31,151.74 399.22,151.74 
+		399.22,131.62 524.96,131.62 524.96,68.96 330.8,68.96 	"/>
+	<path d="M886.18,68.96H756.07v228.22h68.96v-86.22h61.15c55.83,0,78.27-19.83,78.27-69.56C964.45,89.65,942.01,68.96,886.18,68.96z
+		 M886.17,151.74h-61.14v-20.12h61.14c5.74,0,10.41,2.87,10.41,9.77C896.58,148.86,891.91,151.74,886.17,151.74z"/>
+</g>
+</svg>
diff --git a/images/contents/gem.jpeg b/images/contents/gem.jpeg
new file mode 100644
index 000000000..220a094c6
Binary files /dev/null and b/images/contents/gem.jpeg differ
diff --git a/images/contents/iex-auto-reload.mp4 b/images/contents/iex-auto-reload.mp4
new file mode 100644
index 000000000..d21ad3f8b
Binary files /dev/null and b/images/contents/iex-auto-reload.mp4 differ
diff --git a/images/contents/type-warning-case.png b/images/contents/type-warning-case.png
new file mode 100644
index 000000000..118dad1f1
Binary files /dev/null and b/images/contents/type-warning-case.png differ
diff --git a/images/contents/type-warning-function-clause.png b/images/contents/type-warning-function-clause.png
new file mode 100644
index 000000000..4c2fa76dd
Binary files /dev/null and b/images/contents/type-warning-function-clause.png differ
diff --git a/images/contents/type-warning-in-editor.png b/images/contents/type-warning-in-editor.png
new file mode 100644
index 000000000..38293a0c8
Binary files /dev/null and b/images/contents/type-warning-in-editor.png differ
diff --git a/images/contents/type-warning-on-date-comparison.png b/images/contents/type-warning-on-date-comparison.png
new file mode 100644
index 000000000..349372cd6
Binary files /dev/null and b/images/contents/type-warning-on-date-comparison.png differ
diff --git a/images/contents/type-warning-on-struct-field.png b/images/contents/type-warning-on-struct-field.png
new file mode 100644
index 000000000..1d003bf3c
Binary files /dev/null and b/images/contents/type-warning-on-struct-field.png differ
diff --git a/images/contents/type-warning-private.png b/images/contents/type-warning-private.png
new file mode 100644
index 000000000..da05ab1cb
Binary files /dev/null and b/images/contents/type-warning-private.png differ
diff --git a/images/learning/elixir-in-action.jpg b/images/learning/elixir-in-action.jpg
index 59068c9bf..932bce213 100644
Binary files a/images/learning/elixir-in-action.jpg and b/images/learning/elixir-in-action.jpg differ
diff --git a/images/learning/elixir-streams-logo.png b/images/learning/elixir-streams-logo.png
new file mode 100644
index 000000000..48e4434d3
Binary files /dev/null and b/images/learning/elixir-streams-logo.png differ
diff --git a/images/learning/techschool.png b/images/learning/techschool.png
new file mode 100644
index 000000000..3305082ee
Binary files /dev/null and b/images/learning/techschool.png differ
diff --git a/images/social/RSSButton.png b/images/social/RSSButton.png
deleted file mode 100644
index fa66c876e..000000000
Binary files a/images/social/RSSButton.png and /dev/null differ
diff --git a/images/social/elixir-og-card.jpg b/images/social/elixir-og-card.jpg
new file mode 100644
index 000000000..64cd0da91
Binary files /dev/null and b/images/social/elixir-og-card.jpg differ
diff --git a/images/social/rss-feed-icon.svg b/images/social/rss-feed-icon.svg
new file mode 100644
index 000000000..0435819b1
--- /dev/null
+++ b/images/social/rss-feed-icon.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><defs><linearGradient x1=".085" y1=".085" x2=".915" y2=".915" id="a"><stop offset="0" stop-color="#E3702D"/><stop offset=".107" stop-color="#EA7D31"/><stop offset=".35" stop-color="#F69537"/><stop offset=".5" stop-color="#FB9E3A"/><stop offset=".702" stop-color="#EA7C31"/><stop offset=".887" stop-color="#DE642B"/><stop offset="1" stop-color="#D95B29"/></linearGradient></defs><rect width="256" height="256" rx="55" ry="55" fill="#CC5D15"/><rect width="246" height="246" rx="50" ry="50" x="5" y="5" fill="#F49C52"/><rect width="236" height="236" rx="47" ry="47" x="10" y="10" fill="url(#a)"/><circle cx="68" cy="189" r="24" fill="#FFF"/><path d="M160 213h-34a82 82 0 0 0-82-82V97a116 116 0 0 1 116 116z" fill="#FFF"/><path d="M184 213A140 140 0 0 0 44 73V38a175 175 0 0 1 175 175z" fill="#FFF"/></svg>
\ No newline at end of file
diff --git a/index.html b/index.html
index 6d733fda0..66925b0e5 100644
--- a/index.html
+++ b/index.html
@@ -1,6 +1,7 @@
 ---
 section: home
 layout: default
+image: /images/social/elixir-og-card.jpg
 ---
 
 <div class="hfeed">
@@ -17,7 +18,7 @@ <h5>Elixir is a dynamic, functional language for building scalable and maintaina
 %{"E" => 1, "i" => 2, "l" => 1, "r" => 1, "x" => 1}
 {% endhighlight %}
 
-      <p>Check our <a href="/getting-started/introduction.html">getting started guide</a> and our <a href="/learning.html">learning page</a> to begin your journey with Elixir. Or keep scrolling for an overview of the platform, language, and tools.
+      <p>Check our <a href="https://hexdocs.pm/elixir/introduction.html">Getting Started guide</a> and our <a href="/learning.html">Learning page</a> to begin your journey with Elixir. Or keep scrolling for an overview of the platform, language, and tools.
     </div>
   </div>
 
@@ -122,7 +123,7 @@ <h4>Functional programming</h4>
     <h4>Extensibility and DSLs</h4>
 
     <div class="entry-summary">
-      <p>Elixir has been designed to be extensible, allowing developers naturally extend the language to particular domains, in order to increase their productivity.</p>
+      <p>Elixir has been designed to be extensible, allowing developers to naturally extend the language to particular domains, in order to increase their productivity.</p>
 
       <p>As an example, let's write a simple test case using <a href="https://hexdocs.pm/ex_unit/">Elixir's test framework called ExUnit</a>:</p>
 
@@ -195,7 +196,7 @@ <h4>Erlang compatible</h4>
 <<192, 223, 75, 115, ...>>
 {% endhighlight %}
 
-      <p>To learn more about Elixir, check our <a href="/getting-started/introduction.html">getting started guide</a>. We also have <a href="/docs.html">online documentation available</a> and a <a href="/crash-course.html">Crash Course for Erlang developers</a>.</p>
+      <p>To learn more about Elixir, check our <a href="https://hexdocs.pm/elixir/introduction.html">Getting Started guide</a>.</p>
     </div>
   </div>
 </div>
diff --git a/install.bat b/install.bat
new file mode 100755
index 000000000..a6e88101c
--- /dev/null
+++ b/install.bat
@@ -0,0 +1,207 @@
+@echo off
+REM See latest version at:
+REM https://github.com/elixir-lang/elixir-lang.github.com/blob/main/install.bat
+
+setlocal EnableDelayedExpansion
+
+set "otp_version="
+set "elixir_version="
+set "force=false"
+
+goto :main
+
+:usage
+echo Usage: install.bat elixir@ELIXIR_VERSION otp@OTP_VERSION [options]
+echo.
+echo ELIXIR_VERSION can be X.Y.Z, latest, or main.
+echo OTP_VERSION can be X.Y.Z or latest.
+echo.
+echo Options:
+echo.
+echo   -f, --force      Forces installation even if it was previously installed
+echo   -h, --help       Prints this help
+echo.
+echo Examples:
+echo.
+echo   install.bat elixir@1.16.3 otp@26.2.5.4
+echo   install.bat elixir@latest otp@latest
+echo   install.bat elixir@main otp@latest
+echo.
+goto :eof
+
+:main
+for %%i in (%*) do (
+  set arg=%%i
+
+  if "!arg:~0,7!" == "elixir@" (
+    set "elixir_version=!arg:~7!"
+  ) else if "!arg:~0,4!" == "otp@" (
+    set "otp_version=!arg:~4!"
+  ) else if "!arg!" == "-f" (
+    set "force=true"
+  ) else if "!arg!" == "--force" (
+    set "force=true"
+  ) else if "!arg!" == "-h" (
+    call :usage
+    exit /b 0
+  ) else if "!arg!" == "--help" (
+    call :usage
+    exit /b 0
+  ) else (
+    echo error: unknown argument !arg!
+    exit /b 1
+  )
+)
+
+if "%elixir_version%" == "" (
+  call :usage
+  echo error: missing elixir@VERSION argument
+  exit /b 1
+)
+
+if "%otp_version%" == "" (
+  call :usage
+  echo error: missing otp@VERSION argument
+  exit /b 1
+)
+
+if "!otp_version!" == "latest" (
+  set "url=https://github.com/erlang/otp/releases/latest"
+  for /f "tokens=2 delims= " %%a in ('curl -fsS --head "!url!" ^| findstr /I "^location:"') do set url=%%a
+  set "otp_version=!url:*releases/tag/OTP-=!"
+)
+
+if "!elixir_version!" == "latest" (
+  set "url=https://github.com/elixir-lang/elixir/releases/latest"
+  for /f "tokens=2 delims= " %%a in ('curl -fsS --head "!url!" ^| findstr /I "^location:"') do set url=%%a
+  set "elixir_version=!url:*releases/tag/v=!"
+)
+
+for /f "tokens=1 delims=." %%A in ("!otp_version!") do set "elixir_otp_release=%%A"
+for /f "tokens=1,2 delims=." %%A in ("!elixir_version!") do set "elixir_major_minor=%%A.%%B"
+
+if "%elixir_major_minor%" == "1.14" (
+  if %elixir_otp_release% GEQ 25 set "elixir_otp_release=25"
+) else if "%elixir_major_minor%" == "1.15" (
+  if %elixir_otp_release% GEQ 26 set "elixir_otp_release=26"
+) else if "%elixir_major_minor%" == "1.16" (
+  if %elixir_otp_release% GEQ 26 set "elixir_otp_release=26"
+) else if "%elixir_major_minor%" == "1.17" (
+  if %elixir_otp_release% GEQ 27 set "elixir_otp_release=27"
+) else if "%elixir_major_minor%" == "1.18" (
+  if %elixir_otp_release% GEQ 27 set "elixir_otp_release=27"
+) else if "%elixir_major_minor%" == "1.19" (
+  if %elixir_otp_release% GEQ 28 set "elixir_otp_release=28"
+) else (
+  if %elixir_otp_release% GEQ 28 set "elixir_otp_release=28"
+)
+
+set "root_dir=%USERPROFILE%\.elixir-install"
+set "tmp_dir=%root_dir%\tmp"
+mkdir %tmp_dir% 2>nul
+set "otp_dir=%root_dir%\installs\otp\%otp_version%"
+set "elixir_dir=%root_dir%\installs\elixir\%elixir_version%-otp-%elixir_otp_release%"
+
+call :install_otp
+if %errorlevel% neq 0 exit /b 1
+
+set /p="checking OTP... "<nul
+set "PATH=%otp_dir%\bin;%PATH%"
+"%otp_dir%\bin\erl.exe" -noshell -eval "io:put_chars(erlang:system_info(otp_release) ++ "" ok\n""), halt()."
+
+call :install_elixir
+if %errorlevel% neq 0 exit /b 1
+
+set /p="checking Elixir... "<nul
+call "%elixir_dir%\bin\elixir.bat" -e "IO.write(System.version())"
+echo. ok
+
+echo.
+echo If you are using powershell, run this (or add to your $PROFILE):
+echo.
+echo    $env:PATH = "$env:USERPROFILE\.elixir-install\installs\otp\!otp_version!\bin;$env:PATH"
+echo    $env:PATH = "$env:USERPROFILE\.elixir-install\installs\elixir\!elixir_version!-otp-%elixir_otp_release%\bin;$env:PATH"
+echo.
+echo If you are using cmd, run this:
+echo.
+echo    set PATH=%%USERPROFILE%%\.elixir-install\installs\otp\!otp_version!\bin;%%PATH%%
+echo    set PATH=%%USERPROFILE%%\.elixir-install\installs\elixir\!elixir_version!-otp-%elixir_otp_release%\bin;%%PATH%%
+echo.
+goto :eof
+
+:install_otp
+set "otp_zip=otp_win64_%otp_version%.zip"
+
+if "%force%" == "true" (
+  if exist "%otp_dir%" (
+    rmdir /s /q "%otp_dir%"
+  )
+)
+
+if not exist "%otp_dir%\bin" (
+  if exist "%otp_dir%" (
+    rmdir /s /q "%otp_dir%"
+  )
+
+  set otp_url=https://github.com/erlang/otp/releases/download/OTP-!otp_version!/%otp_zip%
+  echo downloading !otp_url!...
+  curl.exe -fsSLo %tmp_dir%\%otp_zip% "!otp_url!" || exit /b 1
+
+  echo unpacking %tmp_dir%\%otp_zip%
+  powershell -NoProfile -Command ^
+    "$ErrorActionPreference='Stop';" ^
+    "try {" ^
+    "  if (-not (Get-Command Expand-Archive -ErrorAction SilentlyContinue)) {" ^
+    "    Add-Type -AssemblyName System.IO.Compression.FileSystem;" ^
+    "    [System.IO.Compression.ZipFile]::ExtractToDirectory('%tmp_dir%\%otp_zip%', '%otp_dir%')" ^
+    "  } else {" ^
+    "    Expand-Archive -LiteralPath '%tmp_dir%\%otp_zip%' -DestinationPath '%otp_dir%' -Force" ^
+    "  }" ^
+    "} catch { Write-Error $_; exit 1 }"
+  del /f /q "%tmp_dir%\%otp_zip%"
+  cd /d "%otp_dir%"
+
+  if not exist "c:\windows\system32\vcruntime140.dll" (
+    echo Installing VC++ Redistributable...
+    .\vc_redist.exe /quiet /norestart
+  )
+)
+exit /b 0
+goto :eof
+
+:install_elixir
+set "elixir_zip=elixir-otp-!elixir_otp_release!.zip"
+
+if "%elixir_version%" == "main" (
+  rem Do not remove this comment
+  set "ref=main-latest"
+) else (
+  rem Do not remove this comment
+  set "ref=v%elixir_version%"
+)
+
+if "%force%" == "true" (
+  if exist "%elixir_dir%" (
+    rmdir /s /q "%elixir_dir%"
+  )
+)
+
+if not exist "%elixir_dir%\bin" (
+  set "elixir_url=https://github.com/elixir-lang/elixir/releases/download/%ref%/elixir-otp-%elixir_otp_release%.zip"
+  echo downloading !elixir_url!...
+  curl.exe -fsSLo "%tmp_dir%\%elixir_zip%" "!elixir_url!" || exit /b 1
+
+  echo unpacking %tmp_dir%\%elixir_zip%
+  powershell -NoProfile -Command ^
+    "$ErrorActionPreference='Stop';" ^
+    "try {" ^
+    "  if (-not (Get-Command Expand-Archive -ErrorAction SilentlyContinue)) {" ^
+    "    Add-Type -AssemblyName System.IO.Compression.FileSystem;" ^
+    "    [System.IO.Compression.ZipFile]::ExtractToDirectory('%tmp_dir%\%elixir_zip%', '%elixir_dir%')" ^
+    "  } else {" ^
+    "    Expand-Archive -LiteralPath '%tmp_dir%\%elixir_zip%' -DestinationPath '%elixir_dir%' -Force" ^
+    "  }" ^
+    "} catch { Write-Error $_; exit 1 }"
+  del /f /q %tmp_dir%\%elixir_zip%
+)
+goto :eof
diff --git a/install.markdown b/install.markdown
index 7fbca6f93..946d83f84 100644
--- a/install.markdown
+++ b/install.markdown
@@ -2,6 +2,7 @@
 title: "Installing Elixir"
 section: install
 layout: default
+image: /images/social/elixir-og-card.jpg
 ---
 {% assign stable = site.data.elixir-versions[site.data.elixir-versions.stable] %}
 
@@ -9,7 +10,7 @@ layout: default
 
 {% include toc.html %}
 
-The quickest way to install Elixir is through a distribution or using one of the available installers. If such an option is not available, then we recommend using the precompiled packages or compiling the language yourself. All of these options are detailed next.
+The quickest way to install Elixir is through install scripts, operating system package manager, or using one of the available installers. If such an option is not available, then we recommend using the precompiled packages or compiling the language yourself. All of these options are detailed next.
 
 Note that Elixir {{ stable.name }} requires Erlang {{ stable.minimum_otp }} or later. Many of the instructions below will automatically install Erlang for you. If they do not, the "Installing Erlang" section has you covered.
 
@@ -21,53 +22,29 @@ Install Elixir according to your operating system and tool of choice.
 
 ### macOS
 
+  - Using [install scripts](#install-scripts)
+
   - Using [Homebrew](https://brew.sh/):
     * Run: `brew install elixir`
 
   - Using [Macports](https://www.macports.org/):
     * Run: `sudo port install elixir`
 
-Note version managers (described below), are also available for macOS.
+  - Using [version managers](#version-managers)
 
 ### GNU/Linux
 
-On Unix systems, there are two options to install Elixir. You can use the Erlang/Elixir packages that are part of your distribution, although those may lag behind in version numbers (especially for LTS releases). In such cases, you can also opt to use a version manager.
-
-#### Version managers
-
-There are many tools that allow developers to install and manage multiple Erlang and Elixir versions. They are useful if you have multiple projects running on different Elixir or Erlang versions, can't install Erlang or Elixir as mentioned above or if the version provided by your package manager is outdated. Here are some of those tools:
-
-  * [asdf](https://github.com/asdf-vm/asdf) - install and manage different [Elixir](https://github.com/asdf-vm/asdf-elixir) and [Erlang](https://github.com/asdf-vm/asdf-erlang) versions
-  * [kiex](https://github.com/taylor/kiex) - install and manage different Elixir versions
-  * [kerl](https://github.com/yrashk/kerl) - install and manage different Erlang versions
-
-Keep in mind that each Elixir version supports specific Erlang/OTP versions. [See the supported versions alongside our docs](/docs).
+Below we list steps for installing Elixir in different distributions. If your distribution is not listed or the steps below do not work, you may consider using [version managers](#version-managers).
 
 #### Distributions
 
-  - **Alpine Linux** (Community repository)
-    * Run: `apk add elixir`
-
   - **Arch Linux** (Community repository)
     * Run: `pacman -S elixir`
 
-  - **Debian**
-    * Run: `sudo apt install elixir`
-
-  - **Debian** (and **Ubuntu**) alternative
-    * Use the [RabbitMQ Packages](https://launchpad.net/~rabbitmq) (might not be up-to-date however likely newer than the distribution)
-
-      ```bash
-      $ sudo add-apt-repository ppa:rabbitmq/rabbitmq-erlang
-      $ sudo apt update
-      $ sudo apt install elixir erlang-dev erlang-xmerl
-      ```
-
-  - **Fedora 21 (and older)**
-    * Run: `yum install elixir`
-
-  - **Fedora 22 (and newer)**
-    * Run `dnf install elixir erlang`
+  - **Fedora**
+    * Fedora's Rawhide repository keeps more recent versions: `sudo dnf --repo=rawhide install elixir elixir-doc erlang erlang-doc`
+    * You may use the default distribution, but those often lag behind: `sudo dnf install elixir erlang`
+    * Documentation is available in separate packages: `sudo dnf install elixir-doc erlang-doc`
 
   - **Gentoo**
     * Run: `emerge --ask dev-lang/elixir`
@@ -75,25 +52,24 @@ Keep in mind that each Elixir version supports specific Erlang/OTP versions. [Se
   - **GNU Guix**
     * Run: `guix package -i elixir`
 
-  - **openSUSE (and SLES)**
-    * Add Elixir/Erlang repository: `zypper ar -f obs://devel:languages:erlang/ Elixir-Factory`
-    * Run: `zypper in elixir`
-    * Optional: if you want to use the latest Erlang, you can use this repository: `zypper ar -f  obs://devel:languages:erlang:Factory Erlang-Factory`
+  - **Ubuntu**
+    * Use [install scripts](#install-scripts) (or alternatively [version managers](#version-managers))
+    * The packages in `apt` tend to lag several versions behind. You may use [RabbitMQ Packages](https://launchpad.net/~rabbitmq) outlined below, which are likely newer than `apt`:
+
+      ```bash
+      $ sudo add-apt-repository ppa:rabbitmq/rabbitmq-erlang
+      $ sudo apt update
+      $ sudo apt install git elixir erlang
+      ```
 
-  - **Slackware**
-    * Using Sbopkg:
-      * Run: `sbopkg -ki "erlang-otp elixir"`
-    * Manually:
-      * Download, build and install from SlackBuilds.org: [`erlang-otp`](https://slackbuilds.org/repository/14.2/development/erlang-otp/), and [`elixir`](https://slackbuilds.org/repository/14.2/development/elixir)
+#### Version managers
 
-  - **Solus**
-    * Run: `eopkg install elixir`
+There are many tools that allow developers to install and manage multiple Erlang and Elixir versions. They are useful if you have multiple projects running on different Elixir or Erlang versions, can't install Erlang or Elixir as mentioned above or if the version provided by your package manager is outdated. Here are some of those tools:
 
-  - **Ubuntu**
-    * Run: `sudo apt install elixir`
+  * [asdf](https://github.com/asdf-vm/asdf) - install and manage different [Elixir](https://github.com/asdf-vm/asdf-elixir) and [Erlang](https://github.com/asdf-vm/asdf-erlang) versions
+  * [kerl](https://github.com/kerl/kerl) - install and manage different Erlang versions
 
-  - **Void Linux**
-    * Run: `xbps-install -S elixir`
+Keep in mind that each Elixir version supports specific Erlang/OTP versions. [See the supported versions alongside our docs](/docs).
 
 ### BSD
 
@@ -119,6 +95,8 @@ Keep in mind that each Elixir version supports specific Erlang/OTP versions. [Se
 {% endfor %}
       Run `erl` in the terminal if you are unsure of your Erlang/OTP version.<br />Previous Elixir versions are available in our [Releases](https://github.com/elixir-lang/elixir/releases) page.
 
+  - Using [install scripts](#install-scripts)
+
   - Using [Scoop](https://scoop.sh/):
     * Install Erlang: `scoop install erlang`
     * Install Elixir: `scoop install elixir`
@@ -126,8 +104,6 @@ Keep in mind that each Elixir version supports specific Erlang/OTP versions. [Se
   - Using [Chocolatey](https://community.chocolatey.org/):
     * Install Elixir (installs Erlang as a dependency): `choco install elixir`
 
-Elixir versions before v1.15 can also be installed using the deprecated [Online Elixir Installer](https://github.com/elixir-lang/elixir-windows-setup/releases/tag/v2.4).
-
 ### Raspberry Pi and embedded devices
 
 To build and package an Elixir application, with the whole operating system, and burn that into a disk or deploy it overwhere, [check out the Nerves project](https://www.nerves-project.org).
@@ -145,6 +121,34 @@ If you are familiar with Docker you can use the official Docker image to get sta
 
 The above will automatically point to the latest Erlang and Elixir available. For production usage, we recommend using [Hex.pm Docker images](https://hub.docker.com/r/hexpm/elixir), which are immutable and point to a specific Erlang and Elixir version.
 
+## Install scripts
+
+Elixir and Erlang/OTP can be quickly installed for macOS, Windows, or Ubuntu using an `install.sh`/`install.bat` script:
+
+If you are using bash (macOS/Ubuntu/Windows), run:
+
+```sh
+curl -fsSO {{ site.url }}/install.sh
+sh install.sh elixir@{{ stable.version }} otp@{{ stable.recommended_otp }}
+installs_dir=$HOME/.elixir-install/installs
+export PATH=$installs_dir/otp/{{ stable.recommended_otp }}/bin:$PATH
+export PATH=$installs_dir/elixir/{{ stable.version }}-otp-{{ stable.otp_versions[0] }}/bin:$PATH
+iex
+```
+
+If you are using PowerShell (Windows), run:
+
+```pwsh
+curl.exe -fsSO {{ site.url }}/install.bat
+.\install.bat elixir@{{ stable.version }} otp@{{ stable.recommended_otp }}
+$installs_dir = "$env:USERPROFILE\.elixir-install\installs"
+$env:PATH = "$installs_dir\otp\{{ stable.recommended_otp }}\bin;$env:PATH"
+$env:PATH = "$installs_dir\elixir\{{ stable.version }}-otp-{{ stable.otp_versions[0] }}\bin;$env:PATH"
+iex.bat
+```
+
+You may want to [set the $PATH environment variable](#setting-path-environment-variable) for your whole system. Use `install.sh --help` or `install.bat --help` to learn more about available arguments and options.
+
 ## Precompiled package
 
 Elixir provides a precompiled package for every release. First [install Erlang](/install.html#installing-erlang) and then download the appropriate precompiled Elixir below. You can consult your Erlang/OTP version by running `erl -s halt`:
@@ -156,7 +160,7 @@ Once you download the release, unpack it, and you are ready to run the `elixir`
 
 ### Mirrors and nightly builds
 
-The links above point directly to the GitHub release. We also host and mirror precompiled packages and nightly builds globally via `repo.hex.pm` using the following URL scheme:
+The links above point directly to the GitHub release. We also host and mirror precompiled packages and nightly builds globally via `builds.hex.pm` using the following URL scheme:
 
     https://builds.hex.pm/builds/elixir/${ELIXIR_VERSION}-otp-${OTP_VERSION}.zip
 
@@ -168,6 +172,10 @@ To use nightly for a given Erlang/OTP version (such as 25), use:
 
     https://builds.hex.pm/builds/elixir/main-otp-25.zip
 
+For a list of all builds, use:
+
+    https://builds.hex.pm/builds/elixir/builds.txt
+
 ## Compiling from source
 
 You can download and compile Elixir in few steps. The first one is to [install Erlang](/install.html#installing-erlang). You will also need [make](https://www.gnu.org/software/make/) available.
@@ -216,6 +224,7 @@ After Elixir is up and running, it is common to have questions as you learn and
 
   * [#elixir on irc.libera.chat](irc://irc.libera.chat/elixir)
   * [Elixir Forum](http://elixirforum.com)
+  * [Elixir on Slack](https://elixir-slack.community)
   * [Elixir on Discord](https://discord.gg/elixir)
   * [elixir tag on StackOverflow](https://stackoverflow.com/questions/tagged/elixir)
 
diff --git a/install.sh b/install.sh
new file mode 100755
index 000000000..f1647a15f
--- /dev/null
+++ b/install.sh
@@ -0,0 +1,298 @@
+#!/bin/sh
+# See latest version at:
+# https://github.com/elixir-lang/elixir-lang.github.com/blob/main/install.sh
+
+set -eu
+
+otp_version=
+elixir_version=
+force=false
+
+usage() {
+  cat<<EOF
+Usage: install.sh elixir@ELIXIR_VERSION otp@OTP_VERSION [options]
+
+ELIXIR_VERSION can be X.Y.Z, latest, or main.
+OTP_VERSION can be X.Y.Z, latest, master, maint, or maint-RELEASE (e.g. maint-27).
+
+Options:
+
+  -f, --force      Forces installation even if it was previously installed
+  -h, --help       Prints this help
+
+Examples:
+
+  sh install.sh elixir@1.16.3 otp@26.2.5.4
+  sh install.sh elixir@latest otp@latest
+  sh install.sh elixir@main otp@master
+
+EOF
+}
+
+main() {
+  for arg in "$@"; do
+    case "$arg" in
+      elixir@*)
+        elixir_version="${arg#elixir@}"
+        ;;
+      otp@*)
+        otp_version="${arg#otp@}"
+        ;;
+      -h|--help)
+        usage
+        exit 0
+        ;;
+      -f|--force)
+        force=true
+        ;;
+      *)
+        echo "error: invalid argument $arg" >&2
+        exit 1
+        ;;
+    esac
+  done
+
+  if [ -z "${elixir_version}" ]; then
+    usage
+    echo "error: missing elixir@VERSION argument"
+    exit 1
+  fi
+
+  if [ -z "${otp_version}" ]; then
+    usage
+    echo "error: missing otp@VERSION argument"
+    exit 1
+  fi
+
+  root_dir="$HOME/.elixir-install"
+  tmp_dir="$root_dir/tmp"
+  mkdir -p "$tmp_dir"
+
+  if [ "${otp_version}" = latest ]; then
+    url=$(curl -fsS --head https://github.com/erlef/otp_builds/releases/latest | grep -i '^location:' | awk '{print $2}' | tr -d '\r\n')
+    tag=$(basename "$url")
+    otp_version="${tag#OTP-}"
+  fi
+
+  if [ "${elixir_version}" = latest ]; then
+    url=$(curl -fsS --head https://github.com/elixir-lang/elixir/releases/latest | grep -i '^location:' | awk '{print $2}' | tr -d '\r\n')
+    tag=$(basename "$url")
+    elixir_version="${tag#v}"
+  fi
+
+  case "${otp_version}" in
+    master|maint*)
+      branch_version=$(curl -fsS https://raw.githubusercontent.com/erlang/otp/refs/heads/${otp_version}/OTP_VERSION | tr -d '\n')
+      elixir_otp_release="${branch_version%%.*}"
+      ;;
+    *)
+      elixir_otp_release="${otp_version%%.*}"
+      ;;
+  esac
+
+  case "$elixir_version" in
+    1.14.*)
+      [ "${elixir_otp_release}" -ge 25 ] && elixir_otp_release=25
+      ;;
+    1.15.*|1.16.*)
+      [ "${elixir_otp_release}" -ge 26 ] && elixir_otp_release=26
+      ;;
+    1.17.*|1.18.*)
+      [ "${elixir_otp_release}" -ge 27 ] && elixir_otp_release=27
+      ;;
+    1.19.*)
+      [ "${elixir_otp_release}" -ge 28 ] && elixir_otp_release=28
+      ;;
+    *)
+      [ "${elixir_otp_release}" -ge 28 ] && elixir_otp_release=28
+      ;;
+  esac
+
+  otp_dir="$root_dir/installs/otp/$otp_version"
+  elixir_dir="${root_dir}/installs/elixir/${elixir_version}-otp-${elixir_otp_release}"
+
+  if unzip_available; then
+    install_otp &
+    pid_otp=$!
+
+    install_elixir &
+    pid_elixir=$!
+
+    wait $pid_otp
+    wait $pid_elixir
+  else
+    # if unzip is missing (e.g. official docker ubuntu image), install otp and elixir
+    # serially because we unzip elixir using OTP zip:extract/2.
+    install_otp
+    install_elixir
+  fi
+
+  printf "checking OTP... "
+  export PATH="$otp_dir/bin:$PATH"
+  erl -noshell -eval 'io:put_chars(erlang:system_info(otp_release) ++ " ok\n"), halt().'
+
+  printf "checking Elixir... "
+  "$elixir_dir/bin/elixir" -e 'IO.puts(System.version() <> " ok")'
+
+  export PATH="$elixir_dir/bin:$PATH"
+cat<<EOF
+
+Run this (or add to your ~/.bashrc or similar file):
+
+    export PATH=\$HOME/.elixir-install/installs/otp/$otp_version/bin:\$PATH
+    export PATH=\$HOME/.elixir-install/installs/elixir/$elixir_version-otp-$elixir_otp_release/bin:\$PATH
+
+EOF
+}
+
+install_otp() {
+  os=$(uname -sm)
+  case "$os" in
+    "Darwin x86_64") target=x86_64-apple-darwin ;;
+    "Darwin arm64")  target=aarch64-apple-darwin ;;
+    "Linux x86_64")  target=x86_64-pc-linux ;;
+    "Linux aarch64") target=aarch64-pc-linux ;;
+    MINGW64*)        target=x86_64-pc-windows ;;
+    *) echo "error: unsupported system $os." && exit 1 ;;
+  esac
+
+  if [ ! -d "${otp_dir}/bin" ] || [ "$force" = true ]; then
+    rm -rf "${otp_dir}"
+
+    case "$target" in
+      *windows) install_otp_windows ;;
+      *darwin) install_otp_darwin ;;
+      *linux) install_otp_linux ;;
+    esac
+  fi
+}
+
+install_otp_darwin() {
+  case "${otp_version}" in
+    master|maint*)
+      ref="${otp_version}-latest"
+      ;;
+    *)
+      ref="OTP-${otp_version}"
+      ;;
+  esac
+
+  otp_tgz="otp-${target}.tar.gz"
+  url="https://github.com/erlef/otp_builds/releases/download/$ref/$otp_tgz"
+
+  download "$url" "$tmp_dir/$otp_tgz"
+
+  echo "unpacking $otp_tgz to $otp_dir..."
+  mkdir -p "$otp_dir"
+  tar xzf "$tmp_dir/$otp_tgz" -C "$otp_dir"
+  rm "$tmp_dir/$otp_tgz"
+}
+
+install_otp_linux() {
+  case "${otp_version}" in
+    master|maint*)
+      otp_tgz="${otp_version}.tar.gz"
+      ;;
+    *)
+      otp_tgz="OTP-${otp_version}.tar.gz"
+      ;;
+  esac
+
+  case "$target" in
+    x86_64*)  arch=amd64 ;;
+    aarch64*) arch=arm64 ;;
+  esac
+
+  id=$(grep '^ID=' /etc/os-release | cut -d '=' -f 2)
+  if [ "${id}" != ubuntu ]; then
+    echo $id is not supported
+    exit 1
+  fi
+  case $(grep '^VERSION_ID=' /etc/os-release | cut -d '"' -f 2) in
+    20*|21*)
+      lts=20.04
+      ;;
+    22*|23*)
+      lts=22.04
+      ;;
+    *)
+      lts=24.04
+      ;;
+  esac
+
+  url="https://builds.hex.pm/builds/otp/${arch}/ubuntu-${lts}/$otp_tgz"
+  download "$url" "$tmp_dir/$otp_tgz"
+
+  echo "unpacking $otp_tgz to $otp_dir..."
+  mkdir -p "$otp_dir"
+  tar xzf "$tmp_dir/$otp_tgz" --strip-components 1 -C "$otp_dir"
+  (cd "$otp_dir" && ./Install -sasl "$PWD")
+  rm "$tmp_dir/$otp_tgz"
+}
+
+install_otp_windows() {
+  otp_zip="otp_win64_$otp_version.zip"
+  url="https://github.com/erlang/otp/releases/download/OTP-$otp_version/$otp_zip"
+  download "$url" "$tmp_dir/$otp_zip"
+
+  echo "unpacking $otp_zip to $otp_dir..."
+  mkdir -p "$otp_dir"
+  unzip -q "$tmp_dir/$otp_zip" -d "$otp_dir"
+  rm "$tmp_dir/$otp_zip"
+  install_vc_redist
+}
+
+install_vc_redist() {
+  if [ ! -f /c/windows/system32/vcruntime140.dll ]; then
+    echo "installing VC++ Redistributable..."
+    (cd $otp_dir && ./vc_redist.exe /quiet /norestart)
+  fi
+}
+
+install_elixir() {
+  elixir_zip="elixir-otp-$elixir_otp_release.zip"
+
+  if [ ! -d "${elixir_dir}/bin" ] || [ "$force" = true ]; then
+    case "${elixir_version}" in
+      main)
+        ref="${elixir_version}-latest"
+        ;;
+      v[0-9]*.[0-9])
+        ref="v${elixir_version}-latest"
+        ;;
+      *)
+        ref="v${elixir_version}"
+        ;;
+    esac
+
+    url="https://github.com/elixir-lang/elixir/releases/download/$ref/$elixir_zip"
+    download "$url" "$tmp_dir/$elixir_zip"
+
+    echo "unpacking $elixir_zip to $elixir_dir..."
+    rm -rf "${elixir_dir}"
+    mkdir -p "${elixir_dir}"
+
+    if unzip_available; then
+      unzip -q "${tmp_dir}/${elixir_zip}" -d "${elixir_dir}"
+    else
+      "${otp_dir}/bin/erl" -noshell -eval \
+        '[Zip,Dir] = init:get_plain_arguments(), {ok,_} = zip:unzip(Zip, [{cwd, Dir}]), halt().' \
+        -- "${tmp_dir}/${elixir_zip}" "${elixir_dir}"
+    fi
+
+    rm "${tmp_dir}/${elixir_zip}"
+  fi
+}
+
+download() {
+  url="$1"
+  output="$2"
+  echo "downloading $url"
+  curl --retry 3 -fsSLo "$output" "$url"
+}
+
+unzip_available() {
+  which unzip >/dev/null 2>&1
+}
+
+main "$@"
diff --git a/learning.markdown b/learning.markdown
index d4d9eaa38..c78d1ba5a 100644
--- a/learning.markdown
+++ b/learning.markdown
@@ -2,21 +2,22 @@
 title: "Learning resources"
 section: learning
 layout: default
+image: /images/social/elixir-og-card.jpg
 ---
 
 # Learning
 
 {% include toc.html %}
 
-Our website provides a [Getting Started guide](/getting-started/introduction.html) to learn more about Elixir's foundations. Later on, it explores how to build projects with [Mix and OTP](/getting-started/mix-otp/introduction-to-mix.html). Elixir also includes [extensive API documentation](/docs.html).
+Elixir's official documentation includes a [Getting Started guide](https://hexdocs.pm/elixir/introduction.html) to learn more about Elixir's foundations. Later on, it explores how to build projects with [Mix and OTP](https://hexdocs.pm/elixir/introduction-to-mix.html). Elixir also includes [extensive API documentation](/docs.html).
 
-Outside of our website, the Elixir Community has also produced plenty of resources to learn the language from different backgrounds and other perspectives. We list some of them below. We are sure you will find a resource that suits your pace and goals.
+The Elixir Community has also produced plenty of resources to learn the language from different backgrounds and other perspectives. We list some of them below. We are sure you will find a resource that suits your pace and goals.
 
 ## Books
 
 <h4 class="resource">Elixir in Action</h4>
 
-<a class="cover" href="https://www.manning.com/books/elixir-in-action-second-edition" title="Elixir in Action
+<a class="cover" href="https://www.manning.com/books/elixir-in-action-third-edition" title="Elixir in Action
 – by Saša Jurić"><img src="/images/learning/elixir-in-action.jpg" alt="Elixir in Action cover" width="190" /></a>
 
 Elixir in Action is a tutorial book that aims to bring developers new to Elixir and Erlang to the point where they can develop complex systems on their own. No knowledge about Elixir, Erlang, or functional programming is required, but it is assumed that a reader has a few years of production experience using mainstream OO languages, for example C#, Java, Python, or Ruby.
@@ -27,7 +28,7 @@ The book starts with a basic introduction to the Elixir language and functional
 
 <h4 class="resource">Programming Elixir 1.6</h4>
 
-<a class="cover" href="https://pragprog.com/book/elixir16/programming-elixir-1-6" title="Programming Elixir 1.6: Functional |&gt; Concurrent |&gt; Pragmatic |&gt; Fun
+<a class="cover" href="https://pragprog.com/titles/elixir16/programming-elixir-1-6/" title="Programming Elixir 1.6: Functional |&gt; Concurrent |&gt; Pragmatic |&gt; Fun
 – by Dave Thomas"><img src="/images/learning/programming-elixir-1-6.jpg" alt="Programming Elixir cover" width="190" /></a>
 
 This book is the introduction to Elixir for experienced programmers, completely updated for Elixir 1.6 and beyond. Explore functional programming without the academic overtones (tell me about monads just one more time). Create concurrent applications, but get them right without all the locking and consistency headaches.
@@ -38,7 +39,7 @@ Meet Elixir, a modern, functional, concurrent language built on the rock-solid E
 
 <h4 class="resource">Adopting Elixir</h4>
 
-<a class="cover" href="https://pragprog.com/book/tvmelixir/adopting-elixir" title="Adopting Elixir: From Concept to Production
+<a class="cover" href="https://pragprog.com/titles/tvmelixir/adopting-elixir/" title="Adopting Elixir: From Concept to Production
 – by Ben Marx, José Valim, Bruce Tate"><img src="/images/learning/adopting-elixir.jpg" alt="Programming Elixir cover" width="190" /></a>
 
 Adoption is more than programming. Elixir is an exciting new language, but to successfully get your application from start to finish, you're going to need to know more than just the language. You need the case studies and strategies in this book.
@@ -59,7 +60,7 @@ This book will teach you the core concepts of the Elixir programming language in
 
 <h4 class="resource">Learn Functional Programming With Elixir</h4>
 
-<a class="cover" href="https://pragprog.com/book/cdc-elixir/learn-functional-programming-with-elixir" title="Learn Functional Programming With Elixir: New Foundations for a New World
+<a class="cover" href="https://pragprog.com/titles/cdc-elixir/learn-functional-programming-with-elixir/" title="Learn Functional Programming With Elixir: New Foundations for a New World
 – by Ulisses Almeida"><img src="/images/learning/learn-functional-programming-with-elixir.jpg" alt="Learn Functional Programming with Elixir cover" width="190" /></a>
 
 Elixir's straightforward syntax and this guided tour give you a clean, simple path to learn modern functional programming techniques. No previous functional programming experience required! This book walks you through the right concepts at the right pace, as you explore immutable values and explicit data transformation, functions, modules, recursive functions, pattern matching, high-order functions, polymorphism, and failure handling, all while avoiding side effects. Don't board the Elixir train with an imperative mindset! To get the most out of functional languages, you need to think functionally. This book will get you there.
@@ -88,7 +89,7 @@ If you're a new Elixir developer who's gone through some basic Elixir tutorials
 
 <h4 class="resource">Metaprogramming Elixir</h4>
 
-<a class="cover" href="https://pragprog.com/book/cmelixir/metaprogramming-elixir" title="Metaprogramming Elixir: Write Less Code, Get More Done and Have Fun
+<a class="cover" href="https://pragprog.com/titles/cmelixir/metaprogramming-elixir/" title="Metaprogramming Elixir: Write Less Code, Get More Done and Have Fun
 – by Chris Mccord"><img src="/images/learning/metaprogramming-elixir.jpg" alt="Metaprogramming Elixir cover" width="190" /></a>
 
 Write code that writes code with Elixir macros. Macros make metaprogramming possible and define the language itself. In this book, you'll learn how to use macros to extend the language with fast, maintainable code and share functionality in ways you never thought possible. You'll discover how to extend Elixir with your own first-class features, optimize performance, and create domain-specific languages.
@@ -97,7 +98,7 @@ Write code that writes code with Elixir macros. Macros make metaprogramming poss
 
 <h4 class="resource">Designing Elixir Systems with OTP</h4>
 
-<a class="cover" href="https://pragprog.com/book/jgotp/designing-elixir-systems-with-otp" title="Designing Elixir Systems with OTP: Write Highly Scalable, Self-Healing Software with Layers
+<a class="cover" href="https://pragprog.com/titles/jgotp/designing-elixir-systems-with-otp/" title="Designing Elixir Systems with OTP: Write Highly Scalable, Self-Healing Software with Layers
 – by James Edward Gray, II and Bruce A. Tate"><img src="/images/learning/designing-elixir-systems.jpg" alt="Designing Elixir Systems with OTP cover" width="190" /></a>
 
 You know how to code in Elixir; now learn to think in it. Learn to design libraries with intelligent layers that shape the right data structures, flow from one function into the next, and present the right APIs. Embrace the same OTP that's kept our telephone systems reliable and fast for over 30 years. Move beyond understanding the OTP functions to knowing what's happening under the hood, and why that matters. Using that knowledge, instinctively know how to design systems that deliver fast and resilient services to your users, all with an Elixir focus.
@@ -210,8 +211,31 @@ Found your start-up, migrate a codebase, build that app! Our midterm and final p
 
 <div class="clear"></div>
 
+<h4 class="resource">TechSchool<span class="free">free</span></h4>
+
+<a class="cover" href="https://techschool.dev/en/bootcamps/fullstack-elixir-and-phoenix" title="TechSchool">
+  <img src="/images/learning/techschool.png" alt="TechSchool" width="190" />
+</a>
+
+TechSchool is an open-source platform that teaches programming through free YouTube videos and other websites. The goal is to make technology education accessible to everyone. It includes several Elixir courses and a complete Fullstack Elixir + Phoenix Bootcamp.
+
+<div class="clear"></div>
+
 ## Screencasts
 
+<h4 class="resource">ElixirStreams<span class="free">free</span></h4>
+
+<a class="cover" href="https://elixirstreams.com" title="ElixirStreams: Elixir and Phoenix tips, courses, and more.">
+  <img src="/images/learning/elixir-streams-logo.png" alt="elixir streams cover" width="190" />
+</a>
+
+ElixirStreams provides free video tips (under 3 mins!) covering a variety of
+Elixir and Phoenix topics. The videos help you sharpen the saw as you learn
+about new tools and tricks, and they keep you up to date with the latest
+developments in the language.
+
+<div class="clear"></div>
+
 <h4 class="resource">ElixirCasts.io<span class="free">free</span></h4>
 
 <a class="cover" href="https://elixircasts.io" title="ElixirCasts: Elixir and Phoenix screencasts.">
@@ -257,11 +281,11 @@ Elixir koans is a fun, easy way to get started with the Elixir programming langu
 
 <div class="clear"></div>
 
-<h4 class="resource">Exercism.io<span class="free">free</span></h4>
+<h4 class="resource">Exercism<span class="free">free</span></h4>
 
-<a class="cover" href="https://exercism.io/tracks/elixir" title="Elixir Track on Exercism.io"> <img src="https://assets.exercism.io/tracks/elixir-bordered-turquoise.png" alt="Exercism.io Elixir track" width="190" /></a>
+<a class="cover" href="https://exercism.org/tracks/elixir" title="Elixir Track on Exercism"> <img src="https://assets.exercism.org/tracks/elixir.svg" alt="Exercism Elixir track" width="190" /></a>
 
-Exercism.io is an open source platform that provides free practice and mentoring in many languages, including Elixir.
+Exercism is an open source platform that provides free practice and mentoring in many languages, including Elixir.
 It features exercises of varying difficulty, from string processing to using OTP, that are mentored by volunteers.
 Once you have completed an exercise you can also view other students' solutions.
 
diff --git a/trademarks.markdown b/trademarks.markdown
index 4317709a2..329585587 100644
--- a/trademarks.markdown
+++ b/trademarks.markdown
@@ -2,6 +2,7 @@
 title: "Trademarks policy"
 section: trademarks
 layout: default
+image: /images/social/elixir-og-card.jpg
 ---
 
 # {{ page.title }}
