OSDN Git Service

Bunches of new docs.
authorSimon Forman <sforman@hushmail.com>
Fri, 22 Jun 2018 04:13:50 +0000 (21:13 -0700)
committerSimon Forman <sforman@hushmail.com>
Fri, 22 Jun 2018 04:13:50 +0000 (21:13 -0700)
Type inference!

A new treatment of recursion combinator patterns.

32 files changed:
Makefile
docs/Makefile
docs/Quadratic.html
docs/Quadratic.ipynb
docs/Quadratic.md
docs/Quadratic.rst
docs/Recursion_Combinators.html [new file with mode: 0644]
docs/Recursion_Combinators.ipynb [new file with mode: 0644]
docs/Recursion_Combinators.md [new file with mode: 0644]
docs/Recursion_Combinators.rst [new file with mode: 0644]
docs/Types.html [new file with mode: 0644]
docs/Types.ipynb [new file with mode: 0644]
docs/Types.md [new file with mode: 0644]
docs/Types.rst [new file with mode: 0644]
docs/notebook_preamble.pyc [new file with mode: 0644]
docs/sphinx_docs/_build/html/_modules/joy/library.html
docs/sphinx_docs/_build/html/_modules/joy/utils/stack.html
docs/sphinx_docs/_build/html/genindex.html
docs/sphinx_docs/_build/html/index.html
docs/sphinx_docs/_build/html/library.html
docs/sphinx_docs/_build/html/notebooks/Newton-Raphson.html
docs/sphinx_docs/_build/html/notebooks/Quadratic.html
docs/sphinx_docs/_build/html/notebooks/Zipper.html
docs/sphinx_docs/_build/html/notebooks/index.html
docs/sphinx_docs/_build/html/objects.inv
docs/sphinx_docs/_build/html/searchindex.js
docs/sphinx_docs/_build/html/stack.html
docs/sphinx_docs/notebooks/Quadratic.rst
docs/sphinx_docs/notebooks/Recursion_Combinators.rst [new file with mode: 0644]
docs/sphinx_docs/notebooks/Types.rst [new file with mode: 0644]
docs/sphinx_docs/notebooks/index.rst
joy/library.py

index abd05ce..d13215b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -13,6 +13,10 @@ clean:
 sdist:
        python ./setup.py sdist
 
+joy/utils/generated_library.py: joy/utils/types.py
+       python -c 'import joy.utils.types ; joy.utils.types.generate_library_code()' > $@
+
+
 # In order to support testing the code as installed
 # create a virtualenv and install the source dist zip there.
 test: sdist
index 2ec9f12..9c7b6eb 100644 (file)
@@ -23,7 +23,7 @@ $(docs_rst): %.rst : %.ipynb
        python -m nbconvert --to rst $<
 
 
-move_us = Generator_Programs.rst Newton-Raphson.rst Ordered_Binary_Trees.rst Quadratic.rst Replacing.rst Treestep.rst Zipper.rst
+move_us = Generator_Programs.rst Newton-Raphson.rst Ordered_Binary_Trees.rst Quadratic.rst Recursion_Combinators.rst Replacing.rst Treestep.rst Types.rst Zipper.rst
 
 mov: $(move_us)
        cp -v $? ./sphinx_docs/notebooks/
index 8df05d1..f726bb7 100644 (file)
@@ -11771,14 +11771,6 @@ div#notebook {
   <div tabindex="-1" id="notebook" class="border-box-sizing">
     <div class="container" id="notebook-container">
 
-<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
-</div>
-<div class="inner_cell">
-<div class="text_cell_render border-box-sizing rendered_html">
-<h1 id="Quadratic-formula"><a href="https://en.wikipedia.org/wiki/Quadratic_formula">Quadratic formula</a><a class="anchor-link" href="#Quadratic-formula">&#182;</a></h1>
-</div>
-</div>
-</div>
 <div class="cell border-box-sizing code_cell rendered">
 <div class="input">
 <div class="prompt input_prompt">In&nbsp;[1]:</div>
@@ -11796,8 +11788,7 @@ div#notebook {
 </div>
 <div class="inner_cell">
 <div class="text_cell_render border-box-sizing rendered_html">
-<p>Cf. <a href="http://www.kevinalbrecht.com/code/joy-mirror/jp-quadratic.html">jp-quadratic.html</a></p>
-
+<h1 id="Quadratic-formula"><a href="https://en.wikipedia.org/wiki/Quadratic_formula">Quadratic formula</a><a class="anchor-link" href="#Quadratic-formula">&#182;</a></h1>
 </div>
 </div>
 </div>
@@ -11805,10 +11796,7 @@ div#notebook {
 </div>
 <div class="inner_cell">
 <div class="text_cell_render border-box-sizing rendered_html">
-
-<pre><code>         -b  +/- sqrt(b^2 - 4 * a * c)
-         -----------------------------
-                    2 * a</code></pre>
+<p>Cf. <a href="http://www.kevinalbrecht.com/code/joy-mirror/jp-quadratic.html">jp-quadratic.html</a></p>
 
 </div>
 </div>
@@ -11817,7 +11805,10 @@ div#notebook {
 </div>
 <div class="inner_cell">
 <div class="text_cell_render border-box-sizing rendered_html">
-<p>$\frac{-b  \pm \sqrt{b^2 - 4ac}}{2a}$</p>
+
+<pre><code>   -b ± sqrt(b^2 - 4 * a * c)
+--------------------------------
+            2 * a</code></pre>
 
 </div>
 </div>
@@ -11826,11 +11817,7 @@ div#notebook {
 </div>
 <div class="inner_cell">
 <div class="text_cell_render border-box-sizing rendered_html">
-<h2 id="Write-a-straightforward-program-with-variable-names.">Write a straightforward program with variable names.<a class="anchor-link" href="#Write-a-straightforward-program-with-variable-names.">&#182;</a></h2>
-<pre><code>b neg b sqr 4 a c * * - sqrt [+] [-] cleave a 2 * [truediv] cons app2
-
-</code></pre>
-<p>We use <code>cleave</code> to compute the sum and difference and then <code>app2</code> to finish computing both roots using a quoted program <code>[2a truediv]</code> built with <code>cons</code>.</p>
+<p>$\frac{-b  \pm \sqrt{b^2 - 4ac}}{2a}$</p>
 
 </div>
 </div>
@@ -11839,22 +11826,7 @@ div#notebook {
 </div>
 <div class="inner_cell">
 <div class="text_cell_render border-box-sizing rendered_html">
-<h3 id="Check-it.">Check it.<a class="anchor-link" href="#Check-it.">&#182;</a></h3><p>Evaluating by hand:</p>
-
-<pre><code> b neg b sqr 4 a c * * - sqrt [+] [-] cleave a 2 * [truediv] cons app2
--b     b sqr 4 a c * * - sqrt [+] [-] cleave a 2 * [truediv] cons app2
--b     b^2   4 a c * * - sqrt [+] [-] cleave a 2 * [truediv] cons app2
--b     b^2 4ac         - sqrt [+] [-] cleave a 2 * [truediv] cons app2
--b     b^2-4ac           sqrt [+] [-] cleave a 2 * [truediv] cons app2
--b sqrt(b^2-4ac)              [+] [-] cleave a 2 * [truediv] cons app2
-
--b -b+sqrt(b^2-4ac)    -b-sqrt(b^2-4ac)    a 2 * [truediv] cons app2
--b -b+sqrt(b^2-4ac)    -b-sqrt(b^2-4ac)    2a    [truediv] cons app2
--b -b+sqrt(b^2-4ac)    -b-sqrt(b^2-4ac)    [2a truediv]         app2
--b -b+sqrt(b^2-4ac)/2a -b-sqrt(b^2-4ac)/2a
-
-</code></pre>
-<p>(Eventually we’ll be able to use e.g. Sympy versions of the Joy commands to do this sort of thing symbolically. This is part of what is meant by a “categorical” language.)</p>
+<h2 id="Write-a-straightforward-program-with-variable-names.">Write a straightforward program with variable names.<a class="anchor-link" href="#Write-a-straightforward-program-with-variable-names.">&#182;</a></h2><p>This math translates to Joy code in a straightforward manner.  We are going to use named variables to keep track of the arguments, then write a definition without them.</p>
 
 </div>
 </div>
@@ -11863,10 +11835,8 @@ div#notebook {
 </div>
 <div class="inner_cell">
 <div class="text_cell_render border-box-sizing rendered_html">
-<h3 id="Cleanup">Cleanup<a class="anchor-link" href="#Cleanup">&#182;</a></h3>
-<pre><code>-b -b+sqrt(b^2-4ac)/2a -b-sqrt(b^2-4ac)/2a                          roll&lt; pop
-   -b+sqrt(b^2-4ac)/2a -b-sqrt(b^2-4ac)/2a -b                             pop
-   -b+sqrt(b^2-4ac)/2a -b-sqrt(b^2-4ac)/2a</code></pre>
+<h3 id="-b"><code>-b</code><a class="anchor-link" href="#-b">&#182;</a></h3>
+<pre><code>b neg</code></pre>
 
 </div>
 </div>
@@ -11875,65 +11845,29 @@ div#notebook {
 </div>
 <div class="inner_cell">
 <div class="text_cell_render border-box-sizing rendered_html">
-<h2 id="Derive-a-definition.">Derive a definition.<a class="anchor-link" href="#Derive-a-definition.">&#182;</a></h2>
-<pre><code>b neg b           sqr 4 a c        * * - sqrt [+] [-] cleave a       2 * [truediv] cons app2 roll&lt; pop
-b    [neg] dupdip sqr 4 a c        * * - sqrt [+] [-] cleave a       2 * [truediv] cons app2 roll&lt; pop
-b a c    [[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave a       2 * [truediv] cons app2 roll&lt; pop
-b a c a    [[[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave] dip 2 * [truediv] cons app2 roll&lt; pop
-b a c over [[[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave] dip 2 * [truediv] cons app2 roll&lt; pop</code></pre>
-
-</div>
-</div>
-</div>
-<div class="cell border-box-sizing code_cell rendered">
-<div class="input">
-<div class="prompt input_prompt">In&nbsp;[2]:</div>
-<div class="inner_cell">
-    <div class="input_area">
-<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">&#39;quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave] dip 2 * [truediv] cons app2 roll&lt; pop&#39;</span><span class="p">)</span>
-</pre></div>
+<h3 id="sqrt(b^2---4-*-a-*-c)"><code>sqrt(b^2 - 4 * a * c)</code><a class="anchor-link" href="#sqrt(b^2---4-*-a-*-c)">&#182;</a></h3>
+<pre><code>b sqr 4 a c * * - sqrt</code></pre>
 
 </div>
 </div>
 </div>
-
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
 </div>
-<div class="cell border-box-sizing code_cell rendered">
-<div class="input">
-<div class="prompt input_prompt">In&nbsp;[3]:</div>
 <div class="inner_cell">
-    <div class="input_area">
-<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">&#39;3 1 1 quadratic&#39;</span><span class="p">)</span>
-</pre></div>
-
-</div>
-</div>
-</div>
-
-<div class="output_wrapper">
-<div class="output">
-
-
-<div class="output_area">
-
-<div class="prompt"></div>
-
-
-<div class="output_subarea output_stream output_stdout output_text">
-<pre>-0.3819660112501051 -2.618033988749895
-</pre>
-</div>
-</div>
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="/2a"><code>/2a</code><a class="anchor-link" href="#/2a">&#182;</a></h3>
+<pre><code>a 2 * /</code></pre>
 
 </div>
 </div>
-
 </div>
 <div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
 </div>
 <div class="inner_cell">
 <div class="text_cell_render border-box-sizing rendered_html">
-<h2 id="Simplify">Simplify<a class="anchor-link" href="#Simplify">&#182;</a></h2><p>We can define a <code>pm</code> plus-or-minus function:</p>
+<h3 id="&#177;"><code>&#177;</code><a class="anchor-link" href="#&#177;">&#182;</a></h3><p>There is a function <code>pm</code> that accepts two values on the stack and replaces them with their sum and difference.</p>
+
+<pre><code>pm == [+] [-] cleave popdd</code></pre>
 
 </div>
 </div>
@@ -11942,8 +11876,11 @@ b a c over [[[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave] dip 2 * [truedi
 </div>
 <div class="inner_cell">
 <div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="Putting-Them-Together">Putting Them Together<a class="anchor-link" href="#Putting-Them-Together">&#182;</a></h3>
+<pre><code>b neg b sqr 4 a c * * - sqrt pm a 2 * [/] cons app2
 
-<pre><code>pm == [+] [-] cleave popdd</code></pre>
+</code></pre>
+<p>We use <code>app2</code> to compute both roots by using a quoted program <code>[2a /]</code> built with <code>cons</code>.</p>
 
 </div>
 </div>
@@ -11952,17 +11889,26 @@ b a c over [[[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave] dip 2 * [truedi
 </div>
 <div class="inner_cell">
 <div class="text_cell_render border-box-sizing rendered_html">
-<p>Then <code>quadratic</code> becomes:</p>
+<h2 id="Derive-a-definition.">Derive a definition.<a class="anchor-link" href="#Derive-a-definition.">&#182;</a></h2><p>Working backwards we use <code>dip</code> and <code>dipd</code> to extract the code from the variables:</p>
+
+<pre><code>b             neg  b      sqr 4 a c   * * - sqrt pm a    2 * [/] cons app2
+b            [neg] dupdip sqr 4 a c   * * - sqrt pm a    2 * [/] cons app2
+b a c       [[neg] dupdip sqr 4] dipd * * - sqrt pm a    2 * [/] cons app2
+b a c a    [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2
+b a c over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2
+
+</code></pre>
+<p>The three arguments are to the left, so we can "chop off" everything to the right and say it's the definition of the <code>quadratic</code> function:</p>
 
 </div>
 </div>
 </div>
 <div class="cell border-box-sizing code_cell rendered">
 <div class="input">
-<div class="prompt input_prompt">In&nbsp;[4]:</div>
+<div class="prompt input_prompt">In&nbsp;[2]:</div>
 <div class="inner_cell">
     <div class="input_area">
-<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">&#39;quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [truediv] cons app2&#39;</span><span class="p">)</span>
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">&#39;quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2&#39;</span><span class="p">)</span>
 </pre></div>
 
 </div>
@@ -11970,9 +11916,18 @@ b a c over [[[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave] dip 2 * [truedi
 </div>
 
 </div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>Let's try it out:</p>
+
+</div>
+</div>
+</div>
 <div class="cell border-box-sizing code_cell rendered">
 <div class="input">
-<div class="prompt input_prompt">In&nbsp;[5]:</div>
+<div class="prompt input_prompt">In&nbsp;[3]:</div>
 <div class="inner_cell">
     <div class="input_area">
 <div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">&#39;3 1 1 quadratic&#39;</span><span class="p">)</span>
@@ -12005,42 +11960,17 @@ b a c over [[[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave] dip 2 * [truedi
 </div>
 <div class="inner_cell">
 <div class="text_cell_render border-box-sizing rendered_html">
-<h3 id="Define-a-&quot;native&quot;-pm-function.">Define a "native" <code>pm</code> function.<a class="anchor-link" href="#Define-a-&quot;native&quot;-pm-function.">&#182;</a></h3><p>The definition of <code>pm</code> above is pretty elegant, but the implementation takes a lot of steps relative to what it's accomplishing.  Since we are likely to use <code>pm</code> more than once in the future, let's write a primitive in Python and add it to the dictionary.  (This has been done already.)</p>
-
-</div>
-</div>
-</div>
-<div class="cell border-box-sizing code_cell rendered">
-<div class="input">
-<div class="prompt input_prompt">In&nbsp;[6]:</div>
-<div class="inner_cell">
-    <div class="input_area">
-<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">pm</span><span class="p">(</span><span class="n">stack</span><span class="p">):</span>
-    <span class="n">a</span><span class="p">,</span> <span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="n">stack</span><span class="p">)</span> <span class="o">=</span> <span class="n">stack</span>
-    <span class="n">p</span><span class="p">,</span> <span class="n">m</span><span class="p">,</span> <span class="o">=</span> <span class="n">b</span> <span class="o">+</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">-</span> <span class="n">a</span>
-    <span class="k">return</span> <span class="n">m</span><span class="p">,</span> <span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">stack</span><span class="p">)</span>
-</pre></div>
-
-</div>
-</div>
-</div>
-
-</div>
-<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
-</div>
-<div class="inner_cell">
-<div class="text_cell_render border-box-sizing rendered_html">
-<p>The resulting trace is short enough to fit on a page.</p>
+<p>If you look at the Joy evaluation trace you can see that the first few lines are the <code>dip</code> and <code>dipd</code> combinators building the main program by incorporating the values on the stack.  Then that program runs and you get the results.  This is pretty typical of Joy code.</p>
 
 </div>
 </div>
 </div>
 <div class="cell border-box-sizing code_cell rendered">
 <div class="input">
-<div class="prompt input_prompt">In&nbsp;[7]:</div>
+<div class="prompt input_prompt">In&nbsp;[4]:</div>
 <div class="inner_cell">
     <div class="input_area">
-<div class=" highlight hl-ipython2"><pre><span></span><span class="n">V</span><span class="p">(</span><span class="s1">&#39;3 1 1 quadratic&#39;</span><span class="p">)</span>
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">V</span><span class="p">(</span><span class="s1">&#39;-5 1 4 quadratic&#39;</span><span class="p">)</span>
 </pre></div>
 
 </div>
@@ -12057,51 +11987,51 @@ b a c over [[[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave] dip 2 * [truedi
 
 
 <div class="output_subarea output_stream output_stdout output_text">
-<pre>                                                    . 3 1 1 quadratic
-                                                  3 . 1 1 quadratic
-                                                3 1 . 1 quadratic
-                                              3 1 1 . quadratic
-                                              3 1 1 . over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [truediv] cons app2
-                                            3 1 1 1 . [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [truediv] cons app2
-  3 1 1 1 [[[neg] dupdip sqr 4] dipd * * - sqrt pm] . dip 2 * [truediv] cons app2
-                                              3 1 1 . [[neg] dupdip sqr 4] dipd * * - sqrt pm 1 2 * [truediv] cons app2
-                         3 1 1 [[neg] dupdip sqr 4] . dipd * * - sqrt pm 1 2 * [truediv] cons app2
-                                                  3 . [neg] dupdip sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                            3 [neg] . dupdip sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                  3 . neg 3 sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                 -3 . 3 sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                               -3 3 . sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                               -3 3 . dup mul 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                             -3 3 3 . mul 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                               -3 9 . 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                             -3 9 4 . 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                           -3 9 4 1 . 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                         -3 9 4 1 1 . * * - sqrt pm 1 2 * [truediv] cons app2
-                                           -3 9 4 1 . * - sqrt pm 1 2 * [truediv] cons app2
-                                             -3 9 4 . - sqrt pm 1 2 * [truediv] cons app2
-                                               -3 5 . sqrt pm 1 2 * [truediv] cons app2
-                                -3 2.23606797749979 . pm 1 2 * [truediv] cons app2
-              -0.7639320225002102 -5.23606797749979 . 1 2 * [truediv] cons app2
-            -0.7639320225002102 -5.23606797749979 1 . 2 * [truediv] cons app2
-          -0.7639320225002102 -5.23606797749979 1 2 . * [truediv] cons app2
-            -0.7639320225002102 -5.23606797749979 2 . [truediv] cons app2
-  -0.7639320225002102 -5.23606797749979 2 [truediv] . cons app2
-  -0.7639320225002102 -5.23606797749979 [2 truediv] . app2
-                  [-0.7639320225002102] [2 truediv] . infra first [-5.23606797749979] [2 truediv] infra first
-                                -0.7639320225002102 . 2 truediv [] swaack first [-5.23606797749979] [2 truediv] infra first
-                              -0.7639320225002102 2 . truediv [] swaack first [-5.23606797749979] [2 truediv] infra first
-                                -0.3819660112501051 . [] swaack first [-5.23606797749979] [2 truediv] infra first
-                             -0.3819660112501051 [] . swaack first [-5.23606797749979] [2 truediv] infra first
-                              [-0.3819660112501051] . first [-5.23606797749979] [2 truediv] infra first
-                                -0.3819660112501051 . [-5.23606797749979] [2 truediv] infra first
-            -0.3819660112501051 [-5.23606797749979] . [2 truediv] infra first
--0.3819660112501051 [-5.23606797749979] [2 truediv] . infra first
-                                  -5.23606797749979 . 2 truediv [-0.3819660112501051] swaack first
-                                -5.23606797749979 2 . truediv [-0.3819660112501051] swaack first
-                                 -2.618033988749895 . [-0.3819660112501051] swaack first
-           -2.618033988749895 [-0.3819660112501051] . swaack first
-           -0.3819660112501051 [-2.618033988749895] . first
-             -0.3819660112501051 -2.618033988749895 . 
+<pre>                                                   . -5 1 4 quadratic
+                                                -5 . 1 4 quadratic
+                                              -5 1 . 4 quadratic
+                                            -5 1 4 . quadratic
+                                            -5 1 4 . over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2
+                                          -5 1 4 1 . [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2
+-5 1 4 1 [[[neg] dupdip sqr 4] dipd * * - sqrt pm] . dip 2 * [/] cons app2
+                                            -5 1 4 . [[neg] dupdip sqr 4] dipd * * - sqrt pm 1 2 * [/] cons app2
+                       -5 1 4 [[neg] dupdip sqr 4] . dipd * * - sqrt pm 1 2 * [/] cons app2
+                                                -5 . [neg] dupdip sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                          -5 [neg] . dupdip sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                                -5 . neg -5 sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                                 5 . -5 sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                              5 -5 . sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                              5 -5 . dup mul 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                           5 -5 -5 . mul 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                              5 25 . 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                            5 25 4 . 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                          5 25 4 1 . 4 * * - sqrt pm 1 2 * [/] cons app2
+                                        5 25 4 1 4 . * * - sqrt pm 1 2 * [/] cons app2
+                                          5 25 4 4 . * - sqrt pm 1 2 * [/] cons app2
+                                           5 25 16 . - sqrt pm 1 2 * [/] cons app2
+                                               5 9 . sqrt pm 1 2 * [/] cons app2
+                                             5 3.0 . pm 1 2 * [/] cons app2
+                                           8.0 2.0 . 1 2 * [/] cons app2
+                                         8.0 2.0 1 . 2 * [/] cons app2
+                                       8.0 2.0 1 2 . * [/] cons app2
+                                         8.0 2.0 2 . [/] cons app2
+                                     8.0 2.0 2 [/] . cons app2
+                                     8.0 2.0 [2 /] . app2
+                                       [8.0] [2 /] . infra first [2.0] [2 /] infra first
+                                               8.0 . 2 / [] swaack first [2.0] [2 /] infra first
+                                             8.0 2 . / [] swaack first [2.0] [2 /] infra first
+                                               4.0 . [] swaack first [2.0] [2 /] infra first
+                                            4.0 [] . swaack first [2.0] [2 /] infra first
+                                             [4.0] . first [2.0] [2 /] infra first
+                                               4.0 . [2.0] [2 /] infra first
+                                         4.0 [2.0] . [2 /] infra first
+                                   4.0 [2.0] [2 /] . infra first
+                                               2.0 . 2 / [4.0] swaack first
+                                             2.0 2 . / [4.0] swaack first
+                                               1.0 . [4.0] swaack first
+                                         1.0 [4.0] . swaack first
+                                         4.0 [1.0] . first
+                                           4.0 1.0 . 
 </pre>
 </div>
 </div>
index d736d60..d159aab 100644 (file)
@@ -1,13 +1,6 @@
 {
  "cells": [
   {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "# [Quadratic formula](https://en.wikipedia.org/wiki/Quadratic_formula)"
-   ]
-  },
-  {
    "cell_type": "code",
    "execution_count": 1,
    "metadata": {},
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Cf. [jp-quadratic.html](http://www.kevinalbrecht.com/code/joy-mirror/jp-quadratic.html)"
+    "# [Quadratic formula](https://en.wikipedia.org/wiki/Quadratic_formula)"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "             -b  +/- sqrt(b^2 - 4 * a * c)\n",
-    "             -----------------------------\n",
-    "                        2 * a"
+    "Cf. [jp-quadratic.html](http://www.kevinalbrecht.com/code/joy-mirror/jp-quadratic.html)"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "$\\frac{-b  \\pm \\sqrt{b^2 - 4ac}}{2a}$"
+    "       -b ± sqrt(b^2 - 4 * a * c)\n",
+    "    --------------------------------\n",
+    "                2 * a"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "## Write a straightforward program with variable names.\n",
-    "\n",
-    "    b neg b sqr 4 a c * * - sqrt [+] [-] cleave a 2 * [truediv] cons app2\n",
-    "\n",
-    "We use `cleave` to compute the sum and difference and then `app2` to finish computing both roots using a quoted program `[2a truediv]` built with `cons`."
+    "$\\frac{-b  \\pm \\sqrt{b^2 - 4ac}}{2a}$"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "### Check it.\n",
-    "Evaluating by hand:\n",
-    "\n",
-    "     b neg b sqr 4 a c * * - sqrt [+] [-] cleave a 2 * [truediv] cons app2\n",
-    "    -b     b sqr 4 a c * * - sqrt [+] [-] cleave a 2 * [truediv] cons app2\n",
-    "    -b     b^2   4 a c * * - sqrt [+] [-] cleave a 2 * [truediv] cons app2\n",
-    "    -b     b^2 4ac         - sqrt [+] [-] cleave a 2 * [truediv] cons app2\n",
-    "    -b     b^2-4ac           sqrt [+] [-] cleave a 2 * [truediv] cons app2\n",
-    "    -b sqrt(b^2-4ac)              [+] [-] cleave a 2 * [truediv] cons app2\n",
-    "\n",
-    "    -b -b+sqrt(b^2-4ac)    -b-sqrt(b^2-4ac)    a 2 * [truediv] cons app2\n",
-    "    -b -b+sqrt(b^2-4ac)    -b-sqrt(b^2-4ac)    2a    [truediv] cons app2\n",
-    "    -b -b+sqrt(b^2-4ac)    -b-sqrt(b^2-4ac)    [2a truediv]         app2\n",
-    "    -b -b+sqrt(b^2-4ac)/2a -b-sqrt(b^2-4ac)/2a\n",
-    "\n",
-    "(Eventually we’ll be able to use e.g. Sympy versions of the Joy commands to do this sort of thing symbolically. This is part of what is meant by a “categorical” language.)"
+    "## Write a straightforward program with variable names.\n",
+    "This math translates to Joy code in a straightforward manner.  We are going to use named variables to keep track of the arguments, then write a definition without them."
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "### Cleanup\n",
-    "    -b -b+sqrt(b^2-4ac)/2a -b-sqrt(b^2-4ac)/2a                          roll< pop\n",
-    "       -b+sqrt(b^2-4ac)/2a -b-sqrt(b^2-4ac)/2a -b                             pop\n",
-    "       -b+sqrt(b^2-4ac)/2a -b-sqrt(b^2-4ac)/2a"
+    "### `-b`\n",
+    "    b neg"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "## Derive a definition.\n",
-    "\n",
-    "    b neg b           sqr 4 a c        * * - sqrt [+] [-] cleave a       2 * [truediv] cons app2 roll< pop\n",
-    "    b    [neg] dupdip sqr 4 a c        * * - sqrt [+] [-] cleave a       2 * [truediv] cons app2 roll< pop\n",
-    "    b a c    [[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave a       2 * [truediv] cons app2 roll< pop\n",
-    "    b a c a    [[[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave] dip 2 * [truediv] cons app2 roll< pop\n",
-    "    b a c over [[[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave] dip 2 * [truediv] cons app2 roll< pop"
+    "### `sqrt(b^2 - 4 * a * c)`\n",
+    "    b sqr 4 a c * * - sqrt"
    ]
   },
   {
-   "cell_type": "code",
-   "execution_count": 2,
+   "cell_type": "markdown",
    "metadata": {},
-   "outputs": [],
    "source": [
-    "define('quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave] dip 2 * [truediv] cons app2 roll< pop')"
+    "### `/2a`\n",
+    "    a 2 * /"
    ]
   },
   {
-   "cell_type": "code",
-   "execution_count": 3,
+   "cell_type": "markdown",
    "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "-0.3819660112501051 -2.618033988749895\n"
-     ]
-    }
-   ],
    "source": [
-    "J('3 1 1 quadratic')"
+    "### `±`\n",
+    "There is a function `pm` that accepts two values on the stack and replaces them with their sum and difference.\n",
+    "\n",
+    "    pm == [+] [-] cleave popdd"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "## Simplify\n",
-    "We can define a `pm` plus-or-minus function:"
+    "### Putting Them Together\n",
+    "\n",
+    "    b neg b sqr 4 a c * * - sqrt pm a 2 * [/] cons app2\n",
+    "\n",
+    "We use `app2` to compute both roots by using a quoted program `[2a /]` built with `cons`."
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "    pm == [+] [-] cleave popdd"
+    "## Derive a definition.\n",
+    "Working backwards we use `dip` and `dipd` to extract the code from the variables:\n",
+    "\n",
+    "    b             neg  b      sqr 4 a c   * * - sqrt pm a    2 * [/] cons app2\n",
+    "    b            [neg] dupdip sqr 4 a c   * * - sqrt pm a    2 * [/] cons app2\n",
+    "    b a c       [[neg] dupdip sqr 4] dipd * * - sqrt pm a    2 * [/] cons app2\n",
+    "    b a c a    [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2\n",
+    "    b a c over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2\n",
+    "\n",
+    "The three arguments are to the left, so we can \"chop off\" everything to the right and say it's the definition of the `quadratic` function:"
    ]
   },
   {
-   "cell_type": "markdown",
+   "cell_type": "code",
+   "execution_count": 2,
    "metadata": {},
+   "outputs": [],
    "source": [
-    "Then `quadratic` becomes:"
+    "define('quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2')"
    ]
   },
   {
-   "cell_type": "code",
-   "execution_count": 4,
+   "cell_type": "markdown",
    "metadata": {},
-   "outputs": [],
    "source": [
-    "define('quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [truediv] cons app2')"
+    "Let's try it out:"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "execution_count": 3,
    "metadata": {},
    "outputs": [
     {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "### Define a \"native\" `pm` function.\n",
-    "The definition of `pm` above is pretty elegant, but the implementation takes a lot of steps relative to what it's accomplishing.  Since we are likely to use `pm` more than once in the future, let's write a primitive in Python and add it to the dictionary.  (This has been done already.)"
+    "If you look at the Joy evaluation trace you can see that the first few lines are the `dip` and `dipd` combinators building the main program by incorporating the values on the stack.  Then that program runs and you get the results.  This is pretty typical of Joy code."
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "def pm(stack):\n",
-    "    a, (b, stack) = stack\n",
-    "    p, m, = b + a, b - a\n",
-    "    return m, (p, stack)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "The resulting trace is short enough to fit on a page."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 7,
+   "execution_count": 4,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "                                                    . 3 1 1 quadratic\n",
-      "                                                  3 . 1 1 quadratic\n",
-      "                                                3 1 . 1 quadratic\n",
-      "                                              3 1 1 . quadratic\n",
-      "                                              3 1 1 . over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [truediv] cons app2\n",
-      "                                            3 1 1 1 . [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [truediv] cons app2\n",
-      "  3 1 1 1 [[[neg] dupdip sqr 4] dipd * * - sqrt pm] . dip 2 * [truediv] cons app2\n",
-      "                                              3 1 1 . [[neg] dupdip sqr 4] dipd * * - sqrt pm 1 2 * [truediv] cons app2\n",
-      "                         3 1 1 [[neg] dupdip sqr 4] . dipd * * - sqrt pm 1 2 * [truediv] cons app2\n",
-      "                                                  3 . [neg] dupdip sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2\n",
-      "                                            3 [neg] . dupdip sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2\n",
-      "                                                  3 . neg 3 sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2\n",
-      "                                                 -3 . 3 sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2\n",
-      "                                               -3 3 . sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2\n",
-      "                                               -3 3 . dup mul 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2\n",
-      "                                             -3 3 3 . mul 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2\n",
-      "                                               -3 9 . 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2\n",
-      "                                             -3 9 4 . 1 1 * * - sqrt pm 1 2 * [truediv] cons app2\n",
-      "                                           -3 9 4 1 . 1 * * - sqrt pm 1 2 * [truediv] cons app2\n",
-      "                                         -3 9 4 1 1 . * * - sqrt pm 1 2 * [truediv] cons app2\n",
-      "                                           -3 9 4 1 . * - sqrt pm 1 2 * [truediv] cons app2\n",
-      "                                             -3 9 4 . - sqrt pm 1 2 * [truediv] cons app2\n",
-      "                                               -3 5 . sqrt pm 1 2 * [truediv] cons app2\n",
-      "                                -3 2.23606797749979 . pm 1 2 * [truediv] cons app2\n",
-      "              -0.7639320225002102 -5.23606797749979 . 1 2 * [truediv] cons app2\n",
-      "            -0.7639320225002102 -5.23606797749979 1 . 2 * [truediv] cons app2\n",
-      "          -0.7639320225002102 -5.23606797749979 1 2 . * [truediv] cons app2\n",
-      "            -0.7639320225002102 -5.23606797749979 2 . [truediv] cons app2\n",
-      "  -0.7639320225002102 -5.23606797749979 2 [truediv] . cons app2\n",
-      "  -0.7639320225002102 -5.23606797749979 [2 truediv] . app2\n",
-      "                  [-0.7639320225002102] [2 truediv] . infra first [-5.23606797749979] [2 truediv] infra first\n",
-      "                                -0.7639320225002102 . 2 truediv [] swaack first [-5.23606797749979] [2 truediv] infra first\n",
-      "                              -0.7639320225002102 2 . truediv [] swaack first [-5.23606797749979] [2 truediv] infra first\n",
-      "                                -0.3819660112501051 . [] swaack first [-5.23606797749979] [2 truediv] infra first\n",
-      "                             -0.3819660112501051 [] . swaack first [-5.23606797749979] [2 truediv] infra first\n",
-      "                              [-0.3819660112501051] . first [-5.23606797749979] [2 truediv] infra first\n",
-      "                                -0.3819660112501051 . [-5.23606797749979] [2 truediv] infra first\n",
-      "            -0.3819660112501051 [-5.23606797749979] . [2 truediv] infra first\n",
-      "-0.3819660112501051 [-5.23606797749979] [2 truediv] . infra first\n",
-      "                                  -5.23606797749979 . 2 truediv [-0.3819660112501051] swaack first\n",
-      "                                -5.23606797749979 2 . truediv [-0.3819660112501051] swaack first\n",
-      "                                 -2.618033988749895 . [-0.3819660112501051] swaack first\n",
-      "           -2.618033988749895 [-0.3819660112501051] . swaack first\n",
-      "           -0.3819660112501051 [-2.618033988749895] . first\n",
-      "             -0.3819660112501051 -2.618033988749895 . \n"
+      "                                                   . -5 1 4 quadratic\n",
+      "                                                -5 . 1 4 quadratic\n",
+      "                                              -5 1 . 4 quadratic\n",
+      "                                            -5 1 4 . quadratic\n",
+      "                                            -5 1 4 . over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2\n",
+      "                                          -5 1 4 1 . [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2\n",
+      "-5 1 4 1 [[[neg] dupdip sqr 4] dipd * * - sqrt pm] . dip 2 * [/] cons app2\n",
+      "                                            -5 1 4 . [[neg] dupdip sqr 4] dipd * * - sqrt pm 1 2 * [/] cons app2\n",
+      "                       -5 1 4 [[neg] dupdip sqr 4] . dipd * * - sqrt pm 1 2 * [/] cons app2\n",
+      "                                                -5 . [neg] dupdip sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2\n",
+      "                                          -5 [neg] . dupdip sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2\n",
+      "                                                -5 . neg -5 sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2\n",
+      "                                                 5 . -5 sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2\n",
+      "                                              5 -5 . sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2\n",
+      "                                              5 -5 . dup mul 4 1 4 * * - sqrt pm 1 2 * [/] cons app2\n",
+      "                                           5 -5 -5 . mul 4 1 4 * * - sqrt pm 1 2 * [/] cons app2\n",
+      "                                              5 25 . 4 1 4 * * - sqrt pm 1 2 * [/] cons app2\n",
+      "                                            5 25 4 . 1 4 * * - sqrt pm 1 2 * [/] cons app2\n",
+      "                                          5 25 4 1 . 4 * * - sqrt pm 1 2 * [/] cons app2\n",
+      "                                        5 25 4 1 4 . * * - sqrt pm 1 2 * [/] cons app2\n",
+      "                                          5 25 4 4 . * - sqrt pm 1 2 * [/] cons app2\n",
+      "                                           5 25 16 . - sqrt pm 1 2 * [/] cons app2\n",
+      "                                               5 9 . sqrt pm 1 2 * [/] cons app2\n",
+      "                                             5 3.0 . pm 1 2 * [/] cons app2\n",
+      "                                           8.0 2.0 . 1 2 * [/] cons app2\n",
+      "                                         8.0 2.0 1 . 2 * [/] cons app2\n",
+      "                                       8.0 2.0 1 2 . * [/] cons app2\n",
+      "                                         8.0 2.0 2 . [/] cons app2\n",
+      "                                     8.0 2.0 2 [/] . cons app2\n",
+      "                                     8.0 2.0 [2 /] . app2\n",
+      "                                       [8.0] [2 /] . infra first [2.0] [2 /] infra first\n",
+      "                                               8.0 . 2 / [] swaack first [2.0] [2 /] infra first\n",
+      "                                             8.0 2 . / [] swaack first [2.0] [2 /] infra first\n",
+      "                                               4.0 . [] swaack first [2.0] [2 /] infra first\n",
+      "                                            4.0 [] . swaack first [2.0] [2 /] infra first\n",
+      "                                             [4.0] . first [2.0] [2 /] infra first\n",
+      "                                               4.0 . [2.0] [2 /] infra first\n",
+      "                                         4.0 [2.0] . [2 /] infra first\n",
+      "                                   4.0 [2.0] [2 /] . infra first\n",
+      "                                               2.0 . 2 / [4.0] swaack first\n",
+      "                                             2.0 2 . / [4.0] swaack first\n",
+      "                                               1.0 . [4.0] swaack first\n",
+      "                                         1.0 [4.0] . swaack first\n",
+      "                                         4.0 [1.0] . first\n",
+      "                                           4.0 1.0 . \n"
      ]
     }
    ],
    "source": [
-    "V('3 1 1 quadratic')"
+    "V('-5 1 4 quadratic')"
    ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
   }
  ],
  "metadata": {
index c55abe5..182e4c7 100644 (file)
@@ -1,79 +1,59 @@
 
-# [Quadratic formula](https://en.wikipedia.org/wiki/Quadratic_formula)
-
 
 ```python
 from notebook_preamble import J, V, define
 ```
 
+# [Quadratic formula](https://en.wikipedia.org/wiki/Quadratic_formula)
+
 Cf. [jp-quadratic.html](http://www.kevinalbrecht.com/code/joy-mirror/jp-quadratic.html)
 
-             -b  +/- sqrt(b^2 - 4 * a * c)
-             -----------------------------
-                        2 * a
+       -b ± sqrt(b^2 - 4 * a * c)
+    --------------------------------
+                2 * a
 
 $\frac{-b  \pm \sqrt{b^2 - 4ac}}{2a}$
 
 ## Write a straightforward program with variable names.
+This math translates to Joy code in a straightforward manner.  We are going to use named variables to keep track of the arguments, then write a definition without them.
 
-    b neg b sqr 4 a c * * - sqrt [+] [-] cleave a 2 * [truediv] cons app2
+### `-b`
+    b neg
 
-We use `cleave` to compute the sum and difference and then `app2` to finish computing both roots using a quoted program `[2a truediv]` built with `cons`.
+### `sqrt(b^2 - 4 * a * c)`
+    b sqr 4 a c * * - sqrt
 
-### Check it.
-Evaluating by hand:
+### `/2a`
+    a 2 * /
 
-     b neg b sqr 4 a c * * - sqrt [+] [-] cleave a 2 * [truediv] cons app2
-    -b     b sqr 4 a c * * - sqrt [+] [-] cleave a 2 * [truediv] cons app2
-    -b     b^2   4 a c * * - sqrt [+] [-] cleave a 2 * [truediv] cons app2
-    -b     b^2 4ac         - sqrt [+] [-] cleave a 2 * [truediv] cons app2
-    -b     b^2-4ac           sqrt [+] [-] cleave a 2 * [truediv] cons app2
-    -b sqrt(b^2-4ac)              [+] [-] cleave a 2 * [truediv] cons app2
+### `±`
+There is a function `pm` that accepts two values on the stack and replaces them with their sum and difference.
 
-    -b -b+sqrt(b^2-4ac)    -b-sqrt(b^2-4ac)    a 2 * [truediv] cons app2
-    -b -b+sqrt(b^2-4ac)    -b-sqrt(b^2-4ac)    2a    [truediv] cons app2
-    -b -b+sqrt(b^2-4ac)    -b-sqrt(b^2-4ac)    [2a truediv]         app2
-    -b -b+sqrt(b^2-4ac)/2a -b-sqrt(b^2-4ac)/2a
+    pm == [+] [-] cleave popdd
+
+### Putting Them Together
 
-(Eventually we’ll be able to use e.g. Sympy versions of the Joy commands to do this sort of thing symbolically. This is part of what is meant by a “categorical” language.)
+    b neg b sqr 4 a c * * - sqrt pm a 2 * [/] cons app2
 
-### Cleanup
-    -b -b+sqrt(b^2-4ac)/2a -b-sqrt(b^2-4ac)/2a                          roll< pop
-       -b+sqrt(b^2-4ac)/2a -b-sqrt(b^2-4ac)/2a -b                             pop
-       -b+sqrt(b^2-4ac)/2a -b-sqrt(b^2-4ac)/2a
+We use `app2` to compute both roots by using a quoted program `[2a /]` built with `cons`.
 
 ## Derive a definition.
+Working backwards we use `dip` and `dipd` to extract the code from the variables:
 
-    b neg b           sqr 4 a c        * * - sqrt [+] [-] cleave a       2 * [truediv] cons app2 roll< pop
-    b    [neg] dupdip sqr 4 a c        * * - sqrt [+] [-] cleave a       2 * [truediv] cons app2 roll< pop
-    b a c    [[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave a       2 * [truediv] cons app2 roll< pop
-    b a c a    [[[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave] dip 2 * [truediv] cons app2 roll< pop
-    b a c over [[[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave] dip 2 * [truediv] cons app2 roll< pop
+    b             neg  b      sqr 4 a c   * * - sqrt pm a    2 * [/] cons app2
+    b            [neg] dupdip sqr 4 a c   * * - sqrt pm a    2 * [/] cons app2
+    b a c       [[neg] dupdip sqr 4] dipd * * - sqrt pm a    2 * [/] cons app2
+    b a c a    [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2
+    b a c over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2
 
-
-```python
-define('quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave] dip 2 * [truediv] cons app2 roll< pop')
-```
+The three arguments are to the left, so we can "chop off" everything to the right and say it's the definition of the `quadratic` function:
 
 
 ```python
-J('3 1 1 quadratic')
+define('quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2')
 ```
 
-    -0.3819660112501051 -2.618033988749895
-
-
-## Simplify
-We can define a `pm` plus-or-minus function:
-
-    pm == [+] [-] cleave popdd
-
-Then `quadratic` becomes:
-
-
-```python
-define('quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [truediv] cons app2')
-```
+Let's try it out:
 
 
 ```python
@@ -83,67 +63,56 @@ J('3 1 1 quadratic')
     -0.3819660112501051 -2.618033988749895
 
 
-### Define a "native" `pm` function.
-The definition of `pm` above is pretty elegant, but the implementation takes a lot of steps relative to what it's accomplishing.  Since we are likely to use `pm` more than once in the future, let's write a primitive in Python and add it to the dictionary.  (This has been done already.)
-
-
-```python
-def pm(stack):
-    a, (b, stack) = stack
-    p, m, = b + a, b - a
-    return m, (p, stack)
-```
-
-The resulting trace is short enough to fit on a page.
+If you look at the Joy evaluation trace you can see that the first few lines are the `dip` and `dipd` combinators building the main program by incorporating the values on the stack.  Then that program runs and you get the results.  This is pretty typical of Joy code.
 
 
 ```python
-V('3 1 1 quadratic')
+V('-5 1 4 quadratic')
 ```
 
-                                                        . 3 1 1 quadratic
-                                                      3 . 1 1 quadratic
-                                                    3 1 . 1 quadratic
-                                                  3 1 1 . quadratic
-                                                  3 1 1 . over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [truediv] cons app2
-                                                3 1 1 1 . [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [truediv] cons app2
-      3 1 1 1 [[[neg] dupdip sqr 4] dipd * * - sqrt pm] . dip 2 * [truediv] cons app2
-                                                  3 1 1 . [[neg] dupdip sqr 4] dipd * * - sqrt pm 1 2 * [truediv] cons app2
-                             3 1 1 [[neg] dupdip sqr 4] . dipd * * - sqrt pm 1 2 * [truediv] cons app2
-                                                      3 . [neg] dupdip sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                3 [neg] . dupdip sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                      3 . neg 3 sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                     -3 . 3 sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                   -3 3 . sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                   -3 3 . dup mul 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                 -3 3 3 . mul 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                   -3 9 . 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                 -3 9 4 . 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                               -3 9 4 1 . 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                             -3 9 4 1 1 . * * - sqrt pm 1 2 * [truediv] cons app2
-                                               -3 9 4 1 . * - sqrt pm 1 2 * [truediv] cons app2
-                                                 -3 9 4 . - sqrt pm 1 2 * [truediv] cons app2
-                                                   -3 5 . sqrt pm 1 2 * [truediv] cons app2
-                                    -3 2.23606797749979 . pm 1 2 * [truediv] cons app2
-                  -0.7639320225002102 -5.23606797749979 . 1 2 * [truediv] cons app2
-                -0.7639320225002102 -5.23606797749979 1 . 2 * [truediv] cons app2
-              -0.7639320225002102 -5.23606797749979 1 2 . * [truediv] cons app2
-                -0.7639320225002102 -5.23606797749979 2 . [truediv] cons app2
-      -0.7639320225002102 -5.23606797749979 2 [truediv] . cons app2
-      -0.7639320225002102 -5.23606797749979 [2 truediv] . app2
-                      [-0.7639320225002102] [2 truediv] . infra first [-5.23606797749979] [2 truediv] infra first
-                                    -0.7639320225002102 . 2 truediv [] swaack first [-5.23606797749979] [2 truediv] infra first
-                                  -0.7639320225002102 2 . truediv [] swaack first [-5.23606797749979] [2 truediv] infra first
-                                    -0.3819660112501051 . [] swaack first [-5.23606797749979] [2 truediv] infra first
-                                 -0.3819660112501051 [] . swaack first [-5.23606797749979] [2 truediv] infra first
-                                  [-0.3819660112501051] . first [-5.23606797749979] [2 truediv] infra first
-                                    -0.3819660112501051 . [-5.23606797749979] [2 truediv] infra first
-                -0.3819660112501051 [-5.23606797749979] . [2 truediv] infra first
-    -0.3819660112501051 [-5.23606797749979] [2 truediv] . infra first
-                                      -5.23606797749979 . 2 truediv [-0.3819660112501051] swaack first
-                                    -5.23606797749979 2 . truediv [-0.3819660112501051] swaack first
-                                     -2.618033988749895 . [-0.3819660112501051] swaack first
-               -2.618033988749895 [-0.3819660112501051] . swaack first
-               -0.3819660112501051 [-2.618033988749895] . first
-                 -0.3819660112501051 -2.618033988749895 . 
+                                                       . -5 1 4 quadratic
+                                                    -5 . 1 4 quadratic
+                                                  -5 1 . 4 quadratic
+                                                -5 1 4 . quadratic
+                                                -5 1 4 . over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2
+                                              -5 1 4 1 . [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2
+    -5 1 4 1 [[[neg] dupdip sqr 4] dipd * * - sqrt pm] . dip 2 * [/] cons app2
+                                                -5 1 4 . [[neg] dupdip sqr 4] dipd * * - sqrt pm 1 2 * [/] cons app2
+                           -5 1 4 [[neg] dupdip sqr 4] . dipd * * - sqrt pm 1 2 * [/] cons app2
+                                                    -5 . [neg] dupdip sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                              -5 [neg] . dupdip sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                                    -5 . neg -5 sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                                     5 . -5 sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                                  5 -5 . sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                                  5 -5 . dup mul 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                               5 -5 -5 . mul 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                                  5 25 . 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                                5 25 4 . 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                              5 25 4 1 . 4 * * - sqrt pm 1 2 * [/] cons app2
+                                            5 25 4 1 4 . * * - sqrt pm 1 2 * [/] cons app2
+                                              5 25 4 4 . * - sqrt pm 1 2 * [/] cons app2
+                                               5 25 16 . - sqrt pm 1 2 * [/] cons app2
+                                                   5 9 . sqrt pm 1 2 * [/] cons app2
+                                                 5 3.0 . pm 1 2 * [/] cons app2
+                                               8.0 2.0 . 1 2 * [/] cons app2
+                                             8.0 2.0 1 . 2 * [/] cons app2
+                                           8.0 2.0 1 2 . * [/] cons app2
+                                             8.0 2.0 2 . [/] cons app2
+                                         8.0 2.0 2 [/] . cons app2
+                                         8.0 2.0 [2 /] . app2
+                                           [8.0] [2 /] . infra first [2.0] [2 /] infra first
+                                                   8.0 . 2 / [] swaack first [2.0] [2 /] infra first
+                                                 8.0 2 . / [] swaack first [2.0] [2 /] infra first
+                                                   4.0 . [] swaack first [2.0] [2 /] infra first
+                                                4.0 [] . swaack first [2.0] [2 /] infra first
+                                                 [4.0] . first [2.0] [2 /] infra first
+                                                   4.0 . [2.0] [2 /] infra first
+                                             4.0 [2.0] . [2 /] infra first
+                                       4.0 [2.0] [2 /] . infra first
+                                                   2.0 . 2 / [4.0] swaack first
+                                                 2.0 2 . / [4.0] swaack first
+                                                   1.0 . [4.0] swaack first
+                                             1.0 [4.0] . swaack first
+                                             4.0 [1.0] . first
+                                               4.0 1.0 . 
 
index 9975abb..60e312f 100644 (file)
 
-`Quadratic formula <https://en.wikipedia.org/wiki/Quadratic_formula>`__
-=======================================================================
-
 .. code:: ipython2
 
     from notebook_preamble import J, V, define
 
+`Quadratic formula <https://en.wikipedia.org/wiki/Quadratic_formula>`__
+=======================================================================
+
 Cf.
 `jp-quadratic.html <http://www.kevinalbrecht.com/code/joy-mirror/jp-quadratic.html>`__
 
 ::
 
-             -b  +/- sqrt(b^2 - 4 * a * c)
-             -----------------------------
-                        2 * a
+       -b ± sqrt(b^2 - 4 * a * c)
+    --------------------------------
+                2 * a
 
 :math:`\frac{-b \pm \sqrt{b^2 - 4ac}}{2a}`
 
 Write a straightforward program with variable names.
 ----------------------------------------------------
 
-::
-
-    b neg b sqr 4 a c * * - sqrt [+] [-] cleave a 2 * [truediv] cons app2
-
-We use ``cleave`` to compute the sum and difference and then ``app2`` to
-finish computing both roots using a quoted program ``[2a truediv]``
-built with ``cons``.
+This math translates to Joy code in a straightforward manner. We are
+going to use named variables to keep track of the arguments, then write
+a definition without them.
 
-Check it.
-~~~~~~~~~
-
-Evaluating by hand:
+``-b``
+~~~~~~
 
 ::
 
-     b neg b sqr 4 a c * * - sqrt [+] [-] cleave a 2 * [truediv] cons app2
-    -b     b sqr 4 a c * * - sqrt [+] [-] cleave a 2 * [truediv] cons app2
-    -b     b^2   4 a c * * - sqrt [+] [-] cleave a 2 * [truediv] cons app2
-    -b     b^2 4ac         - sqrt [+] [-] cleave a 2 * [truediv] cons app2
-    -b     b^2-4ac           sqrt [+] [-] cleave a 2 * [truediv] cons app2
-    -b sqrt(b^2-4ac)              [+] [-] cleave a 2 * [truediv] cons app2
-
-    -b -b+sqrt(b^2-4ac)    -b-sqrt(b^2-4ac)    a 2 * [truediv] cons app2
-    -b -b+sqrt(b^2-4ac)    -b-sqrt(b^2-4ac)    2a    [truediv] cons app2
-    -b -b+sqrt(b^2-4ac)    -b-sqrt(b^2-4ac)    [2a truediv]         app2
-    -b -b+sqrt(b^2-4ac)/2a -b-sqrt(b^2-4ac)/2a
+    b neg
 
-(Eventually we’ll be able to use e.g. Sympy versions of the Joy commands
-to do this sort of thing symbolically. This is part of what is meant by
-a “categorical” language.)
-
-Cleanup
-~~~~~~~
+``sqrt(b^2 - 4 * a * c)``
+~~~~~~~~~~~~~~~~~~~~~~~~~
 
 ::
 
-    -b -b+sqrt(b^2-4ac)/2a -b-sqrt(b^2-4ac)/2a                          roll< pop
-       -b+sqrt(b^2-4ac)/2a -b-sqrt(b^2-4ac)/2a -b                             pop
-       -b+sqrt(b^2-4ac)/2a -b-sqrt(b^2-4ac)/2a
+    b sqr 4 a c * * - sqrt
 
-Derive a definition.
---------------------
+``/2a``
+~~~~~~~
 
 ::
 
-    b neg b           sqr 4 a c        * * - sqrt [+] [-] cleave a       2 * [truediv] cons app2 roll< pop
-    b    [neg] dupdip sqr 4 a c        * * - sqrt [+] [-] cleave a       2 * [truediv] cons app2 roll< pop
-    b a c    [[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave a       2 * [truediv] cons app2 roll< pop
-    b a c a    [[[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave] dip 2 * [truediv] cons app2 roll< pop
-    b a c over [[[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave] dip 2 * [truediv] cons app2 roll< pop
+    a 2 * /
 
-.. code:: ipython2
+``±``
+~~~~~
 
-    define('quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave] dip 2 * [truediv] cons app2 roll< pop')
+There is a function ``pm`` that accepts two values on the stack and
+replaces them with their sum and difference.
 
-.. code:: ipython2
+::
 
-    J('3 1 1 quadratic')
+    pm == [+] [-] cleave popdd
 
+Putting Them Together
+~~~~~~~~~~~~~~~~~~~~~
 
-.. parsed-literal::
+::
 
-    -0.3819660112501051 -2.618033988749895
+    b neg b sqr 4 a c * * - sqrt pm a 2 * [/] cons app2
 
+We use ``app2`` to compute both roots by using a quoted program
+``[2a /]`` built with ``cons``.
 
-Simplify
---------
+Derive a definition.
+--------------------
 
-We can define a ``pm`` plus-or-minus function:
+Working backwards we use ``dip`` and ``dipd`` to extract the code from
+the variables:
 
 ::
 
-    pm == [+] [-] cleave popdd
+    b             neg  b      sqr 4 a c   * * - sqrt pm a    2 * [/] cons app2
+    b            [neg] dupdip sqr 4 a c   * * - sqrt pm a    2 * [/] cons app2
+    b a c       [[neg] dupdip sqr 4] dipd * * - sqrt pm a    2 * [/] cons app2
+    b a c a    [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2
+    b a c over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2
 
-Then ``quadratic`` becomes:
+The three arguments are to the left, so we can "chop off" everything to
+the right and say it's the definition of the ``quadratic`` function:
 
 .. code:: ipython2
 
-    define('quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [truediv] cons app2')
+    define('quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2')
+
+Let's try it out:
 
 .. code:: ipython2
 
@@ -110,74 +98,61 @@ Then ``quadratic`` becomes:
     -0.3819660112501051 -2.618033988749895
 
 
-Define a "native" ``pm`` function.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The definition of ``pm`` above is pretty elegant, but the implementation
-takes a lot of steps relative to what it's accomplishing. Since we are
-likely to use ``pm`` more than once in the future, let's write a
-primitive in Python and add it to the dictionary. (This has been done
-already.)
-
-.. code:: ipython2
-
-    def pm(stack):
-        a, (b, stack) = stack
-        p, m, = b + a, b - a
-        return m, (p, stack)
-
-The resulting trace is short enough to fit on a page.
+If you look at the Joy evaluation trace you can see that the first few
+lines are the ``dip`` and ``dipd`` combinators building the main program
+by incorporating the values on the stack. Then that program runs and you
+get the results. This is pretty typical of Joy code.
 
 .. code:: ipython2
 
-    V('3 1 1 quadratic')
+    V('-5 1 4 quadratic')
 
 
 .. parsed-literal::
 
-                                                        . 3 1 1 quadratic
-                                                      3 . 1 1 quadratic
-                                                    3 1 . 1 quadratic
-                                                  3 1 1 . quadratic
-                                                  3 1 1 . over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [truediv] cons app2
-                                                3 1 1 1 . [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [truediv] cons app2
-      3 1 1 1 [[[neg] dupdip sqr 4] dipd * * - sqrt pm] . dip 2 * [truediv] cons app2
-                                                  3 1 1 . [[neg] dupdip sqr 4] dipd * * - sqrt pm 1 2 * [truediv] cons app2
-                             3 1 1 [[neg] dupdip sqr 4] . dipd * * - sqrt pm 1 2 * [truediv] cons app2
-                                                      3 . [neg] dupdip sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                3 [neg] . dupdip sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                      3 . neg 3 sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                     -3 . 3 sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                   -3 3 . sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                   -3 3 . dup mul 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                 -3 3 3 . mul 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                   -3 9 . 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                 -3 9 4 . 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                               -3 9 4 1 . 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                             -3 9 4 1 1 . * * - sqrt pm 1 2 * [truediv] cons app2
-                                               -3 9 4 1 . * - sqrt pm 1 2 * [truediv] cons app2
-                                                 -3 9 4 . - sqrt pm 1 2 * [truediv] cons app2
-                                                   -3 5 . sqrt pm 1 2 * [truediv] cons app2
-                                    -3 2.23606797749979 . pm 1 2 * [truediv] cons app2
-                  -0.7639320225002102 -5.23606797749979 . 1 2 * [truediv] cons app2
-                -0.7639320225002102 -5.23606797749979 1 . 2 * [truediv] cons app2
-              -0.7639320225002102 -5.23606797749979 1 2 . * [truediv] cons app2
-                -0.7639320225002102 -5.23606797749979 2 . [truediv] cons app2
-      -0.7639320225002102 -5.23606797749979 2 [truediv] . cons app2
-      -0.7639320225002102 -5.23606797749979 [2 truediv] . app2
-                      [-0.7639320225002102] [2 truediv] . infra first [-5.23606797749979] [2 truediv] infra first
-                                    -0.7639320225002102 . 2 truediv [] swaack first [-5.23606797749979] [2 truediv] infra first
-                                  -0.7639320225002102 2 . truediv [] swaack first [-5.23606797749979] [2 truediv] infra first
-                                    -0.3819660112501051 . [] swaack first [-5.23606797749979] [2 truediv] infra first
-                                 -0.3819660112501051 [] . swaack first [-5.23606797749979] [2 truediv] infra first
-                                  [-0.3819660112501051] . first [-5.23606797749979] [2 truediv] infra first
-                                    -0.3819660112501051 . [-5.23606797749979] [2 truediv] infra first
-                -0.3819660112501051 [-5.23606797749979] . [2 truediv] infra first
-    -0.3819660112501051 [-5.23606797749979] [2 truediv] . infra first
-                                      -5.23606797749979 . 2 truediv [-0.3819660112501051] swaack first
-                                    -5.23606797749979 2 . truediv [-0.3819660112501051] swaack first
-                                     -2.618033988749895 . [-0.3819660112501051] swaack first
-               -2.618033988749895 [-0.3819660112501051] . swaack first
-               -0.3819660112501051 [-2.618033988749895] . first
-                 -0.3819660112501051 -2.618033988749895 . 
+                                                       . -5 1 4 quadratic
+                                                    -5 . 1 4 quadratic
+                                                  -5 1 . 4 quadratic
+                                                -5 1 4 . quadratic
+                                                -5 1 4 . over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2
+                                              -5 1 4 1 . [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2
+    -5 1 4 1 [[[neg] dupdip sqr 4] dipd * * - sqrt pm] . dip 2 * [/] cons app2
+                                                -5 1 4 . [[neg] dupdip sqr 4] dipd * * - sqrt pm 1 2 * [/] cons app2
+                           -5 1 4 [[neg] dupdip sqr 4] . dipd * * - sqrt pm 1 2 * [/] cons app2
+                                                    -5 . [neg] dupdip sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                              -5 [neg] . dupdip sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                                    -5 . neg -5 sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                                     5 . -5 sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                                  5 -5 . sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                                  5 -5 . dup mul 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                               5 -5 -5 . mul 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                                  5 25 . 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                                5 25 4 . 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                              5 25 4 1 . 4 * * - sqrt pm 1 2 * [/] cons app2
+                                            5 25 4 1 4 . * * - sqrt pm 1 2 * [/] cons app2
+                                              5 25 4 4 . * - sqrt pm 1 2 * [/] cons app2
+                                               5 25 16 . - sqrt pm 1 2 * [/] cons app2
+                                                   5 9 . sqrt pm 1 2 * [/] cons app2
+                                                 5 3.0 . pm 1 2 * [/] cons app2
+                                               8.0 2.0 . 1 2 * [/] cons app2
+                                             8.0 2.0 1 . 2 * [/] cons app2
+                                           8.0 2.0 1 2 . * [/] cons app2
+                                             8.0 2.0 2 . [/] cons app2
+                                         8.0 2.0 2 [/] . cons app2
+                                         8.0 2.0 [2 /] . app2
+                                           [8.0] [2 /] . infra first [2.0] [2 /] infra first
+                                                   8.0 . 2 / [] swaack first [2.0] [2 /] infra first
+                                                 8.0 2 . / [] swaack first [2.0] [2 /] infra first
+                                                   4.0 . [] swaack first [2.0] [2 /] infra first
+                                                4.0 [] . swaack first [2.0] [2 /] infra first
+                                                 [4.0] . first [2.0] [2 /] infra first
+                                                   4.0 . [2.0] [2 /] infra first
+                                             4.0 [2.0] . [2 /] infra first
+                                       4.0 [2.0] [2 /] . infra first
+                                                   2.0 . 2 / [4.0] swaack first
+                                                 2.0 2 . / [4.0] swaack first
+                                                   1.0 . [4.0] swaack first
+                                             1.0 [4.0] . swaack first
+                                             4.0 [1.0] . first
+                                               4.0 1.0 . 
 
diff --git a/docs/Recursion_Combinators.html b/docs/Recursion_Combinators.html
new file mode 100644 (file)
index 0000000..122cb59
--- /dev/null
@@ -0,0 +1,12857 @@
+<!DOCTYPE html>
+<html>
+<head><meta charset="utf-8" />
+<title>Recursion_Combinators</title><script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.10/require.min.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
+
+<style type="text/css">
+    /*!
+*
+* Twitter Bootstrap
+*
+*/
+/*!
+ * Bootstrap v3.3.7 (http://getbootstrap.com)
+ * Copyright 2011-2016 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
+html {
+  font-family: sans-serif;
+  -ms-text-size-adjust: 100%;
+  -webkit-text-size-adjust: 100%;
+}
+body {
+  margin: 0;
+}
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+menu,
+nav,
+section,
+summary {
+  display: block;
+}
+audio,
+canvas,
+progress,
+video {
+  display: inline-block;
+  vertical-align: baseline;
+}
+audio:not([controls]) {
+  display: none;
+  height: 0;
+}
+[hidden],
+template {
+  display: none;
+}
+a {
+  background-color: transparent;
+}
+a:active,
+a:hover {
+  outline: 0;
+}
+abbr[title] {
+  border-bottom: 1px dotted;
+}
+b,
+strong {
+  font-weight: bold;
+}
+dfn {
+  font-style: italic;
+}
+h1 {
+  font-size: 2em;
+  margin: 0.67em 0;
+}
+mark {
+  background: #ff0;
+  color: #000;
+}
+small {
+  font-size: 80%;
+}
+sub,
+sup {
+  font-size: 75%;
+  line-height: 0;
+  position: relative;
+  vertical-align: baseline;
+}
+sup {
+  top: -0.5em;
+}
+sub {
+  bottom: -0.25em;
+}
+img {
+  border: 0;
+}
+svg:not(:root) {
+  overflow: hidden;
+}
+figure {
+  margin: 1em 40px;
+}
+hr {
+  box-sizing: content-box;
+  height: 0;
+}
+pre {
+  overflow: auto;
+}
+code,
+kbd,
+pre,
+samp {
+  font-family: monospace, monospace;
+  font-size: 1em;
+}
+button,
+input,
+optgroup,
+select,
+textarea {
+  color: inherit;
+  font: inherit;
+  margin: 0;
+}
+button {
+  overflow: visible;
+}
+button,
+select {
+  text-transform: none;
+}
+button,
+html input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+  -webkit-appearance: button;
+  cursor: pointer;
+}
+button[disabled],
+html input[disabled] {
+  cursor: default;
+}
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+  border: 0;
+  padding: 0;
+}
+input {
+  line-height: normal;
+}
+input[type="checkbox"],
+input[type="radio"] {
+  box-sizing: border-box;
+  padding: 0;
+}
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+  height: auto;
+}
+input[type="search"] {
+  -webkit-appearance: textfield;
+  box-sizing: content-box;
+}
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+  -webkit-appearance: none;
+}
+fieldset {
+  border: 1px solid #c0c0c0;
+  margin: 0 2px;
+  padding: 0.35em 0.625em 0.75em;
+}
+legend {
+  border: 0;
+  padding: 0;
+}
+textarea {
+  overflow: auto;
+}
+optgroup {
+  font-weight: bold;
+}
+table {
+  border-collapse: collapse;
+  border-spacing: 0;
+}
+td,
+th {
+  padding: 0;
+}
+/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */
+@media print {
+  *,
+  *:before,
+  *:after {
+    background: transparent !important;
+    color: #000 !important;
+    box-shadow: none !important;
+    text-shadow: none !important;
+  }
+  a,
+  a:visited {
+    text-decoration: underline;
+  }
+  a[href]:after {
+    content: " (" attr(href) ")";
+  }
+  abbr[title]:after {
+    content: " (" attr(title) ")";
+  }
+  a[href^="#"]:after,
+  a[href^="javascript:"]:after {
+    content: "";
+  }
+  pre,
+  blockquote {
+    border: 1px solid #999;
+    page-break-inside: avoid;
+  }
+  thead {
+    display: table-header-group;
+  }
+  tr,
+  img {
+    page-break-inside: avoid;
+  }
+  img {
+    max-width: 100% !important;
+  }
+  p,
+  h2,
+  h3 {
+    orphans: 3;
+    widows: 3;
+  }
+  h2,
+  h3 {
+    page-break-after: avoid;
+  }
+  .navbar {
+    display: none;
+  }
+  .btn > .caret,
+  .dropup > .btn > .caret {
+    border-top-color: #000 !important;
+  }
+  .label {
+    border: 1px solid #000;
+  }
+  .table {
+    border-collapse: collapse !important;
+  }
+  .table td,
+  .table th {
+    background-color: #fff !important;
+  }
+  .table-bordered th,
+  .table-bordered td {
+    border: 1px solid #ddd !important;
+  }
+}
+@font-face {
+  font-family: 'Glyphicons Halflings';
+  src: url('../components/bootstrap/fonts/glyphicons-halflings-regular.eot');
+  src: url('../components/bootstrap/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../components/bootstrap/fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../components/bootstrap/fonts/glyphicons-halflings-regular.woff') format('woff'), url('../components/bootstrap/fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../components/bootstrap/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
+}
+.glyphicon {
+  position: relative;
+  top: 1px;
+  display: inline-block;
+  font-family: 'Glyphicons Halflings';
+  font-style: normal;
+  font-weight: normal;
+  line-height: 1;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+.glyphicon-asterisk:before {
+  content: "\002a";
+}
+.glyphicon-plus:before {
+  content: "\002b";
+}
+.glyphicon-euro:before,
+.glyphicon-eur:before {
+  content: "\20ac";
+}
+.glyphicon-minus:before {
+  content: "\2212";
+}
+.glyphicon-cloud:before {
+  content: "\2601";
+}
+.glyphicon-envelope:before {
+  content: "\2709";
+}
+.glyphicon-pencil:before {
+  content: "\270f";
+}
+.glyphicon-glass:before {
+  content: "\e001";
+}
+.glyphicon-music:before {
+  content: "\e002";
+}
+.glyphicon-search:before {
+  content: "\e003";
+}
+.glyphicon-heart:before {
+  content: "\e005";
+}
+.glyphicon-star:before {
+  content: "\e006";
+}
+.glyphicon-star-empty:before {
+  content: "\e007";
+}
+.glyphicon-user:before {
+  content: "\e008";
+}
+.glyphicon-film:before {
+  content: "\e009";
+}
+.glyphicon-th-large:before {
+  content: "\e010";
+}
+.glyphicon-th:before {
+  content: "\e011";
+}
+.glyphicon-th-list:before {
+  content: "\e012";
+}
+.glyphicon-ok:before {
+  content: "\e013";
+}
+.glyphicon-remove:before {
+  content: "\e014";
+}
+.glyphicon-zoom-in:before {
+  content: "\e015";
+}
+.glyphicon-zoom-out:before {
+  content: "\e016";
+}
+.glyphicon-off:before {
+  content: "\e017";
+}
+.glyphicon-signal:before {
+  content: "\e018";
+}
+.glyphicon-cog:before {
+  content: "\e019";
+}
+.glyphicon-trash:before {
+  content: "\e020";
+}
+.glyphicon-home:before {
+  content: "\e021";
+}
+.glyphicon-file:before {
+  content: "\e022";
+}
+.glyphicon-time:before {
+  content: "\e023";
+}
+.glyphicon-road:before {
+  content: "\e024";
+}
+.glyphicon-download-alt:before {
+  content: "\e025";
+}
+.glyphicon-download:before {
+  content: "\e026";
+}
+.glyphicon-upload:before {
+  content: "\e027";
+}
+.glyphicon-inbox:before {
+  content: "\e028";
+}
+.glyphicon-play-circle:before {
+  content: "\e029";
+}
+.glyphicon-repeat:before {
+  content: "\e030";
+}
+.glyphicon-refresh:before {
+  content: "\e031";
+}
+.glyphicon-list-alt:before {
+  content: "\e032";
+}
+.glyphicon-lock:before {
+  content: "\e033";
+}
+.glyphicon-flag:before {
+  content: "\e034";
+}
+.glyphicon-headphones:before {
+  content: "\e035";
+}
+.glyphicon-volume-off:before {
+  content: "\e036";
+}
+.glyphicon-volume-down:before {
+  content: "\e037";
+}
+.glyphicon-volume-up:before {
+  content: "\e038";
+}
+.glyphicon-qrcode:before {
+  content: "\e039";
+}
+.glyphicon-barcode:before {
+  content: "\e040";
+}
+.glyphicon-tag:before {
+  content: "\e041";
+}
+.glyphicon-tags:before {
+  content: "\e042";
+}
+.glyphicon-book:before {
+  content: "\e043";
+}
+.glyphicon-bookmark:before {
+  content: "\e044";
+}
+.glyphicon-print:before {
+  content: "\e045";
+}
+.glyphicon-camera:before {
+  content: "\e046";
+}
+.glyphicon-font:before {
+  content: "\e047";
+}
+.glyphicon-bold:before {
+  content: "\e048";
+}
+.glyphicon-italic:before {
+  content: "\e049";
+}
+.glyphicon-text-height:before {
+  content: "\e050";
+}
+.glyphicon-text-width:before {
+  content: "\e051";
+}
+.glyphicon-align-left:before {
+  content: "\e052";
+}
+.glyphicon-align-center:before {
+  content: "\e053";
+}
+.glyphicon-align-right:before {
+  content: "\e054";
+}
+.glyphicon-align-justify:before {
+  content: "\e055";
+}
+.glyphicon-list:before {
+  content: "\e056";
+}
+.glyphicon-indent-left:before {
+  content: "\e057";
+}
+.glyphicon-indent-right:before {
+  content: "\e058";
+}
+.glyphicon-facetime-video:before {
+  content: "\e059";
+}
+.glyphicon-picture:before {
+  content: "\e060";
+}
+.glyphicon-map-marker:before {
+  content: "\e062";
+}
+.glyphicon-adjust:before {
+  content: "\e063";
+}
+.glyphicon-tint:before {
+  content: "\e064";
+}
+.glyphicon-edit:before {
+  content: "\e065";
+}
+.glyphicon-share:before {
+  content: "\e066";
+}
+.glyphicon-check:before {
+  content: "\e067";
+}
+.glyphicon-move:before {
+  content: "\e068";
+}
+.glyphicon-step-backward:before {
+  content: "\e069";
+}
+.glyphicon-fast-backward:before {
+  content: "\e070";
+}
+.glyphicon-backward:before {
+  content: "\e071";
+}
+.glyphicon-play:before {
+  content: "\e072";
+}
+.glyphicon-pause:before {
+  content: "\e073";
+}
+.glyphicon-stop:before {
+  content: "\e074";
+}
+.glyphicon-forward:before {
+  content: "\e075";
+}
+.glyphicon-fast-forward:before {
+  content: "\e076";
+}
+.glyphicon-step-forward:before {
+  content: "\e077";
+}
+.glyphicon-eject:before {
+  content: "\e078";
+}
+.glyphicon-chevron-left:before {
+  content: "\e079";
+}
+.glyphicon-chevron-right:before {
+  content: "\e080";
+}
+.glyphicon-plus-sign:before {
+  content: "\e081";
+}
+.glyphicon-minus-sign:before {
+  content: "\e082";
+}
+.glyphicon-remove-sign:before {
+  content: "\e083";
+}
+.glyphicon-ok-sign:before {
+  content: "\e084";
+}
+.glyphicon-question-sign:before {
+  content: "\e085";
+}
+.glyphicon-info-sign:before {
+  content: "\e086";
+}
+.glyphicon-screenshot:before {
+  content: "\e087";
+}
+.glyphicon-remove-circle:before {
+  content: "\e088";
+}
+.glyphicon-ok-circle:before {
+  content: "\e089";
+}
+.glyphicon-ban-circle:before {
+  content: "\e090";
+}
+.glyphicon-arrow-left:before {
+  content: "\e091";
+}
+.glyphicon-arrow-right:before {
+  content: "\e092";
+}
+.glyphicon-arrow-up:before {
+  content: "\e093";
+}
+.glyphicon-arrow-down:before {
+  content: "\e094";
+}
+.glyphicon-share-alt:before {
+  content: "\e095";
+}
+.glyphicon-resize-full:before {
+  content: "\e096";
+}
+.glyphicon-resize-small:before {
+  content: "\e097";
+}
+.glyphicon-exclamation-sign:before {
+  content: "\e101";
+}
+.glyphicon-gift:before {
+  content: "\e102";
+}
+.glyphicon-leaf:before {
+  content: "\e103";
+}
+.glyphicon-fire:before {
+  content: "\e104";
+}
+.glyphicon-eye-open:before {
+  content: "\e105";
+}
+.glyphicon-eye-close:before {
+  content: "\e106";
+}
+.glyphicon-warning-sign:before {
+  content: "\e107";
+}
+.glyphicon-plane:before {
+  content: "\e108";
+}
+.glyphicon-calendar:before {
+  content: "\e109";
+}
+.glyphicon-random:before {
+  content: "\e110";
+}
+.glyphicon-comment:before {
+  content: "\e111";
+}
+.glyphicon-magnet:before {
+  content: "\e112";
+}
+.glyphicon-chevron-up:before {
+  content: "\e113";
+}
+.glyphicon-chevron-down:before {
+  content: "\e114";
+}
+.glyphicon-retweet:before {
+  content: "\e115";
+}
+.glyphicon-shopping-cart:before {
+  content: "\e116";
+}
+.glyphicon-folder-close:before {
+  content: "\e117";
+}
+.glyphicon-folder-open:before {
+  content: "\e118";
+}
+.glyphicon-resize-vertical:before {
+  content: "\e119";
+}
+.glyphicon-resize-horizontal:before {
+  content: "\e120";
+}
+.glyphicon-hdd:before {
+  content: "\e121";
+}
+.glyphicon-bullhorn:before {
+  content: "\e122";
+}
+.glyphicon-bell:before {
+  content: "\e123";
+}
+.glyphicon-certificate:before {
+  content: "\e124";
+}
+.glyphicon-thumbs-up:before {
+  content: "\e125";
+}
+.glyphicon-thumbs-down:before {
+  content: "\e126";
+}
+.glyphicon-hand-right:before {
+  content: "\e127";
+}
+.glyphicon-hand-left:before {
+  content: "\e128";
+}
+.glyphicon-hand-up:before {
+  content: "\e129";
+}
+.glyphicon-hand-down:before {
+  content: "\e130";
+}
+.glyphicon-circle-arrow-right:before {
+  content: "\e131";
+}
+.glyphicon-circle-arrow-left:before {
+  content: "\e132";
+}
+.glyphicon-circle-arrow-up:before {
+  content: "\e133";
+}
+.glyphicon-circle-arrow-down:before {
+  content: "\e134";
+}
+.glyphicon-globe:before {
+  content: "\e135";
+}
+.glyphicon-wrench:before {
+  content: "\e136";
+}
+.glyphicon-tasks:before {
+  content: "\e137";
+}
+.glyphicon-filter:before {
+  content: "\e138";
+}
+.glyphicon-briefcase:before {
+  content: "\e139";
+}
+.glyphicon-fullscreen:before {
+  content: "\e140";
+}
+.glyphicon-dashboard:before {
+  content: "\e141";
+}
+.glyphicon-paperclip:before {
+  content: "\e142";
+}
+.glyphicon-heart-empty:before {
+  content: "\e143";
+}
+.glyphicon-link:before {
+  content: "\e144";
+}
+.glyphicon-phone:before {
+  content: "\e145";
+}
+.glyphicon-pushpin:before {
+  content: "\e146";
+}
+.glyphicon-usd:before {
+  content: "\e148";
+}
+.glyphicon-gbp:before {
+  content: "\e149";
+}
+.glyphicon-sort:before {
+  content: "\e150";
+}
+.glyphicon-sort-by-alphabet:before {
+  content: "\e151";
+}
+.glyphicon-sort-by-alphabet-alt:before {
+  content: "\e152";
+}
+.glyphicon-sort-by-order:before {
+  content: "\e153";
+}
+.glyphicon-sort-by-order-alt:before {
+  content: "\e154";
+}
+.glyphicon-sort-by-attributes:before {
+  content: "\e155";
+}
+.glyphicon-sort-by-attributes-alt:before {
+  content: "\e156";
+}
+.glyphicon-unchecked:before {
+  content: "\e157";
+}
+.glyphicon-expand:before {
+  content: "\e158";
+}
+.glyphicon-collapse-down:before {
+  content: "\e159";
+}
+.glyphicon-collapse-up:before {
+  content: "\e160";
+}
+.glyphicon-log-in:before {
+  content: "\e161";
+}
+.glyphicon-flash:before {
+  content: "\e162";
+}
+.glyphicon-log-out:before {
+  content: "\e163";
+}
+.glyphicon-new-window:before {
+  content: "\e164";
+}
+.glyphicon-record:before {
+  content: "\e165";
+}
+.glyphicon-save:before {
+  content: "\e166";
+}
+.glyphicon-open:before {
+  content: "\e167";
+}
+.glyphicon-saved:before {
+  content: "\e168";
+}
+.glyphicon-import:before {
+  content: "\e169";
+}
+.glyphicon-export:before {
+  content: "\e170";
+}
+.glyphicon-send:before {
+  content: "\e171";
+}
+.glyphicon-floppy-disk:before {
+  content: "\e172";
+}
+.glyphicon-floppy-saved:before {
+  content: "\e173";
+}
+.glyphicon-floppy-remove:before {
+  content: "\e174";
+}
+.glyphicon-floppy-save:before {
+  content: "\e175";
+}
+.glyphicon-floppy-open:before {
+  content: "\e176";
+}
+.glyphicon-credit-card:before {
+  content: "\e177";
+}
+.glyphicon-transfer:before {
+  content: "\e178";
+}
+.glyphicon-cutlery:before {
+  content: "\e179";
+}
+.glyphicon-header:before {
+  content: "\e180";
+}
+.glyphicon-compressed:before {
+  content: "\e181";
+}
+.glyphicon-earphone:before {
+  content: "\e182";
+}
+.glyphicon-phone-alt:before {
+  content: "\e183";
+}
+.glyphicon-tower:before {
+  content: "\e184";
+}
+.glyphicon-stats:before {
+  content: "\e185";
+}
+.glyphicon-sd-video:before {
+  content: "\e186";
+}
+.glyphicon-hd-video:before {
+  content: "\e187";
+}
+.glyphicon-subtitles:before {
+  content: "\e188";
+}
+.glyphicon-sound-stereo:before {
+  content: "\e189";
+}
+.glyphicon-sound-dolby:before {
+  content: "\e190";
+}
+.glyphicon-sound-5-1:before {
+  content: "\e191";
+}
+.glyphicon-sound-6-1:before {
+  content: "\e192";
+}
+.glyphicon-sound-7-1:before {
+  content: "\e193";
+}
+.glyphicon-copyright-mark:before {
+  content: "\e194";
+}
+.glyphicon-registration-mark:before {
+  content: "\e195";
+}
+.glyphicon-cloud-download:before {
+  content: "\e197";
+}
+.glyphicon-cloud-upload:before {
+  content: "\e198";
+}
+.glyphicon-tree-conifer:before {
+  content: "\e199";
+}
+.glyphicon-tree-deciduous:before {
+  content: "\e200";
+}
+.glyphicon-cd:before {
+  content: "\e201";
+}
+.glyphicon-save-file:before {
+  content: "\e202";
+}
+.glyphicon-open-file:before {
+  content: "\e203";
+}
+.glyphicon-level-up:before {
+  content: "\e204";
+}
+.glyphicon-copy:before {
+  content: "\e205";
+}
+.glyphicon-paste:before {
+  content: "\e206";
+}
+.glyphicon-alert:before {
+  content: "\e209";
+}
+.glyphicon-equalizer:before {
+  content: "\e210";
+}
+.glyphicon-king:before {
+  content: "\e211";
+}
+.glyphicon-queen:before {
+  content: "\e212";
+}
+.glyphicon-pawn:before {
+  content: "\e213";
+}
+.glyphicon-bishop:before {
+  content: "\e214";
+}
+.glyphicon-knight:before {
+  content: "\e215";
+}
+.glyphicon-baby-formula:before {
+  content: "\e216";
+}
+.glyphicon-tent:before {
+  content: "\26fa";
+}
+.glyphicon-blackboard:before {
+  content: "\e218";
+}
+.glyphicon-bed:before {
+  content: "\e219";
+}
+.glyphicon-apple:before {
+  content: "\f8ff";
+}
+.glyphicon-erase:before {
+  content: "\e221";
+}
+.glyphicon-hourglass:before {
+  content: "\231b";
+}
+.glyphicon-lamp:before {
+  content: "\e223";
+}
+.glyphicon-duplicate:before {
+  content: "\e224";
+}
+.glyphicon-piggy-bank:before {
+  content: "\e225";
+}
+.glyphicon-scissors:before {
+  content: "\e226";
+}
+.glyphicon-bitcoin:before {
+  content: "\e227";
+}
+.glyphicon-btc:before {
+  content: "\e227";
+}
+.glyphicon-xbt:before {
+  content: "\e227";
+}
+.glyphicon-yen:before {
+  content: "\00a5";
+}
+.glyphicon-jpy:before {
+  content: "\00a5";
+}
+.glyphicon-ruble:before {
+  content: "\20bd";
+}
+.glyphicon-rub:before {
+  content: "\20bd";
+}
+.glyphicon-scale:before {
+  content: "\e230";
+}
+.glyphicon-ice-lolly:before {
+  content: "\e231";
+}
+.glyphicon-ice-lolly-tasted:before {
+  content: "\e232";
+}
+.glyphicon-education:before {
+  content: "\e233";
+}
+.glyphicon-option-horizontal:before {
+  content: "\e234";
+}
+.glyphicon-option-vertical:before {
+  content: "\e235";
+}
+.glyphicon-menu-hamburger:before {
+  content: "\e236";
+}
+.glyphicon-modal-window:before {
+  content: "\e237";
+}
+.glyphicon-oil:before {
+  content: "\e238";
+}
+.glyphicon-grain:before {
+  content: "\e239";
+}
+.glyphicon-sunglasses:before {
+  content: "\e240";
+}
+.glyphicon-text-size:before {
+  content: "\e241";
+}
+.glyphicon-text-color:before {
+  content: "\e242";
+}
+.glyphicon-text-background:before {
+  content: "\e243";
+}
+.glyphicon-object-align-top:before {
+  content: "\e244";
+}
+.glyphicon-object-align-bottom:before {
+  content: "\e245";
+}
+.glyphicon-object-align-horizontal:before {
+  content: "\e246";
+}
+.glyphicon-object-align-left:before {
+  content: "\e247";
+}
+.glyphicon-object-align-vertical:before {
+  content: "\e248";
+}
+.glyphicon-object-align-right:before {
+  content: "\e249";
+}
+.glyphicon-triangle-right:before {
+  content: "\e250";
+}
+.glyphicon-triangle-left:before {
+  content: "\e251";
+}
+.glyphicon-triangle-bottom:before {
+  content: "\e252";
+}
+.glyphicon-triangle-top:before {
+  content: "\e253";
+}
+.glyphicon-console:before {
+  content: "\e254";
+}
+.glyphicon-superscript:before {
+  content: "\e255";
+}
+.glyphicon-subscript:before {
+  content: "\e256";
+}
+.glyphicon-menu-left:before {
+  content: "\e257";
+}
+.glyphicon-menu-right:before {
+  content: "\e258";
+}
+.glyphicon-menu-down:before {
+  content: "\e259";
+}
+.glyphicon-menu-up:before {
+  content: "\e260";
+}
+* {
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+}
+*:before,
+*:after {
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+}
+html {
+  font-size: 10px;
+  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+body {
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-size: 13px;
+  line-height: 1.42857143;
+  color: #000;
+  background-color: #fff;
+}
+input,
+button,
+select,
+textarea {
+  font-family: inherit;
+  font-size: inherit;
+  line-height: inherit;
+}
+a {
+  color: #337ab7;
+  text-decoration: none;
+}
+a:hover,
+a:focus {
+  color: #23527c;
+  text-decoration: underline;
+}
+a:focus {
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+figure {
+  margin: 0;
+}
+img {
+  vertical-align: middle;
+}
+.img-responsive,
+.thumbnail > img,
+.thumbnail a > img,
+.carousel-inner > .item > img,
+.carousel-inner > .item > a > img {
+  display: block;
+  max-width: 100%;
+  height: auto;
+}
+.img-rounded {
+  border-radius: 3px;
+}
+.img-thumbnail {
+  padding: 4px;
+  line-height: 1.42857143;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-radius: 2px;
+  -webkit-transition: all 0.2s ease-in-out;
+  -o-transition: all 0.2s ease-in-out;
+  transition: all 0.2s ease-in-out;
+  display: inline-block;
+  max-width: 100%;
+  height: auto;
+}
+.img-circle {
+  border-radius: 50%;
+}
+hr {
+  margin-top: 18px;
+  margin-bottom: 18px;
+  border: 0;
+  border-top: 1px solid #eeeeee;
+}
+.sr-only {
+  position: absolute;
+  width: 1px;
+  height: 1px;
+  margin: -1px;
+  padding: 0;
+  overflow: hidden;
+  clip: rect(0, 0, 0, 0);
+  border: 0;
+}
+.sr-only-focusable:active,
+.sr-only-focusable:focus {
+  position: static;
+  width: auto;
+  height: auto;
+  margin: 0;
+  overflow: visible;
+  clip: auto;
+}
+[role="button"] {
+  cursor: pointer;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+.h1,
+.h2,
+.h3,
+.h4,
+.h5,
+.h6 {
+  font-family: inherit;
+  font-weight: 500;
+  line-height: 1.1;
+  color: inherit;
+}
+h1 small,
+h2 small,
+h3 small,
+h4 small,
+h5 small,
+h6 small,
+.h1 small,
+.h2 small,
+.h3 small,
+.h4 small,
+.h5 small,
+.h6 small,
+h1 .small,
+h2 .small,
+h3 .small,
+h4 .small,
+h5 .small,
+h6 .small,
+.h1 .small,
+.h2 .small,
+.h3 .small,
+.h4 .small,
+.h5 .small,
+.h6 .small {
+  font-weight: normal;
+  line-height: 1;
+  color: #777777;
+}
+h1,
+.h1,
+h2,
+.h2,
+h3,
+.h3 {
+  margin-top: 18px;
+  margin-bottom: 9px;
+}
+h1 small,
+.h1 small,
+h2 small,
+.h2 small,
+h3 small,
+.h3 small,
+h1 .small,
+.h1 .small,
+h2 .small,
+.h2 .small,
+h3 .small,
+.h3 .small {
+  font-size: 65%;
+}
+h4,
+.h4,
+h5,
+.h5,
+h6,
+.h6 {
+  margin-top: 9px;
+  margin-bottom: 9px;
+}
+h4 small,
+.h4 small,
+h5 small,
+.h5 small,
+h6 small,
+.h6 small,
+h4 .small,
+.h4 .small,
+h5 .small,
+.h5 .small,
+h6 .small,
+.h6 .small {
+  font-size: 75%;
+}
+h1,
+.h1 {
+  font-size: 33px;
+}
+h2,
+.h2 {
+  font-size: 27px;
+}
+h3,
+.h3 {
+  font-size: 23px;
+}
+h4,
+.h4 {
+  font-size: 17px;
+}
+h5,
+.h5 {
+  font-size: 13px;
+}
+h6,
+.h6 {
+  font-size: 12px;
+}
+p {
+  margin: 0 0 9px;
+}
+.lead {
+  margin-bottom: 18px;
+  font-size: 14px;
+  font-weight: 300;
+  line-height: 1.4;
+}
+@media (min-width: 768px) {
+  .lead {
+    font-size: 19.5px;
+  }
+}
+small,
+.small {
+  font-size: 92%;
+}
+mark,
+.mark {
+  background-color: #fcf8e3;
+  padding: .2em;
+}
+.text-left {
+  text-align: left;
+}
+.text-right {
+  text-align: right;
+}
+.text-center {
+  text-align: center;
+}
+.text-justify {
+  text-align: justify;
+}
+.text-nowrap {
+  white-space: nowrap;
+}
+.text-lowercase {
+  text-transform: lowercase;
+}
+.text-uppercase {
+  text-transform: uppercase;
+}
+.text-capitalize {
+  text-transform: capitalize;
+}
+.text-muted {
+  color: #777777;
+}
+.text-primary {
+  color: #337ab7;
+}
+a.text-primary:hover,
+a.text-primary:focus {
+  color: #286090;
+}
+.text-success {
+  color: #3c763d;
+}
+a.text-success:hover,
+a.text-success:focus {
+  color: #2b542c;
+}
+.text-info {
+  color: #31708f;
+}
+a.text-info:hover,
+a.text-info:focus {
+  color: #245269;
+}
+.text-warning {
+  color: #8a6d3b;
+}
+a.text-warning:hover,
+a.text-warning:focus {
+  color: #66512c;
+}
+.text-danger {
+  color: #a94442;
+}
+a.text-danger:hover,
+a.text-danger:focus {
+  color: #843534;
+}
+.bg-primary {
+  color: #fff;
+  background-color: #337ab7;
+}
+a.bg-primary:hover,
+a.bg-primary:focus {
+  background-color: #286090;
+}
+.bg-success {
+  background-color: #dff0d8;
+}
+a.bg-success:hover,
+a.bg-success:focus {
+  background-color: #c1e2b3;
+}
+.bg-info {
+  background-color: #d9edf7;
+}
+a.bg-info:hover,
+a.bg-info:focus {
+  background-color: #afd9ee;
+}
+.bg-warning {
+  background-color: #fcf8e3;
+}
+a.bg-warning:hover,
+a.bg-warning:focus {
+  background-color: #f7ecb5;
+}
+.bg-danger {
+  background-color: #f2dede;
+}
+a.bg-danger:hover,
+a.bg-danger:focus {
+  background-color: #e4b9b9;
+}
+.page-header {
+  padding-bottom: 8px;
+  margin: 36px 0 18px;
+  border-bottom: 1px solid #eeeeee;
+}
+ul,
+ol {
+  margin-top: 0;
+  margin-bottom: 9px;
+}
+ul ul,
+ol ul,
+ul ol,
+ol ol {
+  margin-bottom: 0;
+}
+.list-unstyled {
+  padding-left: 0;
+  list-style: none;
+}
+.list-inline {
+  padding-left: 0;
+  list-style: none;
+  margin-left: -5px;
+}
+.list-inline > li {
+  display: inline-block;
+  padding-left: 5px;
+  padding-right: 5px;
+}
+dl {
+  margin-top: 0;
+  margin-bottom: 18px;
+}
+dt,
+dd {
+  line-height: 1.42857143;
+}
+dt {
+  font-weight: bold;
+}
+dd {
+  margin-left: 0;
+}
+@media (min-width: 541px) {
+  .dl-horizontal dt {
+    float: left;
+    width: 160px;
+    clear: left;
+    text-align: right;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+  .dl-horizontal dd {
+    margin-left: 180px;
+  }
+}
+abbr[title],
+abbr[data-original-title] {
+  cursor: help;
+  border-bottom: 1px dotted #777777;
+}
+.initialism {
+  font-size: 90%;
+  text-transform: uppercase;
+}
+blockquote {
+  padding: 9px 18px;
+  margin: 0 0 18px;
+  font-size: inherit;
+  border-left: 5px solid #eeeeee;
+}
+blockquote p:last-child,
+blockquote ul:last-child,
+blockquote ol:last-child {
+  margin-bottom: 0;
+}
+blockquote footer,
+blockquote small,
+blockquote .small {
+  display: block;
+  font-size: 80%;
+  line-height: 1.42857143;
+  color: #777777;
+}
+blockquote footer:before,
+blockquote small:before,
+blockquote .small:before {
+  content: '\2014 \00A0';
+}
+.blockquote-reverse,
+blockquote.pull-right {
+  padding-right: 15px;
+  padding-left: 0;
+  border-right: 5px solid #eeeeee;
+  border-left: 0;
+  text-align: right;
+}
+.blockquote-reverse footer:before,
+blockquote.pull-right footer:before,
+.blockquote-reverse small:before,
+blockquote.pull-right small:before,
+.blockquote-reverse .small:before,
+blockquote.pull-right .small:before {
+  content: '';
+}
+.blockquote-reverse footer:after,
+blockquote.pull-right footer:after,
+.blockquote-reverse small:after,
+blockquote.pull-right small:after,
+.blockquote-reverse .small:after,
+blockquote.pull-right .small:after {
+  content: '\00A0 \2014';
+}
+address {
+  margin-bottom: 18px;
+  font-style: normal;
+  line-height: 1.42857143;
+}
+code,
+kbd,
+pre,
+samp {
+  font-family: monospace;
+}
+code {
+  padding: 2px 4px;
+  font-size: 90%;
+  color: #c7254e;
+  background-color: #f9f2f4;
+  border-radius: 2px;
+}
+kbd {
+  padding: 2px 4px;
+  font-size: 90%;
+  color: #888;
+  background-color: transparent;
+  border-radius: 1px;
+  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);
+}
+kbd kbd {
+  padding: 0;
+  font-size: 100%;
+  font-weight: bold;
+  box-shadow: none;
+}
+pre {
+  display: block;
+  padding: 8.5px;
+  margin: 0 0 9px;
+  font-size: 12px;
+  line-height: 1.42857143;
+  word-break: break-all;
+  word-wrap: break-word;
+  color: #333333;
+  background-color: #f5f5f5;
+  border: 1px solid #ccc;
+  border-radius: 2px;
+}
+pre code {
+  padding: 0;
+  font-size: inherit;
+  color: inherit;
+  white-space: pre-wrap;
+  background-color: transparent;
+  border-radius: 0;
+}
+.pre-scrollable {
+  max-height: 340px;
+  overflow-y: scroll;
+}
+.container {
+  margin-right: auto;
+  margin-left: auto;
+  padding-left: 0px;
+  padding-right: 0px;
+}
+@media (min-width: 768px) {
+  .container {
+    width: 768px;
+  }
+}
+@media (min-width: 992px) {
+  .container {
+    width: 940px;
+  }
+}
+@media (min-width: 1200px) {
+  .container {
+    width: 1140px;
+  }
+}
+.container-fluid {
+  margin-right: auto;
+  margin-left: auto;
+  padding-left: 0px;
+  padding-right: 0px;
+}
+.row {
+  margin-left: 0px;
+  margin-right: 0px;
+}
+.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {
+  position: relative;
+  min-height: 1px;
+  padding-left: 0px;
+  padding-right: 0px;
+}
+.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {
+  float: left;
+}
+.col-xs-12 {
+  width: 100%;
+}
+.col-xs-11 {
+  width: 91.66666667%;
+}
+.col-xs-10 {
+  width: 83.33333333%;
+}
+.col-xs-9 {
+  width: 75%;
+}
+.col-xs-8 {
+  width: 66.66666667%;
+}
+.col-xs-7 {
+  width: 58.33333333%;
+}
+.col-xs-6 {
+  width: 50%;
+}
+.col-xs-5 {
+  width: 41.66666667%;
+}
+.col-xs-4 {
+  width: 33.33333333%;
+}
+.col-xs-3 {
+  width: 25%;
+}
+.col-xs-2 {
+  width: 16.66666667%;
+}
+.col-xs-1 {
+  width: 8.33333333%;
+}
+.col-xs-pull-12 {
+  right: 100%;
+}
+.col-xs-pull-11 {
+  right: 91.66666667%;
+}
+.col-xs-pull-10 {
+  right: 83.33333333%;
+}
+.col-xs-pull-9 {
+  right: 75%;
+}
+.col-xs-pull-8 {
+  right: 66.66666667%;
+}
+.col-xs-pull-7 {
+  right: 58.33333333%;
+}
+.col-xs-pull-6 {
+  right: 50%;
+}
+.col-xs-pull-5 {
+  right: 41.66666667%;
+}
+.col-xs-pull-4 {
+  right: 33.33333333%;
+}
+.col-xs-pull-3 {
+  right: 25%;
+}
+.col-xs-pull-2 {
+  right: 16.66666667%;
+}
+.col-xs-pull-1 {
+  right: 8.33333333%;
+}
+.col-xs-pull-0 {
+  right: auto;
+}
+.col-xs-push-12 {
+  left: 100%;
+}
+.col-xs-push-11 {
+  left: 91.66666667%;
+}
+.col-xs-push-10 {
+  left: 83.33333333%;
+}
+.col-xs-push-9 {
+  left: 75%;
+}
+.col-xs-push-8 {
+  left: 66.66666667%;
+}
+.col-xs-push-7 {
+  left: 58.33333333%;
+}
+.col-xs-push-6 {
+  left: 50%;
+}
+.col-xs-push-5 {
+  left: 41.66666667%;
+}
+.col-xs-push-4 {
+  left: 33.33333333%;
+}
+.col-xs-push-3 {
+  left: 25%;
+}
+.col-xs-push-2 {
+  left: 16.66666667%;
+}
+.col-xs-push-1 {
+  left: 8.33333333%;
+}
+.col-xs-push-0 {
+  left: auto;
+}
+.col-xs-offset-12 {
+  margin-left: 100%;
+}
+.col-xs-offset-11 {
+  margin-left: 91.66666667%;
+}
+.col-xs-offset-10 {
+  margin-left: 83.33333333%;
+}
+.col-xs-offset-9 {
+  margin-left: 75%;
+}
+.col-xs-offset-8 {
+  margin-left: 66.66666667%;
+}
+.col-xs-offset-7 {
+  margin-left: 58.33333333%;
+}
+.col-xs-offset-6 {
+  margin-left: 50%;
+}
+.col-xs-offset-5 {
+  margin-left: 41.66666667%;
+}
+.col-xs-offset-4 {
+  margin-left: 33.33333333%;
+}
+.col-xs-offset-3 {
+  margin-left: 25%;
+}
+.col-xs-offset-2 {
+  margin-left: 16.66666667%;
+}
+.col-xs-offset-1 {
+  margin-left: 8.33333333%;
+}
+.col-xs-offset-0 {
+  margin-left: 0%;
+}
+@media (min-width: 768px) {
+  .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {
+    float: left;
+  }
+  .col-sm-12 {
+    width: 100%;
+  }
+  .col-sm-11 {
+    width: 91.66666667%;
+  }
+  .col-sm-10 {
+    width: 83.33333333%;
+  }
+  .col-sm-9 {
+    width: 75%;
+  }
+  .col-sm-8 {
+    width: 66.66666667%;
+  }
+  .col-sm-7 {
+    width: 58.33333333%;
+  }
+  .col-sm-6 {
+    width: 50%;
+  }
+  .col-sm-5 {
+    width: 41.66666667%;
+  }
+  .col-sm-4 {
+    width: 33.33333333%;
+  }
+  .col-sm-3 {
+    width: 25%;
+  }
+  .col-sm-2 {
+    width: 16.66666667%;
+  }
+  .col-sm-1 {
+    width: 8.33333333%;
+  }
+  .col-sm-pull-12 {
+    right: 100%;
+  }
+  .col-sm-pull-11 {
+    right: 91.66666667%;
+  }
+  .col-sm-pull-10 {
+    right: 83.33333333%;
+  }
+  .col-sm-pull-9 {
+    right: 75%;
+  }
+  .col-sm-pull-8 {
+    right: 66.66666667%;
+  }
+  .col-sm-pull-7 {
+    right: 58.33333333%;
+  }
+  .col-sm-pull-6 {
+    right: 50%;
+  }
+  .col-sm-pull-5 {
+    right: 41.66666667%;
+  }
+  .col-sm-pull-4 {
+    right: 33.33333333%;
+  }
+  .col-sm-pull-3 {
+    right: 25%;
+  }
+  .col-sm-pull-2 {
+    right: 16.66666667%;
+  }
+  .col-sm-pull-1 {
+    right: 8.33333333%;
+  }
+  .col-sm-pull-0 {
+    right: auto;
+  }
+  .col-sm-push-12 {
+    left: 100%;
+  }
+  .col-sm-push-11 {
+    left: 91.66666667%;
+  }
+  .col-sm-push-10 {
+    left: 83.33333333%;
+  }
+  .col-sm-push-9 {
+    left: 75%;
+  }
+  .col-sm-push-8 {
+    left: 66.66666667%;
+  }
+  .col-sm-push-7 {
+    left: 58.33333333%;
+  }
+  .col-sm-push-6 {
+    left: 50%;
+  }
+  .col-sm-push-5 {
+    left: 41.66666667%;
+  }
+  .col-sm-push-4 {
+    left: 33.33333333%;
+  }
+  .col-sm-push-3 {
+    left: 25%;
+  }
+  .col-sm-push-2 {
+    left: 16.66666667%;
+  }
+  .col-sm-push-1 {
+    left: 8.33333333%;
+  }
+  .col-sm-push-0 {
+    left: auto;
+  }
+  .col-sm-offset-12 {
+    margin-left: 100%;
+  }
+  .col-sm-offset-11 {
+    margin-left: 91.66666667%;
+  }
+  .col-sm-offset-10 {
+    margin-left: 83.33333333%;
+  }
+  .col-sm-offset-9 {
+    margin-left: 75%;
+  }
+  .col-sm-offset-8 {
+    margin-left: 66.66666667%;
+  }
+  .col-sm-offset-7 {
+    margin-left: 58.33333333%;
+  }
+  .col-sm-offset-6 {
+    margin-left: 50%;
+  }
+  .col-sm-offset-5 {
+    margin-left: 41.66666667%;
+  }
+  .col-sm-offset-4 {
+    margin-left: 33.33333333%;
+  }
+  .col-sm-offset-3 {
+    margin-left: 25%;
+  }
+  .col-sm-offset-2 {
+    margin-left: 16.66666667%;
+  }
+  .col-sm-offset-1 {
+    margin-left: 8.33333333%;
+  }
+  .col-sm-offset-0 {
+    margin-left: 0%;
+  }
+}
+@media (min-width: 992px) {
+  .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {
+    float: left;
+  }
+  .col-md-12 {
+    width: 100%;
+  }
+  .col-md-11 {
+    width: 91.66666667%;
+  }
+  .col-md-10 {
+    width: 83.33333333%;
+  }
+  .col-md-9 {
+    width: 75%;
+  }
+  .col-md-8 {
+    width: 66.66666667%;
+  }
+  .col-md-7 {
+    width: 58.33333333%;
+  }
+  .col-md-6 {
+    width: 50%;
+  }
+  .col-md-5 {
+    width: 41.66666667%;
+  }
+  .col-md-4 {
+    width: 33.33333333%;
+  }
+  .col-md-3 {
+    width: 25%;
+  }
+  .col-md-2 {
+    width: 16.66666667%;
+  }
+  .col-md-1 {
+    width: 8.33333333%;
+  }
+  .col-md-pull-12 {
+    right: 100%;
+  }
+  .col-md-pull-11 {
+    right: 91.66666667%;
+  }
+  .col-md-pull-10 {
+    right: 83.33333333%;
+  }
+  .col-md-pull-9 {
+    right: 75%;
+  }
+  .col-md-pull-8 {
+    right: 66.66666667%;
+  }
+  .col-md-pull-7 {
+    right: 58.33333333%;
+  }
+  .col-md-pull-6 {
+    right: 50%;
+  }
+  .col-md-pull-5 {
+    right: 41.66666667%;
+  }
+  .col-md-pull-4 {
+    right: 33.33333333%;
+  }
+  .col-md-pull-3 {
+    right: 25%;
+  }
+  .col-md-pull-2 {
+    right: 16.66666667%;
+  }
+  .col-md-pull-1 {
+    right: 8.33333333%;
+  }
+  .col-md-pull-0 {
+    right: auto;
+  }
+  .col-md-push-12 {
+    left: 100%;
+  }
+  .col-md-push-11 {
+    left: 91.66666667%;
+  }
+  .col-md-push-10 {
+    left: 83.33333333%;
+  }
+  .col-md-push-9 {
+    left: 75%;
+  }
+  .col-md-push-8 {
+    left: 66.66666667%;
+  }
+  .col-md-push-7 {
+    left: 58.33333333%;
+  }
+  .col-md-push-6 {
+    left: 50%;
+  }
+  .col-md-push-5 {
+    left: 41.66666667%;
+  }
+  .col-md-push-4 {
+    left: 33.33333333%;
+  }
+  .col-md-push-3 {
+    left: 25%;
+  }
+  .col-md-push-2 {
+    left: 16.66666667%;
+  }
+  .col-md-push-1 {
+    left: 8.33333333%;
+  }
+  .col-md-push-0 {
+    left: auto;
+  }
+  .col-md-offset-12 {
+    margin-left: 100%;
+  }
+  .col-md-offset-11 {
+    margin-left: 91.66666667%;
+  }
+  .col-md-offset-10 {
+    margin-left: 83.33333333%;
+  }
+  .col-md-offset-9 {
+    margin-left: 75%;
+  }
+  .col-md-offset-8 {
+    margin-left: 66.66666667%;
+  }
+  .col-md-offset-7 {
+    margin-left: 58.33333333%;
+  }
+  .col-md-offset-6 {
+    margin-left: 50%;
+  }
+  .col-md-offset-5 {
+    margin-left: 41.66666667%;
+  }
+  .col-md-offset-4 {
+    margin-left: 33.33333333%;
+  }
+  .col-md-offset-3 {
+    margin-left: 25%;
+  }
+  .col-md-offset-2 {
+    margin-left: 16.66666667%;
+  }
+  .col-md-offset-1 {
+    margin-left: 8.33333333%;
+  }
+  .col-md-offset-0 {
+    margin-left: 0%;
+  }
+}
+@media (min-width: 1200px) {
+  .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {
+    float: left;
+  }
+  .col-lg-12 {
+    width: 100%;
+  }
+  .col-lg-11 {
+    width: 91.66666667%;
+  }
+  .col-lg-10 {
+    width: 83.33333333%;
+  }
+  .col-lg-9 {
+    width: 75%;
+  }
+  .col-lg-8 {
+    width: 66.66666667%;
+  }
+  .col-lg-7 {
+    width: 58.33333333%;
+  }
+  .col-lg-6 {
+    width: 50%;
+  }
+  .col-lg-5 {
+    width: 41.66666667%;
+  }
+  .col-lg-4 {
+    width: 33.33333333%;
+  }
+  .col-lg-3 {
+    width: 25%;
+  }
+  .col-lg-2 {
+    width: 16.66666667%;
+  }
+  .col-lg-1 {
+    width: 8.33333333%;
+  }
+  .col-lg-pull-12 {
+    right: 100%;
+  }
+  .col-lg-pull-11 {
+    right: 91.66666667%;
+  }
+  .col-lg-pull-10 {
+    right: 83.33333333%;
+  }
+  .col-lg-pull-9 {
+    right: 75%;
+  }
+  .col-lg-pull-8 {
+    right: 66.66666667%;
+  }
+  .col-lg-pull-7 {
+    right: 58.33333333%;
+  }
+  .col-lg-pull-6 {
+    right: 50%;
+  }
+  .col-lg-pull-5 {
+    right: 41.66666667%;
+  }
+  .col-lg-pull-4 {
+    right: 33.33333333%;
+  }
+  .col-lg-pull-3 {
+    right: 25%;
+  }
+  .col-lg-pull-2 {
+    right: 16.66666667%;
+  }
+  .col-lg-pull-1 {
+    right: 8.33333333%;
+  }
+  .col-lg-pull-0 {
+    right: auto;
+  }
+  .col-lg-push-12 {
+    left: 100%;
+  }
+  .col-lg-push-11 {
+    left: 91.66666667%;
+  }
+  .col-lg-push-10 {
+    left: 83.33333333%;
+  }
+  .col-lg-push-9 {
+    left: 75%;
+  }
+  .col-lg-push-8 {
+    left: 66.66666667%;
+  }
+  .col-lg-push-7 {
+    left: 58.33333333%;
+  }
+  .col-lg-push-6 {
+    left: 50%;
+  }
+  .col-lg-push-5 {
+    left: 41.66666667%;
+  }
+  .col-lg-push-4 {
+    left: 33.33333333%;
+  }
+  .col-lg-push-3 {
+    left: 25%;
+  }
+  .col-lg-push-2 {
+    left: 16.66666667%;
+  }
+  .col-lg-push-1 {
+    left: 8.33333333%;
+  }
+  .col-lg-push-0 {
+    left: auto;
+  }
+  .col-lg-offset-12 {
+    margin-left: 100%;
+  }
+  .col-lg-offset-11 {
+    margin-left: 91.66666667%;
+  }
+  .col-lg-offset-10 {
+    margin-left: 83.33333333%;
+  }
+  .col-lg-offset-9 {
+    margin-left: 75%;
+  }
+  .col-lg-offset-8 {
+    margin-left: 66.66666667%;
+  }
+  .col-lg-offset-7 {
+    margin-left: 58.33333333%;
+  }
+  .col-lg-offset-6 {
+    margin-left: 50%;
+  }
+  .col-lg-offset-5 {
+    margin-left: 41.66666667%;
+  }
+  .col-lg-offset-4 {
+    margin-left: 33.33333333%;
+  }
+  .col-lg-offset-3 {
+    margin-left: 25%;
+  }
+  .col-lg-offset-2 {
+    margin-left: 16.66666667%;
+  }
+  .col-lg-offset-1 {
+    margin-left: 8.33333333%;
+  }
+  .col-lg-offset-0 {
+    margin-left: 0%;
+  }
+}
+table {
+  background-color: transparent;
+}
+caption {
+  padding-top: 8px;
+  padding-bottom: 8px;
+  color: #777777;
+  text-align: left;
+}
+th {
+  text-align: left;
+}
+.table {
+  width: 100%;
+  max-width: 100%;
+  margin-bottom: 18px;
+}
+.table > thead > tr > th,
+.table > tbody > tr > th,
+.table > tfoot > tr > th,
+.table > thead > tr > td,
+.table > tbody > tr > td,
+.table > tfoot > tr > td {
+  padding: 8px;
+  line-height: 1.42857143;
+  vertical-align: top;
+  border-top: 1px solid #ddd;
+}
+.table > thead > tr > th {
+  vertical-align: bottom;
+  border-bottom: 2px solid #ddd;
+}
+.table > caption + thead > tr:first-child > th,
+.table > colgroup + thead > tr:first-child > th,
+.table > thead:first-child > tr:first-child > th,
+.table > caption + thead > tr:first-child > td,
+.table > colgroup + thead > tr:first-child > td,
+.table > thead:first-child > tr:first-child > td {
+  border-top: 0;
+}
+.table > tbody + tbody {
+  border-top: 2px solid #ddd;
+}
+.table .table {
+  background-color: #fff;
+}
+.table-condensed > thead > tr > th,
+.table-condensed > tbody > tr > th,
+.table-condensed > tfoot > tr > th,
+.table-condensed > thead > tr > td,
+.table-condensed > tbody > tr > td,
+.table-condensed > tfoot > tr > td {
+  padding: 5px;
+}
+.table-bordered {
+  border: 1px solid #ddd;
+}
+.table-bordered > thead > tr > th,
+.table-bordered > tbody > tr > th,
+.table-bordered > tfoot > tr > th,
+.table-bordered > thead > tr > td,
+.table-bordered > tbody > tr > td,
+.table-bordered > tfoot > tr > td {
+  border: 1px solid #ddd;
+}
+.table-bordered > thead > tr > th,
+.table-bordered > thead > tr > td {
+  border-bottom-width: 2px;
+}
+.table-striped > tbody > tr:nth-of-type(odd) {
+  background-color: #f9f9f9;
+}
+.table-hover > tbody > tr:hover {
+  background-color: #f5f5f5;
+}
+table col[class*="col-"] {
+  position: static;
+  float: none;
+  display: table-column;
+}
+table td[class*="col-"],
+table th[class*="col-"] {
+  position: static;
+  float: none;
+  display: table-cell;
+}
+.table > thead > tr > td.active,
+.table > tbody > tr > td.active,
+.table > tfoot > tr > td.active,
+.table > thead > tr > th.active,
+.table > tbody > tr > th.active,
+.table > tfoot > tr > th.active,
+.table > thead > tr.active > td,
+.table > tbody > tr.active > td,
+.table > tfoot > tr.active > td,
+.table > thead > tr.active > th,
+.table > tbody > tr.active > th,
+.table > tfoot > tr.active > th {
+  background-color: #f5f5f5;
+}
+.table-hover > tbody > tr > td.active:hover,
+.table-hover > tbody > tr > th.active:hover,
+.table-hover > tbody > tr.active:hover > td,
+.table-hover > tbody > tr:hover > .active,
+.table-hover > tbody > tr.active:hover > th {
+  background-color: #e8e8e8;
+}
+.table > thead > tr > td.success,
+.table > tbody > tr > td.success,
+.table > tfoot > tr > td.success,
+.table > thead > tr > th.success,
+.table > tbody > tr > th.success,
+.table > tfoot > tr > th.success,
+.table > thead > tr.success > td,
+.table > tbody > tr.success > td,
+.table > tfoot > tr.success > td,
+.table > thead > tr.success > th,
+.table > tbody > tr.success > th,
+.table > tfoot > tr.success > th {
+  background-color: #dff0d8;
+}
+.table-hover > tbody > tr > td.success:hover,
+.table-hover > tbody > tr > th.success:hover,
+.table-hover > tbody > tr.success:hover > td,
+.table-hover > tbody > tr:hover > .success,
+.table-hover > tbody > tr.success:hover > th {
+  background-color: #d0e9c6;
+}
+.table > thead > tr > td.info,
+.table > tbody > tr > td.info,
+.table > tfoot > tr > td.info,
+.table > thead > tr > th.info,
+.table > tbody > tr > th.info,
+.table > tfoot > tr > th.info,
+.table > thead > tr.info > td,
+.table > tbody > tr.info > td,
+.table > tfoot > tr.info > td,
+.table > thead > tr.info > th,
+.table > tbody > tr.info > th,
+.table > tfoot > tr.info > th {
+  background-color: #d9edf7;
+}
+.table-hover > tbody > tr > td.info:hover,
+.table-hover > tbody > tr > th.info:hover,
+.table-hover > tbody > tr.info:hover > td,
+.table-hover > tbody > tr:hover > .info,
+.table-hover > tbody > tr.info:hover > th {
+  background-color: #c4e3f3;
+}
+.table > thead > tr > td.warning,
+.table > tbody > tr > td.warning,
+.table > tfoot > tr > td.warning,
+.table > thead > tr > th.warning,
+.table > tbody > tr > th.warning,
+.table > tfoot > tr > th.warning,
+.table > thead > tr.warning > td,
+.table > tbody > tr.warning > td,
+.table > tfoot > tr.warning > td,
+.table > thead > tr.warning > th,
+.table > tbody > tr.warning > th,
+.table > tfoot > tr.warning > th {
+  background-color: #fcf8e3;
+}
+.table-hover > tbody > tr > td.warning:hover,
+.table-hover > tbody > tr > th.warning:hover,
+.table-hover > tbody > tr.warning:hover > td,
+.table-hover > tbody > tr:hover > .warning,
+.table-hover > tbody > tr.warning:hover > th {
+  background-color: #faf2cc;
+}
+.table > thead > tr > td.danger,
+.table > tbody > tr > td.danger,
+.table > tfoot > tr > td.danger,
+.table > thead > tr > th.danger,
+.table > tbody > tr > th.danger,
+.table > tfoot > tr > th.danger,
+.table > thead > tr.danger > td,
+.table > tbody > tr.danger > td,
+.table > tfoot > tr.danger > td,
+.table > thead > tr.danger > th,
+.table > tbody > tr.danger > th,
+.table > tfoot > tr.danger > th {
+  background-color: #f2dede;
+}
+.table-hover > tbody > tr > td.danger:hover,
+.table-hover > tbody > tr > th.danger:hover,
+.table-hover > tbody > tr.danger:hover > td,
+.table-hover > tbody > tr:hover > .danger,
+.table-hover > tbody > tr.danger:hover > th {
+  background-color: #ebcccc;
+}
+.table-responsive {
+  overflow-x: auto;
+  min-height: 0.01%;
+}
+@media screen and (max-width: 767px) {
+  .table-responsive {
+    width: 100%;
+    margin-bottom: 13.5px;
+    overflow-y: hidden;
+    -ms-overflow-style: -ms-autohiding-scrollbar;
+    border: 1px solid #ddd;
+  }
+  .table-responsive > .table {
+    margin-bottom: 0;
+  }
+  .table-responsive > .table > thead > tr > th,
+  .table-responsive > .table > tbody > tr > th,
+  .table-responsive > .table > tfoot > tr > th,
+  .table-responsive > .table > thead > tr > td,
+  .table-responsive > .table > tbody > tr > td,
+  .table-responsive > .table > tfoot > tr > td {
+    white-space: nowrap;
+  }
+  .table-responsive > .table-bordered {
+    border: 0;
+  }
+  .table-responsive > .table-bordered > thead > tr > th:first-child,
+  .table-responsive > .table-bordered > tbody > tr > th:first-child,
+  .table-responsive > .table-bordered > tfoot > tr > th:first-child,
+  .table-responsive > .table-bordered > thead > tr > td:first-child,
+  .table-responsive > .table-bordered > tbody > tr > td:first-child,
+  .table-responsive > .table-bordered > tfoot > tr > td:first-child {
+    border-left: 0;
+  }
+  .table-responsive > .table-bordered > thead > tr > th:last-child,
+  .table-responsive > .table-bordered > tbody > tr > th:last-child,
+  .table-responsive > .table-bordered > tfoot > tr > th:last-child,
+  .table-responsive > .table-bordered > thead > tr > td:last-child,
+  .table-responsive > .table-bordered > tbody > tr > td:last-child,
+  .table-responsive > .table-bordered > tfoot > tr > td:last-child {
+    border-right: 0;
+  }
+  .table-responsive > .table-bordered > tbody > tr:last-child > th,
+  .table-responsive > .table-bordered > tfoot > tr:last-child > th,
+  .table-responsive > .table-bordered > tbody > tr:last-child > td,
+  .table-responsive > .table-bordered > tfoot > tr:last-child > td {
+    border-bottom: 0;
+  }
+}
+fieldset {
+  padding: 0;
+  margin: 0;
+  border: 0;
+  min-width: 0;
+}
+legend {
+  display: block;
+  width: 100%;
+  padding: 0;
+  margin-bottom: 18px;
+  font-size: 19.5px;
+  line-height: inherit;
+  color: #333333;
+  border: 0;
+  border-bottom: 1px solid #e5e5e5;
+}
+label {
+  display: inline-block;
+  max-width: 100%;
+  margin-bottom: 5px;
+  font-weight: bold;
+}
+input[type="search"] {
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+}
+input[type="radio"],
+input[type="checkbox"] {
+  margin: 4px 0 0;
+  margin-top: 1px \9;
+  line-height: normal;
+}
+input[type="file"] {
+  display: block;
+}
+input[type="range"] {
+  display: block;
+  width: 100%;
+}
+select[multiple],
+select[size] {
+  height: auto;
+}
+input[type="file"]:focus,
+input[type="radio"]:focus,
+input[type="checkbox"]:focus {
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+output {
+  display: block;
+  padding-top: 7px;
+  font-size: 13px;
+  line-height: 1.42857143;
+  color: #555555;
+}
+.form-control {
+  display: block;
+  width: 100%;
+  height: 32px;
+  padding: 6px 12px;
+  font-size: 13px;
+  line-height: 1.42857143;
+  color: #555555;
+  background-color: #fff;
+  background-image: none;
+  border: 1px solid #ccc;
+  border-radius: 2px;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+  -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+  transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+}
+.form-control:focus {
+  border-color: #66afe9;
+  outline: 0;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
+  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
+}
+.form-control::-moz-placeholder {
+  color: #999;
+  opacity: 1;
+}
+.form-control:-ms-input-placeholder {
+  color: #999;
+}
+.form-control::-webkit-input-placeholder {
+  color: #999;
+}
+.form-control::-ms-expand {
+  border: 0;
+  background-color: transparent;
+}
+.form-control[disabled],
+.form-control[readonly],
+fieldset[disabled] .form-control {
+  background-color: #eeeeee;
+  opacity: 1;
+}
+.form-control[disabled],
+fieldset[disabled] .form-control {
+  cursor: not-allowed;
+}
+textarea.form-control {
+  height: auto;
+}
+input[type="search"] {
+  -webkit-appearance: none;
+}
+@media screen and (-webkit-min-device-pixel-ratio: 0) {
+  input[type="date"].form-control,
+  input[type="time"].form-control,
+  input[type="datetime-local"].form-control,
+  input[type="month"].form-control {
+    line-height: 32px;
+  }
+  input[type="date"].input-sm,
+  input[type="time"].input-sm,
+  input[type="datetime-local"].input-sm,
+  input[type="month"].input-sm,
+  .input-group-sm input[type="date"],
+  .input-group-sm input[type="time"],
+  .input-group-sm input[type="datetime-local"],
+  .input-group-sm input[type="month"] {
+    line-height: 30px;
+  }
+  input[type="date"].input-lg,
+  input[type="time"].input-lg,
+  input[type="datetime-local"].input-lg,
+  input[type="month"].input-lg,
+  .input-group-lg input[type="date"],
+  .input-group-lg input[type="time"],
+  .input-group-lg input[type="datetime-local"],
+  .input-group-lg input[type="month"] {
+    line-height: 45px;
+  }
+}
+.form-group {
+  margin-bottom: 15px;
+}
+.radio,
+.checkbox {
+  position: relative;
+  display: block;
+  margin-top: 10px;
+  margin-bottom: 10px;
+}
+.radio label,
+.checkbox label {
+  min-height: 18px;
+  padding-left: 20px;
+  margin-bottom: 0;
+  font-weight: normal;
+  cursor: pointer;
+}
+.radio input[type="radio"],
+.radio-inline input[type="radio"],
+.checkbox input[type="checkbox"],
+.checkbox-inline input[type="checkbox"] {
+  position: absolute;
+  margin-left: -20px;
+  margin-top: 4px \9;
+}
+.radio + .radio,
+.checkbox + .checkbox {
+  margin-top: -5px;
+}
+.radio-inline,
+.checkbox-inline {
+  position: relative;
+  display: inline-block;
+  padding-left: 20px;
+  margin-bottom: 0;
+  vertical-align: middle;
+  font-weight: normal;
+  cursor: pointer;
+}
+.radio-inline + .radio-inline,
+.checkbox-inline + .checkbox-inline {
+  margin-top: 0;
+  margin-left: 10px;
+}
+input[type="radio"][disabled],
+input[type="checkbox"][disabled],
+input[type="radio"].disabled,
+input[type="checkbox"].disabled,
+fieldset[disabled] input[type="radio"],
+fieldset[disabled] input[type="checkbox"] {
+  cursor: not-allowed;
+}
+.radio-inline.disabled,
+.checkbox-inline.disabled,
+fieldset[disabled] .radio-inline,
+fieldset[disabled] .checkbox-inline {
+  cursor: not-allowed;
+}
+.radio.disabled label,
+.checkbox.disabled label,
+fieldset[disabled] .radio label,
+fieldset[disabled] .checkbox label {
+  cursor: not-allowed;
+}
+.form-control-static {
+  padding-top: 7px;
+  padding-bottom: 7px;
+  margin-bottom: 0;
+  min-height: 31px;
+}
+.form-control-static.input-lg,
+.form-control-static.input-sm {
+  padding-left: 0;
+  padding-right: 0;
+}
+.input-sm {
+  height: 30px;
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 1px;
+}
+select.input-sm {
+  height: 30px;
+  line-height: 30px;
+}
+textarea.input-sm,
+select[multiple].input-sm {
+  height: auto;
+}
+.form-group-sm .form-control {
+  height: 30px;
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 1px;
+}
+.form-group-sm select.form-control {
+  height: 30px;
+  line-height: 30px;
+}
+.form-group-sm textarea.form-control,
+.form-group-sm select[multiple].form-control {
+  height: auto;
+}
+.form-group-sm .form-control-static {
+  height: 30px;
+  min-height: 30px;
+  padding: 6px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+}
+.input-lg {
+  height: 45px;
+  padding: 10px 16px;
+  font-size: 17px;
+  line-height: 1.3333333;
+  border-radius: 3px;
+}
+select.input-lg {
+  height: 45px;
+  line-height: 45px;
+}
+textarea.input-lg,
+select[multiple].input-lg {
+  height: auto;
+}
+.form-group-lg .form-control {
+  height: 45px;
+  padding: 10px 16px;
+  font-size: 17px;
+  line-height: 1.3333333;
+  border-radius: 3px;
+}
+.form-group-lg select.form-control {
+  height: 45px;
+  line-height: 45px;
+}
+.form-group-lg textarea.form-control,
+.form-group-lg select[multiple].form-control {
+  height: auto;
+}
+.form-group-lg .form-control-static {
+  height: 45px;
+  min-height: 35px;
+  padding: 11px 16px;
+  font-size: 17px;
+  line-height: 1.3333333;
+}
+.has-feedback {
+  position: relative;
+}
+.has-feedback .form-control {
+  padding-right: 40px;
+}
+.form-control-feedback {
+  position: absolute;
+  top: 0;
+  right: 0;
+  z-index: 2;
+  display: block;
+  width: 32px;
+  height: 32px;
+  line-height: 32px;
+  text-align: center;
+  pointer-events: none;
+}
+.input-lg + .form-control-feedback,
+.input-group-lg + .form-control-feedback,
+.form-group-lg .form-control + .form-control-feedback {
+  width: 45px;
+  height: 45px;
+  line-height: 45px;
+}
+.input-sm + .form-control-feedback,
+.input-group-sm + .form-control-feedback,
+.form-group-sm .form-control + .form-control-feedback {
+  width: 30px;
+  height: 30px;
+  line-height: 30px;
+}
+.has-success .help-block,
+.has-success .control-label,
+.has-success .radio,
+.has-success .checkbox,
+.has-success .radio-inline,
+.has-success .checkbox-inline,
+.has-success.radio label,
+.has-success.checkbox label,
+.has-success.radio-inline label,
+.has-success.checkbox-inline label {
+  color: #3c763d;
+}
+.has-success .form-control {
+  border-color: #3c763d;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+}
+.has-success .form-control:focus {
+  border-color: #2b542c;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
+}
+.has-success .input-group-addon {
+  color: #3c763d;
+  border-color: #3c763d;
+  background-color: #dff0d8;
+}
+.has-success .form-control-feedback {
+  color: #3c763d;
+}
+.has-warning .help-block,
+.has-warning .control-label,
+.has-warning .radio,
+.has-warning .checkbox,
+.has-warning .radio-inline,
+.has-warning .checkbox-inline,
+.has-warning.radio label,
+.has-warning.checkbox label,
+.has-warning.radio-inline label,
+.has-warning.checkbox-inline label {
+  color: #8a6d3b;
+}
+.has-warning .form-control {
+  border-color: #8a6d3b;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+}
+.has-warning .form-control:focus {
+  border-color: #66512c;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;
+}
+.has-warning .input-group-addon {
+  color: #8a6d3b;
+  border-color: #8a6d3b;
+  background-color: #fcf8e3;
+}
+.has-warning .form-control-feedback {
+  color: #8a6d3b;
+}
+.has-error .help-block,
+.has-error .control-label,
+.has-error .radio,
+.has-error .checkbox,
+.has-error .radio-inline,
+.has-error .checkbox-inline,
+.has-error.radio label,
+.has-error.checkbox label,
+.has-error.radio-inline label,
+.has-error.checkbox-inline label {
+  color: #a94442;
+}
+.has-error .form-control {
+  border-color: #a94442;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+}
+.has-error .form-control:focus {
+  border-color: #843534;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
+}
+.has-error .input-group-addon {
+  color: #a94442;
+  border-color: #a94442;
+  background-color: #f2dede;
+}
+.has-error .form-control-feedback {
+  color: #a94442;
+}
+.has-feedback label ~ .form-control-feedback {
+  top: 23px;
+}
+.has-feedback label.sr-only ~ .form-control-feedback {
+  top: 0;
+}
+.help-block {
+  display: block;
+  margin-top: 5px;
+  margin-bottom: 10px;
+  color: #404040;
+}
+@media (min-width: 768px) {
+  .form-inline .form-group {
+    display: inline-block;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .form-inline .form-control {
+    display: inline-block;
+    width: auto;
+    vertical-align: middle;
+  }
+  .form-inline .form-control-static {
+    display: inline-block;
+  }
+  .form-inline .input-group {
+    display: inline-table;
+    vertical-align: middle;
+  }
+  .form-inline .input-group .input-group-addon,
+  .form-inline .input-group .input-group-btn,
+  .form-inline .input-group .form-control {
+    width: auto;
+  }
+  .form-inline .input-group > .form-control {
+    width: 100%;
+  }
+  .form-inline .control-label {
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .form-inline .radio,
+  .form-inline .checkbox {
+    display: inline-block;
+    margin-top: 0;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .form-inline .radio label,
+  .form-inline .checkbox label {
+    padding-left: 0;
+  }
+  .form-inline .radio input[type="radio"],
+  .form-inline .checkbox input[type="checkbox"] {
+    position: relative;
+    margin-left: 0;
+  }
+  .form-inline .has-feedback .form-control-feedback {
+    top: 0;
+  }
+}
+.form-horizontal .radio,
+.form-horizontal .checkbox,
+.form-horizontal .radio-inline,
+.form-horizontal .checkbox-inline {
+  margin-top: 0;
+  margin-bottom: 0;
+  padding-top: 7px;
+}
+.form-horizontal .radio,
+.form-horizontal .checkbox {
+  min-height: 25px;
+}
+.form-horizontal .form-group {
+  margin-left: 0px;
+  margin-right: 0px;
+}
+@media (min-width: 768px) {
+  .form-horizontal .control-label {
+    text-align: right;
+    margin-bottom: 0;
+    padding-top: 7px;
+  }
+}
+.form-horizontal .has-feedback .form-control-feedback {
+  right: 0px;
+}
+@media (min-width: 768px) {
+  .form-horizontal .form-group-lg .control-label {
+    padding-top: 11px;
+    font-size: 17px;
+  }
+}
+@media (min-width: 768px) {
+  .form-horizontal .form-group-sm .control-label {
+    padding-top: 6px;
+    font-size: 12px;
+  }
+}
+.btn {
+  display: inline-block;
+  margin-bottom: 0;
+  font-weight: normal;
+  text-align: center;
+  vertical-align: middle;
+  touch-action: manipulation;
+  cursor: pointer;
+  background-image: none;
+  border: 1px solid transparent;
+  white-space: nowrap;
+  padding: 6px 12px;
+  font-size: 13px;
+  line-height: 1.42857143;
+  border-radius: 2px;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+}
+.btn:focus,
+.btn:active:focus,
+.btn.active:focus,
+.btn.focus,
+.btn:active.focus,
+.btn.active.focus {
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+.btn:hover,
+.btn:focus,
+.btn.focus {
+  color: #333;
+  text-decoration: none;
+}
+.btn:active,
+.btn.active {
+  outline: 0;
+  background-image: none;
+  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+}
+.btn.disabled,
+.btn[disabled],
+fieldset[disabled] .btn {
+  cursor: not-allowed;
+  opacity: 0.65;
+  filter: alpha(opacity=65);
+  -webkit-box-shadow: none;
+  box-shadow: none;
+}
+a.btn.disabled,
+fieldset[disabled] a.btn {
+  pointer-events: none;
+}
+.btn-default {
+  color: #333;
+  background-color: #fff;
+  border-color: #ccc;
+}
+.btn-default:focus,
+.btn-default.focus {
+  color: #333;
+  background-color: #e6e6e6;
+  border-color: #8c8c8c;
+}
+.btn-default:hover {
+  color: #333;
+  background-color: #e6e6e6;
+  border-color: #adadad;
+}
+.btn-default:active,
+.btn-default.active,
+.open > .dropdown-toggle.btn-default {
+  color: #333;
+  background-color: #e6e6e6;
+  border-color: #adadad;
+}
+.btn-default:active:hover,
+.btn-default.active:hover,
+.open > .dropdown-toggle.btn-default:hover,
+.btn-default:active:focus,
+.btn-default.active:focus,
+.open > .dropdown-toggle.btn-default:focus,
+.btn-default:active.focus,
+.btn-default.active.focus,
+.open > .dropdown-toggle.btn-default.focus {
+  color: #333;
+  background-color: #d4d4d4;
+  border-color: #8c8c8c;
+}
+.btn-default:active,
+.btn-default.active,
+.open > .dropdown-toggle.btn-default {
+  background-image: none;
+}
+.btn-default.disabled:hover,
+.btn-default[disabled]:hover,
+fieldset[disabled] .btn-default:hover,
+.btn-default.disabled:focus,
+.btn-default[disabled]:focus,
+fieldset[disabled] .btn-default:focus,
+.btn-default.disabled.focus,
+.btn-default[disabled].focus,
+fieldset[disabled] .btn-default.focus {
+  background-color: #fff;
+  border-color: #ccc;
+}
+.btn-default .badge {
+  color: #fff;
+  background-color: #333;
+}
+.btn-primary {
+  color: #fff;
+  background-color: #337ab7;
+  border-color: #2e6da4;
+}
+.btn-primary:focus,
+.btn-primary.focus {
+  color: #fff;
+  background-color: #286090;
+  border-color: #122b40;
+}
+.btn-primary:hover {
+  color: #fff;
+  background-color: #286090;
+  border-color: #204d74;
+}
+.btn-primary:active,
+.btn-primary.active,
+.open > .dropdown-toggle.btn-primary {
+  color: #fff;
+  background-color: #286090;
+  border-color: #204d74;
+}
+.btn-primary:active:hover,
+.btn-primary.active:hover,
+.open > .dropdown-toggle.btn-primary:hover,
+.btn-primary:active:focus,
+.btn-primary.active:focus,
+.open > .dropdown-toggle.btn-primary:focus,
+.btn-primary:active.focus,
+.btn-primary.active.focus,
+.open > .dropdown-toggle.btn-primary.focus {
+  color: #fff;
+  background-color: #204d74;
+  border-color: #122b40;
+}
+.btn-primary:active,
+.btn-primary.active,
+.open > .dropdown-toggle.btn-primary {
+  background-image: none;
+}
+.btn-primary.disabled:hover,
+.btn-primary[disabled]:hover,
+fieldset[disabled] .btn-primary:hover,
+.btn-primary.disabled:focus,
+.btn-primary[disabled]:focus,
+fieldset[disabled] .btn-primary:focus,
+.btn-primary.disabled.focus,
+.btn-primary[disabled].focus,
+fieldset[disabled] .btn-primary.focus {
+  background-color: #337ab7;
+  border-color: #2e6da4;
+}
+.btn-primary .badge {
+  color: #337ab7;
+  background-color: #fff;
+}
+.btn-success {
+  color: #fff;
+  background-color: #5cb85c;
+  border-color: #4cae4c;
+}
+.btn-success:focus,
+.btn-success.focus {
+  color: #fff;
+  background-color: #449d44;
+  border-color: #255625;
+}
+.btn-success:hover {
+  color: #fff;
+  background-color: #449d44;
+  border-color: #398439;
+}
+.btn-success:active,
+.btn-success.active,
+.open > .dropdown-toggle.btn-success {
+  color: #fff;
+  background-color: #449d44;
+  border-color: #398439;
+}
+.btn-success:active:hover,
+.btn-success.active:hover,
+.open > .dropdown-toggle.btn-success:hover,
+.btn-success:active:focus,
+.btn-success.active:focus,
+.open > .dropdown-toggle.btn-success:focus,
+.btn-success:active.focus,
+.btn-success.active.focus,
+.open > .dropdown-toggle.btn-success.focus {
+  color: #fff;
+  background-color: #398439;
+  border-color: #255625;
+}
+.btn-success:active,
+.btn-success.active,
+.open > .dropdown-toggle.btn-success {
+  background-image: none;
+}
+.btn-success.disabled:hover,
+.btn-success[disabled]:hover,
+fieldset[disabled] .btn-success:hover,
+.btn-success.disabled:focus,
+.btn-success[disabled]:focus,
+fieldset[disabled] .btn-success:focus,
+.btn-success.disabled.focus,
+.btn-success[disabled].focus,
+fieldset[disabled] .btn-success.focus {
+  background-color: #5cb85c;
+  border-color: #4cae4c;
+}
+.btn-success .badge {
+  color: #5cb85c;
+  background-color: #fff;
+}
+.btn-info {
+  color: #fff;
+  background-color: #5bc0de;
+  border-color: #46b8da;
+}
+.btn-info:focus,
+.btn-info.focus {
+  color: #fff;
+  background-color: #31b0d5;
+  border-color: #1b6d85;
+}
+.btn-info:hover {
+  color: #fff;
+  background-color: #31b0d5;
+  border-color: #269abc;
+}
+.btn-info:active,
+.btn-info.active,
+.open > .dropdown-toggle.btn-info {
+  color: #fff;
+  background-color: #31b0d5;
+  border-color: #269abc;
+}
+.btn-info:active:hover,
+.btn-info.active:hover,
+.open > .dropdown-toggle.btn-info:hover,
+.btn-info:active:focus,
+.btn-info.active:focus,
+.open > .dropdown-toggle.btn-info:focus,
+.btn-info:active.focus,
+.btn-info.active.focus,
+.open > .dropdown-toggle.btn-info.focus {
+  color: #fff;
+  background-color: #269abc;
+  border-color: #1b6d85;
+}
+.btn-info:active,
+.btn-info.active,
+.open > .dropdown-toggle.btn-info {
+  background-image: none;
+}
+.btn-info.disabled:hover,
+.btn-info[disabled]:hover,
+fieldset[disabled] .btn-info:hover,
+.btn-info.disabled:focus,
+.btn-info[disabled]:focus,
+fieldset[disabled] .btn-info:focus,
+.btn-info.disabled.focus,
+.btn-info[disabled].focus,
+fieldset[disabled] .btn-info.focus {
+  background-color: #5bc0de;
+  border-color: #46b8da;
+}
+.btn-info .badge {
+  color: #5bc0de;
+  background-color: #fff;
+}
+.btn-warning {
+  color: #fff;
+  background-color: #f0ad4e;
+  border-color: #eea236;
+}
+.btn-warning:focus,
+.btn-warning.focus {
+  color: #fff;
+  background-color: #ec971f;
+  border-color: #985f0d;
+}
+.btn-warning:hover {
+  color: #fff;
+  background-color: #ec971f;
+  border-color: #d58512;
+}
+.btn-warning:active,
+.btn-warning.active,
+.open > .dropdown-toggle.btn-warning {
+  color: #fff;
+  background-color: #ec971f;
+  border-color: #d58512;
+}
+.btn-warning:active:hover,
+.btn-warning.active:hover,
+.open > .dropdown-toggle.btn-warning:hover,
+.btn-warning:active:focus,
+.btn-warning.active:focus,
+.open > .dropdown-toggle.btn-warning:focus,
+.btn-warning:active.focus,
+.btn-warning.active.focus,
+.open > .dropdown-toggle.btn-warning.focus {
+  color: #fff;
+  background-color: #d58512;
+  border-color: #985f0d;
+}
+.btn-warning:active,
+.btn-warning.active,
+.open > .dropdown-toggle.btn-warning {
+  background-image: none;
+}
+.btn-warning.disabled:hover,
+.btn-warning[disabled]:hover,
+fieldset[disabled] .btn-warning:hover,
+.btn-warning.disabled:focus,
+.btn-warning[disabled]:focus,
+fieldset[disabled] .btn-warning:focus,
+.btn-warning.disabled.focus,
+.btn-warning[disabled].focus,
+fieldset[disabled] .btn-warning.focus {
+  background-color: #f0ad4e;
+  border-color: #eea236;
+}
+.btn-warning .badge {
+  color: #f0ad4e;
+  background-color: #fff;
+}
+.btn-danger {
+  color: #fff;
+  background-color: #d9534f;
+  border-color: #d43f3a;
+}
+.btn-danger:focus,
+.btn-danger.focus {
+  color: #fff;
+  background-color: #c9302c;
+  border-color: #761c19;
+}
+.btn-danger:hover {
+  color: #fff;
+  background-color: #c9302c;
+  border-color: #ac2925;
+}
+.btn-danger:active,
+.btn-danger.active,
+.open > .dropdown-toggle.btn-danger {
+  color: #fff;
+  background-color: #c9302c;
+  border-color: #ac2925;
+}
+.btn-danger:active:hover,
+.btn-danger.active:hover,
+.open > .dropdown-toggle.btn-danger:hover,
+.btn-danger:active:focus,
+.btn-danger.active:focus,
+.open > .dropdown-toggle.btn-danger:focus,
+.btn-danger:active.focus,
+.btn-danger.active.focus,
+.open > .dropdown-toggle.btn-danger.focus {
+  color: #fff;
+  background-color: #ac2925;
+  border-color: #761c19;
+}
+.btn-danger:active,
+.btn-danger.active,
+.open > .dropdown-toggle.btn-danger {
+  background-image: none;
+}
+.btn-danger.disabled:hover,
+.btn-danger[disabled]:hover,
+fieldset[disabled] .btn-danger:hover,
+.btn-danger.disabled:focus,
+.btn-danger[disabled]:focus,
+fieldset[disabled] .btn-danger:focus,
+.btn-danger.disabled.focus,
+.btn-danger[disabled].focus,
+fieldset[disabled] .btn-danger.focus {
+  background-color: #d9534f;
+  border-color: #d43f3a;
+}
+.btn-danger .badge {
+  color: #d9534f;
+  background-color: #fff;
+}
+.btn-link {
+  color: #337ab7;
+  font-weight: normal;
+  border-radius: 0;
+}
+.btn-link,
+.btn-link:active,
+.btn-link.active,
+.btn-link[disabled],
+fieldset[disabled] .btn-link {
+  background-color: transparent;
+  -webkit-box-shadow: none;
+  box-shadow: none;
+}
+.btn-link,
+.btn-link:hover,
+.btn-link:focus,
+.btn-link:active {
+  border-color: transparent;
+}
+.btn-link:hover,
+.btn-link:focus {
+  color: #23527c;
+  text-decoration: underline;
+  background-color: transparent;
+}
+.btn-link[disabled]:hover,
+fieldset[disabled] .btn-link:hover,
+.btn-link[disabled]:focus,
+fieldset[disabled] .btn-link:focus {
+  color: #777777;
+  text-decoration: none;
+}
+.btn-lg,
+.btn-group-lg > .btn {
+  padding: 10px 16px;
+  font-size: 17px;
+  line-height: 1.3333333;
+  border-radius: 3px;
+}
+.btn-sm,
+.btn-group-sm > .btn {
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 1px;
+}
+.btn-xs,
+.btn-group-xs > .btn {
+  padding: 1px 5px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 1px;
+}
+.btn-block {
+  display: block;
+  width: 100%;
+}
+.btn-block + .btn-block {
+  margin-top: 5px;
+}
+input[type="submit"].btn-block,
+input[type="reset"].btn-block,
+input[type="button"].btn-block {
+  width: 100%;
+}
+.fade {
+  opacity: 0;
+  -webkit-transition: opacity 0.15s linear;
+  -o-transition: opacity 0.15s linear;
+  transition: opacity 0.15s linear;
+}
+.fade.in {
+  opacity: 1;
+}
+.collapse {
+  display: none;
+}
+.collapse.in {
+  display: block;
+}
+tr.collapse.in {
+  display: table-row;
+}
+tbody.collapse.in {
+  display: table-row-group;
+}
+.collapsing {
+  position: relative;
+  height: 0;
+  overflow: hidden;
+  -webkit-transition-property: height, visibility;
+  transition-property: height, visibility;
+  -webkit-transition-duration: 0.35s;
+  transition-duration: 0.35s;
+  -webkit-transition-timing-function: ease;
+  transition-timing-function: ease;
+}
+.caret {
+  display: inline-block;
+  width: 0;
+  height: 0;
+  margin-left: 2px;
+  vertical-align: middle;
+  border-top: 4px dashed;
+  border-top: 4px solid \9;
+  border-right: 4px solid transparent;
+  border-left: 4px solid transparent;
+}
+.dropup,
+.dropdown {
+  position: relative;
+}
+.dropdown-toggle:focus {
+  outline: 0;
+}
+.dropdown-menu {
+  position: absolute;
+  top: 100%;
+  left: 0;
+  z-index: 1000;
+  display: none;
+  float: left;
+  min-width: 160px;
+  padding: 5px 0;
+  margin: 2px 0 0;
+  list-style: none;
+  font-size: 13px;
+  text-align: left;
+  background-color: #fff;
+  border: 1px solid #ccc;
+  border: 1px solid rgba(0, 0, 0, 0.15);
+  border-radius: 2px;
+  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+  background-clip: padding-box;
+}
+.dropdown-menu.pull-right {
+  right: 0;
+  left: auto;
+}
+.dropdown-menu .divider {
+  height: 1px;
+  margin: 8px 0;
+  overflow: hidden;
+  background-color: #e5e5e5;
+}
+.dropdown-menu > li > a {
+  display: block;
+  padding: 3px 20px;
+  clear: both;
+  font-weight: normal;
+  line-height: 1.42857143;
+  color: #333333;
+  white-space: nowrap;
+}
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus {
+  text-decoration: none;
+  color: #262626;
+  background-color: #f5f5f5;
+}
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+  color: #fff;
+  text-decoration: none;
+  outline: 0;
+  background-color: #337ab7;
+}
+.dropdown-menu > .disabled > a,
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+  color: #777777;
+}
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+  text-decoration: none;
+  background-color: transparent;
+  background-image: none;
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  cursor: not-allowed;
+}
+.open > .dropdown-menu {
+  display: block;
+}
+.open > a {
+  outline: 0;
+}
+.dropdown-menu-right {
+  left: auto;
+  right: 0;
+}
+.dropdown-menu-left {
+  left: 0;
+  right: auto;
+}
+.dropdown-header {
+  display: block;
+  padding: 3px 20px;
+  font-size: 12px;
+  line-height: 1.42857143;
+  color: #777777;
+  white-space: nowrap;
+}
+.dropdown-backdrop {
+  position: fixed;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  top: 0;
+  z-index: 990;
+}
+.pull-right > .dropdown-menu {
+  right: 0;
+  left: auto;
+}
+.dropup .caret,
+.navbar-fixed-bottom .dropdown .caret {
+  border-top: 0;
+  border-bottom: 4px dashed;
+  border-bottom: 4px solid \9;
+  content: "";
+}
+.dropup .dropdown-menu,
+.navbar-fixed-bottom .dropdown .dropdown-menu {
+  top: auto;
+  bottom: 100%;
+  margin-bottom: 2px;
+}
+@media (min-width: 541px) {
+  .navbar-right .dropdown-menu {
+    left: auto;
+    right: 0;
+  }
+  .navbar-right .dropdown-menu-left {
+    left: 0;
+    right: auto;
+  }
+}
+.btn-group,
+.btn-group-vertical {
+  position: relative;
+  display: inline-block;
+  vertical-align: middle;
+}
+.btn-group > .btn,
+.btn-group-vertical > .btn {
+  position: relative;
+  float: left;
+}
+.btn-group > .btn:hover,
+.btn-group-vertical > .btn:hover,
+.btn-group > .btn:focus,
+.btn-group-vertical > .btn:focus,
+.btn-group > .btn:active,
+.btn-group-vertical > .btn:active,
+.btn-group > .btn.active,
+.btn-group-vertical > .btn.active {
+  z-index: 2;
+}
+.btn-group .btn + .btn,
+.btn-group .btn + .btn-group,
+.btn-group .btn-group + .btn,
+.btn-group .btn-group + .btn-group {
+  margin-left: -1px;
+}
+.btn-toolbar {
+  margin-left: -5px;
+}
+.btn-toolbar .btn,
+.btn-toolbar .btn-group,
+.btn-toolbar .input-group {
+  float: left;
+}
+.btn-toolbar > .btn,
+.btn-toolbar > .btn-group,
+.btn-toolbar > .input-group {
+  margin-left: 5px;
+}
+.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {
+  border-radius: 0;
+}
+.btn-group > .btn:first-child {
+  margin-left: 0;
+}
+.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {
+  border-bottom-right-radius: 0;
+  border-top-right-radius: 0;
+}
+.btn-group > .btn:last-child:not(:first-child),
+.btn-group > .dropdown-toggle:not(:first-child) {
+  border-bottom-left-radius: 0;
+  border-top-left-radius: 0;
+}
+.btn-group > .btn-group {
+  float: left;
+}
+.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {
+  border-radius: 0;
+}
+.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,
+.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
+  border-bottom-right-radius: 0;
+  border-top-right-radius: 0;
+}
+.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {
+  border-bottom-left-radius: 0;
+  border-top-left-radius: 0;
+}
+.btn-group .dropdown-toggle:active,
+.btn-group.open .dropdown-toggle {
+  outline: 0;
+}
+.btn-group > .btn + .dropdown-toggle {
+  padding-left: 8px;
+  padding-right: 8px;
+}
+.btn-group > .btn-lg + .dropdown-toggle {
+  padding-left: 12px;
+  padding-right: 12px;
+}
+.btn-group.open .dropdown-toggle {
+  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+}
+.btn-group.open .dropdown-toggle.btn-link {
+  -webkit-box-shadow: none;
+  box-shadow: none;
+}
+.btn .caret {
+  margin-left: 0;
+}
+.btn-lg .caret {
+  border-width: 5px 5px 0;
+  border-bottom-width: 0;
+}
+.dropup .btn-lg .caret {
+  border-width: 0 5px 5px;
+}
+.btn-group-vertical > .btn,
+.btn-group-vertical > .btn-group,
+.btn-group-vertical > .btn-group > .btn {
+  display: block;
+  float: none;
+  width: 100%;
+  max-width: 100%;
+}
+.btn-group-vertical > .btn-group > .btn {
+  float: none;
+}
+.btn-group-vertical > .btn + .btn,
+.btn-group-vertical > .btn + .btn-group,
+.btn-group-vertical > .btn-group + .btn,
+.btn-group-vertical > .btn-group + .btn-group {
+  margin-top: -1px;
+  margin-left: 0;
+}
+.btn-group-vertical > .btn:not(:first-child):not(:last-child) {
+  border-radius: 0;
+}
+.btn-group-vertical > .btn:first-child:not(:last-child) {
+  border-top-right-radius: 2px;
+  border-top-left-radius: 2px;
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.btn-group-vertical > .btn:last-child:not(:first-child) {
+  border-top-right-radius: 0;
+  border-top-left-radius: 0;
+  border-bottom-right-radius: 2px;
+  border-bottom-left-radius: 2px;
+}
+.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {
+  border-radius: 0;
+}
+.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,
+.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {
+  border-top-right-radius: 0;
+  border-top-left-radius: 0;
+}
+.btn-group-justified {
+  display: table;
+  width: 100%;
+  table-layout: fixed;
+  border-collapse: separate;
+}
+.btn-group-justified > .btn,
+.btn-group-justified > .btn-group {
+  float: none;
+  display: table-cell;
+  width: 1%;
+}
+.btn-group-justified > .btn-group .btn {
+  width: 100%;
+}
+.btn-group-justified > .btn-group .dropdown-menu {
+  left: auto;
+}
+[data-toggle="buttons"] > .btn input[type="radio"],
+[data-toggle="buttons"] > .btn-group > .btn input[type="radio"],
+[data-toggle="buttons"] > .btn input[type="checkbox"],
+[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] {
+  position: absolute;
+  clip: rect(0, 0, 0, 0);
+  pointer-events: none;
+}
+.input-group {
+  position: relative;
+  display: table;
+  border-collapse: separate;
+}
+.input-group[class*="col-"] {
+  float: none;
+  padding-left: 0;
+  padding-right: 0;
+}
+.input-group .form-control {
+  position: relative;
+  z-index: 2;
+  float: left;
+  width: 100%;
+  margin-bottom: 0;
+}
+.input-group .form-control:focus {
+  z-index: 3;
+}
+.input-group-lg > .form-control,
+.input-group-lg > .input-group-addon,
+.input-group-lg > .input-group-btn > .btn {
+  height: 45px;
+  padding: 10px 16px;
+  font-size: 17px;
+  line-height: 1.3333333;
+  border-radius: 3px;
+}
+select.input-group-lg > .form-control,
+select.input-group-lg > .input-group-addon,
+select.input-group-lg > .input-group-btn > .btn {
+  height: 45px;
+  line-height: 45px;
+}
+textarea.input-group-lg > .form-control,
+textarea.input-group-lg > .input-group-addon,
+textarea.input-group-lg > .input-group-btn > .btn,
+select[multiple].input-group-lg > .form-control,
+select[multiple].input-group-lg > .input-group-addon,
+select[multiple].input-group-lg > .input-group-btn > .btn {
+  height: auto;
+}
+.input-group-sm > .form-control,
+.input-group-sm > .input-group-addon,
+.input-group-sm > .input-group-btn > .btn {
+  height: 30px;
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 1px;
+}
+select.input-group-sm > .form-control,
+select.input-group-sm > .input-group-addon,
+select.input-group-sm > .input-group-btn > .btn {
+  height: 30px;
+  line-height: 30px;
+}
+textarea.input-group-sm > .form-control,
+textarea.input-group-sm > .input-group-addon,
+textarea.input-group-sm > .input-group-btn > .btn,
+select[multiple].input-group-sm > .form-control,
+select[multiple].input-group-sm > .input-group-addon,
+select[multiple].input-group-sm > .input-group-btn > .btn {
+  height: auto;
+}
+.input-group-addon,
+.input-group-btn,
+.input-group .form-control {
+  display: table-cell;
+}
+.input-group-addon:not(:first-child):not(:last-child),
+.input-group-btn:not(:first-child):not(:last-child),
+.input-group .form-control:not(:first-child):not(:last-child) {
+  border-radius: 0;
+}
+.input-group-addon,
+.input-group-btn {
+  width: 1%;
+  white-space: nowrap;
+  vertical-align: middle;
+}
+.input-group-addon {
+  padding: 6px 12px;
+  font-size: 13px;
+  font-weight: normal;
+  line-height: 1;
+  color: #555555;
+  text-align: center;
+  background-color: #eeeeee;
+  border: 1px solid #ccc;
+  border-radius: 2px;
+}
+.input-group-addon.input-sm {
+  padding: 5px 10px;
+  font-size: 12px;
+  border-radius: 1px;
+}
+.input-group-addon.input-lg {
+  padding: 10px 16px;
+  font-size: 17px;
+  border-radius: 3px;
+}
+.input-group-addon input[type="radio"],
+.input-group-addon input[type="checkbox"] {
+  margin-top: 0;
+}
+.input-group .form-control:first-child,
+.input-group-addon:first-child,
+.input-group-btn:first-child > .btn,
+.input-group-btn:first-child > .btn-group > .btn,
+.input-group-btn:first-child > .dropdown-toggle,
+.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),
+.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {
+  border-bottom-right-radius: 0;
+  border-top-right-radius: 0;
+}
+.input-group-addon:first-child {
+  border-right: 0;
+}
+.input-group .form-control:last-child,
+.input-group-addon:last-child,
+.input-group-btn:last-child > .btn,
+.input-group-btn:last-child > .btn-group > .btn,
+.input-group-btn:last-child > .dropdown-toggle,
+.input-group-btn:first-child > .btn:not(:first-child),
+.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {
+  border-bottom-left-radius: 0;
+  border-top-left-radius: 0;
+}
+.input-group-addon:last-child {
+  border-left: 0;
+}
+.input-group-btn {
+  position: relative;
+  font-size: 0;
+  white-space: nowrap;
+}
+.input-group-btn > .btn {
+  position: relative;
+}
+.input-group-btn > .btn + .btn {
+  margin-left: -1px;
+}
+.input-group-btn > .btn:hover,
+.input-group-btn > .btn:focus,
+.input-group-btn > .btn:active {
+  z-index: 2;
+}
+.input-group-btn:first-child > .btn,
+.input-group-btn:first-child > .btn-group {
+  margin-right: -1px;
+}
+.input-group-btn:last-child > .btn,
+.input-group-btn:last-child > .btn-group {
+  z-index: 2;
+  margin-left: -1px;
+}
+.nav {
+  margin-bottom: 0;
+  padding-left: 0;
+  list-style: none;
+}
+.nav > li {
+  position: relative;
+  display: block;
+}
+.nav > li > a {
+  position: relative;
+  display: block;
+  padding: 10px 15px;
+}
+.nav > li > a:hover,
+.nav > li > a:focus {
+  text-decoration: none;
+  background-color: #eeeeee;
+}
+.nav > li.disabled > a {
+  color: #777777;
+}
+.nav > li.disabled > a:hover,
+.nav > li.disabled > a:focus {
+  color: #777777;
+  text-decoration: none;
+  background-color: transparent;
+  cursor: not-allowed;
+}
+.nav .open > a,
+.nav .open > a:hover,
+.nav .open > a:focus {
+  background-color: #eeeeee;
+  border-color: #337ab7;
+}
+.nav .nav-divider {
+  height: 1px;
+  margin: 8px 0;
+  overflow: hidden;
+  background-color: #e5e5e5;
+}
+.nav > li > a > img {
+  max-width: none;
+}
+.nav-tabs {
+  border-bottom: 1px solid #ddd;
+}
+.nav-tabs > li {
+  float: left;
+  margin-bottom: -1px;
+}
+.nav-tabs > li > a {
+  margin-right: 2px;
+  line-height: 1.42857143;
+  border: 1px solid transparent;
+  border-radius: 2px 2px 0 0;
+}
+.nav-tabs > li > a:hover {
+  border-color: #eeeeee #eeeeee #ddd;
+}
+.nav-tabs > li.active > a,
+.nav-tabs > li.active > a:hover,
+.nav-tabs > li.active > a:focus {
+  color: #555555;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-bottom-color: transparent;
+  cursor: default;
+}
+.nav-tabs.nav-justified {
+  width: 100%;
+  border-bottom: 0;
+}
+.nav-tabs.nav-justified > li {
+  float: none;
+}
+.nav-tabs.nav-justified > li > a {
+  text-align: center;
+  margin-bottom: 5px;
+}
+.nav-tabs.nav-justified > .dropdown .dropdown-menu {
+  top: auto;
+  left: auto;
+}
+@media (min-width: 768px) {
+  .nav-tabs.nav-justified > li {
+    display: table-cell;
+    width: 1%;
+  }
+  .nav-tabs.nav-justified > li > a {
+    margin-bottom: 0;
+  }
+}
+.nav-tabs.nav-justified > li > a {
+  margin-right: 0;
+  border-radius: 2px;
+}
+.nav-tabs.nav-justified > .active > a,
+.nav-tabs.nav-justified > .active > a:hover,
+.nav-tabs.nav-justified > .active > a:focus {
+  border: 1px solid #ddd;
+}
+@media (min-width: 768px) {
+  .nav-tabs.nav-justified > li > a {
+    border-bottom: 1px solid #ddd;
+    border-radius: 2px 2px 0 0;
+  }
+  .nav-tabs.nav-justified > .active > a,
+  .nav-tabs.nav-justified > .active > a:hover,
+  .nav-tabs.nav-justified > .active > a:focus {
+    border-bottom-color: #fff;
+  }
+}
+.nav-pills > li {
+  float: left;
+}
+.nav-pills > li > a {
+  border-radius: 2px;
+}
+.nav-pills > li + li {
+  margin-left: 2px;
+}
+.nav-pills > li.active > a,
+.nav-pills > li.active > a:hover,
+.nav-pills > li.active > a:focus {
+  color: #fff;
+  background-color: #337ab7;
+}
+.nav-stacked > li {
+  float: none;
+}
+.nav-stacked > li + li {
+  margin-top: 2px;
+  margin-left: 0;
+}
+.nav-justified {
+  width: 100%;
+}
+.nav-justified > li {
+  float: none;
+}
+.nav-justified > li > a {
+  text-align: center;
+  margin-bottom: 5px;
+}
+.nav-justified > .dropdown .dropdown-menu {
+  top: auto;
+  left: auto;
+}
+@media (min-width: 768px) {
+  .nav-justified > li {
+    display: table-cell;
+    width: 1%;
+  }
+  .nav-justified > li > a {
+    margin-bottom: 0;
+  }
+}
+.nav-tabs-justified {
+  border-bottom: 0;
+}
+.nav-tabs-justified > li > a {
+  margin-right: 0;
+  border-radius: 2px;
+}
+.nav-tabs-justified > .active > a,
+.nav-tabs-justified > .active > a:hover,
+.nav-tabs-justified > .active > a:focus {
+  border: 1px solid #ddd;
+}
+@media (min-width: 768px) {
+  .nav-tabs-justified > li > a {
+    border-bottom: 1px solid #ddd;
+    border-radius: 2px 2px 0 0;
+  }
+  .nav-tabs-justified > .active > a,
+  .nav-tabs-justified > .active > a:hover,
+  .nav-tabs-justified > .active > a:focus {
+    border-bottom-color: #fff;
+  }
+}
+.tab-content > .tab-pane {
+  display: none;
+}
+.tab-content > .active {
+  display: block;
+}
+.nav-tabs .dropdown-menu {
+  margin-top: -1px;
+  border-top-right-radius: 0;
+  border-top-left-radius: 0;
+}
+.navbar {
+  position: relative;
+  min-height: 30px;
+  margin-bottom: 18px;
+  border: 1px solid transparent;
+}
+@media (min-width: 541px) {
+  .navbar {
+    border-radius: 2px;
+  }
+}
+@media (min-width: 541px) {
+  .navbar-header {
+    float: left;
+  }
+}
+.navbar-collapse {
+  overflow-x: visible;
+  padding-right: 0px;
+  padding-left: 0px;
+  border-top: 1px solid transparent;
+  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);
+  -webkit-overflow-scrolling: touch;
+}
+.navbar-collapse.in {
+  overflow-y: auto;
+}
+@media (min-width: 541px) {
+  .navbar-collapse {
+    width: auto;
+    border-top: 0;
+    box-shadow: none;
+  }
+  .navbar-collapse.collapse {
+    display: block !important;
+    height: auto !important;
+    padding-bottom: 0;
+    overflow: visible !important;
+  }
+  .navbar-collapse.in {
+    overflow-y: visible;
+  }
+  .navbar-fixed-top .navbar-collapse,
+  .navbar-static-top .navbar-collapse,
+  .navbar-fixed-bottom .navbar-collapse {
+    padding-left: 0;
+    padding-right: 0;
+  }
+}
+.navbar-fixed-top .navbar-collapse,
+.navbar-fixed-bottom .navbar-collapse {
+  max-height: 340px;
+}
+@media (max-device-width: 540px) and (orientation: landscape) {
+  .navbar-fixed-top .navbar-collapse,
+  .navbar-fixed-bottom .navbar-collapse {
+    max-height: 200px;
+  }
+}
+.container > .navbar-header,
+.container-fluid > .navbar-header,
+.container > .navbar-collapse,
+.container-fluid > .navbar-collapse {
+  margin-right: 0px;
+  margin-left: 0px;
+}
+@media (min-width: 541px) {
+  .container > .navbar-header,
+  .container-fluid > .navbar-header,
+  .container > .navbar-collapse,
+  .container-fluid > .navbar-collapse {
+    margin-right: 0;
+    margin-left: 0;
+  }
+}
+.navbar-static-top {
+  z-index: 1000;
+  border-width: 0 0 1px;
+}
+@media (min-width: 541px) {
+  .navbar-static-top {
+    border-radius: 0;
+  }
+}
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+  position: fixed;
+  right: 0;
+  left: 0;
+  z-index: 1030;
+}
+@media (min-width: 541px) {
+  .navbar-fixed-top,
+  .navbar-fixed-bottom {
+    border-radius: 0;
+  }
+}
+.navbar-fixed-top {
+  top: 0;
+  border-width: 0 0 1px;
+}
+.navbar-fixed-bottom {
+  bottom: 0;
+  margin-bottom: 0;
+  border-width: 1px 0 0;
+}
+.navbar-brand {
+  float: left;
+  padding: 6px 0px;
+  font-size: 17px;
+  line-height: 18px;
+  height: 30px;
+}
+.navbar-brand:hover,
+.navbar-brand:focus {
+  text-decoration: none;
+}
+.navbar-brand > img {
+  display: block;
+}
+@media (min-width: 541px) {
+  .navbar > .container .navbar-brand,
+  .navbar > .container-fluid .navbar-brand {
+    margin-left: 0px;
+  }
+}
+.navbar-toggle {
+  position: relative;
+  float: right;
+  margin-right: 0px;
+  padding: 9px 10px;
+  margin-top: -2px;
+  margin-bottom: -2px;
+  background-color: transparent;
+  background-image: none;
+  border: 1px solid transparent;
+  border-radius: 2px;
+}
+.navbar-toggle:focus {
+  outline: 0;
+}
+.navbar-toggle .icon-bar {
+  display: block;
+  width: 22px;
+  height: 2px;
+  border-radius: 1px;
+}
+.navbar-toggle .icon-bar + .icon-bar {
+  margin-top: 4px;
+}
+@media (min-width: 541px) {
+  .navbar-toggle {
+    display: none;
+  }
+}
+.navbar-nav {
+  margin: 3px 0px;
+}
+.navbar-nav > li > a {
+  padding-top: 10px;
+  padding-bottom: 10px;
+  line-height: 18px;
+}
+@media (max-width: 540px) {
+  .navbar-nav .open .dropdown-menu {
+    position: static;
+    float: none;
+    width: auto;
+    margin-top: 0;
+    background-color: transparent;
+    border: 0;
+    box-shadow: none;
+  }
+  .navbar-nav .open .dropdown-menu > li > a,
+  .navbar-nav .open .dropdown-menu .dropdown-header {
+    padding: 5px 15px 5px 25px;
+  }
+  .navbar-nav .open .dropdown-menu > li > a {
+    line-height: 18px;
+  }
+  .navbar-nav .open .dropdown-menu > li > a:hover,
+  .navbar-nav .open .dropdown-menu > li > a:focus {
+    background-image: none;
+  }
+}
+@media (min-width: 541px) {
+  .navbar-nav {
+    float: left;
+    margin: 0;
+  }
+  .navbar-nav > li {
+    float: left;
+  }
+  .navbar-nav > li > a {
+    padding-top: 6px;
+    padding-bottom: 6px;
+  }
+}
+.navbar-form {
+  margin-left: 0px;
+  margin-right: 0px;
+  padding: 10px 0px;
+  border-top: 1px solid transparent;
+  border-bottom: 1px solid transparent;
+  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+  margin-top: -1px;
+  margin-bottom: -1px;
+}
+@media (min-width: 768px) {
+  .navbar-form .form-group {
+    display: inline-block;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .navbar-form .form-control {
+    display: inline-block;
+    width: auto;
+    vertical-align: middle;
+  }
+  .navbar-form .form-control-static {
+    display: inline-block;
+  }
+  .navbar-form .input-group {
+    display: inline-table;
+    vertical-align: middle;
+  }
+  .navbar-form .input-group .input-group-addon,
+  .navbar-form .input-group .input-group-btn,
+  .navbar-form .input-group .form-control {
+    width: auto;
+  }
+  .navbar-form .input-group > .form-control {
+    width: 100%;
+  }
+  .navbar-form .control-label {
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .navbar-form .radio,
+  .navbar-form .checkbox {
+    display: inline-block;
+    margin-top: 0;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .navbar-form .radio label,
+  .navbar-form .checkbox label {
+    padding-left: 0;
+  }
+  .navbar-form .radio input[type="radio"],
+  .navbar-form .checkbox input[type="checkbox"] {
+    position: relative;
+    margin-left: 0;
+  }
+  .navbar-form .has-feedback .form-control-feedback {
+    top: 0;
+  }
+}
+@media (max-width: 540px) {
+  .navbar-form .form-group {
+    margin-bottom: 5px;
+  }
+  .navbar-form .form-group:last-child {
+    margin-bottom: 0;
+  }
+}
+@media (min-width: 541px) {
+  .navbar-form {
+    width: auto;
+    border: 0;
+    margin-left: 0;
+    margin-right: 0;
+    padding-top: 0;
+    padding-bottom: 0;
+    -webkit-box-shadow: none;
+    box-shadow: none;
+  }
+}
+.navbar-nav > li > .dropdown-menu {
+  margin-top: 0;
+  border-top-right-radius: 0;
+  border-top-left-radius: 0;
+}
+.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {
+  margin-bottom: 0;
+  border-top-right-radius: 2px;
+  border-top-left-radius: 2px;
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.navbar-btn {
+  margin-top: -1px;
+  margin-bottom: -1px;
+}
+.navbar-btn.btn-sm {
+  margin-top: 0px;
+  margin-bottom: 0px;
+}
+.navbar-btn.btn-xs {
+  margin-top: 4px;
+  margin-bottom: 4px;
+}
+.navbar-text {
+  margin-top: 6px;
+  margin-bottom: 6px;
+}
+@media (min-width: 541px) {
+  .navbar-text {
+    float: left;
+    margin-left: 0px;
+    margin-right: 0px;
+  }
+}
+@media (min-width: 541px) {
+  .navbar-left {
+    float: left !important;
+    float: left;
+  }
+  .navbar-right {
+    float: right !important;
+    float: right;
+    margin-right: 0px;
+  }
+  .navbar-right ~ .navbar-right {
+    margin-right: 0;
+  }
+}
+.navbar-default {
+  background-color: #f8f8f8;
+  border-color: #e7e7e7;
+}
+.navbar-default .navbar-brand {
+  color: #777;
+}
+.navbar-default .navbar-brand:hover,
+.navbar-default .navbar-brand:focus {
+  color: #5e5e5e;
+  background-color: transparent;
+}
+.navbar-default .navbar-text {
+  color: #777;
+}
+.navbar-default .navbar-nav > li > a {
+  color: #777;
+}
+.navbar-default .navbar-nav > li > a:hover,
+.navbar-default .navbar-nav > li > a:focus {
+  color: #333;
+  background-color: transparent;
+}
+.navbar-default .navbar-nav > .active > a,
+.navbar-default .navbar-nav > .active > a:hover,
+.navbar-default .navbar-nav > .active > a:focus {
+  color: #555;
+  background-color: #e7e7e7;
+}
+.navbar-default .navbar-nav > .disabled > a,
+.navbar-default .navbar-nav > .disabled > a:hover,
+.navbar-default .navbar-nav > .disabled > a:focus {
+  color: #ccc;
+  background-color: transparent;
+}
+.navbar-default .navbar-toggle {
+  border-color: #ddd;
+}
+.navbar-default .navbar-toggle:hover,
+.navbar-default .navbar-toggle:focus {
+  background-color: #ddd;
+}
+.navbar-default .navbar-toggle .icon-bar {
+  background-color: #888;
+}
+.navbar-default .navbar-collapse,
+.navbar-default .navbar-form {
+  border-color: #e7e7e7;
+}
+.navbar-default .navbar-nav > .open > a,
+.navbar-default .navbar-nav > .open > a:hover,
+.navbar-default .navbar-nav > .open > a:focus {
+  background-color: #e7e7e7;
+  color: #555;
+}
+@media (max-width: 540px) {
+  .navbar-default .navbar-nav .open .dropdown-menu > li > a {
+    color: #777;
+  }
+  .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,
+  .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {
+    color: #333;
+    background-color: transparent;
+  }
+  .navbar-default .navbar-nav .open .dropdown-menu > .active > a,
+  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,
+  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {
+    color: #555;
+    background-color: #e7e7e7;
+  }
+  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,
+  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,
+  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {
+    color: #ccc;
+    background-color: transparent;
+  }
+}
+.navbar-default .navbar-link {
+  color: #777;
+}
+.navbar-default .navbar-link:hover {
+  color: #333;
+}
+.navbar-default .btn-link {
+  color: #777;
+}
+.navbar-default .btn-link:hover,
+.navbar-default .btn-link:focus {
+  color: #333;
+}
+.navbar-default .btn-link[disabled]:hover,
+fieldset[disabled] .navbar-default .btn-link:hover,
+.navbar-default .btn-link[disabled]:focus,
+fieldset[disabled] .navbar-default .btn-link:focus {
+  color: #ccc;
+}
+.navbar-inverse {
+  background-color: #222;
+  border-color: #080808;
+}
+.navbar-inverse .navbar-brand {
+  color: #9d9d9d;
+}
+.navbar-inverse .navbar-brand:hover,
+.navbar-inverse .navbar-brand:focus {
+  color: #fff;
+  background-color: transparent;
+}
+.navbar-inverse .navbar-text {
+  color: #9d9d9d;
+}
+.navbar-inverse .navbar-nav > li > a {
+  color: #9d9d9d;
+}
+.navbar-inverse .navbar-nav > li > a:hover,
+.navbar-inverse .navbar-nav > li > a:focus {
+  color: #fff;
+  background-color: transparent;
+}
+.navbar-inverse .navbar-nav > .active > a,
+.navbar-inverse .navbar-nav > .active > a:hover,
+.navbar-inverse .navbar-nav > .active > a:focus {
+  color: #fff;
+  background-color: #080808;
+}
+.navbar-inverse .navbar-nav > .disabled > a,
+.navbar-inverse .navbar-nav > .disabled > a:hover,
+.navbar-inverse .navbar-nav > .disabled > a:focus {
+  color: #444;
+  background-color: transparent;
+}
+.navbar-inverse .navbar-toggle {
+  border-color: #333;
+}
+.navbar-inverse .navbar-toggle:hover,
+.navbar-inverse .navbar-toggle:focus {
+  background-color: #333;
+}
+.navbar-inverse .navbar-toggle .icon-bar {
+  background-color: #fff;
+}
+.navbar-inverse .navbar-collapse,
+.navbar-inverse .navbar-form {
+  border-color: #101010;
+}
+.navbar-inverse .navbar-nav > .open > a,
+.navbar-inverse .navbar-nav > .open > a:hover,
+.navbar-inverse .navbar-nav > .open > a:focus {
+  background-color: #080808;
+  color: #fff;
+}
+@media (max-width: 540px) {
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {
+    border-color: #080808;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu .divider {
+    background-color: #080808;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {
+    color: #9d9d9d;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {
+    color: #fff;
+    background-color: transparent;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {
+    color: #fff;
+    background-color: #080808;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {
+    color: #444;
+    background-color: transparent;
+  }
+}
+.navbar-inverse .navbar-link {
+  color: #9d9d9d;
+}
+.navbar-inverse .navbar-link:hover {
+  color: #fff;
+}
+.navbar-inverse .btn-link {
+  color: #9d9d9d;
+}
+.navbar-inverse .btn-link:hover,
+.navbar-inverse .btn-link:focus {
+  color: #fff;
+}
+.navbar-inverse .btn-link[disabled]:hover,
+fieldset[disabled] .navbar-inverse .btn-link:hover,
+.navbar-inverse .btn-link[disabled]:focus,
+fieldset[disabled] .navbar-inverse .btn-link:focus {
+  color: #444;
+}
+.breadcrumb {
+  padding: 8px 15px;
+  margin-bottom: 18px;
+  list-style: none;
+  background-color: #f5f5f5;
+  border-radius: 2px;
+}
+.breadcrumb > li {
+  display: inline-block;
+}
+.breadcrumb > li + li:before {
+  content: "/\00a0";
+  padding: 0 5px;
+  color: #5e5e5e;
+}
+.breadcrumb > .active {
+  color: #777777;
+}
+.pagination {
+  display: inline-block;
+  padding-left: 0;
+  margin: 18px 0;
+  border-radius: 2px;
+}
+.pagination > li {
+  display: inline;
+}
+.pagination > li > a,
+.pagination > li > span {
+  position: relative;
+  float: left;
+  padding: 6px 12px;
+  line-height: 1.42857143;
+  text-decoration: none;
+  color: #337ab7;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  margin-left: -1px;
+}
+.pagination > li:first-child > a,
+.pagination > li:first-child > span {
+  margin-left: 0;
+  border-bottom-left-radius: 2px;
+  border-top-left-radius: 2px;
+}
+.pagination > li:last-child > a,
+.pagination > li:last-child > span {
+  border-bottom-right-radius: 2px;
+  border-top-right-radius: 2px;
+}
+.pagination > li > a:hover,
+.pagination > li > span:hover,
+.pagination > li > a:focus,
+.pagination > li > span:focus {
+  z-index: 2;
+  color: #23527c;
+  background-color: #eeeeee;
+  border-color: #ddd;
+}
+.pagination > .active > a,
+.pagination > .active > span,
+.pagination > .active > a:hover,
+.pagination > .active > span:hover,
+.pagination > .active > a:focus,
+.pagination > .active > span:focus {
+  z-index: 3;
+  color: #fff;
+  background-color: #337ab7;
+  border-color: #337ab7;
+  cursor: default;
+}
+.pagination > .disabled > span,
+.pagination > .disabled > span:hover,
+.pagination > .disabled > span:focus,
+.pagination > .disabled > a,
+.pagination > .disabled > a:hover,
+.pagination > .disabled > a:focus {
+  color: #777777;
+  background-color: #fff;
+  border-color: #ddd;
+  cursor: not-allowed;
+}
+.pagination-lg > li > a,
+.pagination-lg > li > span {
+  padding: 10px 16px;
+  font-size: 17px;
+  line-height: 1.3333333;
+}
+.pagination-lg > li:first-child > a,
+.pagination-lg > li:first-child > span {
+  border-bottom-left-radius: 3px;
+  border-top-left-radius: 3px;
+}
+.pagination-lg > li:last-child > a,
+.pagination-lg > li:last-child > span {
+  border-bottom-right-radius: 3px;
+  border-top-right-radius: 3px;
+}
+.pagination-sm > li > a,
+.pagination-sm > li > span {
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+}
+.pagination-sm > li:first-child > a,
+.pagination-sm > li:first-child > span {
+  border-bottom-left-radius: 1px;
+  border-top-left-radius: 1px;
+}
+.pagination-sm > li:last-child > a,
+.pagination-sm > li:last-child > span {
+  border-bottom-right-radius: 1px;
+  border-top-right-radius: 1px;
+}
+.pager {
+  padding-left: 0;
+  margin: 18px 0;
+  list-style: none;
+  text-align: center;
+}
+.pager li {
+  display: inline;
+}
+.pager li > a,
+.pager li > span {
+  display: inline-block;
+  padding: 5px 14px;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-radius: 15px;
+}
+.pager li > a:hover,
+.pager li > a:focus {
+  text-decoration: none;
+  background-color: #eeeeee;
+}
+.pager .next > a,
+.pager .next > span {
+  float: right;
+}
+.pager .previous > a,
+.pager .previous > span {
+  float: left;
+}
+.pager .disabled > a,
+.pager .disabled > a:hover,
+.pager .disabled > a:focus,
+.pager .disabled > span {
+  color: #777777;
+  background-color: #fff;
+  cursor: not-allowed;
+}
+.label {
+  display: inline;
+  padding: .2em .6em .3em;
+  font-size: 75%;
+  font-weight: bold;
+  line-height: 1;
+  color: #fff;
+  text-align: center;
+  white-space: nowrap;
+  vertical-align: baseline;
+  border-radius: .25em;
+}
+a.label:hover,
+a.label:focus {
+  color: #fff;
+  text-decoration: none;
+  cursor: pointer;
+}
+.label:empty {
+  display: none;
+}
+.btn .label {
+  position: relative;
+  top: -1px;
+}
+.label-default {
+  background-color: #777777;
+}
+.label-default[href]:hover,
+.label-default[href]:focus {
+  background-color: #5e5e5e;
+}
+.label-primary {
+  background-color: #337ab7;
+}
+.label-primary[href]:hover,
+.label-primary[href]:focus {
+  background-color: #286090;
+}
+.label-success {
+  background-color: #5cb85c;
+}
+.label-success[href]:hover,
+.label-success[href]:focus {
+  background-color: #449d44;
+}
+.label-info {
+  background-color: #5bc0de;
+}
+.label-info[href]:hover,
+.label-info[href]:focus {
+  background-color: #31b0d5;
+}
+.label-warning {
+  background-color: #f0ad4e;
+}
+.label-warning[href]:hover,
+.label-warning[href]:focus {
+  background-color: #ec971f;
+}
+.label-danger {
+  background-color: #d9534f;
+}
+.label-danger[href]:hover,
+.label-danger[href]:focus {
+  background-color: #c9302c;
+}
+.badge {
+  display: inline-block;
+  min-width: 10px;
+  padding: 3px 7px;
+  font-size: 12px;
+  font-weight: bold;
+  color: #fff;
+  line-height: 1;
+  vertical-align: middle;
+  white-space: nowrap;
+  text-align: center;
+  background-color: #777777;
+  border-radius: 10px;
+}
+.badge:empty {
+  display: none;
+}
+.btn .badge {
+  position: relative;
+  top: -1px;
+}
+.btn-xs .badge,
+.btn-group-xs > .btn .badge {
+  top: 0;
+  padding: 1px 5px;
+}
+a.badge:hover,
+a.badge:focus {
+  color: #fff;
+  text-decoration: none;
+  cursor: pointer;
+}
+.list-group-item.active > .badge,
+.nav-pills > .active > a > .badge {
+  color: #337ab7;
+  background-color: #fff;
+}
+.list-group-item > .badge {
+  float: right;
+}
+.list-group-item > .badge + .badge {
+  margin-right: 5px;
+}
+.nav-pills > li > a > .badge {
+  margin-left: 3px;
+}
+.jumbotron {
+  padding-top: 30px;
+  padding-bottom: 30px;
+  margin-bottom: 30px;
+  color: inherit;
+  background-color: #eeeeee;
+}
+.jumbotron h1,
+.jumbotron .h1 {
+  color: inherit;
+}
+.jumbotron p {
+  margin-bottom: 15px;
+  font-size: 20px;
+  font-weight: 200;
+}
+.jumbotron > hr {
+  border-top-color: #d5d5d5;
+}
+.container .jumbotron,
+.container-fluid .jumbotron {
+  border-radius: 3px;
+  padding-left: 0px;
+  padding-right: 0px;
+}
+.jumbotron .container {
+  max-width: 100%;
+}
+@media screen and (min-width: 768px) {
+  .jumbotron {
+    padding-top: 48px;
+    padding-bottom: 48px;
+  }
+  .container .jumbotron,
+  .container-fluid .jumbotron {
+    padding-left: 60px;
+    padding-right: 60px;
+  }
+  .jumbotron h1,
+  .jumbotron .h1 {
+    font-size: 59px;
+  }
+}
+.thumbnail {
+  display: block;
+  padding: 4px;
+  margin-bottom: 18px;
+  line-height: 1.42857143;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-radius: 2px;
+  -webkit-transition: border 0.2s ease-in-out;
+  -o-transition: border 0.2s ease-in-out;
+  transition: border 0.2s ease-in-out;
+}
+.thumbnail > img,
+.thumbnail a > img {
+  margin-left: auto;
+  margin-right: auto;
+}
+a.thumbnail:hover,
+a.thumbnail:focus,
+a.thumbnail.active {
+  border-color: #337ab7;
+}
+.thumbnail .caption {
+  padding: 9px;
+  color: #000;
+}
+.alert {
+  padding: 15px;
+  margin-bottom: 18px;
+  border: 1px solid transparent;
+  border-radius: 2px;
+}
+.alert h4 {
+  margin-top: 0;
+  color: inherit;
+}
+.alert .alert-link {
+  font-weight: bold;
+}
+.alert > p,
+.alert > ul {
+  margin-bottom: 0;
+}
+.alert > p + p {
+  margin-top: 5px;
+}
+.alert-dismissable,
+.alert-dismissible {
+  padding-right: 35px;
+}
+.alert-dismissable .close,
+.alert-dismissible .close {
+  position: relative;
+  top: -2px;
+  right: -21px;
+  color: inherit;
+}
+.alert-success {
+  background-color: #dff0d8;
+  border-color: #d6e9c6;
+  color: #3c763d;
+}
+.alert-success hr {
+  border-top-color: #c9e2b3;
+}
+.alert-success .alert-link {
+  color: #2b542c;
+}
+.alert-info {
+  background-color: #d9edf7;
+  border-color: #bce8f1;
+  color: #31708f;
+}
+.alert-info hr {
+  border-top-color: #a6e1ec;
+}
+.alert-info .alert-link {
+  color: #245269;
+}
+.alert-warning {
+  background-color: #fcf8e3;
+  border-color: #faebcc;
+  color: #8a6d3b;
+}
+.alert-warning hr {
+  border-top-color: #f7e1b5;
+}
+.alert-warning .alert-link {
+  color: #66512c;
+}
+.alert-danger {
+  background-color: #f2dede;
+  border-color: #ebccd1;
+  color: #a94442;
+}
+.alert-danger hr {
+  border-top-color: #e4b9c0;
+}
+.alert-danger .alert-link {
+  color: #843534;
+}
+@-webkit-keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+@keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+.progress {
+  overflow: hidden;
+  height: 18px;
+  margin-bottom: 18px;
+  background-color: #f5f5f5;
+  border-radius: 2px;
+  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+}
+.progress-bar {
+  float: left;
+  width: 0%;
+  height: 100%;
+  font-size: 12px;
+  line-height: 18px;
+  color: #fff;
+  text-align: center;
+  background-color: #337ab7;
+  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+  -webkit-transition: width 0.6s ease;
+  -o-transition: width 0.6s ease;
+  transition: width 0.6s ease;
+}
+.progress-striped .progress-bar,
+.progress-bar-striped {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-size: 40px 40px;
+}
+.progress.active .progress-bar,
+.progress-bar.active {
+  -webkit-animation: progress-bar-stripes 2s linear infinite;
+  -o-animation: progress-bar-stripes 2s linear infinite;
+  animation: progress-bar-stripes 2s linear infinite;
+}
+.progress-bar-success {
+  background-color: #5cb85c;
+}
+.progress-striped .progress-bar-success {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+.progress-bar-info {
+  background-color: #5bc0de;
+}
+.progress-striped .progress-bar-info {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+.progress-bar-warning {
+  background-color: #f0ad4e;
+}
+.progress-striped .progress-bar-warning {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+.progress-bar-danger {
+  background-color: #d9534f;
+}
+.progress-striped .progress-bar-danger {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+.media {
+  margin-top: 15px;
+}
+.media:first-child {
+  margin-top: 0;
+}
+.media,
+.media-body {
+  zoom: 1;
+  overflow: hidden;
+}
+.media-body {
+  width: 10000px;
+}
+.media-object {
+  display: block;
+}
+.media-object.img-thumbnail {
+  max-width: none;
+}
+.media-right,
+.media > .pull-right {
+  padding-left: 10px;
+}
+.media-left,
+.media > .pull-left {
+  padding-right: 10px;
+}
+.media-left,
+.media-right,
+.media-body {
+  display: table-cell;
+  vertical-align: top;
+}
+.media-middle {
+  vertical-align: middle;
+}
+.media-bottom {
+  vertical-align: bottom;
+}
+.media-heading {
+  margin-top: 0;
+  margin-bottom: 5px;
+}
+.media-list {
+  padding-left: 0;
+  list-style: none;
+}
+.list-group {
+  margin-bottom: 20px;
+  padding-left: 0;
+}
+.list-group-item {
+  position: relative;
+  display: block;
+  padding: 10px 15px;
+  margin-bottom: -1px;
+  background-color: #fff;
+  border: 1px solid #ddd;
+}
+.list-group-item:first-child {
+  border-top-right-radius: 2px;
+  border-top-left-radius: 2px;
+}
+.list-group-item:last-child {
+  margin-bottom: 0;
+  border-bottom-right-radius: 2px;
+  border-bottom-left-radius: 2px;
+}
+a.list-group-item,
+button.list-group-item {
+  color: #555;
+}
+a.list-group-item .list-group-item-heading,
+button.list-group-item .list-group-item-heading {
+  color: #333;
+}
+a.list-group-item:hover,
+button.list-group-item:hover,
+a.list-group-item:focus,
+button.list-group-item:focus {
+  text-decoration: none;
+  color: #555;
+  background-color: #f5f5f5;
+}
+button.list-group-item {
+  width: 100%;
+  text-align: left;
+}
+.list-group-item.disabled,
+.list-group-item.disabled:hover,
+.list-group-item.disabled:focus {
+  background-color: #eeeeee;
+  color: #777777;
+  cursor: not-allowed;
+}
+.list-group-item.disabled .list-group-item-heading,
+.list-group-item.disabled:hover .list-group-item-heading,
+.list-group-item.disabled:focus .list-group-item-heading {
+  color: inherit;
+}
+.list-group-item.disabled .list-group-item-text,
+.list-group-item.disabled:hover .list-group-item-text,
+.list-group-item.disabled:focus .list-group-item-text {
+  color: #777777;
+}
+.list-group-item.active,
+.list-group-item.active:hover,
+.list-group-item.active:focus {
+  z-index: 2;
+  color: #fff;
+  background-color: #337ab7;
+  border-color: #337ab7;
+}
+.list-group-item.active .list-group-item-heading,
+.list-group-item.active:hover .list-group-item-heading,
+.list-group-item.active:focus .list-group-item-heading,
+.list-group-item.active .list-group-item-heading > small,
+.list-group-item.active:hover .list-group-item-heading > small,
+.list-group-item.active:focus .list-group-item-heading > small,
+.list-group-item.active .list-group-item-heading > .small,
+.list-group-item.active:hover .list-group-item-heading > .small,
+.list-group-item.active:focus .list-group-item-heading > .small {
+  color: inherit;
+}
+.list-group-item.active .list-group-item-text,
+.list-group-item.active:hover .list-group-item-text,
+.list-group-item.active:focus .list-group-item-text {
+  color: #c7ddef;
+}
+.list-group-item-success {
+  color: #3c763d;
+  background-color: #dff0d8;
+}
+a.list-group-item-success,
+button.list-group-item-success {
+  color: #3c763d;
+}
+a.list-group-item-success .list-group-item-heading,
+button.list-group-item-success .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-success:hover,
+button.list-group-item-success:hover,
+a.list-group-item-success:focus,
+button.list-group-item-success:focus {
+  color: #3c763d;
+  background-color: #d0e9c6;
+}
+a.list-group-item-success.active,
+button.list-group-item-success.active,
+a.list-group-item-success.active:hover,
+button.list-group-item-success.active:hover,
+a.list-group-item-success.active:focus,
+button.list-group-item-success.active:focus {
+  color: #fff;
+  background-color: #3c763d;
+  border-color: #3c763d;
+}
+.list-group-item-info {
+  color: #31708f;
+  background-color: #d9edf7;
+}
+a.list-group-item-info,
+button.list-group-item-info {
+  color: #31708f;
+}
+a.list-group-item-info .list-group-item-heading,
+button.list-group-item-info .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-info:hover,
+button.list-group-item-info:hover,
+a.list-group-item-info:focus,
+button.list-group-item-info:focus {
+  color: #31708f;
+  background-color: #c4e3f3;
+}
+a.list-group-item-info.active,
+button.list-group-item-info.active,
+a.list-group-item-info.active:hover,
+button.list-group-item-info.active:hover,
+a.list-group-item-info.active:focus,
+button.list-group-item-info.active:focus {
+  color: #fff;
+  background-color: #31708f;
+  border-color: #31708f;
+}
+.list-group-item-warning {
+  color: #8a6d3b;
+  background-color: #fcf8e3;
+}
+a.list-group-item-warning,
+button.list-group-item-warning {
+  color: #8a6d3b;
+}
+a.list-group-item-warning .list-group-item-heading,
+button.list-group-item-warning .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-warning:hover,
+button.list-group-item-warning:hover,
+a.list-group-item-warning:focus,
+button.list-group-item-warning:focus {
+  color: #8a6d3b;
+  background-color: #faf2cc;
+}
+a.list-group-item-warning.active,
+button.list-group-item-warning.active,
+a.list-group-item-warning.active:hover,
+button.list-group-item-warning.active:hover,
+a.list-group-item-warning.active:focus,
+button.list-group-item-warning.active:focus {
+  color: #fff;
+  background-color: #8a6d3b;
+  border-color: #8a6d3b;
+}
+.list-group-item-danger {
+  color: #a94442;
+  background-color: #f2dede;
+}
+a.list-group-item-danger,
+button.list-group-item-danger {
+  color: #a94442;
+}
+a.list-group-item-danger .list-group-item-heading,
+button.list-group-item-danger .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-danger:hover,
+button.list-group-item-danger:hover,
+a.list-group-item-danger:focus,
+button.list-group-item-danger:focus {
+  color: #a94442;
+  background-color: #ebcccc;
+}
+a.list-group-item-danger.active,
+button.list-group-item-danger.active,
+a.list-group-item-danger.active:hover,
+button.list-group-item-danger.active:hover,
+a.list-group-item-danger.active:focus,
+button.list-group-item-danger.active:focus {
+  color: #fff;
+  background-color: #a94442;
+  border-color: #a94442;
+}
+.list-group-item-heading {
+  margin-top: 0;
+  margin-bottom: 5px;
+}
+.list-group-item-text {
+  margin-bottom: 0;
+  line-height: 1.3;
+}
+.panel {
+  margin-bottom: 18px;
+  background-color: #fff;
+  border: 1px solid transparent;
+  border-radius: 2px;
+  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
+  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
+}
+.panel-body {
+  padding: 15px;
+}
+.panel-heading {
+  padding: 10px 15px;
+  border-bottom: 1px solid transparent;
+  border-top-right-radius: 1px;
+  border-top-left-radius: 1px;
+}
+.panel-heading > .dropdown .dropdown-toggle {
+  color: inherit;
+}
+.panel-title {
+  margin-top: 0;
+  margin-bottom: 0;
+  font-size: 15px;
+  color: inherit;
+}
+.panel-title > a,
+.panel-title > small,
+.panel-title > .small,
+.panel-title > small > a,
+.panel-title > .small > a {
+  color: inherit;
+}
+.panel-footer {
+  padding: 10px 15px;
+  background-color: #f5f5f5;
+  border-top: 1px solid #ddd;
+  border-bottom-right-radius: 1px;
+  border-bottom-left-radius: 1px;
+}
+.panel > .list-group,
+.panel > .panel-collapse > .list-group {
+  margin-bottom: 0;
+}
+.panel > .list-group .list-group-item,
+.panel > .panel-collapse > .list-group .list-group-item {
+  border-width: 1px 0;
+  border-radius: 0;
+}
+.panel > .list-group:first-child .list-group-item:first-child,
+.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {
+  border-top: 0;
+  border-top-right-radius: 1px;
+  border-top-left-radius: 1px;
+}
+.panel > .list-group:last-child .list-group-item:last-child,
+.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {
+  border-bottom: 0;
+  border-bottom-right-radius: 1px;
+  border-bottom-left-radius: 1px;
+}
+.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {
+  border-top-right-radius: 0;
+  border-top-left-radius: 0;
+}
+.panel-heading + .list-group .list-group-item:first-child {
+  border-top-width: 0;
+}
+.list-group + .panel-footer {
+  border-top-width: 0;
+}
+.panel > .table,
+.panel > .table-responsive > .table,
+.panel > .panel-collapse > .table {
+  margin-bottom: 0;
+}
+.panel > .table caption,
+.panel > .table-responsive > .table caption,
+.panel > .panel-collapse > .table caption {
+  padding-left: 15px;
+  padding-right: 15px;
+}
+.panel > .table:first-child,
+.panel > .table-responsive:first-child > .table:first-child {
+  border-top-right-radius: 1px;
+  border-top-left-radius: 1px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {
+  border-top-left-radius: 1px;
+  border-top-right-radius: 1px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,
+.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {
+  border-top-left-radius: 1px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,
+.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {
+  border-top-right-radius: 1px;
+}
+.panel > .table:last-child,
+.panel > .table-responsive:last-child > .table:last-child {
+  border-bottom-right-radius: 1px;
+  border-bottom-left-radius: 1px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {
+  border-bottom-left-radius: 1px;
+  border-bottom-right-radius: 1px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
+.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {
+  border-bottom-left-radius: 1px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
+.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {
+  border-bottom-right-radius: 1px;
+}
+.panel > .panel-body + .table,
+.panel > .panel-body + .table-responsive,
+.panel > .table + .panel-body,
+.panel > .table-responsive + .panel-body {
+  border-top: 1px solid #ddd;
+}
+.panel > .table > tbody:first-child > tr:first-child th,
+.panel > .table > tbody:first-child > tr:first-child td {
+  border-top: 0;
+}
+.panel > .table-bordered,
+.panel > .table-responsive > .table-bordered {
+  border: 0;
+}
+.panel > .table-bordered > thead > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,
+.panel > .table-bordered > tbody > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,
+.panel > .table-bordered > tfoot > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,
+.panel > .table-bordered > thead > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,
+.panel > .table-bordered > tbody > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,
+.panel > .table-bordered > tfoot > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {
+  border-left: 0;
+}
+.panel > .table-bordered > thead > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,
+.panel > .table-bordered > tbody > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,
+.panel > .table-bordered > tfoot > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,
+.panel > .table-bordered > thead > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,
+.panel > .table-bordered > tbody > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,
+.panel > .table-bordered > tfoot > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {
+  border-right: 0;
+}
+.panel > .table-bordered > thead > tr:first-child > td,
+.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,
+.panel > .table-bordered > tbody > tr:first-child > td,
+.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,
+.panel > .table-bordered > thead > tr:first-child > th,
+.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,
+.panel > .table-bordered > tbody > tr:first-child > th,
+.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {
+  border-bottom: 0;
+}
+.panel > .table-bordered > tbody > tr:last-child > td,
+.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,
+.panel > .table-bordered > tfoot > tr:last-child > td,
+.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,
+.panel > .table-bordered > tbody > tr:last-child > th,
+.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,
+.panel > .table-bordered > tfoot > tr:last-child > th,
+.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {
+  border-bottom: 0;
+}
+.panel > .table-responsive {
+  border: 0;
+  margin-bottom: 0;
+}
+.panel-group {
+  margin-bottom: 18px;
+}
+.panel-group .panel {
+  margin-bottom: 0;
+  border-radius: 2px;
+}
+.panel-group .panel + .panel {
+  margin-top: 5px;
+}
+.panel-group .panel-heading {
+  border-bottom: 0;
+}
+.panel-group .panel-heading + .panel-collapse > .panel-body,
+.panel-group .panel-heading + .panel-collapse > .list-group {
+  border-top: 1px solid #ddd;
+}
+.panel-group .panel-footer {
+  border-top: 0;
+}
+.panel-group .panel-footer + .panel-collapse .panel-body {
+  border-bottom: 1px solid #ddd;
+}
+.panel-default {
+  border-color: #ddd;
+}
+.panel-default > .panel-heading {
+  color: #333333;
+  background-color: #f5f5f5;
+  border-color: #ddd;
+}
+.panel-default > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #ddd;
+}
+.panel-default > .panel-heading .badge {
+  color: #f5f5f5;
+  background-color: #333333;
+}
+.panel-default > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #ddd;
+}
+.panel-primary {
+  border-color: #337ab7;
+}
+.panel-primary > .panel-heading {
+  color: #fff;
+  background-color: #337ab7;
+  border-color: #337ab7;
+}
+.panel-primary > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #337ab7;
+}
+.panel-primary > .panel-heading .badge {
+  color: #337ab7;
+  background-color: #fff;
+}
+.panel-primary > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #337ab7;
+}
+.panel-success {
+  border-color: #d6e9c6;
+}
+.panel-success > .panel-heading {
+  color: #3c763d;
+  background-color: #dff0d8;
+  border-color: #d6e9c6;
+}
+.panel-success > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #d6e9c6;
+}
+.panel-success > .panel-heading .badge {
+  color: #dff0d8;
+  background-color: #3c763d;
+}
+.panel-success > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #d6e9c6;
+}
+.panel-info {
+  border-color: #bce8f1;
+}
+.panel-info > .panel-heading {
+  color: #31708f;
+  background-color: #d9edf7;
+  border-color: #bce8f1;
+}
+.panel-info > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #bce8f1;
+}
+.panel-info > .panel-heading .badge {
+  color: #d9edf7;
+  background-color: #31708f;
+}
+.panel-info > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #bce8f1;
+}
+.panel-warning {
+  border-color: #faebcc;
+}
+.panel-warning > .panel-heading {
+  color: #8a6d3b;
+  background-color: #fcf8e3;
+  border-color: #faebcc;
+}
+.panel-warning > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #faebcc;
+}
+.panel-warning > .panel-heading .badge {
+  color: #fcf8e3;
+  background-color: #8a6d3b;
+}
+.panel-warning > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #faebcc;
+}
+.panel-danger {
+  border-color: #ebccd1;
+}
+.panel-danger > .panel-heading {
+  color: #a94442;
+  background-color: #f2dede;
+  border-color: #ebccd1;
+}
+.panel-danger > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #ebccd1;
+}
+.panel-danger > .panel-heading .badge {
+  color: #f2dede;
+  background-color: #a94442;
+}
+.panel-danger > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #ebccd1;
+}
+.embed-responsive {
+  position: relative;
+  display: block;
+  height: 0;
+  padding: 0;
+  overflow: hidden;
+}
+.embed-responsive .embed-responsive-item,
+.embed-responsive iframe,
+.embed-responsive embed,
+.embed-responsive object,
+.embed-responsive video {
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  height: 100%;
+  width: 100%;
+  border: 0;
+}
+.embed-responsive-16by9 {
+  padding-bottom: 56.25%;
+}
+.embed-responsive-4by3 {
+  padding-bottom: 75%;
+}
+.well {
+  min-height: 20px;
+  padding: 19px;
+  margin-bottom: 20px;
+  background-color: #f5f5f5;
+  border: 1px solid #e3e3e3;
+  border-radius: 2px;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+}
+.well blockquote {
+  border-color: #ddd;
+  border-color: rgba(0, 0, 0, 0.15);
+}
+.well-lg {
+  padding: 24px;
+  border-radius: 3px;
+}
+.well-sm {
+  padding: 9px;
+  border-radius: 1px;
+}
+.close {
+  float: right;
+  font-size: 19.5px;
+  font-weight: bold;
+  line-height: 1;
+  color: #000;
+  text-shadow: 0 1px 0 #fff;
+  opacity: 0.2;
+  filter: alpha(opacity=20);
+}
+.close:hover,
+.close:focus {
+  color: #000;
+  text-decoration: none;
+  cursor: pointer;
+  opacity: 0.5;
+  filter: alpha(opacity=50);
+}
+button.close {
+  padding: 0;
+  cursor: pointer;
+  background: transparent;
+  border: 0;
+  -webkit-appearance: none;
+}
+.modal-open {
+  overflow: hidden;
+}
+.modal {
+  display: none;
+  overflow: hidden;
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 1050;
+  -webkit-overflow-scrolling: touch;
+  outline: 0;
+}
+.modal.fade .modal-dialog {
+  -webkit-transform: translate(0, -25%);
+  -ms-transform: translate(0, -25%);
+  -o-transform: translate(0, -25%);
+  transform: translate(0, -25%);
+  -webkit-transition: -webkit-transform 0.3s ease-out;
+  -moz-transition: -moz-transform 0.3s ease-out;
+  -o-transition: -o-transform 0.3s ease-out;
+  transition: transform 0.3s ease-out;
+}
+.modal.in .modal-dialog {
+  -webkit-transform: translate(0, 0);
+  -ms-transform: translate(0, 0);
+  -o-transform: translate(0, 0);
+  transform: translate(0, 0);
+}
+.modal-open .modal {
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+.modal-dialog {
+  position: relative;
+  width: auto;
+  margin: 10px;
+}
+.modal-content {
+  position: relative;
+  background-color: #fff;
+  border: 1px solid #999;
+  border: 1px solid rgba(0, 0, 0, 0.2);
+  border-radius: 3px;
+  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
+  box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
+  background-clip: padding-box;
+  outline: 0;
+}
+.modal-backdrop {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 1040;
+  background-color: #000;
+}
+.modal-backdrop.fade {
+  opacity: 0;
+  filter: alpha(opacity=0);
+}
+.modal-backdrop.in {
+  opacity: 0.5;
+  filter: alpha(opacity=50);
+}
+.modal-header {
+  padding: 15px;
+  border-bottom: 1px solid #e5e5e5;
+}
+.modal-header .close {
+  margin-top: -2px;
+}
+.modal-title {
+  margin: 0;
+  line-height: 1.42857143;
+}
+.modal-body {
+  position: relative;
+  padding: 15px;
+}
+.modal-footer {
+  padding: 15px;
+  text-align: right;
+  border-top: 1px solid #e5e5e5;
+}
+.modal-footer .btn + .btn {
+  margin-left: 5px;
+  margin-bottom: 0;
+}
+.modal-footer .btn-group .btn + .btn {
+  margin-left: -1px;
+}
+.modal-footer .btn-block + .btn-block {
+  margin-left: 0;
+}
+.modal-scrollbar-measure {
+  position: absolute;
+  top: -9999px;
+  width: 50px;
+  height: 50px;
+  overflow: scroll;
+}
+@media (min-width: 768px) {
+  .modal-dialog {
+    width: 600px;
+    margin: 30px auto;
+  }
+  .modal-content {
+    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
+    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
+  }
+  .modal-sm {
+    width: 300px;
+  }
+}
+@media (min-width: 992px) {
+  .modal-lg {
+    width: 900px;
+  }
+}
+.tooltip {
+  position: absolute;
+  z-index: 1070;
+  display: block;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-style: normal;
+  font-weight: normal;
+  letter-spacing: normal;
+  line-break: auto;
+  line-height: 1.42857143;
+  text-align: left;
+  text-align: start;
+  text-decoration: none;
+  text-shadow: none;
+  text-transform: none;
+  white-space: normal;
+  word-break: normal;
+  word-spacing: normal;
+  word-wrap: normal;
+  font-size: 12px;
+  opacity: 0;
+  filter: alpha(opacity=0);
+}
+.tooltip.in {
+  opacity: 0.9;
+  filter: alpha(opacity=90);
+}
+.tooltip.top {
+  margin-top: -3px;
+  padding: 5px 0;
+}
+.tooltip.right {
+  margin-left: 3px;
+  padding: 0 5px;
+}
+.tooltip.bottom {
+  margin-top: 3px;
+  padding: 5px 0;
+}
+.tooltip.left {
+  margin-left: -3px;
+  padding: 0 5px;
+}
+.tooltip-inner {
+  max-width: 200px;
+  padding: 3px 8px;
+  color: #fff;
+  text-align: center;
+  background-color: #000;
+  border-radius: 2px;
+}
+.tooltip-arrow {
+  position: absolute;
+  width: 0;
+  height: 0;
+  border-color: transparent;
+  border-style: solid;
+}
+.tooltip.top .tooltip-arrow {
+  bottom: 0;
+  left: 50%;
+  margin-left: -5px;
+  border-width: 5px 5px 0;
+  border-top-color: #000;
+}
+.tooltip.top-left .tooltip-arrow {
+  bottom: 0;
+  right: 5px;
+  margin-bottom: -5px;
+  border-width: 5px 5px 0;
+  border-top-color: #000;
+}
+.tooltip.top-right .tooltip-arrow {
+  bottom: 0;
+  left: 5px;
+  margin-bottom: -5px;
+  border-width: 5px 5px 0;
+  border-top-color: #000;
+}
+.tooltip.right .tooltip-arrow {
+  top: 50%;
+  left: 0;
+  margin-top: -5px;
+  border-width: 5px 5px 5px 0;
+  border-right-color: #000;
+}
+.tooltip.left .tooltip-arrow {
+  top: 50%;
+  right: 0;
+  margin-top: -5px;
+  border-width: 5px 0 5px 5px;
+  border-left-color: #000;
+}
+.tooltip.bottom .tooltip-arrow {
+  top: 0;
+  left: 50%;
+  margin-left: -5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000;
+}
+.tooltip.bottom-left .tooltip-arrow {
+  top: 0;
+  right: 5px;
+  margin-top: -5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000;
+}
+.tooltip.bottom-right .tooltip-arrow {
+  top: 0;
+  left: 5px;
+  margin-top: -5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000;
+}
+.popover {
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: 1060;
+  display: none;
+  max-width: 276px;
+  padding: 1px;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-style: normal;
+  font-weight: normal;
+  letter-spacing: normal;
+  line-break: auto;
+  line-height: 1.42857143;
+  text-align: left;
+  text-align: start;
+  text-decoration: none;
+  text-shadow: none;
+  text-transform: none;
+  white-space: normal;
+  word-break: normal;
+  word-spacing: normal;
+  word-wrap: normal;
+  font-size: 13px;
+  background-color: #fff;
+  background-clip: padding-box;
+  border: 1px solid #ccc;
+  border: 1px solid rgba(0, 0, 0, 0.2);
+  border-radius: 3px;
+  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+}
+.popover.top {
+  margin-top: -10px;
+}
+.popover.right {
+  margin-left: 10px;
+}
+.popover.bottom {
+  margin-top: 10px;
+}
+.popover.left {
+  margin-left: -10px;
+}
+.popover-title {
+  margin: 0;
+  padding: 8px 14px;
+  font-size: 13px;
+  background-color: #f7f7f7;
+  border-bottom: 1px solid #ebebeb;
+  border-radius: 2px 2px 0 0;
+}
+.popover-content {
+  padding: 9px 14px;
+}
+.popover > .arrow,
+.popover > .arrow:after {
+  position: absolute;
+  display: block;
+  width: 0;
+  height: 0;
+  border-color: transparent;
+  border-style: solid;
+}
+.popover > .arrow {
+  border-width: 11px;
+}
+.popover > .arrow:after {
+  border-width: 10px;
+  content: "";
+}
+.popover.top > .arrow {
+  left: 50%;
+  margin-left: -11px;
+  border-bottom-width: 0;
+  border-top-color: #999999;
+  border-top-color: rgba(0, 0, 0, 0.25);
+  bottom: -11px;
+}
+.popover.top > .arrow:after {
+  content: " ";
+  bottom: 1px;
+  margin-left: -10px;
+  border-bottom-width: 0;
+  border-top-color: #fff;
+}
+.popover.right > .arrow {
+  top: 50%;
+  left: -11px;
+  margin-top: -11px;
+  border-left-width: 0;
+  border-right-color: #999999;
+  border-right-color: rgba(0, 0, 0, 0.25);
+}
+.popover.right > .arrow:after {
+  content: " ";
+  left: 1px;
+  bottom: -10px;
+  border-left-width: 0;
+  border-right-color: #fff;
+}
+.popover.bottom > .arrow {
+  left: 50%;
+  margin-left: -11px;
+  border-top-width: 0;
+  border-bottom-color: #999999;
+  border-bottom-color: rgba(0, 0, 0, 0.25);
+  top: -11px;
+}
+.popover.bottom > .arrow:after {
+  content: " ";
+  top: 1px;
+  margin-left: -10px;
+  border-top-width: 0;
+  border-bottom-color: #fff;
+}
+.popover.left > .arrow {
+  top: 50%;
+  right: -11px;
+  margin-top: -11px;
+  border-right-width: 0;
+  border-left-color: #999999;
+  border-left-color: rgba(0, 0, 0, 0.25);
+}
+.popover.left > .arrow:after {
+  content: " ";
+  right: 1px;
+  border-right-width: 0;
+  border-left-color: #fff;
+  bottom: -10px;
+}
+.carousel {
+  position: relative;
+}
+.carousel-inner {
+  position: relative;
+  overflow: hidden;
+  width: 100%;
+}
+.carousel-inner > .item {
+  display: none;
+  position: relative;
+  -webkit-transition: 0.6s ease-in-out left;
+  -o-transition: 0.6s ease-in-out left;
+  transition: 0.6s ease-in-out left;
+}
+.carousel-inner > .item > img,
+.carousel-inner > .item > a > img {
+  line-height: 1;
+}
+@media all and (transform-3d), (-webkit-transform-3d) {
+  .carousel-inner > .item {
+    -webkit-transition: -webkit-transform 0.6s ease-in-out;
+    -moz-transition: -moz-transform 0.6s ease-in-out;
+    -o-transition: -o-transform 0.6s ease-in-out;
+    transition: transform 0.6s ease-in-out;
+    -webkit-backface-visibility: hidden;
+    -moz-backface-visibility: hidden;
+    backface-visibility: hidden;
+    -webkit-perspective: 1000px;
+    -moz-perspective: 1000px;
+    perspective: 1000px;
+  }
+  .carousel-inner > .item.next,
+  .carousel-inner > .item.active.right {
+    -webkit-transform: translate3d(100%, 0, 0);
+    transform: translate3d(100%, 0, 0);
+    left: 0;
+  }
+  .carousel-inner > .item.prev,
+  .carousel-inner > .item.active.left {
+    -webkit-transform: translate3d(-100%, 0, 0);
+    transform: translate3d(-100%, 0, 0);
+    left: 0;
+  }
+  .carousel-inner > .item.next.left,
+  .carousel-inner > .item.prev.right,
+  .carousel-inner > .item.active {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+    left: 0;
+  }
+}
+.carousel-inner > .active,
+.carousel-inner > .next,
+.carousel-inner > .prev {
+  display: block;
+}
+.carousel-inner > .active {
+  left: 0;
+}
+.carousel-inner > .next,
+.carousel-inner > .prev {
+  position: absolute;
+  top: 0;
+  width: 100%;
+}
+.carousel-inner > .next {
+  left: 100%;
+}
+.carousel-inner > .prev {
+  left: -100%;
+}
+.carousel-inner > .next.left,
+.carousel-inner > .prev.right {
+  left: 0;
+}
+.carousel-inner > .active.left {
+  left: -100%;
+}
+.carousel-inner > .active.right {
+  left: 100%;
+}
+.carousel-control {
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  width: 15%;
+  opacity: 0.5;
+  filter: alpha(opacity=50);
+  font-size: 20px;
+  color: #fff;
+  text-align: center;
+  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
+  background-color: rgba(0, 0, 0, 0);
+}
+.carousel-control.left {
+  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);
+  background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);
+  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);
+  background-repeat: repeat-x;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);
+}
+.carousel-control.right {
+  left: auto;
+  right: 0;
+  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);
+  background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);
+  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);
+  background-repeat: repeat-x;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);
+}
+.carousel-control:hover,
+.carousel-control:focus {
+  outline: 0;
+  color: #fff;
+  text-decoration: none;
+  opacity: 0.9;
+  filter: alpha(opacity=90);
+}
+.carousel-control .icon-prev,
+.carousel-control .icon-next,
+.carousel-control .glyphicon-chevron-left,
+.carousel-control .glyphicon-chevron-right {
+  position: absolute;
+  top: 50%;
+  margin-top: -10px;
+  z-index: 5;
+  display: inline-block;
+}
+.carousel-control .icon-prev,
+.carousel-control .glyphicon-chevron-left {
+  left: 50%;
+  margin-left: -10px;
+}
+.carousel-control .icon-next,
+.carousel-control .glyphicon-chevron-right {
+  right: 50%;
+  margin-right: -10px;
+}
+.carousel-control .icon-prev,
+.carousel-control .icon-next {
+  width: 20px;
+  height: 20px;
+  line-height: 1;
+  font-family: serif;
+}
+.carousel-control .icon-prev:before {
+  content: '\2039';
+}
+.carousel-control .icon-next:before {
+  content: '\203a';
+}
+.carousel-indicators {
+  position: absolute;
+  bottom: 10px;
+  left: 50%;
+  z-index: 15;
+  width: 60%;
+  margin-left: -30%;
+  padding-left: 0;
+  list-style: none;
+  text-align: center;
+}
+.carousel-indicators li {
+  display: inline-block;
+  width: 10px;
+  height: 10px;
+  margin: 1px;
+  text-indent: -999px;
+  border: 1px solid #fff;
+  border-radius: 10px;
+  cursor: pointer;
+  background-color: #000 \9;
+  background-color: rgba(0, 0, 0, 0);
+}
+.carousel-indicators .active {
+  margin: 0;
+  width: 12px;
+  height: 12px;
+  background-color: #fff;
+}
+.carousel-caption {
+  position: absolute;
+  left: 15%;
+  right: 15%;
+  bottom: 20px;
+  z-index: 10;
+  padding-top: 20px;
+  padding-bottom: 20px;
+  color: #fff;
+  text-align: center;
+  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
+}
+.carousel-caption .btn {
+  text-shadow: none;
+}
+@media screen and (min-width: 768px) {
+  .carousel-control .glyphicon-chevron-left,
+  .carousel-control .glyphicon-chevron-right,
+  .carousel-control .icon-prev,
+  .carousel-control .icon-next {
+    width: 30px;
+    height: 30px;
+    margin-top: -10px;
+    font-size: 30px;
+  }
+  .carousel-control .glyphicon-chevron-left,
+  .carousel-control .icon-prev {
+    margin-left: -10px;
+  }
+  .carousel-control .glyphicon-chevron-right,
+  .carousel-control .icon-next {
+    margin-right: -10px;
+  }
+  .carousel-caption {
+    left: 20%;
+    right: 20%;
+    padding-bottom: 30px;
+  }
+  .carousel-indicators {
+    bottom: 20px;
+  }
+}
+.clearfix:before,
+.clearfix:after,
+.dl-horizontal dd:before,
+.dl-horizontal dd:after,
+.container:before,
+.container:after,
+.container-fluid:before,
+.container-fluid:after,
+.row:before,
+.row:after,
+.form-horizontal .form-group:before,
+.form-horizontal .form-group:after,
+.btn-toolbar:before,
+.btn-toolbar:after,
+.btn-group-vertical > .btn-group:before,
+.btn-group-vertical > .btn-group:after,
+.nav:before,
+.nav:after,
+.navbar:before,
+.navbar:after,
+.navbar-header:before,
+.navbar-header:after,
+.navbar-collapse:before,
+.navbar-collapse:after,
+.pager:before,
+.pager:after,
+.panel-body:before,
+.panel-body:after,
+.modal-header:before,
+.modal-header:after,
+.modal-footer:before,
+.modal-footer:after,
+.item_buttons:before,
+.item_buttons:after {
+  content: " ";
+  display: table;
+}
+.clearfix:after,
+.dl-horizontal dd:after,
+.container:after,
+.container-fluid:after,
+.row:after,
+.form-horizontal .form-group:after,
+.btn-toolbar:after,
+.btn-group-vertical > .btn-group:after,
+.nav:after,
+.navbar:after,
+.navbar-header:after,
+.navbar-collapse:after,
+.pager:after,
+.panel-body:after,
+.modal-header:after,
+.modal-footer:after,
+.item_buttons:after {
+  clear: both;
+}
+.center-block {
+  display: block;
+  margin-left: auto;
+  margin-right: auto;
+}
+.pull-right {
+  float: right !important;
+}
+.pull-left {
+  float: left !important;
+}
+.hide {
+  display: none !important;
+}
+.show {
+  display: block !important;
+}
+.invisible {
+  visibility: hidden;
+}
+.text-hide {
+  font: 0/0 a;
+  color: transparent;
+  text-shadow: none;
+  background-color: transparent;
+  border: 0;
+}
+.hidden {
+  display: none !important;
+}
+.affix {
+  position: fixed;
+}
+@-ms-viewport {
+  width: device-width;
+}
+.visible-xs,
+.visible-sm,
+.visible-md,
+.visible-lg {
+  display: none !important;
+}
+.visible-xs-block,
+.visible-xs-inline,
+.visible-xs-inline-block,
+.visible-sm-block,
+.visible-sm-inline,
+.visible-sm-inline-block,
+.visible-md-block,
+.visible-md-inline,
+.visible-md-inline-block,
+.visible-lg-block,
+.visible-lg-inline,
+.visible-lg-inline-block {
+  display: none !important;
+}
+@media (max-width: 767px) {
+  .visible-xs {
+    display: block !important;
+  }
+  table.visible-xs {
+    display: table !important;
+  }
+  tr.visible-xs {
+    display: table-row !important;
+  }
+  th.visible-xs,
+  td.visible-xs {
+    display: table-cell !important;
+  }
+}
+@media (max-width: 767px) {
+  .visible-xs-block {
+    display: block !important;
+  }
+}
+@media (max-width: 767px) {
+  .visible-xs-inline {
+    display: inline !important;
+  }
+}
+@media (max-width: 767px) {
+  .visible-xs-inline-block {
+    display: inline-block !important;
+  }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm {
+    display: block !important;
+  }
+  table.visible-sm {
+    display: table !important;
+  }
+  tr.visible-sm {
+    display: table-row !important;
+  }
+  th.visible-sm,
+  td.visible-sm {
+    display: table-cell !important;
+  }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm-block {
+    display: block !important;
+  }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm-inline {
+    display: inline !important;
+  }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm-inline-block {
+    display: inline-block !important;
+  }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md {
+    display: block !important;
+  }
+  table.visible-md {
+    display: table !important;
+  }
+  tr.visible-md {
+    display: table-row !important;
+  }
+  th.visible-md,
+  td.visible-md {
+    display: table-cell !important;
+  }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md-block {
+    display: block !important;
+  }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md-inline {
+    display: inline !important;
+  }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md-inline-block {
+    display: inline-block !important;
+  }
+}
+@media (min-width: 1200px) {
+  .visible-lg {
+    display: block !important;
+  }
+  table.visible-lg {
+    display: table !important;
+  }
+  tr.visible-lg {
+    display: table-row !important;
+  }
+  th.visible-lg,
+  td.visible-lg {
+    display: table-cell !important;
+  }
+}
+@media (min-width: 1200px) {
+  .visible-lg-block {
+    display: block !important;
+  }
+}
+@media (min-width: 1200px) {
+  .visible-lg-inline {
+    display: inline !important;
+  }
+}
+@media (min-width: 1200px) {
+  .visible-lg-inline-block {
+    display: inline-block !important;
+  }
+}
+@media (max-width: 767px) {
+  .hidden-xs {
+    display: none !important;
+  }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+  .hidden-sm {
+    display: none !important;
+  }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+  .hidden-md {
+    display: none !important;
+  }
+}
+@media (min-width: 1200px) {
+  .hidden-lg {
+    display: none !important;
+  }
+}
+.visible-print {
+  display: none !important;
+}
+@media print {
+  .visible-print {
+    display: block !important;
+  }
+  table.visible-print {
+    display: table !important;
+  }
+  tr.visible-print {
+    display: table-row !important;
+  }
+  th.visible-print,
+  td.visible-print {
+    display: table-cell !important;
+  }
+}
+.visible-print-block {
+  display: none !important;
+}
+@media print {
+  .visible-print-block {
+    display: block !important;
+  }
+}
+.visible-print-inline {
+  display: none !important;
+}
+@media print {
+  .visible-print-inline {
+    display: inline !important;
+  }
+}
+.visible-print-inline-block {
+  display: none !important;
+}
+@media print {
+  .visible-print-inline-block {
+    display: inline-block !important;
+  }
+}
+@media print {
+  .hidden-print {
+    display: none !important;
+  }
+}
+/*!
+*
+* Font Awesome
+*
+*/
+/*!
+ *  Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome
+ *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
+ */
+/* FONT PATH
+ * -------------------------- */
+@font-face {
+  font-family: 'FontAwesome';
+  src: url('../components/font-awesome/fonts/fontawesome-webfont.eot?v=4.2.0');
+  src: url('../components/font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.2.0') format('embedded-opentype'), url('../components/font-awesome/fonts/fontawesome-webfont.woff?v=4.2.0') format('woff'), url('../components/font-awesome/fonts/fontawesome-webfont.ttf?v=4.2.0') format('truetype'), url('../components/font-awesome/fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular') format('svg');
+  font-weight: normal;
+  font-style: normal;
+}
+.fa {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+/* makes the font 33% larger relative to the icon container */
+.fa-lg {
+  font-size: 1.33333333em;
+  line-height: 0.75em;
+  vertical-align: -15%;
+}
+.fa-2x {
+  font-size: 2em;
+}
+.fa-3x {
+  font-size: 3em;
+}
+.fa-4x {
+  font-size: 4em;
+}
+.fa-5x {
+  font-size: 5em;
+}
+.fa-fw {
+  width: 1.28571429em;
+  text-align: center;
+}
+.fa-ul {
+  padding-left: 0;
+  margin-left: 2.14285714em;
+  list-style-type: none;
+}
+.fa-ul > li {
+  position: relative;
+}
+.fa-li {
+  position: absolute;
+  left: -2.14285714em;
+  width: 2.14285714em;
+  top: 0.14285714em;
+  text-align: center;
+}
+.fa-li.fa-lg {
+  left: -1.85714286em;
+}
+.fa-border {
+  padding: .2em .25em .15em;
+  border: solid 0.08em #eee;
+  border-radius: .1em;
+}
+.pull-right {
+  float: right;
+}
+.pull-left {
+  float: left;
+}
+.fa.pull-left {
+  margin-right: .3em;
+}
+.fa.pull-right {
+  margin-left: .3em;
+}
+.fa-spin {
+  -webkit-animation: fa-spin 2s infinite linear;
+  animation: fa-spin 2s infinite linear;
+}
+@-webkit-keyframes fa-spin {
+  0% {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+  100% {
+    -webkit-transform: rotate(359deg);
+    transform: rotate(359deg);
+  }
+}
+@keyframes fa-spin {
+  0% {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+  100% {
+    -webkit-transform: rotate(359deg);
+    transform: rotate(359deg);
+  }
+}
+.fa-rotate-90 {
+  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
+  -webkit-transform: rotate(90deg);
+  -ms-transform: rotate(90deg);
+  transform: rotate(90deg);
+}
+.fa-rotate-180 {
+  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
+  -webkit-transform: rotate(180deg);
+  -ms-transform: rotate(180deg);
+  transform: rotate(180deg);
+}
+.fa-rotate-270 {
+  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
+  -webkit-transform: rotate(270deg);
+  -ms-transform: rotate(270deg);
+  transform: rotate(270deg);
+}
+.fa-flip-horizontal {
+  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);
+  -webkit-transform: scale(-1, 1);
+  -ms-transform: scale(-1, 1);
+  transform: scale(-1, 1);
+}
+.fa-flip-vertical {
+  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);
+  -webkit-transform: scale(1, -1);
+  -ms-transform: scale(1, -1);
+  transform: scale(1, -1);
+}
+:root .fa-rotate-90,
+:root .fa-rotate-180,
+:root .fa-rotate-270,
+:root .fa-flip-horizontal,
+:root .fa-flip-vertical {
+  filter: none;
+}
+.fa-stack {
+  position: relative;
+  display: inline-block;
+  width: 2em;
+  height: 2em;
+  line-height: 2em;
+  vertical-align: middle;
+}
+.fa-stack-1x,
+.fa-stack-2x {
+  position: absolute;
+  left: 0;
+  width: 100%;
+  text-align: center;
+}
+.fa-stack-1x {
+  line-height: inherit;
+}
+.fa-stack-2x {
+  font-size: 2em;
+}
+.fa-inverse {
+  color: #fff;
+}
+/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
+   readers do not read off random characters that represent icons */
+.fa-glass:before {
+  content: "\f000";
+}
+.fa-music:before {
+  content: "\f001";
+}
+.fa-search:before {
+  content: "\f002";
+}
+.fa-envelope-o:before {
+  content: "\f003";
+}
+.fa-heart:before {
+  content: "\f004";
+}
+.fa-star:before {
+  content: "\f005";
+}
+.fa-star-o:before {
+  content: "\f006";
+}
+.fa-user:before {
+  content: "\f007";
+}
+.fa-film:before {
+  content: "\f008";
+}
+.fa-th-large:before {
+  content: "\f009";
+}
+.fa-th:before {
+  content: "\f00a";
+}
+.fa-th-list:before {
+  content: "\f00b";
+}
+.fa-check:before {
+  content: "\f00c";
+}
+.fa-remove:before,
+.fa-close:before,
+.fa-times:before {
+  content: "\f00d";
+}
+.fa-search-plus:before {
+  content: "\f00e";
+}
+.fa-search-minus:before {
+  content: "\f010";
+}
+.fa-power-off:before {
+  content: "\f011";
+}
+.fa-signal:before {
+  content: "\f012";
+}
+.fa-gear:before,
+.fa-cog:before {
+  content: "\f013";
+}
+.fa-trash-o:before {
+  content: "\f014";
+}
+.fa-home:before {
+  content: "\f015";
+}
+.fa-file-o:before {
+  content: "\f016";
+}
+.fa-clock-o:before {
+  content: "\f017";
+}
+.fa-road:before {
+  content: "\f018";
+}
+.fa-download:before {
+  content: "\f019";
+}
+.fa-arrow-circle-o-down:before {
+  content: "\f01a";
+}
+.fa-arrow-circle-o-up:before {
+  content: "\f01b";
+}
+.fa-inbox:before {
+  content: "\f01c";
+}
+.fa-play-circle-o:before {
+  content: "\f01d";
+}
+.fa-rotate-right:before,
+.fa-repeat:before {
+  content: "\f01e";
+}
+.fa-refresh:before {
+  content: "\f021";
+}
+.fa-list-alt:before {
+  content: "\f022";
+}
+.fa-lock:before {
+  content: "\f023";
+}
+.fa-flag:before {
+  content: "\f024";
+}
+.fa-headphones:before {
+  content: "\f025";
+}
+.fa-volume-off:before {
+  content: "\f026";
+}
+.fa-volume-down:before {
+  content: "\f027";
+}
+.fa-volume-up:before {
+  content: "\f028";
+}
+.fa-qrcode:before {
+  content: "\f029";
+}
+.fa-barcode:before {
+  content: "\f02a";
+}
+.fa-tag:before {
+  content: "\f02b";
+}
+.fa-tags:before {
+  content: "\f02c";
+}
+.fa-book:before {
+  content: "\f02d";
+}
+.fa-bookmark:before {
+  content: "\f02e";
+}
+.fa-print:before {
+  content: "\f02f";
+}
+.fa-camera:before {
+  content: "\f030";
+}
+.fa-font:before {
+  content: "\f031";
+}
+.fa-bold:before {
+  content: "\f032";
+}
+.fa-italic:before {
+  content: "\f033";
+}
+.fa-text-height:before {
+  content: "\f034";
+}
+.fa-text-width:before {
+  content: "\f035";
+}
+.fa-align-left:before {
+  content: "\f036";
+}
+.fa-align-center:before {
+  content: "\f037";
+}
+.fa-align-right:before {
+  content: "\f038";
+}
+.fa-align-justify:before {
+  content: "\f039";
+}
+.fa-list:before {
+  content: "\f03a";
+}
+.fa-dedent:before,
+.fa-outdent:before {
+  content: "\f03b";
+}
+.fa-indent:before {
+  content: "\f03c";
+}
+.fa-video-camera:before {
+  content: "\f03d";
+}
+.fa-photo:before,
+.fa-image:before,
+.fa-picture-o:before {
+  content: "\f03e";
+}
+.fa-pencil:before {
+  content: "\f040";
+}
+.fa-map-marker:before {
+  content: "\f041";
+}
+.fa-adjust:before {
+  content: "\f042";
+}
+.fa-tint:before {
+  content: "\f043";
+}
+.fa-edit:before,
+.fa-pencil-square-o:before {
+  content: "\f044";
+}
+.fa-share-square-o:before {
+  content: "\f045";
+}
+.fa-check-square-o:before {
+  content: "\f046";
+}
+.fa-arrows:before {
+  content: "\f047";
+}
+.fa-step-backward:before {
+  content: "\f048";
+}
+.fa-fast-backward:before {
+  content: "\f049";
+}
+.fa-backward:before {
+  content: "\f04a";
+}
+.fa-play:before {
+  content: "\f04b";
+}
+.fa-pause:before {
+  content: "\f04c";
+}
+.fa-stop:before {
+  content: "\f04d";
+}
+.fa-forward:before {
+  content: "\f04e";
+}
+.fa-fast-forward:before {
+  content: "\f050";
+}
+.fa-step-forward:before {
+  content: "\f051";
+}
+.fa-eject:before {
+  content: "\f052";
+}
+.fa-chevron-left:before {
+  content: "\f053";
+}
+.fa-chevron-right:before {
+  content: "\f054";
+}
+.fa-plus-circle:before {
+  content: "\f055";
+}
+.fa-minus-circle:before {
+  content: "\f056";
+}
+.fa-times-circle:before {
+  content: "\f057";
+}
+.fa-check-circle:before {
+  content: "\f058";
+}
+.fa-question-circle:before {
+  content: "\f059";
+}
+.fa-info-circle:before {
+  content: "\f05a";
+}
+.fa-crosshairs:before {
+  content: "\f05b";
+}
+.fa-times-circle-o:before {
+  content: "\f05c";
+}
+.fa-check-circle-o:before {
+  content: "\f05d";
+}
+.fa-ban:before {
+  content: "\f05e";
+}
+.fa-arrow-left:before {
+  content: "\f060";
+}
+.fa-arrow-right:before {
+  content: "\f061";
+}
+.fa-arrow-up:before {
+  content: "\f062";
+}
+.fa-arrow-down:before {
+  content: "\f063";
+}
+.fa-mail-forward:before,
+.fa-share:before {
+  content: "\f064";
+}
+.fa-expand:before {
+  content: "\f065";
+}
+.fa-compress:before {
+  content: "\f066";
+}
+.fa-plus:before {
+  content: "\f067";
+}
+.fa-minus:before {
+  content: "\f068";
+}
+.fa-asterisk:before {
+  content: "\f069";
+}
+.fa-exclamation-circle:before {
+  content: "\f06a";
+}
+.fa-gift:before {
+  content: "\f06b";
+}
+.fa-leaf:before {
+  content: "\f06c";
+}
+.fa-fire:before {
+  content: "\f06d";
+}
+.fa-eye:before {
+  content: "\f06e";
+}
+.fa-eye-slash:before {
+  content: "\f070";
+}
+.fa-warning:before,
+.fa-exclamation-triangle:before {
+  content: "\f071";
+}
+.fa-plane:before {
+  content: "\f072";
+}
+.fa-calendar:before {
+  content: "\f073";
+}
+.fa-random:before {
+  content: "\f074";
+}
+.fa-comment:before {
+  content: "\f075";
+}
+.fa-magnet:before {
+  content: "\f076";
+}
+.fa-chevron-up:before {
+  content: "\f077";
+}
+.fa-chevron-down:before {
+  content: "\f078";
+}
+.fa-retweet:before {
+  content: "\f079";
+}
+.fa-shopping-cart:before {
+  content: "\f07a";
+}
+.fa-folder:before {
+  content: "\f07b";
+}
+.fa-folder-open:before {
+  content: "\f07c";
+}
+.fa-arrows-v:before {
+  content: "\f07d";
+}
+.fa-arrows-h:before {
+  content: "\f07e";
+}
+.fa-bar-chart-o:before,
+.fa-bar-chart:before {
+  content: "\f080";
+}
+.fa-twitter-square:before {
+  content: "\f081";
+}
+.fa-facebook-square:before {
+  content: "\f082";
+}
+.fa-camera-retro:before {
+  content: "\f083";
+}
+.fa-key:before {
+  content: "\f084";
+}
+.fa-gears:before,
+.fa-cogs:before {
+  content: "\f085";
+}
+.fa-comments:before {
+  content: "\f086";
+}
+.fa-thumbs-o-up:before {
+  content: "\f087";
+}
+.fa-thumbs-o-down:before {
+  content: "\f088";
+}
+.fa-star-half:before {
+  content: "\f089";
+}
+.fa-heart-o:before {
+  content: "\f08a";
+}
+.fa-sign-out:before {
+  content: "\f08b";
+}
+.fa-linkedin-square:before {
+  content: "\f08c";
+}
+.fa-thumb-tack:before {
+  content: "\f08d";
+}
+.fa-external-link:before {
+  content: "\f08e";
+}
+.fa-sign-in:before {
+  content: "\f090";
+}
+.fa-trophy:before {
+  content: "\f091";
+}
+.fa-github-square:before {
+  content: "\f092";
+}
+.fa-upload:before {
+  content: "\f093";
+}
+.fa-lemon-o:before {
+  content: "\f094";
+}
+.fa-phone:before {
+  content: "\f095";
+}
+.fa-square-o:before {
+  content: "\f096";
+}
+.fa-bookmark-o:before {
+  content: "\f097";
+}
+.fa-phone-square:before {
+  content: "\f098";
+}
+.fa-twitter:before {
+  content: "\f099";
+}
+.fa-facebook:before {
+  content: "\f09a";
+}
+.fa-github:before {
+  content: "\f09b";
+}
+.fa-unlock:before {
+  content: "\f09c";
+}
+.fa-credit-card:before {
+  content: "\f09d";
+}
+.fa-rss:before {
+  content: "\f09e";
+}
+.fa-hdd-o:before {
+  content: "\f0a0";
+}
+.fa-bullhorn:before {
+  content: "\f0a1";
+}
+.fa-bell:before {
+  content: "\f0f3";
+}
+.fa-certificate:before {
+  content: "\f0a3";
+}
+.fa-hand-o-right:before {
+  content: "\f0a4";
+}
+.fa-hand-o-left:before {
+  content: "\f0a5";
+}
+.fa-hand-o-up:before {
+  content: "\f0a6";
+}
+.fa-hand-o-down:before {
+  content: "\f0a7";
+}
+.fa-arrow-circle-left:before {
+  content: "\f0a8";
+}
+.fa-arrow-circle-right:before {
+  content: "\f0a9";
+}
+.fa-arrow-circle-up:before {
+  content: "\f0aa";
+}
+.fa-arrow-circle-down:before {
+  content: "\f0ab";
+}
+.fa-globe:before {
+  content: "\f0ac";
+}
+.fa-wrench:before {
+  content: "\f0ad";
+}
+.fa-tasks:before {
+  content: "\f0ae";
+}
+.fa-filter:before {
+  content: "\f0b0";
+}
+.fa-briefcase:before {
+  content: "\f0b1";
+}
+.fa-arrows-alt:before {
+  content: "\f0b2";
+}
+.fa-group:before,
+.fa-users:before {
+  content: "\f0c0";
+}
+.fa-chain:before,
+.fa-link:before {
+  content: "\f0c1";
+}
+.fa-cloud:before {
+  content: "\f0c2";
+}
+.fa-flask:before {
+  content: "\f0c3";
+}
+.fa-cut:before,
+.fa-scissors:before {
+  content: "\f0c4";
+}
+.fa-copy:before,
+.fa-files-o:before {
+  content: "\f0c5";
+}
+.fa-paperclip:before {
+  content: "\f0c6";
+}
+.fa-save:before,
+.fa-floppy-o:before {
+  content: "\f0c7";
+}
+.fa-square:before {
+  content: "\f0c8";
+}
+.fa-navicon:before,
+.fa-reorder:before,
+.fa-bars:before {
+  content: "\f0c9";
+}
+.fa-list-ul:before {
+  content: "\f0ca";
+}
+.fa-list-ol:before {
+  content: "\f0cb";
+}
+.fa-strikethrough:before {
+  content: "\f0cc";
+}
+.fa-underline:before {
+  content: "\f0cd";
+}
+.fa-table:before {
+  content: "\f0ce";
+}
+.fa-magic:before {
+  content: "\f0d0";
+}
+.fa-truck:before {
+  content: "\f0d1";
+}
+.fa-pinterest:before {
+  content: "\f0d2";
+}
+.fa-pinterest-square:before {
+  content: "\f0d3";
+}
+.fa-google-plus-square:before {
+  content: "\f0d4";
+}
+.fa-google-plus:before {
+  content: "\f0d5";
+}
+.fa-money:before {
+  content: "\f0d6";
+}
+.fa-caret-down:before {
+  content: "\f0d7";
+}
+.fa-caret-up:before {
+  content: "\f0d8";
+}
+.fa-caret-left:before {
+  content: "\f0d9";
+}
+.fa-caret-right:before {
+  content: "\f0da";
+}
+.fa-columns:before {
+  content: "\f0db";
+}
+.fa-unsorted:before,
+.fa-sort:before {
+  content: "\f0dc";
+}
+.fa-sort-down:before,
+.fa-sort-desc:before {
+  content: "\f0dd";
+}
+.fa-sort-up:before,
+.fa-sort-asc:before {
+  content: "\f0de";
+}
+.fa-envelope:before {
+  content: "\f0e0";
+}
+.fa-linkedin:before {
+  content: "\f0e1";
+}
+.fa-rotate-left:before,
+.fa-undo:before {
+  content: "\f0e2";
+}
+.fa-legal:before,
+.fa-gavel:before {
+  content: "\f0e3";
+}
+.fa-dashboard:before,
+.fa-tachometer:before {
+  content: "\f0e4";
+}
+.fa-comment-o:before {
+  content: "\f0e5";
+}
+.fa-comments-o:before {
+  content: "\f0e6";
+}
+.fa-flash:before,
+.fa-bolt:before {
+  content: "\f0e7";
+}
+.fa-sitemap:before {
+  content: "\f0e8";
+}
+.fa-umbrella:before {
+  content: "\f0e9";
+}
+.fa-paste:before,
+.fa-clipboard:before {
+  content: "\f0ea";
+}
+.fa-lightbulb-o:before {
+  content: "\f0eb";
+}
+.fa-exchange:before {
+  content: "\f0ec";
+}
+.fa-cloud-download:before {
+  content: "\f0ed";
+}
+.fa-cloud-upload:before {
+  content: "\f0ee";
+}
+.fa-user-md:before {
+  content: "\f0f0";
+}
+.fa-stethoscope:before {
+  content: "\f0f1";
+}
+.fa-suitcase:before {
+  content: "\f0f2";
+}
+.fa-bell-o:before {
+  content: "\f0a2";
+}
+.fa-coffee:before {
+  content: "\f0f4";
+}
+.fa-cutlery:before {
+  content: "\f0f5";
+}
+.fa-file-text-o:before {
+  content: "\f0f6";
+}
+.fa-building-o:before {
+  content: "\f0f7";
+}
+.fa-hospital-o:before {
+  content: "\f0f8";
+}
+.fa-ambulance:before {
+  content: "\f0f9";
+}
+.fa-medkit:before {
+  content: "\f0fa";
+}
+.fa-fighter-jet:before {
+  content: "\f0fb";
+}
+.fa-beer:before {
+  content: "\f0fc";
+}
+.fa-h-square:before {
+  content: "\f0fd";
+}
+.fa-plus-square:before {
+  content: "\f0fe";
+}
+.fa-angle-double-left:before {
+  content: "\f100";
+}
+.fa-angle-double-right:before {
+  content: "\f101";
+}
+.fa-angle-double-up:before {
+  content: "\f102";
+}
+.fa-angle-double-down:before {
+  content: "\f103";
+}
+.fa-angle-left:before {
+  content: "\f104";
+}
+.fa-angle-right:before {
+  content: "\f105";
+}
+.fa-angle-up:before {
+  content: "\f106";
+}
+.fa-angle-down:before {
+  content: "\f107";
+}
+.fa-desktop:before {
+  content: "\f108";
+}
+.fa-laptop:before {
+  content: "\f109";
+}
+.fa-tablet:before {
+  content: "\f10a";
+}
+.fa-mobile-phone:before,
+.fa-mobile:before {
+  content: "\f10b";
+}
+.fa-circle-o:before {
+  content: "\f10c";
+}
+.fa-quote-left:before {
+  content: "\f10d";
+}
+.fa-quote-right:before {
+  content: "\f10e";
+}
+.fa-spinner:before {
+  content: "\f110";
+}
+.fa-circle:before {
+  content: "\f111";
+}
+.fa-mail-reply:before,
+.fa-reply:before {
+  content: "\f112";
+}
+.fa-github-alt:before {
+  content: "\f113";
+}
+.fa-folder-o:before {
+  content: "\f114";
+}
+.fa-folder-open-o:before {
+  content: "\f115";
+}
+.fa-smile-o:before {
+  content: "\f118";
+}
+.fa-frown-o:before {
+  content: "\f119";
+}
+.fa-meh-o:before {
+  content: "\f11a";
+}
+.fa-gamepad:before {
+  content: "\f11b";
+}
+.fa-keyboard-o:before {
+  content: "\f11c";
+}
+.fa-flag-o:before {
+  content: "\f11d";
+}
+.fa-flag-checkered:before {
+  content: "\f11e";
+}
+.fa-terminal:before {
+  content: "\f120";
+}
+.fa-code:before {
+  content: "\f121";
+}
+.fa-mail-reply-all:before,
+.fa-reply-all:before {
+  content: "\f122";
+}
+.fa-star-half-empty:before,
+.fa-star-half-full:before,
+.fa-star-half-o:before {
+  content: "\f123";
+}
+.fa-location-arrow:before {
+  content: "\f124";
+}
+.fa-crop:before {
+  content: "\f125";
+}
+.fa-code-fork:before {
+  content: "\f126";
+}
+.fa-unlink:before,
+.fa-chain-broken:before {
+  content: "\f127";
+}
+.fa-question:before {
+  content: "\f128";
+}
+.fa-info:before {
+  content: "\f129";
+}
+.fa-exclamation:before {
+  content: "\f12a";
+}
+.fa-superscript:before {
+  content: "\f12b";
+}
+.fa-subscript:before {
+  content: "\f12c";
+}
+.fa-eraser:before {
+  content: "\f12d";
+}
+.fa-puzzle-piece:before {
+  content: "\f12e";
+}
+.fa-microphone:before {
+  content: "\f130";
+}
+.fa-microphone-slash:before {
+  content: "\f131";
+}
+.fa-shield:before {
+  content: "\f132";
+}
+.fa-calendar-o:before {
+  content: "\f133";
+}
+.fa-fire-extinguisher:before {
+  content: "\f134";
+}
+.fa-rocket:before {
+  content: "\f135";
+}
+.fa-maxcdn:before {
+  content: "\f136";
+}
+.fa-chevron-circle-left:before {
+  content: "\f137";
+}
+.fa-chevron-circle-right:before {
+  content: "\f138";
+}
+.fa-chevron-circle-up:before {
+  content: "\f139";
+}
+.fa-chevron-circle-down:before {
+  content: "\f13a";
+}
+.fa-html5:before {
+  content: "\f13b";
+}
+.fa-css3:before {
+  content: "\f13c";
+}
+.fa-anchor:before {
+  content: "\f13d";
+}
+.fa-unlock-alt:before {
+  content: "\f13e";
+}
+.fa-bullseye:before {
+  content: "\f140";
+}
+.fa-ellipsis-h:before {
+  content: "\f141";
+}
+.fa-ellipsis-v:before {
+  content: "\f142";
+}
+.fa-rss-square:before {
+  content: "\f143";
+}
+.fa-play-circle:before {
+  content: "\f144";
+}
+.fa-ticket:before {
+  content: "\f145";
+}
+.fa-minus-square:before {
+  content: "\f146";
+}
+.fa-minus-square-o:before {
+  content: "\f147";
+}
+.fa-level-up:before {
+  content: "\f148";
+}
+.fa-level-down:before {
+  content: "\f149";
+}
+.fa-check-square:before {
+  content: "\f14a";
+}
+.fa-pencil-square:before {
+  content: "\f14b";
+}
+.fa-external-link-square:before {
+  content: "\f14c";
+}
+.fa-share-square:before {
+  content: "\f14d";
+}
+.fa-compass:before {
+  content: "\f14e";
+}
+.fa-toggle-down:before,
+.fa-caret-square-o-down:before {
+  content: "\f150";
+}
+.fa-toggle-up:before,
+.fa-caret-square-o-up:before {
+  content: "\f151";
+}
+.fa-toggle-right:before,
+.fa-caret-square-o-right:before {
+  content: "\f152";
+}
+.fa-euro:before,
+.fa-eur:before {
+  content: "\f153";
+}
+.fa-gbp:before {
+  content: "\f154";
+}
+.fa-dollar:before,
+.fa-usd:before {
+  content: "\f155";
+}
+.fa-rupee:before,
+.fa-inr:before {
+  content: "\f156";
+}
+.fa-cny:before,
+.fa-rmb:before,
+.fa-yen:before,
+.fa-jpy:before {
+  content: "\f157";
+}
+.fa-ruble:before,
+.fa-rouble:before,
+.fa-rub:before {
+  content: "\f158";
+}
+.fa-won:before,
+.fa-krw:before {
+  content: "\f159";
+}
+.fa-bitcoin:before,
+.fa-btc:before {
+  content: "\f15a";
+}
+.fa-file:before {
+  content: "\f15b";
+}
+.fa-file-text:before {
+  content: "\f15c";
+}
+.fa-sort-alpha-asc:before {
+  content: "\f15d";
+}
+.fa-sort-alpha-desc:before {
+  content: "\f15e";
+}
+.fa-sort-amount-asc:before {
+  content: "\f160";
+}
+.fa-sort-amount-desc:before {
+  content: "\f161";
+}
+.fa-sort-numeric-asc:before {
+  content: "\f162";
+}
+.fa-sort-numeric-desc:before {
+  content: "\f163";
+}
+.fa-thumbs-up:before {
+  content: "\f164";
+}
+.fa-thumbs-down:before {
+  content: "\f165";
+}
+.fa-youtube-square:before {
+  content: "\f166";
+}
+.fa-youtube:before {
+  content: "\f167";
+}
+.fa-xing:before {
+  content: "\f168";
+}
+.fa-xing-square:before {
+  content: "\f169";
+}
+.fa-youtube-play:before {
+  content: "\f16a";
+}
+.fa-dropbox:before {
+  content: "\f16b";
+}
+.fa-stack-overflow:before {
+  content: "\f16c";
+}
+.fa-instagram:before {
+  content: "\f16d";
+}
+.fa-flickr:before {
+  content: "\f16e";
+}
+.fa-adn:before {
+  content: "\f170";
+}
+.fa-bitbucket:before {
+  content: "\f171";
+}
+.fa-bitbucket-square:before {
+  content: "\f172";
+}
+.fa-tumblr:before {
+  content: "\f173";
+}
+.fa-tumblr-square:before {
+  content: "\f174";
+}
+.fa-long-arrow-down:before {
+  content: "\f175";
+}
+.fa-long-arrow-up:before {
+  content: "\f176";
+}
+.fa-long-arrow-left:before {
+  content: "\f177";
+}
+.fa-long-arrow-right:before {
+  content: "\f178";
+}
+.fa-apple:before {
+  content: "\f179";
+}
+.fa-windows:before {
+  content: "\f17a";
+}
+.fa-android:before {
+  content: "\f17b";
+}
+.fa-linux:before {
+  content: "\f17c";
+}
+.fa-dribbble:before {
+  content: "\f17d";
+}
+.fa-skype:before {
+  content: "\f17e";
+}
+.fa-foursquare:before {
+  content: "\f180";
+}
+.fa-trello:before {
+  content: "\f181";
+}
+.fa-female:before {
+  content: "\f182";
+}
+.fa-male:before {
+  content: "\f183";
+}
+.fa-gittip:before {
+  content: "\f184";
+}
+.fa-sun-o:before {
+  content: "\f185";
+}
+.fa-moon-o:before {
+  content: "\f186";
+}
+.fa-archive:before {
+  content: "\f187";
+}
+.fa-bug:before {
+  content: "\f188";
+}
+.fa-vk:before {
+  content: "\f189";
+}
+.fa-weibo:before {
+  content: "\f18a";
+}
+.fa-renren:before {
+  content: "\f18b";
+}
+.fa-pagelines:before {
+  content: "\f18c";
+}
+.fa-stack-exchange:before {
+  content: "\f18d";
+}
+.fa-arrow-circle-o-right:before {
+  content: "\f18e";
+}
+.fa-arrow-circle-o-left:before {
+  content: "\f190";
+}
+.fa-toggle-left:before,
+.fa-caret-square-o-left:before {
+  content: "\f191";
+}
+.fa-dot-circle-o:before {
+  content: "\f192";
+}
+.fa-wheelchair:before {
+  content: "\f193";
+}
+.fa-vimeo-square:before {
+  content: "\f194";
+}
+.fa-turkish-lira:before,
+.fa-try:before {
+  content: "\f195";
+}
+.fa-plus-square-o:before {
+  content: "\f196";
+}
+.fa-space-shuttle:before {
+  content: "\f197";
+}
+.fa-slack:before {
+  content: "\f198";
+}
+.fa-envelope-square:before {
+  content: "\f199";
+}
+.fa-wordpress:before {
+  content: "\f19a";
+}
+.fa-openid:before {
+  content: "\f19b";
+}
+.fa-institution:before,
+.fa-bank:before,
+.fa-university:before {
+  content: "\f19c";
+}
+.fa-mortar-board:before,
+.fa-graduation-cap:before {
+  content: "\f19d";
+}
+.fa-yahoo:before {
+  content: "\f19e";
+}
+.fa-google:before {
+  content: "\f1a0";
+}
+.fa-reddit:before {
+  content: "\f1a1";
+}
+.fa-reddit-square:before {
+  content: "\f1a2";
+}
+.fa-stumbleupon-circle:before {
+  content: "\f1a3";
+}
+.fa-stumbleupon:before {
+  content: "\f1a4";
+}
+.fa-delicious:before {
+  content: "\f1a5";
+}
+.fa-digg:before {
+  content: "\f1a6";
+}
+.fa-pied-piper:before {
+  content: "\f1a7";
+}
+.fa-pied-piper-alt:before {
+  content: "\f1a8";
+}
+.fa-drupal:before {
+  content: "\f1a9";
+}
+.fa-joomla:before {
+  content: "\f1aa";
+}
+.fa-language:before {
+  content: "\f1ab";
+}
+.fa-fax:before {
+  content: "\f1ac";
+}
+.fa-building:before {
+  content: "\f1ad";
+}
+.fa-child:before {
+  content: "\f1ae";
+}
+.fa-paw:before {
+  content: "\f1b0";
+}
+.fa-spoon:before {
+  content: "\f1b1";
+}
+.fa-cube:before {
+  content: "\f1b2";
+}
+.fa-cubes:before {
+  content: "\f1b3";
+}
+.fa-behance:before {
+  content: "\f1b4";
+}
+.fa-behance-square:before {
+  content: "\f1b5";
+}
+.fa-steam:before {
+  content: "\f1b6";
+}
+.fa-steam-square:before {
+  content: "\f1b7";
+}
+.fa-recycle:before {
+  content: "\f1b8";
+}
+.fa-automobile:before,
+.fa-car:before {
+  content: "\f1b9";
+}
+.fa-cab:before,
+.fa-taxi:before {
+  content: "\f1ba";
+}
+.fa-tree:before {
+  content: "\f1bb";
+}
+.fa-spotify:before {
+  content: "\f1bc";
+}
+.fa-deviantart:before {
+  content: "\f1bd";
+}
+.fa-soundcloud:before {
+  content: "\f1be";
+}
+.fa-database:before {
+  content: "\f1c0";
+}
+.fa-file-pdf-o:before {
+  content: "\f1c1";
+}
+.fa-file-word-o:before {
+  content: "\f1c2";
+}
+.fa-file-excel-o:before {
+  content: "\f1c3";
+}
+.fa-file-powerpoint-o:before {
+  content: "\f1c4";
+}
+.fa-file-photo-o:before,
+.fa-file-picture-o:before,
+.fa-file-image-o:before {
+  content: "\f1c5";
+}
+.fa-file-zip-o:before,
+.fa-file-archive-o:before {
+  content: "\f1c6";
+}
+.fa-file-sound-o:before,
+.fa-file-audio-o:before {
+  content: "\f1c7";
+}
+.fa-file-movie-o:before,
+.fa-file-video-o:before {
+  content: "\f1c8";
+}
+.fa-file-code-o:before {
+  content: "\f1c9";
+}
+.fa-vine:before {
+  content: "\f1ca";
+}
+.fa-codepen:before {
+  content: "\f1cb";
+}
+.fa-jsfiddle:before {
+  content: "\f1cc";
+}
+.fa-life-bouy:before,
+.fa-life-buoy:before,
+.fa-life-saver:before,
+.fa-support:before,
+.fa-life-ring:before {
+  content: "\f1cd";
+}
+.fa-circle-o-notch:before {
+  content: "\f1ce";
+}
+.fa-ra:before,
+.fa-rebel:before {
+  content: "\f1d0";
+}
+.fa-ge:before,
+.fa-empire:before {
+  content: "\f1d1";
+}
+.fa-git-square:before {
+  content: "\f1d2";
+}
+.fa-git:before {
+  content: "\f1d3";
+}
+.fa-hacker-news:before {
+  content: "\f1d4";
+}
+.fa-tencent-weibo:before {
+  content: "\f1d5";
+}
+.fa-qq:before {
+  content: "\f1d6";
+}
+.fa-wechat:before,
+.fa-weixin:before {
+  content: "\f1d7";
+}
+.fa-send:before,
+.fa-paper-plane:before {
+  content: "\f1d8";
+}
+.fa-send-o:before,
+.fa-paper-plane-o:before {
+  content: "\f1d9";
+}
+.fa-history:before {
+  content: "\f1da";
+}
+.fa-circle-thin:before {
+  content: "\f1db";
+}
+.fa-header:before {
+  content: "\f1dc";
+}
+.fa-paragraph:before {
+  content: "\f1dd";
+}
+.fa-sliders:before {
+  content: "\f1de";
+}
+.fa-share-alt:before {
+  content: "\f1e0";
+}
+.fa-share-alt-square:before {
+  content: "\f1e1";
+}
+.fa-bomb:before {
+  content: "\f1e2";
+}
+.fa-soccer-ball-o:before,
+.fa-futbol-o:before {
+  content: "\f1e3";
+}
+.fa-tty:before {
+  content: "\f1e4";
+}
+.fa-binoculars:before {
+  content: "\f1e5";
+}
+.fa-plug:before {
+  content: "\f1e6";
+}
+.fa-slideshare:before {
+  content: "\f1e7";
+}
+.fa-twitch:before {
+  content: "\f1e8";
+}
+.fa-yelp:before {
+  content: "\f1e9";
+}
+.fa-newspaper-o:before {
+  content: "\f1ea";
+}
+.fa-wifi:before {
+  content: "\f1eb";
+}
+.fa-calculator:before {
+  content: "\f1ec";
+}
+.fa-paypal:before {
+  content: "\f1ed";
+}
+.fa-google-wallet:before {
+  content: "\f1ee";
+}
+.fa-cc-visa:before {
+  content: "\f1f0";
+}
+.fa-cc-mastercard:before {
+  content: "\f1f1";
+}
+.fa-cc-discover:before {
+  content: "\f1f2";
+}
+.fa-cc-amex:before {
+  content: "\f1f3";
+}
+.fa-cc-paypal:before {
+  content: "\f1f4";
+}
+.fa-cc-stripe:before {
+  content: "\f1f5";
+}
+.fa-bell-slash:before {
+  content: "\f1f6";
+}
+.fa-bell-slash-o:before {
+  content: "\f1f7";
+}
+.fa-trash:before {
+  content: "\f1f8";
+}
+.fa-copyright:before {
+  content: "\f1f9";
+}
+.fa-at:before {
+  content: "\f1fa";
+}
+.fa-eyedropper:before {
+  content: "\f1fb";
+}
+.fa-paint-brush:before {
+  content: "\f1fc";
+}
+.fa-birthday-cake:before {
+  content: "\f1fd";
+}
+.fa-area-chart:before {
+  content: "\f1fe";
+}
+.fa-pie-chart:before {
+  content: "\f200";
+}
+.fa-line-chart:before {
+  content: "\f201";
+}
+.fa-lastfm:before {
+  content: "\f202";
+}
+.fa-lastfm-square:before {
+  content: "\f203";
+}
+.fa-toggle-off:before {
+  content: "\f204";
+}
+.fa-toggle-on:before {
+  content: "\f205";
+}
+.fa-bicycle:before {
+  content: "\f206";
+}
+.fa-bus:before {
+  content: "\f207";
+}
+.fa-ioxhost:before {
+  content: "\f208";
+}
+.fa-angellist:before {
+  content: "\f209";
+}
+.fa-cc:before {
+  content: "\f20a";
+}
+.fa-shekel:before,
+.fa-sheqel:before,
+.fa-ils:before {
+  content: "\f20b";
+}
+.fa-meanpath:before {
+  content: "\f20c";
+}
+/*!
+*
+* IPython base
+*
+*/
+.modal.fade .modal-dialog {
+  -webkit-transform: translate(0, 0);
+  -ms-transform: translate(0, 0);
+  -o-transform: translate(0, 0);
+  transform: translate(0, 0);
+}
+code {
+  color: #000;
+}
+pre {
+  font-size: inherit;
+  line-height: inherit;
+}
+label {
+  font-weight: normal;
+}
+/* Make the page background atleast 100% the height of the view port */
+/* Make the page itself atleast 70% the height of the view port */
+.border-box-sizing {
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+}
+.corner-all {
+  border-radius: 2px;
+}
+.no-padding {
+  padding: 0px;
+}
+/* Flexible box model classes */
+/* Taken from Alex Russell http://infrequently.org/2009/08/css-3-progress/ */
+/* This file is a compatability layer.  It allows the usage of flexible box 
+model layouts accross multiple browsers, including older browsers.  The newest,
+universal implementation of the flexible box model is used when available (see
+`Modern browsers` comments below).  Browsers that are known to implement this 
+new spec completely include:
+
+    Firefox 28.0+
+    Chrome 29.0+
+    Internet Explorer 11+ 
+    Opera 17.0+
+
+Browsers not listed, including Safari, are supported via the styling under the
+`Old browsers` comments below.
+*/
+.hbox {
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: horizontal;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: horizontal;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: horizontal;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: row;
+  align-items: stretch;
+}
+.hbox > * {
+  /* Old browsers */
+  -webkit-box-flex: 0;
+  -moz-box-flex: 0;
+  box-flex: 0;
+  /* Modern browsers */
+  flex: none;
+}
+.vbox {
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: vertical;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: vertical;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: column;
+  align-items: stretch;
+}
+.vbox > * {
+  /* Old browsers */
+  -webkit-box-flex: 0;
+  -moz-box-flex: 0;
+  box-flex: 0;
+  /* Modern browsers */
+  flex: none;
+}
+.hbox.reverse,
+.vbox.reverse,
+.reverse {
+  /* Old browsers */
+  -webkit-box-direction: reverse;
+  -moz-box-direction: reverse;
+  box-direction: reverse;
+  /* Modern browsers */
+  flex-direction: row-reverse;
+}
+.hbox.box-flex0,
+.vbox.box-flex0,
+.box-flex0 {
+  /* Old browsers */
+  -webkit-box-flex: 0;
+  -moz-box-flex: 0;
+  box-flex: 0;
+  /* Modern browsers */
+  flex: none;
+  width: auto;
+}
+.hbox.box-flex1,
+.vbox.box-flex1,
+.box-flex1 {
+  /* Old browsers */
+  -webkit-box-flex: 1;
+  -moz-box-flex: 1;
+  box-flex: 1;
+  /* Modern browsers */
+  flex: 1;
+}
+.hbox.box-flex,
+.vbox.box-flex,
+.box-flex {
+  /* Old browsers */
+  /* Old browsers */
+  -webkit-box-flex: 1;
+  -moz-box-flex: 1;
+  box-flex: 1;
+  /* Modern browsers */
+  flex: 1;
+}
+.hbox.box-flex2,
+.vbox.box-flex2,
+.box-flex2 {
+  /* Old browsers */
+  -webkit-box-flex: 2;
+  -moz-box-flex: 2;
+  box-flex: 2;
+  /* Modern browsers */
+  flex: 2;
+}
+.box-group1 {
+  /*  Deprecated */
+  -webkit-box-flex-group: 1;
+  -moz-box-flex-group: 1;
+  box-flex-group: 1;
+}
+.box-group2 {
+  /* Deprecated */
+  -webkit-box-flex-group: 2;
+  -moz-box-flex-group: 2;
+  box-flex-group: 2;
+}
+.hbox.start,
+.vbox.start,
+.start {
+  /* Old browsers */
+  -webkit-box-pack: start;
+  -moz-box-pack: start;
+  box-pack: start;
+  /* Modern browsers */
+  justify-content: flex-start;
+}
+.hbox.end,
+.vbox.end,
+.end {
+  /* Old browsers */
+  -webkit-box-pack: end;
+  -moz-box-pack: end;
+  box-pack: end;
+  /* Modern browsers */
+  justify-content: flex-end;
+}
+.hbox.center,
+.vbox.center,
+.center {
+  /* Old browsers */
+  -webkit-box-pack: center;
+  -moz-box-pack: center;
+  box-pack: center;
+  /* Modern browsers */
+  justify-content: center;
+}
+.hbox.baseline,
+.vbox.baseline,
+.baseline {
+  /* Old browsers */
+  -webkit-box-pack: baseline;
+  -moz-box-pack: baseline;
+  box-pack: baseline;
+  /* Modern browsers */
+  justify-content: baseline;
+}
+.hbox.stretch,
+.vbox.stretch,
+.stretch {
+  /* Old browsers */
+  -webkit-box-pack: stretch;
+  -moz-box-pack: stretch;
+  box-pack: stretch;
+  /* Modern browsers */
+  justify-content: stretch;
+}
+.hbox.align-start,
+.vbox.align-start,
+.align-start {
+  /* Old browsers */
+  -webkit-box-align: start;
+  -moz-box-align: start;
+  box-align: start;
+  /* Modern browsers */
+  align-items: flex-start;
+}
+.hbox.align-end,
+.vbox.align-end,
+.align-end {
+  /* Old browsers */
+  -webkit-box-align: end;
+  -moz-box-align: end;
+  box-align: end;
+  /* Modern browsers */
+  align-items: flex-end;
+}
+.hbox.align-center,
+.vbox.align-center,
+.align-center {
+  /* Old browsers */
+  -webkit-box-align: center;
+  -moz-box-align: center;
+  box-align: center;
+  /* Modern browsers */
+  align-items: center;
+}
+.hbox.align-baseline,
+.vbox.align-baseline,
+.align-baseline {
+  /* Old browsers */
+  -webkit-box-align: baseline;
+  -moz-box-align: baseline;
+  box-align: baseline;
+  /* Modern browsers */
+  align-items: baseline;
+}
+.hbox.align-stretch,
+.vbox.align-stretch,
+.align-stretch {
+  /* Old browsers */
+  -webkit-box-align: stretch;
+  -moz-box-align: stretch;
+  box-align: stretch;
+  /* Modern browsers */
+  align-items: stretch;
+}
+div.error {
+  margin: 2em;
+  text-align: center;
+}
+div.error > h1 {
+  font-size: 500%;
+  line-height: normal;
+}
+div.error > p {
+  font-size: 200%;
+  line-height: normal;
+}
+div.traceback-wrapper {
+  text-align: left;
+  max-width: 800px;
+  margin: auto;
+}
+/**
+ * Primary styles
+ *
+ * Author: Jupyter Development Team
+ */
+body {
+  background-color: #fff;
+  /* This makes sure that the body covers the entire window and needs to
+       be in a different element than the display: box in wrapper below */
+  position: absolute;
+  left: 0px;
+  right: 0px;
+  top: 0px;
+  bottom: 0px;
+  overflow: visible;
+}
+body > #header {
+  /* Initially hidden to prevent FLOUC */
+  display: none;
+  background-color: #fff;
+  /* Display over codemirror */
+  position: relative;
+  z-index: 100;
+}
+body > #header #header-container {
+  padding-bottom: 5px;
+  padding-top: 5px;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+}
+body > #header .header-bar {
+  width: 100%;
+  height: 1px;
+  background: #e7e7e7;
+  margin-bottom: -1px;
+}
+@media print {
+  body > #header {
+    display: none !important;
+  }
+}
+#header-spacer {
+  width: 100%;
+  visibility: hidden;
+}
+@media print {
+  #header-spacer {
+    display: none;
+  }
+}
+#ipython_notebook {
+  padding-left: 0px;
+  padding-top: 1px;
+  padding-bottom: 1px;
+}
+@media (max-width: 991px) {
+  #ipython_notebook {
+    margin-left: 10px;
+  }
+}
+[dir="rtl"] #ipython_notebook {
+  float: right !important;
+}
+#noscript {
+  width: auto;
+  padding-top: 16px;
+  padding-bottom: 16px;
+  text-align: center;
+  font-size: 22px;
+  color: red;
+  font-weight: bold;
+}
+#ipython_notebook img {
+  height: 28px;
+}
+#site {
+  width: 100%;
+  display: none;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+  overflow: auto;
+}
+@media print {
+  #site {
+    height: auto !important;
+  }
+}
+/* Smaller buttons */
+.ui-button .ui-button-text {
+  padding: 0.2em 0.8em;
+  font-size: 77%;
+}
+input.ui-button {
+  padding: 0.3em 0.9em;
+}
+span#login_widget {
+  float: right;
+}
+span#login_widget > .button,
+#logout {
+  color: #333;
+  background-color: #fff;
+  border-color: #ccc;
+}
+span#login_widget > .button:focus,
+#logout:focus,
+span#login_widget > .button.focus,
+#logout.focus {
+  color: #333;
+  background-color: #e6e6e6;
+  border-color: #8c8c8c;
+}
+span#login_widget > .button:hover,
+#logout:hover {
+  color: #333;
+  background-color: #e6e6e6;
+  border-color: #adadad;
+}
+span#login_widget > .button:active,
+#logout:active,
+span#login_widget > .button.active,
+#logout.active,
+.open > .dropdown-togglespan#login_widget > .button,
+.open > .dropdown-toggle#logout {
+  color: #333;
+  background-color: #e6e6e6;
+  border-color: #adadad;
+}
+span#login_widget > .button:active:hover,
+#logout:active:hover,
+span#login_widget > .button.active:hover,
+#logout.active:hover,
+.open > .dropdown-togglespan#login_widget > .button:hover,
+.open > .dropdown-toggle#logout:hover,
+span#login_widget > .button:active:focus,
+#logout:active:focus,
+span#login_widget > .button.active:focus,
+#logout.active:focus,
+.open > .dropdown-togglespan#login_widget > .button:focus,
+.open > .dropdown-toggle#logout:focus,
+span#login_widget > .button:active.focus,
+#logout:active.focus,
+span#login_widget > .button.active.focus,
+#logout.active.focus,
+.open > .dropdown-togglespan#login_widget > .button.focus,
+.open > .dropdown-toggle#logout.focus {
+  color: #333;
+  background-color: #d4d4d4;
+  border-color: #8c8c8c;
+}
+span#login_widget > .button:active,
+#logout:active,
+span#login_widget > .button.active,
+#logout.active,
+.open > .dropdown-togglespan#login_widget > .button,
+.open > .dropdown-toggle#logout {
+  background-image: none;
+}
+span#login_widget > .button.disabled:hover,
+#logout.disabled:hover,
+span#login_widget > .button[disabled]:hover,
+#logout[disabled]:hover,
+fieldset[disabled] span#login_widget > .button:hover,
+fieldset[disabled] #logout:hover,
+span#login_widget > .button.disabled:focus,
+#logout.disabled:focus,
+span#login_widget > .button[disabled]:focus,
+#logout[disabled]:focus,
+fieldset[disabled] span#login_widget > .button:focus,
+fieldset[disabled] #logout:focus,
+span#login_widget > .button.disabled.focus,
+#logout.disabled.focus,
+span#login_widget > .button[disabled].focus,
+#logout[disabled].focus,
+fieldset[disabled] span#login_widget > .button.focus,
+fieldset[disabled] #logout.focus {
+  background-color: #fff;
+  border-color: #ccc;
+}
+span#login_widget > .button .badge,
+#logout .badge {
+  color: #fff;
+  background-color: #333;
+}
+.nav-header {
+  text-transform: none;
+}
+#header > span {
+  margin-top: 10px;
+}
+.modal_stretch .modal-dialog {
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: vertical;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: vertical;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: column;
+  align-items: stretch;
+  min-height: 80vh;
+}
+.modal_stretch .modal-dialog .modal-body {
+  max-height: calc(100vh - 200px);
+  overflow: auto;
+  flex: 1;
+}
+@media (min-width: 768px) {
+  .modal .modal-dialog {
+    width: 700px;
+  }
+}
+@media (min-width: 768px) {
+  select.form-control {
+    margin-left: 12px;
+    margin-right: 12px;
+  }
+}
+/*!
+*
+* IPython auth
+*
+*/
+.center-nav {
+  display: inline-block;
+  margin-bottom: -4px;
+}
+/*!
+*
+* IPython tree view
+*
+*/
+/* We need an invisible input field on top of the sentense*/
+/* "Drag file onto the list ..." */
+.alternate_upload {
+  background-color: none;
+  display: inline;
+}
+.alternate_upload.form {
+  padding: 0;
+  margin: 0;
+}
+.alternate_upload input.fileinput {
+  text-align: center;
+  vertical-align: middle;
+  display: inline;
+  opacity: 0;
+  z-index: 2;
+  width: 12ex;
+  margin-right: -12ex;
+}
+.alternate_upload .btn-upload {
+  height: 22px;
+}
+/**
+ * Primary styles
+ *
+ * Author: Jupyter Development Team
+ */
+[dir="rtl"] #tabs li {
+  float: right;
+}
+ul#tabs {
+  margin-bottom: 4px;
+}
+[dir="rtl"] ul#tabs {
+  margin-right: 0px;
+}
+ul#tabs a {
+  padding-top: 6px;
+  padding-bottom: 4px;
+}
+ul.breadcrumb a:focus,
+ul.breadcrumb a:hover {
+  text-decoration: none;
+}
+ul.breadcrumb i.icon-home {
+  font-size: 16px;
+  margin-right: 4px;
+}
+ul.breadcrumb span {
+  color: #5e5e5e;
+}
+.list_toolbar {
+  padding: 4px 0 4px 0;
+  vertical-align: middle;
+}
+.list_toolbar .tree-buttons {
+  padding-top: 1px;
+}
+[dir="rtl"] .list_toolbar .tree-buttons {
+  float: left !important;
+}
+[dir="rtl"] .list_toolbar .pull-right {
+  padding-top: 1px;
+  float: left !important;
+}
+[dir="rtl"] .list_toolbar .pull-left {
+  float: right !important;
+}
+.dynamic-buttons {
+  padding-top: 3px;
+  display: inline-block;
+}
+.list_toolbar [class*="span"] {
+  min-height: 24px;
+}
+.list_header {
+  font-weight: bold;
+  background-color: #EEE;
+}
+.list_placeholder {
+  font-weight: bold;
+  padding-top: 4px;
+  padding-bottom: 4px;
+  padding-left: 7px;
+  padding-right: 7px;
+}
+.list_container {
+  margin-top: 4px;
+  margin-bottom: 20px;
+  border: 1px solid #ddd;
+  border-radius: 2px;
+}
+.list_container > div {
+  border-bottom: 1px solid #ddd;
+}
+.list_container > div:hover .list-item {
+  background-color: red;
+}
+.list_container > div:last-child {
+  border: none;
+}
+.list_item:hover .list_item {
+  background-color: #ddd;
+}
+.list_item a {
+  text-decoration: none;
+}
+.list_item:hover {
+  background-color: #fafafa;
+}
+.list_header > div,
+.list_item > div {
+  padding-top: 4px;
+  padding-bottom: 4px;
+  padding-left: 7px;
+  padding-right: 7px;
+  line-height: 22px;
+}
+.list_header > div input,
+.list_item > div input {
+  margin-right: 7px;
+  margin-left: 14px;
+  vertical-align: baseline;
+  line-height: 22px;
+  position: relative;
+  top: -1px;
+}
+.list_header > div .item_link,
+.list_item > div .item_link {
+  margin-left: -1px;
+  vertical-align: baseline;
+  line-height: 22px;
+}
+.new-file input[type=checkbox] {
+  visibility: hidden;
+}
+.item_name {
+  line-height: 22px;
+  height: 24px;
+}
+.item_icon {
+  font-size: 14px;
+  color: #5e5e5e;
+  margin-right: 7px;
+  margin-left: 7px;
+  line-height: 22px;
+  vertical-align: baseline;
+}
+.item_buttons {
+  line-height: 1em;
+  margin-left: -5px;
+}
+.item_buttons .btn,
+.item_buttons .btn-group,
+.item_buttons .input-group {
+  float: left;
+}
+.item_buttons > .btn,
+.item_buttons > .btn-group,
+.item_buttons > .input-group {
+  margin-left: 5px;
+}
+.item_buttons .btn {
+  min-width: 13ex;
+}
+.item_buttons .running-indicator {
+  padding-top: 4px;
+  color: #5cb85c;
+}
+.item_buttons .kernel-name {
+  padding-top: 4px;
+  color: #5bc0de;
+  margin-right: 7px;
+  float: left;
+}
+.toolbar_info {
+  height: 24px;
+  line-height: 24px;
+}
+.list_item input:not([type=checkbox]) {
+  padding-top: 3px;
+  padding-bottom: 3px;
+  height: 22px;
+  line-height: 14px;
+  margin: 0px;
+}
+.highlight_text {
+  color: blue;
+}
+#project_name {
+  display: inline-block;
+  padding-left: 7px;
+  margin-left: -2px;
+}
+#project_name > .breadcrumb {
+  padding: 0px;
+  margin-bottom: 0px;
+  background-color: transparent;
+  font-weight: bold;
+}
+#tree-selector {
+  padding-right: 0px;
+}
+[dir="rtl"] #tree-selector a {
+  float: right;
+}
+#button-select-all {
+  min-width: 50px;
+}
+#select-all {
+  margin-left: 7px;
+  margin-right: 2px;
+}
+.menu_icon {
+  margin-right: 2px;
+}
+.tab-content .row {
+  margin-left: 0px;
+  margin-right: 0px;
+}
+.folder_icon:before {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  content: "\f114";
+}
+.folder_icon:before.pull-left {
+  margin-right: .3em;
+}
+.folder_icon:before.pull-right {
+  margin-left: .3em;
+}
+.notebook_icon:before {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  content: "\f02d";
+  position: relative;
+  top: -1px;
+}
+.notebook_icon:before.pull-left {
+  margin-right: .3em;
+}
+.notebook_icon:before.pull-right {
+  margin-left: .3em;
+}
+.running_notebook_icon:before {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  content: "\f02d";
+  position: relative;
+  top: -1px;
+  color: #5cb85c;
+}
+.running_notebook_icon:before.pull-left {
+  margin-right: .3em;
+}
+.running_notebook_icon:before.pull-right {
+  margin-left: .3em;
+}
+.file_icon:before {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  content: "\f016";
+  position: relative;
+  top: -2px;
+}
+.file_icon:before.pull-left {
+  margin-right: .3em;
+}
+.file_icon:before.pull-right {
+  margin-left: .3em;
+}
+#notebook_toolbar .pull-right {
+  padding-top: 0px;
+  margin-right: -1px;
+}
+ul#new-menu {
+  left: auto;
+  right: 0;
+}
+[dir="rtl"] #new-menu {
+  text-align: right;
+}
+.kernel-menu-icon {
+  padding-right: 12px;
+  width: 24px;
+  content: "\f096";
+}
+.kernel-menu-icon:before {
+  content: "\f096";
+}
+.kernel-menu-icon-current:before {
+  content: "\f00c";
+}
+#tab_content {
+  padding-top: 20px;
+}
+#running .panel-group .panel {
+  margin-top: 3px;
+  margin-bottom: 1em;
+}
+#running .panel-group .panel .panel-heading {
+  background-color: #EEE;
+  padding-top: 4px;
+  padding-bottom: 4px;
+  padding-left: 7px;
+  padding-right: 7px;
+  line-height: 22px;
+}
+#running .panel-group .panel .panel-heading a:focus,
+#running .panel-group .panel .panel-heading a:hover {
+  text-decoration: none;
+}
+#running .panel-group .panel .panel-body {
+  padding: 0px;
+}
+#running .panel-group .panel .panel-body .list_container {
+  margin-top: 0px;
+  margin-bottom: 0px;
+  border: 0px;
+  border-radius: 0px;
+}
+#running .panel-group .panel .panel-body .list_container .list_item {
+  border-bottom: 1px solid #ddd;
+}
+#running .panel-group .panel .panel-body .list_container .list_item:last-child {
+  border-bottom: 0px;
+}
+[dir="rtl"] #running .col-sm-8 {
+  float: right !important;
+}
+.delete-button {
+  display: none;
+}
+.duplicate-button {
+  display: none;
+}
+.rename-button {
+  display: none;
+}
+.shutdown-button {
+  display: none;
+}
+.dynamic-instructions {
+  display: inline-block;
+  padding-top: 4px;
+}
+/*!
+*
+* IPython text editor webapp
+*
+*/
+.selected-keymap i.fa {
+  padding: 0px 5px;
+}
+.selected-keymap i.fa:before {
+  content: "\f00c";
+}
+#mode-menu {
+  overflow: auto;
+  max-height: 20em;
+}
+.edit_app #header {
+  -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+  box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+}
+.edit_app #menubar .navbar {
+  /* Use a negative 1 bottom margin, so the border overlaps the border of the
+    header */
+  margin-bottom: -1px;
+}
+.dirty-indicator {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  width: 20px;
+}
+.dirty-indicator.pull-left {
+  margin-right: .3em;
+}
+.dirty-indicator.pull-right {
+  margin-left: .3em;
+}
+.dirty-indicator-dirty {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  width: 20px;
+}
+.dirty-indicator-dirty.pull-left {
+  margin-right: .3em;
+}
+.dirty-indicator-dirty.pull-right {
+  margin-left: .3em;
+}
+.dirty-indicator-clean {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  width: 20px;
+}
+.dirty-indicator-clean.pull-left {
+  margin-right: .3em;
+}
+.dirty-indicator-clean.pull-right {
+  margin-left: .3em;
+}
+.dirty-indicator-clean:before {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  content: "\f00c";
+}
+.dirty-indicator-clean:before.pull-left {
+  margin-right: .3em;
+}
+.dirty-indicator-clean:before.pull-right {
+  margin-left: .3em;
+}
+#filename {
+  font-size: 16pt;
+  display: table;
+  padding: 0px 5px;
+}
+#current-mode {
+  padding-left: 5px;
+  padding-right: 5px;
+}
+#texteditor-backdrop {
+  padding-top: 20px;
+  padding-bottom: 20px;
+}
+@media not print {
+  #texteditor-backdrop {
+    background-color: #EEE;
+  }
+}
+@media print {
+  #texteditor-backdrop #texteditor-container .CodeMirror-gutter,
+  #texteditor-backdrop #texteditor-container .CodeMirror-gutters {
+    background-color: #fff;
+  }
+}
+@media not print {
+  #texteditor-backdrop #texteditor-container .CodeMirror-gutter,
+  #texteditor-backdrop #texteditor-container .CodeMirror-gutters {
+    background-color: #fff;
+  }
+}
+@media not print {
+  #texteditor-backdrop #texteditor-container {
+    padding: 0px;
+    background-color: #fff;
+    -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+    box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+  }
+}
+/*!
+*
+* IPython notebook
+*
+*/
+/* CSS font colors for translated ANSI colors. */
+.ansibold {
+  font-weight: bold;
+}
+/* use dark versions for foreground, to improve visibility */
+.ansiblack {
+  color: black;
+}
+.ansired {
+  color: darkred;
+}
+.ansigreen {
+  color: darkgreen;
+}
+.ansiyellow {
+  color: #c4a000;
+}
+.ansiblue {
+  color: darkblue;
+}
+.ansipurple {
+  color: darkviolet;
+}
+.ansicyan {
+  color: steelblue;
+}
+.ansigray {
+  color: gray;
+}
+/* and light for background, for the same reason */
+.ansibgblack {
+  background-color: black;
+}
+.ansibgred {
+  background-color: red;
+}
+.ansibggreen {
+  background-color: green;
+}
+.ansibgyellow {
+  background-color: yellow;
+}
+.ansibgblue {
+  background-color: blue;
+}
+.ansibgpurple {
+  background-color: magenta;
+}
+.ansibgcyan {
+  background-color: cyan;
+}
+.ansibggray {
+  background-color: gray;
+}
+div.cell {
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: vertical;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: vertical;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: column;
+  align-items: stretch;
+  border-radius: 2px;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+  border-width: 1px;
+  border-style: solid;
+  border-color: transparent;
+  width: 100%;
+  padding: 5px;
+  /* This acts as a spacer between cells, that is outside the border */
+  margin: 0px;
+  outline: none;
+  border-left-width: 1px;
+  padding-left: 5px;
+  background: linear-gradient(to right, transparent -40px, transparent 1px, transparent 1px, transparent 100%);
+}
+div.cell.jupyter-soft-selected {
+  border-left-color: #90CAF9;
+  border-left-color: #E3F2FD;
+  border-left-width: 1px;
+  padding-left: 5px;
+  border-right-color: #E3F2FD;
+  border-right-width: 1px;
+  background: #E3F2FD;
+}
+@media print {
+  div.cell.jupyter-soft-selected {
+    border-color: transparent;
+  }
+}
+div.cell.selected {
+  border-color: #ababab;
+  border-left-width: 0px;
+  padding-left: 6px;
+  background: linear-gradient(to right, #42A5F5 -40px, #42A5F5 5px, transparent 5px, transparent 100%);
+}
+@media print {
+  div.cell.selected {
+    border-color: transparent;
+  }
+}
+div.cell.selected.jupyter-soft-selected {
+  border-left-width: 0;
+  padding-left: 6px;
+  background: linear-gradient(to right, #42A5F5 -40px, #42A5F5 7px, #E3F2FD 7px, #E3F2FD 100%);
+}
+.edit_mode div.cell.selected {
+  border-color: #66BB6A;
+  border-left-width: 0px;
+  padding-left: 6px;
+  background: linear-gradient(to right, #66BB6A -40px, #66BB6A 5px, transparent 5px, transparent 100%);
+}
+@media print {
+  .edit_mode div.cell.selected {
+    border-color: transparent;
+  }
+}
+.prompt {
+  /* This needs to be wide enough for 3 digit prompt numbers: In[100]: */
+  min-width: 14ex;
+  /* This padding is tuned to match the padding on the CodeMirror editor. */
+  padding: 0.4em;
+  margin: 0px;
+  font-family: monospace;
+  text-align: right;
+  /* This has to match that of the the CodeMirror class line-height below */
+  line-height: 1.21429em;
+  /* Don't highlight prompt number selection */
+  -webkit-touch-callout: none;
+  -webkit-user-select: none;
+  -khtml-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+  /* Use default cursor */
+  cursor: default;
+}
+@media (max-width: 540px) {
+  .prompt {
+    text-align: left;
+  }
+}
+div.inner_cell {
+  min-width: 0;
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: vertical;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: vertical;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: column;
+  align-items: stretch;
+  /* Old browsers */
+  -webkit-box-flex: 1;
+  -moz-box-flex: 1;
+  box-flex: 1;
+  /* Modern browsers */
+  flex: 1;
+}
+/* input_area and input_prompt must match in top border and margin for alignment */
+div.input_area {
+  border: 1px solid #cfcfcf;
+  border-radius: 2px;
+  background: #f7f7f7;
+  line-height: 1.21429em;
+}
+/* This is needed so that empty prompt areas can collapse to zero height when there
+   is no content in the output_subarea and the prompt. The main purpose of this is
+   to make sure that empty JavaScript output_subareas have no height. */
+div.prompt:empty {
+  padding-top: 0;
+  padding-bottom: 0;
+}
+div.unrecognized_cell {
+  padding: 5px 5px 5px 0px;
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: horizontal;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: horizontal;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: horizontal;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: row;
+  align-items: stretch;
+}
+div.unrecognized_cell .inner_cell {
+  border-radius: 2px;
+  padding: 5px;
+  font-weight: bold;
+  color: red;
+  border: 1px solid #cfcfcf;
+  background: #eaeaea;
+}
+div.unrecognized_cell .inner_cell a {
+  color: inherit;
+  text-decoration: none;
+}
+div.unrecognized_cell .inner_cell a:hover {
+  color: inherit;
+  text-decoration: none;
+}
+@media (max-width: 540px) {
+  div.unrecognized_cell > div.prompt {
+    display: none;
+  }
+}
+div.code_cell {
+  /* avoid page breaking on code cells when printing */
+}
+@media print {
+  div.code_cell {
+    page-break-inside: avoid;
+  }
+}
+/* any special styling for code cells that are currently running goes here */
+div.input {
+  page-break-inside: avoid;
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: horizontal;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: horizontal;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: horizontal;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: row;
+  align-items: stretch;
+}
+@media (max-width: 540px) {
+  div.input {
+    /* Old browsers */
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+    -webkit-box-align: stretch;
+    display: -moz-box;
+    -moz-box-orient: vertical;
+    -moz-box-align: stretch;
+    display: box;
+    box-orient: vertical;
+    box-align: stretch;
+    /* Modern browsers */
+    display: flex;
+    flex-direction: column;
+    align-items: stretch;
+  }
+}
+/* input_area and input_prompt must match in top border and margin for alignment */
+div.input_prompt {
+  color: #303F9F;
+  border-top: 1px solid transparent;
+}
+div.input_area > div.highlight {
+  margin: 0.4em;
+  border: none;
+  padding: 0px;
+  background-color: transparent;
+}
+div.input_area > div.highlight > pre {
+  margin: 0px;
+  border: none;
+  padding: 0px;
+  background-color: transparent;
+}
+/* The following gets added to the <head> if it is detected that the user has a
+ * monospace font with inconsistent normal/bold/italic height.  See
+ * notebookmain.js.  Such fonts will have keywords vertically offset with
+ * respect to the rest of the text.  The user should select a better font.
+ * See: https://github.com/ipython/ipython/issues/1503
+ *
+ * .CodeMirror span {
+ *      vertical-align: bottom;
+ * }
+ */
+.CodeMirror {
+  line-height: 1.21429em;
+  /* Changed from 1em to our global default */
+  font-size: 14px;
+  height: auto;
+  /* Changed to auto to autogrow */
+  background: none;
+  /* Changed from white to allow our bg to show through */
+}
+.CodeMirror-scroll {
+  /*  The CodeMirror docs are a bit fuzzy on if overflow-y should be hidden or visible.*/
+  /*  We have found that if it is visible, vertical scrollbars appear with font size changes.*/
+  overflow-y: hidden;
+  overflow-x: auto;
+}
+.CodeMirror-lines {
+  /* In CM2, this used to be 0.4em, but in CM3 it went to 4px. We need the em value because */
+  /* we have set a different line-height and want this to scale with that. */
+  padding: 0.4em;
+}
+.CodeMirror-linenumber {
+  padding: 0 8px 0 4px;
+}
+.CodeMirror-gutters {
+  border-bottom-left-radius: 2px;
+  border-top-left-radius: 2px;
+}
+.CodeMirror pre {
+  /* In CM3 this went to 4px from 0 in CM2. We need the 0 value because of how we size */
+  /* .CodeMirror-lines */
+  padding: 0;
+  border: 0;
+  border-radius: 0;
+}
+/*
+
+Original style from softwaremaniacs.org (c) Ivan Sagalaev <Maniac@SoftwareManiacs.Org>
+Adapted from GitHub theme
+
+*/
+.highlight-base {
+  color: #000;
+}
+.highlight-variable {
+  color: #000;
+}
+.highlight-variable-2 {
+  color: #1a1a1a;
+}
+.highlight-variable-3 {
+  color: #333333;
+}
+.highlight-string {
+  color: #BA2121;
+}
+.highlight-comment {
+  color: #408080;
+  font-style: italic;
+}
+.highlight-number {
+  color: #080;
+}
+.highlight-atom {
+  color: #88F;
+}
+.highlight-keyword {
+  color: #008000;
+  font-weight: bold;
+}
+.highlight-builtin {
+  color: #008000;
+}
+.highlight-error {
+  color: #f00;
+}
+.highlight-operator {
+  color: #AA22FF;
+  font-weight: bold;
+}
+.highlight-meta {
+  color: #AA22FF;
+}
+/* previously not defined, copying from default codemirror */
+.highlight-def {
+  color: #00f;
+}
+.highlight-string-2 {
+  color: #f50;
+}
+.highlight-qualifier {
+  color: #555;
+}
+.highlight-bracket {
+  color: #997;
+}
+.highlight-tag {
+  color: #170;
+}
+.highlight-attribute {
+  color: #00c;
+}
+.highlight-header {
+  color: blue;
+}
+.highlight-quote {
+  color: #090;
+}
+.highlight-link {
+  color: #00c;
+}
+/* apply the same style to codemirror */
+.cm-s-ipython span.cm-keyword {
+  color: #008000;
+  font-weight: bold;
+}
+.cm-s-ipython span.cm-atom {
+  color: #88F;
+}
+.cm-s-ipython span.cm-number {
+  color: #080;
+}
+.cm-s-ipython span.cm-def {
+  color: #00f;
+}
+.cm-s-ipython span.cm-variable {
+  color: #000;
+}
+.cm-s-ipython span.cm-operator {
+  color: #AA22FF;
+  font-weight: bold;
+}
+.cm-s-ipython span.cm-variable-2 {
+  color: #1a1a1a;
+}
+.cm-s-ipython span.cm-variable-3 {
+  color: #333333;
+}
+.cm-s-ipython span.cm-comment {
+  color: #408080;
+  font-style: italic;
+}
+.cm-s-ipython span.cm-string {
+  color: #BA2121;
+}
+.cm-s-ipython span.cm-string-2 {
+  color: #f50;
+}
+.cm-s-ipython span.cm-meta {
+  color: #AA22FF;
+}
+.cm-s-ipython span.cm-qualifier {
+  color: #555;
+}
+.cm-s-ipython span.cm-builtin {
+  color: #008000;
+}
+.cm-s-ipython span.cm-bracket {
+  color: #997;
+}
+.cm-s-ipython span.cm-tag {
+  color: #170;
+}
+.cm-s-ipython span.cm-attribute {
+  color: #00c;
+}
+.cm-s-ipython span.cm-header {
+  color: blue;
+}
+.cm-s-ipython span.cm-quote {
+  color: #090;
+}
+.cm-s-ipython span.cm-link {
+  color: #00c;
+}
+.cm-s-ipython span.cm-error {
+  color: #f00;
+}
+.cm-s-ipython span.cm-tab {
+  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=);
+  background-position: right;
+  background-repeat: no-repeat;
+}
+div.output_wrapper {
+  /* this position must be relative to enable descendents to be absolute within it */
+  position: relative;
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: vertical;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: vertical;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: column;
+  align-items: stretch;
+  z-index: 1;
+}
+/* class for the output area when it should be height-limited */
+div.output_scroll {
+  /* ideally, this would be max-height, but FF barfs all over that */
+  height: 24em;
+  /* FF needs this *and the wrapper* to specify full width, or it will shrinkwrap */
+  width: 100%;
+  overflow: auto;
+  border-radius: 2px;
+  -webkit-box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.8);
+  box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.8);
+  display: block;
+}
+/* output div while it is collapsed */
+div.output_collapsed {
+  margin: 0px;
+  padding: 0px;
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: vertical;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: vertical;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: column;
+  align-items: stretch;
+}
+div.out_prompt_overlay {
+  height: 100%;
+  padding: 0px 0.4em;
+  position: absolute;
+  border-radius: 2px;
+}
+div.out_prompt_overlay:hover {
+  /* use inner shadow to get border that is computed the same on WebKit/FF */
+  -webkit-box-shadow: inset 0 0 1px #000;
+  box-shadow: inset 0 0 1px #000;
+  background: rgba(240, 240, 240, 0.5);
+}
+div.output_prompt {
+  color: #D84315;
+}
+/* This class is the outer container of all output sections. */
+div.output_area {
+  padding: 0px;
+  page-break-inside: avoid;
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: horizontal;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: horizontal;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: horizontal;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: row;
+  align-items: stretch;
+}
+div.output_area .MathJax_Display {
+  text-align: left !important;
+}
+div.output_area .rendered_html table {
+  margin-left: 0;
+  margin-right: 0;
+}
+div.output_area .rendered_html img {
+  margin-left: 0;
+  margin-right: 0;
+}
+div.output_area img,
+div.output_area svg {
+  max-width: 100%;
+  height: auto;
+}
+div.output_area img.unconfined,
+div.output_area svg.unconfined {
+  max-width: none;
+}
+/* This is needed to protect the pre formating from global settings such
+   as that of bootstrap */
+.output {
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: vertical;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: vertical;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: column;
+  align-items: stretch;
+}
+@media (max-width: 540px) {
+  div.output_area {
+    /* Old browsers */
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+    -webkit-box-align: stretch;
+    display: -moz-box;
+    -moz-box-orient: vertical;
+    -moz-box-align: stretch;
+    display: box;
+    box-orient: vertical;
+    box-align: stretch;
+    /* Modern browsers */
+    display: flex;
+    flex-direction: column;
+    align-items: stretch;
+  }
+}
+div.output_area pre {
+  margin: 0;
+  padding: 0;
+  border: 0;
+  vertical-align: baseline;
+  color: black;
+  background-color: transparent;
+  border-radius: 0;
+}
+/* This class is for the output subarea inside the output_area and after
+   the prompt div. */
+div.output_subarea {
+  overflow-x: auto;
+  padding: 0.4em;
+  /* Old browsers */
+  -webkit-box-flex: 1;
+  -moz-box-flex: 1;
+  box-flex: 1;
+  /* Modern browsers */
+  flex: 1;
+  max-width: calc(100% - 14ex);
+}
+div.output_scroll div.output_subarea {
+  overflow-x: visible;
+}
+/* The rest of the output_* classes are for special styling of the different
+   output types */
+/* all text output has this class: */
+div.output_text {
+  text-align: left;
+  color: #000;
+  /* This has to match that of the the CodeMirror class line-height below */
+  line-height: 1.21429em;
+}
+/* stdout/stderr are 'text' as well as 'stream', but execute_result/error are *not* streams */
+div.output_stderr {
+  background: #fdd;
+  /* very light red background for stderr */
+}
+div.output_latex {
+  text-align: left;
+}
+/* Empty output_javascript divs should have no height */
+div.output_javascript:empty {
+  padding: 0;
+}
+.js-error {
+  color: darkred;
+}
+/* raw_input styles */
+div.raw_input_container {
+  line-height: 1.21429em;
+  padding-top: 5px;
+}
+pre.raw_input_prompt {
+  /* nothing needed here. */
+}
+input.raw_input {
+  font-family: monospace;
+  font-size: inherit;
+  color: inherit;
+  width: auto;
+  /* make sure input baseline aligns with prompt */
+  vertical-align: baseline;
+  /* padding + margin = 0.5em between prompt and cursor */
+  padding: 0em 0.25em;
+  margin: 0em 0.25em;
+}
+input.raw_input:focus {
+  box-shadow: none;
+}
+p.p-space {
+  margin-bottom: 10px;
+}
+div.output_unrecognized {
+  padding: 5px;
+  font-weight: bold;
+  color: red;
+}
+div.output_unrecognized a {
+  color: inherit;
+  text-decoration: none;
+}
+div.output_unrecognized a:hover {
+  color: inherit;
+  text-decoration: none;
+}
+.rendered_html {
+  color: #000;
+  /* any extras will just be numbers: */
+}
+.rendered_html em {
+  font-style: italic;
+}
+.rendered_html strong {
+  font-weight: bold;
+}
+.rendered_html u {
+  text-decoration: underline;
+}
+.rendered_html :link {
+  text-decoration: underline;
+}
+.rendered_html :visited {
+  text-decoration: underline;
+}
+.rendered_html h1 {
+  font-size: 185.7%;
+  margin: 1.08em 0 0 0;
+  font-weight: bold;
+  line-height: 1.0;
+}
+.rendered_html h2 {
+  font-size: 157.1%;
+  margin: 1.27em 0 0 0;
+  font-weight: bold;
+  line-height: 1.0;
+}
+.rendered_html h3 {
+  font-size: 128.6%;
+  margin: 1.55em 0 0 0;
+  font-weight: bold;
+  line-height: 1.0;
+}
+.rendered_html h4 {
+  font-size: 100%;
+  margin: 2em 0 0 0;
+  font-weight: bold;
+  line-height: 1.0;
+}
+.rendered_html h5 {
+  font-size: 100%;
+  margin: 2em 0 0 0;
+  font-weight: bold;
+  line-height: 1.0;
+  font-style: italic;
+}
+.rendered_html h6 {
+  font-size: 100%;
+  margin: 2em 0 0 0;
+  font-weight: bold;
+  line-height: 1.0;
+  font-style: italic;
+}
+.rendered_html h1:first-child {
+  margin-top: 0.538em;
+}
+.rendered_html h2:first-child {
+  margin-top: 0.636em;
+}
+.rendered_html h3:first-child {
+  margin-top: 0.777em;
+}
+.rendered_html h4:first-child {
+  margin-top: 1em;
+}
+.rendered_html h5:first-child {
+  margin-top: 1em;
+}
+.rendered_html h6:first-child {
+  margin-top: 1em;
+}
+.rendered_html ul {
+  list-style: disc;
+  margin: 0em 2em;
+  padding-left: 0px;
+}
+.rendered_html ul ul {
+  list-style: square;
+  margin: 0em 2em;
+}
+.rendered_html ul ul ul {
+  list-style: circle;
+  margin: 0em 2em;
+}
+.rendered_html ol {
+  list-style: decimal;
+  margin: 0em 2em;
+  padding-left: 0px;
+}
+.rendered_html ol ol {
+  list-style: upper-alpha;
+  margin: 0em 2em;
+}
+.rendered_html ol ol ol {
+  list-style: lower-alpha;
+  margin: 0em 2em;
+}
+.rendered_html ol ol ol ol {
+  list-style: lower-roman;
+  margin: 0em 2em;
+}
+.rendered_html ol ol ol ol ol {
+  list-style: decimal;
+  margin: 0em 2em;
+}
+.rendered_html * + ul {
+  margin-top: 1em;
+}
+.rendered_html * + ol {
+  margin-top: 1em;
+}
+.rendered_html hr {
+  color: black;
+  background-color: black;
+}
+.rendered_html pre {
+  margin: 1em 2em;
+}
+.rendered_html pre,
+.rendered_html code {
+  border: 0;
+  background-color: #fff;
+  color: #000;
+  font-size: 100%;
+  padding: 0px;
+}
+.rendered_html blockquote {
+  margin: 1em 2em;
+}
+.rendered_html table {
+  margin-left: auto;
+  margin-right: auto;
+  border: 1px solid black;
+  border-collapse: collapse;
+}
+.rendered_html tr,
+.rendered_html th,
+.rendered_html td {
+  border: 1px solid black;
+  border-collapse: collapse;
+  margin: 1em 2em;
+}
+.rendered_html td,
+.rendered_html th {
+  text-align: left;
+  vertical-align: middle;
+  padding: 4px;
+}
+.rendered_html th {
+  font-weight: bold;
+}
+.rendered_html * + table {
+  margin-top: 1em;
+}
+.rendered_html p {
+  text-align: left;
+}
+.rendered_html * + p {
+  margin-top: 1em;
+}
+.rendered_html img {
+  display: block;
+  margin-left: auto;
+  margin-right: auto;
+}
+.rendered_html * + img {
+  margin-top: 1em;
+}
+.rendered_html img,
+.rendered_html svg {
+  max-width: 100%;
+  height: auto;
+}
+.rendered_html img.unconfined,
+.rendered_html svg.unconfined {
+  max-width: none;
+}
+div.text_cell {
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: horizontal;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: horizontal;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: horizontal;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: row;
+  align-items: stretch;
+}
+@media (max-width: 540px) {
+  div.text_cell > div.prompt {
+    display: none;
+  }
+}
+div.text_cell_render {
+  /*font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;*/
+  outline: none;
+  resize: none;
+  width: inherit;
+  border-style: none;
+  padding: 0.5em 0.5em 0.5em 0.4em;
+  color: #000;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+}
+a.anchor-link:link {
+  text-decoration: none;
+  padding: 0px 20px;
+  visibility: hidden;
+}
+h1:hover .anchor-link,
+h2:hover .anchor-link,
+h3:hover .anchor-link,
+h4:hover .anchor-link,
+h5:hover .anchor-link,
+h6:hover .anchor-link {
+  visibility: visible;
+}
+.text_cell.rendered .input_area {
+  display: none;
+}
+.text_cell.rendered .rendered_html {
+  overflow-x: auto;
+  overflow-y: hidden;
+}
+.text_cell.unrendered .text_cell_render {
+  display: none;
+}
+.cm-header-1,
+.cm-header-2,
+.cm-header-3,
+.cm-header-4,
+.cm-header-5,
+.cm-header-6 {
+  font-weight: bold;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+}
+.cm-header-1 {
+  font-size: 185.7%;
+}
+.cm-header-2 {
+  font-size: 157.1%;
+}
+.cm-header-3 {
+  font-size: 128.6%;
+}
+.cm-header-4 {
+  font-size: 110%;
+}
+.cm-header-5 {
+  font-size: 100%;
+  font-style: italic;
+}
+.cm-header-6 {
+  font-size: 100%;
+  font-style: italic;
+}
+/*!
+*
+* IPython notebook webapp
+*
+*/
+@media (max-width: 767px) {
+  .notebook_app {
+    padding-left: 0px;
+    padding-right: 0px;
+  }
+}
+#ipython-main-app {
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+  height: 100%;
+}
+div#notebook_panel {
+  margin: 0px;
+  padding: 0px;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+  height: 100%;
+}
+div#notebook {
+  font-size: 14px;
+  line-height: 20px;
+  overflow-y: hidden;
+  overflow-x: auto;
+  width: 100%;
+  /* This spaces the page away from the edge of the notebook area */
+  padding-top: 20px;
+  margin: 0px;
+  outline: none;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+  min-height: 100%;
+}
+@media not print {
+  #notebook-container {
+    padding: 15px;
+    background-color: #fff;
+    min-height: 0;
+    -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+    box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+  }
+}
+@media print {
+  #notebook-container {
+    width: 100%;
+  }
+}
+div.ui-widget-content {
+  border: 1px solid #ababab;
+  outline: none;
+}
+pre.dialog {
+  background-color: #f7f7f7;
+  border: 1px solid #ddd;
+  border-radius: 2px;
+  padding: 0.4em;
+  padding-left: 2em;
+}
+p.dialog {
+  padding: 0.2em;
+}
+/* Word-wrap output correctly.  This is the CSS3 spelling, though Firefox seems
+   to not honor it correctly.  Webkit browsers (Chrome, rekonq, Safari) do.
+ */
+pre,
+code,
+kbd,
+samp {
+  white-space: pre-wrap;
+}
+#fonttest {
+  font-family: monospace;
+}
+p {
+  margin-bottom: 0;
+}
+.end_space {
+  min-height: 100px;
+  transition: height .2s ease;
+}
+.notebook_app > #header {
+  -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+  box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+}
+@media not print {
+  .notebook_app {
+    background-color: #EEE;
+  }
+}
+kbd {
+  border-style: solid;
+  border-width: 1px;
+  box-shadow: none;
+  margin: 2px;
+  padding-left: 2px;
+  padding-right: 2px;
+  padding-top: 1px;
+  padding-bottom: 1px;
+}
+/* CSS for the cell toolbar */
+.celltoolbar {
+  border: thin solid #CFCFCF;
+  border-bottom: none;
+  background: #EEE;
+  border-radius: 2px 2px 0px 0px;
+  width: 100%;
+  height: 29px;
+  padding-right: 4px;
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: horizontal;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: horizontal;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: horizontal;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: row;
+  align-items: stretch;
+  /* Old browsers */
+  -webkit-box-pack: end;
+  -moz-box-pack: end;
+  box-pack: end;
+  /* Modern browsers */
+  justify-content: flex-end;
+  display: -webkit-flex;
+}
+@media print {
+  .celltoolbar {
+    display: none;
+  }
+}
+.ctb_hideshow {
+  display: none;
+  vertical-align: bottom;
+}
+/* ctb_show is added to the ctb_hideshow div to show the cell toolbar.
+   Cell toolbars are only shown when the ctb_global_show class is also set.
+*/
+.ctb_global_show .ctb_show.ctb_hideshow {
+  display: block;
+}
+.ctb_global_show .ctb_show + .input_area,
+.ctb_global_show .ctb_show + div.text_cell_input,
+.ctb_global_show .ctb_show ~ div.text_cell_render {
+  border-top-right-radius: 0px;
+  border-top-left-radius: 0px;
+}
+.ctb_global_show .ctb_show ~ div.text_cell_render {
+  border: 1px solid #cfcfcf;
+}
+.celltoolbar {
+  font-size: 87%;
+  padding-top: 3px;
+}
+.celltoolbar select {
+  display: block;
+  width: 100%;
+  height: 32px;
+  padding: 6px 12px;
+  font-size: 13px;
+  line-height: 1.42857143;
+  color: #555555;
+  background-color: #fff;
+  background-image: none;
+  border: 1px solid #ccc;
+  border-radius: 2px;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+  -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+  transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+  height: 30px;
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 1px;
+  width: inherit;
+  font-size: inherit;
+  height: 22px;
+  padding: 0px;
+  display: inline-block;
+}
+.celltoolbar select:focus {
+  border-color: #66afe9;
+  outline: 0;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
+  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
+}
+.celltoolbar select::-moz-placeholder {
+  color: #999;
+  opacity: 1;
+}
+.celltoolbar select:-ms-input-placeholder {
+  color: #999;
+}
+.celltoolbar select::-webkit-input-placeholder {
+  color: #999;
+}
+.celltoolbar select::-ms-expand {
+  border: 0;
+  background-color: transparent;
+}
+.celltoolbar select[disabled],
+.celltoolbar select[readonly],
+fieldset[disabled] .celltoolbar select {
+  background-color: #eeeeee;
+  opacity: 1;
+}
+.celltoolbar select[disabled],
+fieldset[disabled] .celltoolbar select {
+  cursor: not-allowed;
+}
+textarea.celltoolbar select {
+  height: auto;
+}
+select.celltoolbar select {
+  height: 30px;
+  line-height: 30px;
+}
+textarea.celltoolbar select,
+select[multiple].celltoolbar select {
+  height: auto;
+}
+.celltoolbar label {
+  margin-left: 5px;
+  margin-right: 5px;
+}
+.completions {
+  position: absolute;
+  z-index: 110;
+  overflow: hidden;
+  border: 1px solid #ababab;
+  border-radius: 2px;
+  -webkit-box-shadow: 0px 6px 10px -1px #adadad;
+  box-shadow: 0px 6px 10px -1px #adadad;
+  line-height: 1;
+}
+.completions select {
+  background: white;
+  outline: none;
+  border: none;
+  padding: 0px;
+  margin: 0px;
+  overflow: auto;
+  font-family: monospace;
+  font-size: 110%;
+  color: #000;
+  width: auto;
+}
+.completions select option.context {
+  color: #286090;
+}
+#kernel_logo_widget {
+  float: right !important;
+  float: right;
+}
+#kernel_logo_widget .current_kernel_logo {
+  display: none;
+  margin-top: -1px;
+  margin-bottom: -1px;
+  width: 32px;
+  height: 32px;
+}
+#menubar {
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+  margin-top: 1px;
+}
+#menubar .navbar {
+  border-top: 1px;
+  border-radius: 0px 0px 2px 2px;
+  margin-bottom: 0px;
+}
+#menubar .navbar-toggle {
+  float: left;
+  padding-top: 7px;
+  padding-bottom: 7px;
+  border: none;
+}
+#menubar .navbar-collapse {
+  clear: left;
+}
+.nav-wrapper {
+  border-bottom: 1px solid #e7e7e7;
+}
+i.menu-icon {
+  padding-top: 4px;
+}
+ul#help_menu li a {
+  overflow: hidden;
+  padding-right: 2.2em;
+}
+ul#help_menu li a i {
+  margin-right: -1.2em;
+}
+.dropdown-submenu {
+  position: relative;
+}
+.dropdown-submenu > .dropdown-menu {
+  top: 0;
+  left: 100%;
+  margin-top: -6px;
+  margin-left: -1px;
+}
+.dropdown-submenu:hover > .dropdown-menu {
+  display: block;
+}
+.dropdown-submenu > a:after {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  display: block;
+  content: "\f0da";
+  float: right;
+  color: #333333;
+  margin-top: 2px;
+  margin-right: -10px;
+}
+.dropdown-submenu > a:after.pull-left {
+  margin-right: .3em;
+}
+.dropdown-submenu > a:after.pull-right {
+  margin-left: .3em;
+}
+.dropdown-submenu:hover > a:after {
+  color: #262626;
+}
+.dropdown-submenu.pull-left {
+  float: none;
+}
+.dropdown-submenu.pull-left > .dropdown-menu {
+  left: -100%;
+  margin-left: 10px;
+}
+#notification_area {
+  float: right !important;
+  float: right;
+  z-index: 10;
+}
+.indicator_area {
+  float: right !important;
+  float: right;
+  color: #777;
+  margin-left: 5px;
+  margin-right: 5px;
+  width: 11px;
+  z-index: 10;
+  text-align: center;
+  width: auto;
+}
+#kernel_indicator {
+  float: right !important;
+  float: right;
+  color: #777;
+  margin-left: 5px;
+  margin-right: 5px;
+  width: 11px;
+  z-index: 10;
+  text-align: center;
+  width: auto;
+  border-left: 1px solid;
+}
+#kernel_indicator .kernel_indicator_name {
+  padding-left: 5px;
+  padding-right: 5px;
+}
+#modal_indicator {
+  float: right !important;
+  float: right;
+  color: #777;
+  margin-left: 5px;
+  margin-right: 5px;
+  width: 11px;
+  z-index: 10;
+  text-align: center;
+  width: auto;
+}
+#readonly-indicator {
+  float: right !important;
+  float: right;
+  color: #777;
+  margin-left: 5px;
+  margin-right: 5px;
+  width: 11px;
+  z-index: 10;
+  text-align: center;
+  width: auto;
+  margin-top: 2px;
+  margin-bottom: 0px;
+  margin-left: 0px;
+  margin-right: 0px;
+  display: none;
+}
+.modal_indicator:before {
+  width: 1.28571429em;
+  text-align: center;
+}
+.edit_mode .modal_indicator:before {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  content: "\f040";
+}
+.edit_mode .modal_indicator:before.pull-left {
+  margin-right: .3em;
+}
+.edit_mode .modal_indicator:before.pull-right {
+  margin-left: .3em;
+}
+.command_mode .modal_indicator:before {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  content: ' ';
+}
+.command_mode .modal_indicator:before.pull-left {
+  margin-right: .3em;
+}
+.command_mode .modal_indicator:before.pull-right {
+  margin-left: .3em;
+}
+.kernel_idle_icon:before {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  content: "\f10c";
+}
+.kernel_idle_icon:before.pull-left {
+  margin-right: .3em;
+}
+.kernel_idle_icon:before.pull-right {
+  margin-left: .3em;
+}
+.kernel_busy_icon:before {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  content: "\f111";
+}
+.kernel_busy_icon:before.pull-left {
+  margin-right: .3em;
+}
+.kernel_busy_icon:before.pull-right {
+  margin-left: .3em;
+}
+.kernel_dead_icon:before {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  content: "\f1e2";
+}
+.kernel_dead_icon:before.pull-left {
+  margin-right: .3em;
+}
+.kernel_dead_icon:before.pull-right {
+  margin-left: .3em;
+}
+.kernel_disconnected_icon:before {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  content: "\f127";
+}
+.kernel_disconnected_icon:before.pull-left {
+  margin-right: .3em;
+}
+.kernel_disconnected_icon:before.pull-right {
+  margin-left: .3em;
+}
+.notification_widget {
+  color: #777;
+  z-index: 10;
+  background: rgba(240, 240, 240, 0.5);
+  margin-right: 4px;
+  color: #333;
+  background-color: #fff;
+  border-color: #ccc;
+}
+.notification_widget:focus,
+.notification_widget.focus {
+  color: #333;
+  background-color: #e6e6e6;
+  border-color: #8c8c8c;
+}
+.notification_widget:hover {
+  color: #333;
+  background-color: #e6e6e6;
+  border-color: #adadad;
+}
+.notification_widget:active,
+.notification_widget.active,
+.open > .dropdown-toggle.notification_widget {
+  color: #333;
+  background-color: #e6e6e6;
+  border-color: #adadad;
+}
+.notification_widget:active:hover,
+.notification_widget.active:hover,
+.open > .dropdown-toggle.notification_widget:hover,
+.notification_widget:active:focus,
+.notification_widget.active:focus,
+.open > .dropdown-toggle.notification_widget:focus,
+.notification_widget:active.focus,
+.notification_widget.active.focus,
+.open > .dropdown-toggle.notification_widget.focus {
+  color: #333;
+  background-color: #d4d4d4;
+  border-color: #8c8c8c;
+}
+.notification_widget:active,
+.notification_widget.active,
+.open > .dropdown-toggle.notification_widget {
+  background-image: none;
+}
+.notification_widget.disabled:hover,
+.notification_widget[disabled]:hover,
+fieldset[disabled] .notification_widget:hover,
+.notification_widget.disabled:focus,
+.notification_widget[disabled]:focus,
+fieldset[disabled] .notification_widget:focus,
+.notification_widget.disabled.focus,
+.notification_widget[disabled].focus,
+fieldset[disabled] .notification_widget.focus {
+  background-color: #fff;
+  border-color: #ccc;
+}
+.notification_widget .badge {
+  color: #fff;
+  background-color: #333;
+}
+.notification_widget.warning {
+  color: #fff;
+  background-color: #f0ad4e;
+  border-color: #eea236;
+}
+.notification_widget.warning:focus,
+.notification_widget.warning.focus {
+  color: #fff;
+  background-color: #ec971f;
+  border-color: #985f0d;
+}
+.notification_widget.warning:hover {
+  color: #fff;
+  background-color: #ec971f;
+  border-color: #d58512;
+}
+.notification_widget.warning:active,
+.notification_widget.warning.active,
+.open > .dropdown-toggle.notification_widget.warning {
+  color: #fff;
+  background-color: #ec971f;
+  border-color: #d58512;
+}
+.notification_widget.warning:active:hover,
+.notification_widget.warning.active:hover,
+.open > .dropdown-toggle.notification_widget.warning:hover,
+.notification_widget.warning:active:focus,
+.notification_widget.warning.active:focus,
+.open > .dropdown-toggle.notification_widget.warning:focus,
+.notification_widget.warning:active.focus,
+.notification_widget.warning.active.focus,
+.open > .dropdown-toggle.notification_widget.warning.focus {
+  color: #fff;
+  background-color: #d58512;
+  border-color: #985f0d;
+}
+.notification_widget.warning:active,
+.notification_widget.warning.active,
+.open > .dropdown-toggle.notification_widget.warning {
+  background-image: none;
+}
+.notification_widget.warning.disabled:hover,
+.notification_widget.warning[disabled]:hover,
+fieldset[disabled] .notification_widget.warning:hover,
+.notification_widget.warning.disabled:focus,
+.notification_widget.warning[disabled]:focus,
+fieldset[disabled] .notification_widget.warning:focus,
+.notification_widget.warning.disabled.focus,
+.notification_widget.warning[disabled].focus,
+fieldset[disabled] .notification_widget.warning.focus {
+  background-color: #f0ad4e;
+  border-color: #eea236;
+}
+.notification_widget.warning .badge {
+  color: #f0ad4e;
+  background-color: #fff;
+}
+.notification_widget.success {
+  color: #fff;
+  background-color: #5cb85c;
+  border-color: #4cae4c;
+}
+.notification_widget.success:focus,
+.notification_widget.success.focus {
+  color: #fff;
+  background-color: #449d44;
+  border-color: #255625;
+}
+.notification_widget.success:hover {
+  color: #fff;
+  background-color: #449d44;
+  border-color: #398439;
+}
+.notification_widget.success:active,
+.notification_widget.success.active,
+.open > .dropdown-toggle.notification_widget.success {
+  color: #fff;
+  background-color: #449d44;
+  border-color: #398439;
+}
+.notification_widget.success:active:hover,
+.notification_widget.success.active:hover,
+.open > .dropdown-toggle.notification_widget.success:hover,
+.notification_widget.success:active:focus,
+.notification_widget.success.active:focus,
+.open > .dropdown-toggle.notification_widget.success:focus,
+.notification_widget.success:active.focus,
+.notification_widget.success.active.focus,
+.open > .dropdown-toggle.notification_widget.success.focus {
+  color: #fff;
+  background-color: #398439;
+  border-color: #255625;
+}
+.notification_widget.success:active,
+.notification_widget.success.active,
+.open > .dropdown-toggle.notification_widget.success {
+  background-image: none;
+}
+.notification_widget.success.disabled:hover,
+.notification_widget.success[disabled]:hover,
+fieldset[disabled] .notification_widget.success:hover,
+.notification_widget.success.disabled:focus,
+.notification_widget.success[disabled]:focus,
+fieldset[disabled] .notification_widget.success:focus,
+.notification_widget.success.disabled.focus,
+.notification_widget.success[disabled].focus,
+fieldset[disabled] .notification_widget.success.focus {
+  background-color: #5cb85c;
+  border-color: #4cae4c;
+}
+.notification_widget.success .badge {
+  color: #5cb85c;
+  background-color: #fff;
+}
+.notification_widget.info {
+  color: #fff;
+  background-color: #5bc0de;
+  border-color: #46b8da;
+}
+.notification_widget.info:focus,
+.notification_widget.info.focus {
+  color: #fff;
+  background-color: #31b0d5;
+  border-color: #1b6d85;
+}
+.notification_widget.info:hover {
+  color: #fff;
+  background-color: #31b0d5;
+  border-color: #269abc;
+}
+.notification_widget.info:active,
+.notification_widget.info.active,
+.open > .dropdown-toggle.notification_widget.info {
+  color: #fff;
+  background-color: #31b0d5;
+  border-color: #269abc;
+}
+.notification_widget.info:active:hover,
+.notification_widget.info.active:hover,
+.open > .dropdown-toggle.notification_widget.info:hover,
+.notification_widget.info:active:focus,
+.notification_widget.info.active:focus,
+.open > .dropdown-toggle.notification_widget.info:focus,
+.notification_widget.info:active.focus,
+.notification_widget.info.active.focus,
+.open > .dropdown-toggle.notification_widget.info.focus {
+  color: #fff;
+  background-color: #269abc;
+  border-color: #1b6d85;
+}
+.notification_widget.info:active,
+.notification_widget.info.active,
+.open > .dropdown-toggle.notification_widget.info {
+  background-image: none;
+}
+.notification_widget.info.disabled:hover,
+.notification_widget.info[disabled]:hover,
+fieldset[disabled] .notification_widget.info:hover,
+.notification_widget.info.disabled:focus,
+.notification_widget.info[disabled]:focus,
+fieldset[disabled] .notification_widget.info:focus,
+.notification_widget.info.disabled.focus,
+.notification_widget.info[disabled].focus,
+fieldset[disabled] .notification_widget.info.focus {
+  background-color: #5bc0de;
+  border-color: #46b8da;
+}
+.notification_widget.info .badge {
+  color: #5bc0de;
+  background-color: #fff;
+}
+.notification_widget.danger {
+  color: #fff;
+  background-color: #d9534f;
+  border-color: #d43f3a;
+}
+.notification_widget.danger:focus,
+.notification_widget.danger.focus {
+  color: #fff;
+  background-color: #c9302c;
+  border-color: #761c19;
+}
+.notification_widget.danger:hover {
+  color: #fff;
+  background-color: #c9302c;
+  border-color: #ac2925;
+}
+.notification_widget.danger:active,
+.notification_widget.danger.active,
+.open > .dropdown-toggle.notification_widget.danger {
+  color: #fff;
+  background-color: #c9302c;
+  border-color: #ac2925;
+}
+.notification_widget.danger:active:hover,
+.notification_widget.danger.active:hover,
+.open > .dropdown-toggle.notification_widget.danger:hover,
+.notification_widget.danger:active:focus,
+.notification_widget.danger.active:focus,
+.open > .dropdown-toggle.notification_widget.danger:focus,
+.notification_widget.danger:active.focus,
+.notification_widget.danger.active.focus,
+.open > .dropdown-toggle.notification_widget.danger.focus {
+  color: #fff;
+  background-color: #ac2925;
+  border-color: #761c19;
+}
+.notification_widget.danger:active,
+.notification_widget.danger.active,
+.open > .dropdown-toggle.notification_widget.danger {
+  background-image: none;
+}
+.notification_widget.danger.disabled:hover,
+.notification_widget.danger[disabled]:hover,
+fieldset[disabled] .notification_widget.danger:hover,
+.notification_widget.danger.disabled:focus,
+.notification_widget.danger[disabled]:focus,
+fieldset[disabled] .notification_widget.danger:focus,
+.notification_widget.danger.disabled.focus,
+.notification_widget.danger[disabled].focus,
+fieldset[disabled] .notification_widget.danger.focus {
+  background-color: #d9534f;
+  border-color: #d43f3a;
+}
+.notification_widget.danger .badge {
+  color: #d9534f;
+  background-color: #fff;
+}
+div#pager {
+  background-color: #fff;
+  font-size: 14px;
+  line-height: 20px;
+  overflow: hidden;
+  display: none;
+  position: fixed;
+  bottom: 0px;
+  width: 100%;
+  max-height: 50%;
+  padding-top: 8px;
+  -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+  box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+  /* Display over codemirror */
+  z-index: 100;
+  /* Hack which prevents jquery ui resizable from changing top. */
+  top: auto !important;
+}
+div#pager pre {
+  line-height: 1.21429em;
+  color: #000;
+  background-color: #f7f7f7;
+  padding: 0.4em;
+}
+div#pager #pager-button-area {
+  position: absolute;
+  top: 8px;
+  right: 20px;
+}
+div#pager #pager-contents {
+  position: relative;
+  overflow: auto;
+  width: 100%;
+  height: 100%;
+}
+div#pager #pager-contents #pager-container {
+  position: relative;
+  padding: 15px 0px;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+}
+div#pager .ui-resizable-handle {
+  top: 0px;
+  height: 8px;
+  background: #f7f7f7;
+  border-top: 1px solid #cfcfcf;
+  border-bottom: 1px solid #cfcfcf;
+  /* This injects handle bars (a short, wide = symbol) for 
+        the resize handle. */
+}
+div#pager .ui-resizable-handle::after {
+  content: '';
+  top: 2px;
+  left: 50%;
+  height: 3px;
+  width: 30px;
+  margin-left: -15px;
+  position: absolute;
+  border-top: 1px solid #cfcfcf;
+}
+.quickhelp {
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: horizontal;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: horizontal;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: horizontal;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: row;
+  align-items: stretch;
+  line-height: 1.8em;
+}
+.shortcut_key {
+  display: inline-block;
+  width: 21ex;
+  text-align: right;
+  font-family: monospace;
+}
+.shortcut_descr {
+  display: inline-block;
+  /* Old browsers */
+  -webkit-box-flex: 1;
+  -moz-box-flex: 1;
+  box-flex: 1;
+  /* Modern browsers */
+  flex: 1;
+}
+span.save_widget {
+  margin-top: 6px;
+}
+span.save_widget span.filename {
+  height: 1em;
+  line-height: 1em;
+  padding: 3px;
+  margin-left: 16px;
+  border: none;
+  font-size: 146.5%;
+  border-radius: 2px;
+}
+span.save_widget span.filename:hover {
+  background-color: #e6e6e6;
+}
+span.checkpoint_status,
+span.autosave_status {
+  font-size: small;
+}
+@media (max-width: 767px) {
+  span.save_widget {
+    font-size: small;
+  }
+  span.checkpoint_status,
+  span.autosave_status {
+    display: none;
+  }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+  span.checkpoint_status {
+    display: none;
+  }
+  span.autosave_status {
+    font-size: x-small;
+  }
+}
+.toolbar {
+  padding: 0px;
+  margin-left: -5px;
+  margin-top: 2px;
+  margin-bottom: 5px;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+}
+.toolbar select,
+.toolbar label {
+  width: auto;
+  vertical-align: middle;
+  margin-right: 2px;
+  margin-bottom: 0px;
+  display: inline;
+  font-size: 92%;
+  margin-left: 0.3em;
+  margin-right: 0.3em;
+  padding: 0px;
+  padding-top: 3px;
+}
+.toolbar .btn {
+  padding: 2px 8px;
+}
+.toolbar .btn-group {
+  margin-top: 0px;
+  margin-left: 5px;
+}
+#maintoolbar {
+  margin-bottom: -3px;
+  margin-top: -8px;
+  border: 0px;
+  min-height: 27px;
+  margin-left: 0px;
+  padding-top: 11px;
+  padding-bottom: 3px;
+}
+#maintoolbar .navbar-text {
+  float: none;
+  vertical-align: middle;
+  text-align: right;
+  margin-left: 5px;
+  margin-right: 0px;
+  margin-top: 0px;
+}
+.select-xs {
+  height: 24px;
+}
+.pulse,
+.dropdown-menu > li > a.pulse,
+li.pulse > a.dropdown-toggle,
+li.pulse.open > a.dropdown-toggle {
+  background-color: #F37626;
+  color: white;
+}
+/**
+ * Primary styles
+ *
+ * Author: Jupyter Development Team
+ */
+/** WARNING IF YOU ARE EDITTING THIS FILE, if this is a .css file, It has a lot
+ * of chance of beeing generated from the ../less/[samename].less file, you can
+ * try to get back the less file by reverting somme commit in history
+ **/
+/*
+ * We'll try to get something pretty, so we
+ * have some strange css to have the scroll bar on
+ * the left with fix button on the top right of the tooltip
+ */
+@-moz-keyframes fadeOut {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+  }
+}
+@-webkit-keyframes fadeOut {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+  }
+}
+@-moz-keyframes fadeIn {
+  from {
+    opacity: 0;
+  }
+  to {
+    opacity: 1;
+  }
+}
+@-webkit-keyframes fadeIn {
+  from {
+    opacity: 0;
+  }
+  to {
+    opacity: 1;
+  }
+}
+/*properties of tooltip after "expand"*/
+.bigtooltip {
+  overflow: auto;
+  height: 200px;
+  -webkit-transition-property: height;
+  -webkit-transition-duration: 500ms;
+  -moz-transition-property: height;
+  -moz-transition-duration: 500ms;
+  transition-property: height;
+  transition-duration: 500ms;
+}
+/*properties of tooltip before "expand"*/
+.smalltooltip {
+  -webkit-transition-property: height;
+  -webkit-transition-duration: 500ms;
+  -moz-transition-property: height;
+  -moz-transition-duration: 500ms;
+  transition-property: height;
+  transition-duration: 500ms;
+  text-overflow: ellipsis;
+  overflow: hidden;
+  height: 80px;
+}
+.tooltipbuttons {
+  position: absolute;
+  padding-right: 15px;
+  top: 0px;
+  right: 0px;
+}
+.tooltiptext {
+  /*avoid the button to overlap on some docstring*/
+  padding-right: 30px;
+}
+.ipython_tooltip {
+  max-width: 700px;
+  /*fade-in animation when inserted*/
+  -webkit-animation: fadeOut 400ms;
+  -moz-animation: fadeOut 400ms;
+  animation: fadeOut 400ms;
+  -webkit-animation: fadeIn 400ms;
+  -moz-animation: fadeIn 400ms;
+  animation: fadeIn 400ms;
+  vertical-align: middle;
+  background-color: #f7f7f7;
+  overflow: visible;
+  border: #ababab 1px solid;
+  outline: none;
+  padding: 3px;
+  margin: 0px;
+  padding-left: 7px;
+  font-family: monospace;
+  min-height: 50px;
+  -moz-box-shadow: 0px 6px 10px -1px #adadad;
+  -webkit-box-shadow: 0px 6px 10px -1px #adadad;
+  box-shadow: 0px 6px 10px -1px #adadad;
+  border-radius: 2px;
+  position: absolute;
+  z-index: 1000;
+}
+.ipython_tooltip a {
+  float: right;
+}
+.ipython_tooltip .tooltiptext pre {
+  border: 0;
+  border-radius: 0;
+  font-size: 100%;
+  background-color: #f7f7f7;
+}
+.pretooltiparrow {
+  left: 0px;
+  margin: 0px;
+  top: -16px;
+  width: 40px;
+  height: 16px;
+  overflow: hidden;
+  position: absolute;
+}
+.pretooltiparrow:before {
+  background-color: #f7f7f7;
+  border: 1px #ababab solid;
+  z-index: 11;
+  content: "";
+  position: absolute;
+  left: 15px;
+  top: 10px;
+  width: 25px;
+  height: 25px;
+  -webkit-transform: rotate(45deg);
+  -moz-transform: rotate(45deg);
+  -ms-transform: rotate(45deg);
+  -o-transform: rotate(45deg);
+}
+ul.typeahead-list i {
+  margin-left: -10px;
+  width: 18px;
+}
+ul.typeahead-list {
+  max-height: 80vh;
+  overflow: auto;
+}
+ul.typeahead-list > li > a {
+  /** Firefox bug **/
+  /* see https://github.com/jupyter/notebook/issues/559 */
+  white-space: normal;
+}
+.cmd-palette .modal-body {
+  padding: 7px;
+}
+.cmd-palette form {
+  background: white;
+}
+.cmd-palette input {
+  outline: none;
+}
+.no-shortcut {
+  display: none;
+}
+.command-shortcut:before {
+  content: "(command)";
+  padding-right: 3px;
+  color: #777777;
+}
+.edit-shortcut:before {
+  content: "(edit)";
+  padding-right: 3px;
+  color: #777777;
+}
+#find-and-replace #replace-preview .match,
+#find-and-replace #replace-preview .insert {
+  background-color: #BBDEFB;
+  border-color: #90CAF9;
+  border-style: solid;
+  border-width: 1px;
+  border-radius: 0px;
+}
+#find-and-replace #replace-preview .replace .match {
+  background-color: #FFCDD2;
+  border-color: #EF9A9A;
+  border-radius: 0px;
+}
+#find-and-replace #replace-preview .replace .insert {
+  background-color: #C8E6C9;
+  border-color: #A5D6A7;
+  border-radius: 0px;
+}
+#find-and-replace #replace-preview {
+  max-height: 60vh;
+  overflow: auto;
+}
+#find-and-replace #replace-preview pre {
+  padding: 5px 10px;
+}
+.terminal-app {
+  background: #EEE;
+}
+.terminal-app #header {
+  background: #fff;
+  -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+  box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+}
+.terminal-app .terminal {
+  width: 100%;
+  float: left;
+  font-family: monospace;
+  color: white;
+  background: black;
+  padding: 0.4em;
+  border-radius: 2px;
+  -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.4);
+  box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.4);
+}
+.terminal-app .terminal,
+.terminal-app .terminal dummy-screen {
+  line-height: 1em;
+  font-size: 14px;
+}
+.terminal-app .terminal .xterm-rows {
+  padding: 10px;
+}
+.terminal-app .terminal-cursor {
+  color: black;
+  background: white;
+}
+.terminal-app #terminado-container {
+  margin-top: 20px;
+}
+/*# sourceMappingURL=style.min.css.map */
+    </style>
+<style type="text/css">
+    .highlight .hll { background-color: #ffffcc }
+.highlight  { background: #f8f8f8; }
+.highlight .c { color: #408080; font-style: italic } /* Comment */
+.highlight .err { border: 1px solid #FF0000 } /* Error */
+.highlight .k { color: #008000; font-weight: bold } /* Keyword */
+.highlight .o { color: #666666 } /* Operator */
+.highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */
+.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #BC7A00 } /* Comment.Preproc */
+.highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */
+.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */
+.highlight .gd { color: #A00000 } /* Generic.Deleted */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #FF0000 } /* Generic.Error */
+.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.highlight .gi { color: #00A000 } /* Generic.Inserted */
+.highlight .go { color: #888888 } /* Generic.Output */
+.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.highlight .gt { color: #0044DD } /* Generic.Traceback */
+.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #008000 } /* Keyword.Pseudo */
+.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #B00040 } /* Keyword.Type */
+.highlight .m { color: #666666 } /* Literal.Number */
+.highlight .s { color: #BA2121 } /* Literal.String */
+.highlight .na { color: #7D9029 } /* Name.Attribute */
+.highlight .nb { color: #008000 } /* Name.Builtin */
+.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
+.highlight .no { color: #880000 } /* Name.Constant */
+.highlight .nd { color: #AA22FF } /* Name.Decorator */
+.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
+.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #0000FF } /* Name.Function */
+.highlight .nl { color: #A0A000 } /* Name.Label */
+.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
+.highlight .nv { color: #19177C } /* Name.Variable */
+.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mb { color: #666666 } /* Literal.Number.Bin */
+.highlight .mf { color: #666666 } /* Literal.Number.Float */
+.highlight .mh { color: #666666 } /* Literal.Number.Hex */
+.highlight .mi { color: #666666 } /* Literal.Number.Integer */
+.highlight .mo { color: #666666 } /* Literal.Number.Oct */
+.highlight .sa { color: #BA2121 } /* Literal.String.Affix */
+.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
+.highlight .sc { color: #BA2121 } /* Literal.String.Char */
+.highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */
+.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
+.highlight .s2 { color: #BA2121 } /* Literal.String.Double */
+.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
+.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.highlight .sx { color: #008000 } /* Literal.String.Other */
+.highlight .sr { color: #BB6688 } /* Literal.String.Regex */
+.highlight .s1 { color: #BA2121 } /* Literal.String.Single */
+.highlight .ss { color: #19177C } /* Literal.String.Symbol */
+.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
+.highlight .fm { color: #0000FF } /* Name.Function.Magic */
+.highlight .vc { color: #19177C } /* Name.Variable.Class */
+.highlight .vg { color: #19177C } /* Name.Variable.Global */
+.highlight .vi { color: #19177C } /* Name.Variable.Instance */
+.highlight .vm { color: #19177C } /* Name.Variable.Magic */
+.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
+    </style>
+<style type="text/css">
+    
+/* Temporary definitions which will become obsolete with Notebook release 5.0 */
+.ansi-black-fg { color: #3E424D; }
+.ansi-black-bg { background-color: #3E424D; }
+.ansi-black-intense-fg { color: #282C36; }
+.ansi-black-intense-bg { background-color: #282C36; }
+.ansi-red-fg { color: #E75C58; }
+.ansi-red-bg { background-color: #E75C58; }
+.ansi-red-intense-fg { color: #B22B31; }
+.ansi-red-intense-bg { background-color: #B22B31; }
+.ansi-green-fg { color: #00A250; }
+.ansi-green-bg { background-color: #00A250; }
+.ansi-green-intense-fg { color: #007427; }
+.ansi-green-intense-bg { background-color: #007427; }
+.ansi-yellow-fg { color: #DDB62B; }
+.ansi-yellow-bg { background-color: #DDB62B; }
+.ansi-yellow-intense-fg { color: #B27D12; }
+.ansi-yellow-intense-bg { background-color: #B27D12; }
+.ansi-blue-fg { color: #208FFB; }
+.ansi-blue-bg { background-color: #208FFB; }
+.ansi-blue-intense-fg { color: #0065CA; }
+.ansi-blue-intense-bg { background-color: #0065CA; }
+.ansi-magenta-fg { color: #D160C4; }
+.ansi-magenta-bg { background-color: #D160C4; }
+.ansi-magenta-intense-fg { color: #A03196; }
+.ansi-magenta-intense-bg { background-color: #A03196; }
+.ansi-cyan-fg { color: #60C6C8; }
+.ansi-cyan-bg { background-color: #60C6C8; }
+.ansi-cyan-intense-fg { color: #258F8F; }
+.ansi-cyan-intense-bg { background-color: #258F8F; }
+.ansi-white-fg { color: #C5C1B4; }
+.ansi-white-bg { background-color: #C5C1B4; }
+.ansi-white-intense-fg { color: #A1A6B2; }
+.ansi-white-intense-bg { background-color: #A1A6B2; }
+
+.ansi-bold { font-weight: bold; }
+
+    </style>
+
+
+<style type="text/css">
+/* Overrides of notebook CSS for static HTML export */
+body {
+  overflow: visible;
+  padding: 8px;
+}
+
+div#notebook {
+  overflow: visible;
+  border-top: none;
+}@media print {
+  div.cell {
+    display: block;
+    page-break-inside: avoid;
+  } 
+  div.output_wrapper { 
+    display: block;
+    page-break-inside: avoid; 
+  }
+  div.output { 
+    display: block;
+    page-break-inside: avoid; 
+  }
+}
+</style>
+
+<!-- Custom stylesheet, it must be in the same directory as the html file -->
+<link rel="stylesheet" href="custom.css">
+
+<!-- Loading mathjax macro -->
+<!-- Load mathjax -->
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS_HTML"></script>
+    <!-- MathJax configuration -->
+    <script type="text/x-mathjax-config">
+    MathJax.Hub.Config({
+        tex2jax: {
+            inlineMath: [ ['$','$'], ["\\(","\\)"] ],
+            displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
+            processEscapes: true,
+            processEnvironments: true
+        },
+        // Center justify equations in code and markdown cells. Elsewhere
+        // we use CSS to left justify single line equations in code cells.
+        displayAlign: 'center',
+        "HTML-CSS": {
+            styles: {'.MathJax_Display': {"margin": 0}},
+            linebreaks: { automatic: true }
+        }
+    });
+    </script>
+    <!-- End of mathjax configuration --></head>
+<body>
+  <div tabindex="-1" id="notebook" class="border-box-sizing">
+    <div class="container" id="notebook-container">
+
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[1]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="kn">from</span> <span class="nn">notebook_preamble</span> <span class="kn">import</span> <span class="n">D</span><span class="p">,</span> <span class="n">DefinitionWrapper</span><span class="p">,</span> <span class="n">J</span><span class="p">,</span> <span class="n">V</span><span class="p">,</span> <span class="n">define</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h1 id="Recursive-Combinators">Recursive Combinators<a class="anchor-link" href="#Recursive-Combinators">&#182;</a></h1><p>This article describes the <code>genrec</code> combinator, how to use it, and several generic specializations.</p>
+
+<pre><code>                      [if] [then] [rec1] [rec2] genrec
+---------------------------------------------------------------------
+   [if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte
+
+
+</code></pre>
+<p>From "Recursion Theory and Joy" (j05cmp.html) by Manfred von Thun:</p>
+<blockquote><p>"The genrec combinator takes four program parameters in addition to
+whatever data parameters it needs. Fourth from the top is an if-part,
+followed by a then-part. If the if-part yields true, then the then-part
+is executed and the combinator terminates. The other two parameters are
+the rec1-part and the rec2-part. If the if-part yields false, the
+rec1-part is executed. Following that the four program parameters and
+the combinator are again pushed onto the stack bundled up in a quoted
+form. Then the rec2-part is executed, where it will find the bundled
+form. Typically it will then execute the bundled form, either with i or
+with app2, or some other combinator."</p>
+</blockquote>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h2 id="Designing-Recursive-Functions">Designing Recursive Functions<a class="anchor-link" href="#Designing-Recursive-Functions">&#182;</a></h2><p>The way to design one of these is to fix your base case and 
+test and then treat <code>R1</code> and <code>R2</code> as an else-part "sandwiching"
+a quotation of the whole function.</p>
+<p>For example, given a (general recursive) function <code>F</code>:</p>
+
+<pre><code>F == [I] [T] [R1]   [R2] genrec
+  == [I] [T] [R1 [F] R2] ifte
+
+</code></pre>
+<p>If the <code>[I]</code> predicate is false you must derive <code>R1</code> and <code>R2</code> from:</p>
+
+<pre><code>... R1 [F] R2
+
+</code></pre>
+<p>Set the stack arguments in front and figure out what <code>R1</code> and <code>R2</code>
+have to do to apply the quoted <code>[F]</code> in the proper way.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h2 id="Primitive-Recursive-Functions">Primitive Recursive Functions<a class="anchor-link" href="#Primitive-Recursive-Functions">&#182;</a></h2><p>Primitive recursive functions are those where <code>R2 == i</code>.</p>
+
+<pre><code>P == [I] [T] [R] primrec
+  == [I] [T] [R [P] i] ifte
+  == [I] [T] [R P] ifte</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h2 id="Hylomorphism"><a href="https://en.wikipedia.org/wiki/Hylomorphism_%28computer_science%29">Hylomorphism</a><a class="anchor-link" href="#Hylomorphism">&#182;</a></h2><p>A <a href="https://en.wikipedia.org/wiki/Hylomorphism_%28computer_science%29">hylomorphism</a> is a recursive function <code>H :: A -&gt; C</code> that converts a value of type <code>A</code> into a value of type <code>C</code> by means of:</p>
+<ul>
+<li>A generator <code>G :: A -&gt; (B, A)</code></li>
+<li>A combiner <code>F :: (B, C) -&gt; C</code></li>
+<li>A predicate <code>P :: A -&gt; Bool</code> to detect the base case</li>
+<li>A base case value <code>c :: C</code></li>
+<li>Recursive calls (zero or more); it has a "call stack in the form of a cons list".</li>
+</ul>
+<p>It may be helpful to see this function implemented in imperative Python code.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[2]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">hylomorphism</span><span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="n">F</span><span class="p">,</span> <span class="n">P</span><span class="p">,</span> <span class="n">G</span><span class="p">):</span>
+    <span class="sd">&#39;&#39;&#39;Return a hylomorphism function H.&#39;&#39;&#39;</span>
+
+    <span class="k">def</span> <span class="nf">H</span><span class="p">(</span><span class="n">a</span><span class="p">):</span>
+        <span class="k">if</span> <span class="n">P</span><span class="p">(</span><span class="n">a</span><span class="p">):</span>
+            <span class="n">result</span> <span class="o">=</span> <span class="n">c</span>
+        <span class="k">else</span><span class="p">:</span>
+            <span class="n">b</span><span class="p">,</span> <span class="n">aa</span> <span class="o">=</span> <span class="n">G</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
+            <span class="n">result</span> <span class="o">=</span> <span class="n">F</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="n">H</span><span class="p">(</span><span class="n">aa</span><span class="p">))</span>  <span class="c1"># b is stored in the stack frame during recursive call to H().</span>
+        <span class="k">return</span> <span class="n">result</span>
+
+    <span class="k">return</span> <span class="n">H</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>Cf. <a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125">"Bananas, Lenses, &amp; Barbed Wire"</a></p>
+<p>Note that during evaluation of <code>H()</code> the intermediate <code>b</code> values are stored in the Python call stack.  This is what is meant by "call stack in the form of a cons list".</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h2 id="Hylomorphism-in-Joy">Hylomorphism in Joy<a class="anchor-link" href="#Hylomorphism-in-Joy">&#182;</a></h2><p>We can define a combinator <code>hylomorphism</code> that will make a hylomorphism combinator <code>H</code> from constituent parts.</p>
+
+<pre><code>H == [P] c [G] [F] hylomorphism
+
+</code></pre>
+<p>The function <code>H</code> is recursive, so we start with <code>ifte</code> and set the else-part to
+some function <code>J</code> that will contain a quoted copy of <code>H</code>.  (The then-part just
+discards the leftover <code>a</code> and replaces it with the base case value <code>c</code>.)</p>
+
+<pre><code>H == [P] [pop c] [J] ifte
+
+</code></pre>
+<p>The else-part <code>J</code> gets just the argument <code>a</code> on the stack.</p>
+
+<pre><code>a J
+a G              The first thing to do is use the generator G
+aa b             which produces b and a new aa
+aa b [H] dip     we recur with H on the new aa
+aa H b F         and run F on the result.
+
+</code></pre>
+<p>This gives us a definition for <code>J</code>.</p>
+
+<pre><code>J == G [H] dip F
+
+</code></pre>
+<p>Plug it in and convert to genrec.</p>
+
+<pre><code>H == [P] [pop c] [G [H] dip F] ifte
+H == [P] [pop c] [G]   [dip F] genrec
+
+</code></pre>
+<p>This is the form of a hylomorphism in Joy, which nicely illustrates that
+it is a simple specialization of the general recursion combinator.</p>
+
+<pre><code>H == [P] c [G] [F] hylomorphism == [P] [pop c] [G] [dip F] genrec</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h2 id="Derivation-of-hylomorphism-combinator">Derivation of <code>hylomorphism</code> combinator<a class="anchor-link" href="#Derivation-of-hylomorphism-combinator">&#182;</a></h2><p>Now we just need to derive a definition that builds the <code>genrec</code> arguments
+out of the pieces given to the <code>hylomorphism</code> combinator.</p>
+
+<pre><code>   [P]      c  [G]     [F] hylomorphism
+------------------------------------------
+   [P] [pop c] [G] [dip F] genrec
+
+</code></pre>
+<p>Working in reverse:</p>
+<ul>
+<li>Use <code>swoncat</code> twice to decouple <code>[c]</code> and <code>[F]</code>.</li>
+<li>Use <code>unit</code> to dequote <code>c</code>.</li>
+<li>Use <code>dipd</code> to untangle <code>[unit [pop] swoncat]</code> from the givens.</li>
+</ul>
+<p>So:</p>
+
+<pre><code>H == [P] [pop c]              [G]                  [dip F] genrec
+     [P] [c]    [pop] swoncat [G]        [F] [dip] swoncat genrec
+     [P] c unit [pop] swoncat [G]        [F] [dip] swoncat genrec
+     [P] c [G] [F] [unit [pop] swoncat] dipd [dip] swoncat genrec
+
+</code></pre>
+<p>At this point all of the arguments (givens) to the hylomorphism are to the left so we have
+a definition for <code>hylomorphism</code>:</p>
+
+<pre><code>hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[3]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">&#39;hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec&#39;</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="Example:-Finding-Triangular-Numbers">Example: Finding <a href="https://en.wikipedia.org/wiki/Triangular_number">Triangular Numbers</a><a class="anchor-link" href="#Example:-Finding-Triangular-Numbers">&#182;</a></h3><p>Let's write a function that, given a positive integer, returns the sum of all positive integers less than that one.  (In this case the types <code>A</code>, <code>B</code> and <code>C</code> are all <code>int</code>.)</p>
+<p>To sum a range of integers from 0 to <em>n</em> - 1:</p>
+<ul>
+<li><code>[P]</code> is <code>[1 &lt;=]</code></li>
+<li><code>c</code> is <code>0</code></li>
+<li><code>[G]</code> is <code>[-- dup]</code></li>
+<li><code>[F]</code> is <code>[+]</code></li>
+</ul>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[4]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">&#39;triangular_number == [1 &lt;=] 0 [-- dup] [+] hylomorphism&#39;</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>Let's try it:</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[5]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">&#39;5 triangular_number&#39;</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>10
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[6]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">&#39;[0 1 2 3 4 5 6] [triangular_number] map&#39;</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>[0 0 1 3 6 10 15]
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h2 id="Four-Specializations">Four Specializations<a class="anchor-link" href="#Four-Specializations">&#182;</a></h2><p>There are at least four kinds of recursive combinator, depending on two choices.  The first choice is whether the combiner function <code>F</code> should be evaluated during the recursion or pushed into the pending expression to be "collapsed" at the end.  The second choice is whether the combiner needs to operate on the current value of the datastructure or the generator's output, in other words, whether <code>F</code> or <code>G</code> should run first in the recursive branch.</p>
+
+<pre><code>H1 ==        [P] [pop c] [G             ] [dip F] genrec
+H2 == c swap [P] [pop]   [G [F]    dip  ] [i]     genrec
+H3 ==        [P] [pop c] [  [G] dupdip  ] [dip F] genrec
+H4 == c swap [P] [pop]   [  [F] dupdip G] [i]     genrec
+
+</code></pre>
+<p>The working of the generator function <code>G</code> differs slightly for each.  Consider the recursive branches:</p>
+
+<pre><code>... a G [H1] dip F                w/ a G == a′ b
+
+... c a G [F] dip H2                 a G == b  a′
+
+... a [G] dupdip [H3] dip F          a G == a′
+
+... c a [F] dupdip G H4              a G == a′
+
+</code></pre>
+<p>The following four sections illustrate how these work, omitting the predicate evaluation.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="H1"><code>H1</code><a class="anchor-link" href="#H1">&#182;</a></h3>
+<pre><code>H1 == [P] [pop c] [G] [dip F] genrec
+
+</code></pre>
+<p>Iterate n times.</p>
+
+<pre><code>... a  G [H1] dip F
+... a′ b [H1] dip F
+... a′ H1 b F
+... a′ G [H1] dip F b F
+... a″ b′ [H1] dip F b F
+... a″ H1 b′ F b F
+... a″ G [H1] dip F b′ F b F
+... a‴ b″ [H1] dip F b′ F b F
+... a‴ H1 b″ F b′ F b F
+... a‴ pop c b″ F b′ F b F
+... c b″ F b′ F b F
+... d      b′ F b F
+... d′          b F
+... d″
+
+</code></pre>
+<p>This form builds up a pending expression (continuation) that contains the intermediate results along with the pending combiner functions.  When the base case is reached the last term is replaced by the identity value <code>c</code> and the continuation "collapses" into the final result using the combiner <code>F</code>.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="H2"><code>H2</code><a class="anchor-link" href="#H2">&#182;</a></h3><p>When you can start with the identity value <code>c</code> on the stack and the combiner <code>F</code> can operate as you go using the intermediate results immediately rather than queuing them up, use this form.  An important difference is that the generator function must return its results in the reverse order.</p>
+
+<pre><code>H2 == c swap [P] [pop] [G [F] dip] primrec
+
+... c a G  [F] dip H2
+... c b a′ [F] dip H2
+... c b F a′ H2
+... d     a′ H2
+... d a′ G  [F] dip H2
+... d b′ a″ [F] dip H2
+... d b′ F a″ H2
+... d′     a″ H2
+... d′ a″ G  [F] dip H2
+... d′ b″ a‴ [F] dip H2
+... d′ b″ F a‴ H2
+... d″      a‴ H2
+... d″ a‴ pop
+... d″</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="H3"><code>H3</code><a class="anchor-link" href="#H3">&#182;</a></h3><p>If you examine the traces above you'll see that the combiner <code>F</code> only gets to operate on the results of <code>G</code>, it never "sees" the first value <code>a</code>.  If the combiner and the generator both need to work on the current value then <code>dup</code> must be used, and the generator must produce one item instead of two (the b is instead the duplicate of a.)</p>
+
+<pre><code>H3 == [P] [pop c] [[G] dupdip] [dip F] genrec
+
+... a [G] dupdip [H3] dip F
+... a  G  a      [H3] dip F
+... a′    a      [H3] dip F
+... a′ H3 a               F
+... a′ [G] dupdip [H3] dip F a F
+... a′  G  a′     [H3] dip F a F
+... a″     a′     [H3] dip F a F
+... a″ H3  a′              F a F
+... a″ [G] dupdip [H3] dip F a′ F a F
+... a″  G    a″   [H3] dip F a′ F a F
+... a‴       a″   [H3] dip F a′ F a F
+... a‴ H3    a″            F a′ F a F
+... a‴ pop c a″ F a′ F a F
+...        c a″ F a′ F a F
+...        d      a′ F a F
+...        d′          a F
+...        d″</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="H4"><code>H4</code><a class="anchor-link" href="#H4">&#182;</a></h3><p>And, last but not least, if you can combine as you go, starting with <code>c</code>, and the combiner <code>F</code> needs to work on the current item, this is the form:</p>
+
+<pre><code>H4 == c swap [P] [pop] [[F] dupdip G] primrec
+
+... c  a  [F] dupdip G H4
+... c  a   F  a      G H4
+... d         a      G H4
+... d  a′              H4
+... d  a′ [F] dupdip G H4
+... d  a′  F  a′     G H4
+... d′        a′     G H4
+... d′ a″              H4
+... d′ a″ [F] dupdip G H4
+... d′ a″  F  a″     G H4
+... d″        a″     G H4
+... d″ a‴              H4
+... d″ a‴ pop
+... d″</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h2 id="Anamorphism">Anamorphism<a class="anchor-link" href="#Anamorphism">&#182;</a></h2><p>An anamorphism can be defined as a hylomorphism that uses <code>[]</code> for <code>c</code> and
+<code>swons</code> for <code>F</code>.  An anamorphic function builds a list of values.</p>
+
+<pre><code>A == [P] [] [G] [swons] hylomorphism</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="range-et.-al."><code>range</code> et. al.<a class="anchor-link" href="#range-et.-al.">&#182;</a></h3><p>An example of an anamorphism is the <code>range</code> function which generates the list of integers from 0 to <em>n</em> - 1 given <em>n</em>.</p>
+<p>Each of the above variations can be used to make four slightly different <code>range</code> functions.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h4 id="range-with-H1"><code>range</code> with <code>H1</code><a class="anchor-link" href="#range-with-H1">&#182;</a></h4>
+<pre><code>H1 == [P]    [pop c]  [G]      [dip F]     genrec
+   == [0 &lt;=] [pop []] [-- dup] [dip swons] genrec</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[7]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">&#39;range == [0 &lt;=] [] [-- dup] [swons] hylomorphism&#39;</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[8]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">&#39;5 range&#39;</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>[4 3 2 1 0]
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h4 id="range-with-H2"><code>range</code> with <code>H2</code><a class="anchor-link" href="#range-with-H2">&#182;</a></h4>
+<pre><code>H2 == c  swap [P]    [pop] [G      [F]     dip] primrec
+   == [] swap [0 &lt;=] [pop] [-- dup [swons] dip] primrec</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[9]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">&#39;range_reverse == [] swap [0 &lt;=] [pop] [-- dup [swons] dip] primrec&#39;</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[10]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">&#39;5 range_reverse&#39;</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>[0 1 2 3 4]
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h4 id="range-with-H3"><code>range</code> with <code>H3</code><a class="anchor-link" href="#range-with-H3">&#182;</a></h4>
+<pre><code>H3 == [P]    [pop c]  [[G]  dupdip] [dip F]     genrec
+   == [0 &lt;=] [pop []] [[--] dupdip] [dip swons] genrec</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[11]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">&#39;ranger == [0 &lt;=] [pop []] [[--] dupdip] [dip swons] genrec&#39;</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[12]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">&#39;5 ranger&#39;</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>[5 4 3 2 1]
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h4 id="range-with-H4"><code>range</code> with <code>H4</code><a class="anchor-link" href="#range-with-H4">&#182;</a></h4>
+<pre><code>H4 == c  swap [P]    [pop] [[F]     dupdip G ] primrec
+   == [] swap [0 &lt;=] [pop] [[swons] dupdip --] primrec</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[13]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">&#39;ranger_reverse == [] swap [0 &lt;=] [pop] [[swons] dupdip --] primrec&#39;</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[14]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">&#39;5 ranger_reverse&#39;</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>[1 2 3 4 5]
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>Hopefully this illustrates the workings of the variations.  For more insight you can run the cells using the <code>V()</code> function instead of the <code>J()</code> function to get a trace of the Joy evaluation.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h2 id="Catamorphism">Catamorphism<a class="anchor-link" href="#Catamorphism">&#182;</a></h2><p>A catamorphism can be defined as a hylomorphism that uses <code>[uncons swap]</code> for <code>[G]</code>
+and <code>[[] =]</code> (or just <code>[not]</code>) for the predicate <code>[P]</code>.  A catamorphic function tears down a list term-by-term and makes some new value.</p>
+
+<pre><code>C == [not] c [uncons swap] [F] hylomorphism</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[15]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">&#39;swuncons == uncons swap&#39;</span><span class="p">)</span>  <span class="c1"># Awkward name.</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>An example of a catamorphism is the sum function.</p>
+
+<pre><code>sum == [not] 0 [swuncons] [+] hylomorphism</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[16]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">&#39;sum == [not] 0 [swuncons] [+] hylomorphism&#39;</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[17]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">&#39;[5 4 3 2 1] sum&#39;</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>15
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="The-step-combinator">The <code>step</code> combinator<a class="anchor-link" href="#The-step-combinator">&#182;</a></h3><p>The <code>step</code> combinator will usually be better to use than <code>catamorphism</code>.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[18]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">&#39;[step] help&#39;</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>Run a quoted program on each item in a sequence.
+::
+
+        ... [] [Q] . step
+     -----------------------
+               ... .
+
+
+       ... [a] [Q] . step
+    ------------------------
+             ... a . Q
+
+
+     ... [a b c] [Q] . step
+  ----------------------------------------
+               ... a . Q [b c] [Q] step
+
+The step combinator executes the quotation on each member of the list
+on top of the stack.
+
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[19]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">&#39;sum == 0 swap [+] step&#39;</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[20]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">&#39;[5 4 3 2 1] sum&#39;</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>15
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h2 id="Example:-Factorial-Function">Example: Factorial Function<a class="anchor-link" href="#Example:-Factorial-Function">&#182;</a></h2><p>For the Factorial function:</p>
+
+<pre><code>H4 == c swap [P] [pop] [[F] dupdip G] primrec
+
+</code></pre>
+<p>With:</p>
+
+<pre><code>c == 1
+F == *
+G == --
+P == 1 &lt;=</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[21]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">&#39;factorial == 1 swap [1 &lt;=] [pop] [[*] dupdip --] primrec&#39;</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[22]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">&#39;5 factorial&#39;</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>120
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h2 id="Example:-tails">Example: <code>tails</code><a class="anchor-link" href="#Example:-tails">&#182;</a></h2><p>An example of a paramorphism for lists given in the <a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125">"Bananas..." paper</a> is <code>tails</code> which returns the list of "tails" of a list.</p>
+
+<pre><code>    [1 2 3] tails
+--------------------
+   [[] [3] [2 3]]</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>We can build as we go, and we want <code>F</code> to run after <code>G</code>, so we use pattern <code>H2</code>:</p>
+
+<pre><code>H2 == c swap [P] [pop] [G [F] dip] primrec</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>We would use:</p>
+
+<pre><code>c == []
+F == swons
+G == rest dup
+P == not</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[23]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">&#39;tails == [] swap [not] [pop] [rest dup [swons] dip] primrec&#39;</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[24]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">&#39;[1 2 3] tails&#39;</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>[[] [3] [2 3]]
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h2 id="Conclusion:-Patterns-of-Recursion">Conclusion: Patterns of Recursion<a class="anchor-link" href="#Conclusion:-Patterns-of-Recursion">&#182;</a></h2><p>Our story so far...</p>
+<h3 id="Hylo-,-Ana-,-Cata-">Hylo-, Ana-, Cata-<a class="anchor-link" href="#Hylo-,-Ana-,-Cata-">&#182;</a></h3>
+<pre><code>H == [P  ] [pop c ] [G          ] [dip F        ] genrec
+A == [P  ] [pop []] [G          ] [dip swap cons] genrec
+C == [not] [pop c ] [uncons swap] [dip F        ] genrec
+
+</code></pre>
+<h3 id="Para-,-?-,-?-">Para-, ?-, ?-<a class="anchor-link" href="#Para-,-?-,-?-">&#182;</a></h3>
+<pre><code>P == c  swap [P  ] [pop] [[F        ] dupdip G          ] primrec
+? == [] swap [P  ] [pop] [[swap cons] dupdip G          ] primrec
+? == c  swap [not] [pop] [[F        ] dupdip uncons swap] primrec</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h2 id="Appendix:-Fun-with-Symbols">Appendix: Fun with Symbols<a class="anchor-link" href="#Appendix:-Fun-with-Symbols">&#182;</a></h2>
+<pre><code>|[ (c, F), (G, P) ]| == (|c, F|) • [(G, P)]
+
+</code></pre>
+<p><a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125">"Bananas, Lenses, &amp; Barbed Wire"</a></p>
+
+<pre><code>(|...|)  [(...)]  [&lt;...&gt;]
+
+</code></pre>
+<p>I think they are having slightly too much fun with the symbols.  However, "Too much is always better than not enough."</p>
+
+</div>
+</div>
+</div>
+    </div>
+  </div>
+</body>
+
+
+
+</html>
diff --git a/docs/Recursion_Combinators.ipynb b/docs/Recursion_Combinators.ipynb
new file mode 100644 (file)
index 0000000..f912ff2
--- /dev/null
@@ -0,0 +1,859 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from notebook_preamble import D, DefinitionWrapper, J, V, define"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Recursive Combinators\n",
+    "\n",
+    "This article describes the `genrec` combinator, how to use it, and several generic specializations.\n",
+    "\n",
+    "                          [if] [then] [rec1] [rec2] genrec\n",
+    "    ---------------------------------------------------------------------\n",
+    "       [if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte\n",
+    "\n",
+    "\n",
+    "From \"Recursion Theory and Joy\" (j05cmp.html) by Manfred von Thun:\n",
+    "\n",
+    "> \"The genrec combinator takes four program parameters in addition to\n",
+    "whatever data parameters it needs. Fourth from the top is an if-part,\n",
+    "followed by a then-part. If the if-part yields true, then the then-part\n",
+    "is executed and the combinator terminates. The other two parameters are\n",
+    "the rec1-part and the rec2-part. If the if-part yields false, the\n",
+    "rec1-part is executed. Following that the four program parameters and\n",
+    "the combinator are again pushed onto the stack bundled up in a quoted\n",
+    "form. Then the rec2-part is executed, where it will find the bundled\n",
+    "form. Typically it will then execute the bundled form, either with i or\n",
+    "with app2, or some other combinator.\""
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Designing Recursive Functions\n",
+    "The way to design one of these is to fix your base case and \n",
+    "test and then treat `R1` and `R2` as an else-part \"sandwiching\"\n",
+    "a quotation of the whole function.\n",
+    "\n",
+    "For example, given a (general recursive) function `F`:\n",
+    "\n",
+    "    F == [I] [T] [R1]   [R2] genrec\n",
+    "      == [I] [T] [R1 [F] R2] ifte\n",
+    "\n",
+    "If the `[I]` predicate is false you must derive `R1` and `R2` from:\n",
+    "\n",
+    "    ... R1 [F] R2\n",
+    "\n",
+    "Set the stack arguments in front and figure out what `R1` and `R2`\n",
+    "have to do to apply the quoted `[F]` in the proper way."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Primitive Recursive Functions\n",
+    "Primitive recursive functions are those where `R2 == i`.\n",
+    "\n",
+    "    P == [I] [T] [R] primrec\n",
+    "      == [I] [T] [R [P] i] ifte\n",
+    "      == [I] [T] [R P] ifte"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## [Hylomorphism](https://en.wikipedia.org/wiki/Hylomorphism_%28computer_science%29)\n",
+    "A [hylomorphism](https://en.wikipedia.org/wiki/Hylomorphism_%28computer_science%29) is a recursive function `H :: A -> C` that converts a value of type `A` into a value of type `C` by means of:\n",
+    "\n",
+    "- A generator `G :: A -> (B, A)`\n",
+    "- A combiner `F :: (B, C) -> C`\n",
+    "- A predicate `P :: A -> Bool` to detect the base case\n",
+    "- A base case value `c :: C`\n",
+    "- Recursive calls (zero or more); it has a \"call stack in the form of a cons list\".\n",
+    "\n",
+    "It may be helpful to see this function implemented in imperative Python code."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def hylomorphism(c, F, P, G):\n",
+    "    '''Return a hylomorphism function H.'''\n",
+    "\n",
+    "    def H(a):\n",
+    "        if P(a):\n",
+    "            result = c\n",
+    "        else:\n",
+    "            b, aa = G(a)\n",
+    "            result = F(b, H(aa))  # b is stored in the stack frame during recursive call to H().\n",
+    "        return result\n",
+    "\n",
+    "    return H"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Cf. [\"Bananas, Lenses, & Barbed Wire\"](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125)\n",
+    "\n",
+    "Note that during evaluation of `H()` the intermediate `b` values are stored in the Python call stack.  This is what is meant by \"call stack in the form of a cons list\"."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Hylomorphism in Joy\n",
+    "We can define a combinator `hylomorphism` that will make a hylomorphism combinator `H` from constituent parts.\n",
+    "\n",
+    "    H == [P] c [G] [F] hylomorphism\n",
+    "\n",
+    "The function `H` is recursive, so we start with `ifte` and set the else-part to\n",
+    "some function `J` that will contain a quoted copy of `H`.  (The then-part just\n",
+    "discards the leftover `a` and replaces it with the base case value `c`.)\n",
+    "\n",
+    "    H == [P] [pop c] [J] ifte\n",
+    "\n",
+    "The else-part `J` gets just the argument `a` on the stack.\n",
+    "\n",
+    "    a J\n",
+    "    a G              The first thing to do is use the generator G\n",
+    "    aa b             which produces b and a new aa\n",
+    "    aa b [H] dip     we recur with H on the new aa\n",
+    "    aa H b F         and run F on the result.\n",
+    "\n",
+    "This gives us a definition for `J`.\n",
+    "\n",
+    "    J == G [H] dip F\n",
+    "\n",
+    "Plug it in and convert to genrec.\n",
+    "\n",
+    "    H == [P] [pop c] [G [H] dip F] ifte\n",
+    "    H == [P] [pop c] [G]   [dip F] genrec\n",
+    "\n",
+    "This is the form of a hylomorphism in Joy, which nicely illustrates that\n",
+    "it is a simple specialization of the general recursion combinator.\n",
+    "\n",
+    "    H == [P] c [G] [F] hylomorphism == [P] [pop c] [G] [dip F] genrec"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Derivation of `hylomorphism` combinator\n",
+    "\n",
+    "Now we just need to derive a definition that builds the `genrec` arguments\n",
+    "out of the pieces given to the `hylomorphism` combinator.\n",
+    "\n",
+    "       [P]      c  [G]     [F] hylomorphism\n",
+    "    ------------------------------------------\n",
+    "       [P] [pop c] [G] [dip F] genrec\n",
+    "\n",
+    "Working in reverse:\n",
+    "\n",
+    "- Use `swoncat` twice to decouple `[c]` and `[F]`.\n",
+    "- Use `unit` to dequote `c`.\n",
+    "- Use `dipd` to untangle `[unit [pop] swoncat]` from the givens.\n",
+    "\n",
+    "So:\n",
+    "\n",
+    "    H == [P] [pop c]              [G]                  [dip F] genrec\n",
+    "         [P] [c]    [pop] swoncat [G]        [F] [dip] swoncat genrec\n",
+    "         [P] c unit [pop] swoncat [G]        [F] [dip] swoncat genrec\n",
+    "         [P] c [G] [F] [unit [pop] swoncat] dipd [dip] swoncat genrec\n",
+    "\n",
+    "At this point all of the arguments (givens) to the hylomorphism are to the left so we have\n",
+    "a definition for `hylomorphism`:\n",
+    "\n",
+    "    hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "define('hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec')"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Example: Finding [Triangular Numbers](https://en.wikipedia.org/wiki/Triangular_number)\n",
+    "Let's write a function that, given a positive integer, returns the sum of all positive integers less than that one.  (In this case the types `A`, `B` and `C` are all `int`.)\n",
+    "\n",
+    "To sum a range of integers from 0 to *n* - 1:\n",
+    "\n",
+    "- `[P]` is `[1 <=]`\n",
+    "- `c` is `0`\n",
+    "- `[G]` is `[-- dup]`\n",
+    "- `[F]` is `[+]`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "define('triangular_number == [1 <=] 0 [-- dup] [+] hylomorphism')"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Let's try it:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "10\n"
+     ]
+    }
+   ],
+   "source": [
+    "J('5 triangular_number')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[0 0 1 3 6 10 15]\n"
+     ]
+    }
+   ],
+   "source": [
+    "J('[0 1 2 3 4 5 6] [triangular_number] map')"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Four Specializations\n",
+    "There are at least four kinds of recursive combinator, depending on two choices.  The first choice is whether the combiner function `F` should be evaluated during the recursion or pushed into the pending expression to be \"collapsed\" at the end.  The second choice is whether the combiner needs to operate on the current value of the datastructure or the generator's output, in other words, whether `F` or `G` should run first in the recursive branch.\n",
+    "\n",
+    "    H1 ==        [P] [pop c] [G             ] [dip F] genrec\n",
+    "    H2 == c swap [P] [pop]   [G [F]    dip  ] [i]     genrec\n",
+    "    H3 ==        [P] [pop c] [  [G] dupdip  ] [dip F] genrec\n",
+    "    H4 == c swap [P] [pop]   [  [F] dupdip G] [i]     genrec\n",
+    "\n",
+    "The working of the generator function `G` differs slightly for each.  Consider the recursive branches:\n",
+    "\n",
+    "    ... a G [H1] dip F                w/ a G == a′ b\n",
+    "    \n",
+    "    ... c a G [F] dip H2                 a G == b  a′\n",
+    "    \n",
+    "    ... a [G] dupdip [H3] dip F          a G == a′\n",
+    "    \n",
+    "    ... c a [F] dupdip G H4              a G == a′\n",
+    "\n",
+    "The following four sections illustrate how these work, omitting the predicate evaluation."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `H1`\n",
+    "\n",
+    "    H1 == [P] [pop c] [G] [dip F] genrec\n",
+    "\n",
+    "Iterate n times.\n",
+    "\n",
+    "    ... a  G [H1] dip F\n",
+    "    ... a′ b [H1] dip F\n",
+    "    ... a′ H1 b F\n",
+    "    ... a′ G [H1] dip F b F\n",
+    "    ... a″ b′ [H1] dip F b F\n",
+    "    ... a″ H1 b′ F b F\n",
+    "    ... a″ G [H1] dip F b′ F b F\n",
+    "    ... a‴ b″ [H1] dip F b′ F b F\n",
+    "    ... a‴ H1 b″ F b′ F b F\n",
+    "    ... a‴ pop c b″ F b′ F b F\n",
+    "    ... c b″ F b′ F b F\n",
+    "    ... d      b′ F b F\n",
+    "    ... d′          b F\n",
+    "    ... d″\n",
+    "\n",
+    "This form builds up a pending expression (continuation) that contains the intermediate results along with the pending combiner functions.  When the base case is reached the last term is replaced by the identity value `c` and the continuation \"collapses\" into the final result using the combiner `F`."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `H2`\n",
+    "When you can start with the identity value `c` on the stack and the combiner `F` can operate as you go using the intermediate results immediately rather than queuing them up, use this form.  An important difference is that the generator function must return its results in the reverse order.\n",
+    "\n",
+    "    H2 == c swap [P] [pop] [G [F] dip] primrec\n",
+    "\n",
+    "    ... c a G  [F] dip H2\n",
+    "    ... c b a′ [F] dip H2\n",
+    "    ... c b F a′ H2\n",
+    "    ... d     a′ H2\n",
+    "    ... d a′ G  [F] dip H2\n",
+    "    ... d b′ a″ [F] dip H2\n",
+    "    ... d b′ F a″ H2\n",
+    "    ... d′     a″ H2\n",
+    "    ... d′ a″ G  [F] dip H2\n",
+    "    ... d′ b″ a‴ [F] dip H2\n",
+    "    ... d′ b″ F a‴ H2\n",
+    "    ... d″      a‴ H2\n",
+    "    ... d″ a‴ pop\n",
+    "    ... d″\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `H3`\n",
+    "If you examine the traces above you'll see that the combiner `F` only gets to operate on the results of `G`, it never \"sees\" the first value `a`.  If the combiner and the generator both need to work on the current value then `dup` must be used, and the generator must produce one item instead of two (the b is instead the duplicate of a.)\n",
+    "\n",
+    "\n",
+    "    H3 == [P] [pop c] [[G] dupdip] [dip F] genrec\n",
+    "\n",
+    "    ... a [G] dupdip [H3] dip F\n",
+    "    ... a  G  a      [H3] dip F\n",
+    "    ... a′    a      [H3] dip F\n",
+    "    ... a′ H3 a               F\n",
+    "    ... a′ [G] dupdip [H3] dip F a F\n",
+    "    ... a′  G  a′     [H3] dip F a F\n",
+    "    ... a″     a′     [H3] dip F a F\n",
+    "    ... a″ H3  a′              F a F\n",
+    "    ... a″ [G] dupdip [H3] dip F a′ F a F\n",
+    "    ... a″  G    a″   [H3] dip F a′ F a F\n",
+    "    ... a‴       a″   [H3] dip F a′ F a F\n",
+    "    ... a‴ H3    a″            F a′ F a F\n",
+    "    ... a‴ pop c a″ F a′ F a F\n",
+    "    ...        c a″ F a′ F a F\n",
+    "    ...        d      a′ F a F\n",
+    "    ...        d′          a F\n",
+    "    ...        d″"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `H4`\n",
+    "And, last but not least, if you can combine as you go, starting with `c`, and the combiner `F` needs to work on the current item, this is the form:\n",
+    "\n",
+    "    H4 == c swap [P] [pop] [[F] dupdip G] primrec\n",
+    "\n",
+    "    ... c  a  [F] dupdip G H4\n",
+    "    ... c  a   F  a      G H4\n",
+    "    ... d         a      G H4\n",
+    "    ... d  a′              H4\n",
+    "    ... d  a′ [F] dupdip G H4\n",
+    "    ... d  a′  F  a′     G H4\n",
+    "    ... d′        a′     G H4\n",
+    "    ... d′ a″              H4\n",
+    "    ... d′ a″ [F] dupdip G H4\n",
+    "    ... d′ a″  F  a″     G H4\n",
+    "    ... d″        a″     G H4\n",
+    "    ... d″ a‴              H4\n",
+    "    ... d″ a‴ pop\n",
+    "    ... d″"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Anamorphism\n",
+    "An anamorphism can be defined as a hylomorphism that uses `[]` for `c` and\n",
+    "`swons` for `F`.  An anamorphic function builds a list of values.\n",
+    "\n",
+    "    A == [P] [] [G] [swons] hylomorphism"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `range` et. al.\n",
+    "An example of an anamorphism is the `range` function which generates the list of integers from 0 to *n* - 1 given *n*.\n",
+    "\n",
+    "Each of the above variations can be used to make four slightly different `range` functions."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### `range` with `H1`\n",
+    "    H1 == [P]    [pop c]  [G]      [dip F]     genrec\n",
+    "       == [0 <=] [pop []] [-- dup] [dip swons] genrec"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "define('range == [0 <=] [] [-- dup] [swons] hylomorphism')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[4 3 2 1 0]\n"
+     ]
+    }
+   ],
+   "source": [
+    "J('5 range')"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### `range` with `H2`\n",
+    "    H2 == c  swap [P]    [pop] [G      [F]     dip] primrec\n",
+    "       == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "define('range_reverse == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[0 1 2 3 4]\n"
+     ]
+    }
+   ],
+   "source": [
+    "J('5 range_reverse')"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### `range` with `H3`\n",
+    "    H3 == [P]    [pop c]  [[G]  dupdip] [dip F]     genrec\n",
+    "       == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "define('ranger == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[5 4 3 2 1]\n"
+     ]
+    }
+   ],
+   "source": [
+    "J('5 ranger')"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### `range` with `H4`\n",
+    "    H4 == c  swap [P]    [pop] [[F]     dupdip G ] primrec\n",
+    "       == [] swap [0 <=] [pop] [[swons] dupdip --] primrec"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "define('ranger_reverse == [] swap [0 <=] [pop] [[swons] dupdip --] primrec')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[1 2 3 4 5]\n"
+     ]
+    }
+   ],
+   "source": [
+    "J('5 ranger_reverse')"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Hopefully this illustrates the workings of the variations.  For more insight you can run the cells using the `V()` function instead of the `J()` function to get a trace of the Joy evaluation."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Catamorphism\n",
+    "A catamorphism can be defined as a hylomorphism that uses `[uncons swap]` for `[G]`\n",
+    "and `[[] =]` (or just `[not]`) for the predicate `[P]`.  A catamorphic function tears down a list term-by-term and makes some new value.\n",
+    "\n",
+    "    C == [not] c [uncons swap] [F] hylomorphism"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "define('swuncons == uncons swap')  # Awkward name."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "An example of a catamorphism is the sum function.\n",
+    "\n",
+    "    sum == [not] 0 [swuncons] [+] hylomorphism"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "define('sum == [not] 0 [swuncons] [+] hylomorphism')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "15\n"
+     ]
+    }
+   ],
+   "source": [
+    "J('[5 4 3 2 1] sum')"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### The `step` combinator\n",
+    "The `step` combinator will usually be better to use than `catamorphism`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Run a quoted program on each item in a sequence.\n",
+      "::\n",
+      "\n",
+      "        ... [] [Q] . step\n",
+      "     -----------------------\n",
+      "               ... .\n",
+      "\n",
+      "\n",
+      "       ... [a] [Q] . step\n",
+      "    ------------------------\n",
+      "             ... a . Q\n",
+      "\n",
+      "\n",
+      "     ... [a b c] [Q] . step\n",
+      "  ----------------------------------------\n",
+      "               ... a . Q [b c] [Q] step\n",
+      "\n",
+      "The step combinator executes the quotation on each member of the list\n",
+      "on top of the stack.\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "J('[step] help')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 19,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "define('sum == 0 swap [+] step')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 20,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "15\n"
+     ]
+    }
+   ],
+   "source": [
+    "J('[5 4 3 2 1] sum')"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Example: Factorial Function\n",
+    "\n",
+    "For the Factorial function:\n",
+    "\n",
+    "    H4 == c swap [P] [pop] [[F] dupdip G] primrec\n",
+    "\n",
+    "With:\n",
+    "\n",
+    "    c == 1\n",
+    "    F == *\n",
+    "    G == --\n",
+    "    P == 1 <="
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 21,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "define('factorial == 1 swap [1 <=] [pop] [[*] dupdip --] primrec')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 22,
+   "metadata": {
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "120\n"
+     ]
+    }
+   ],
+   "source": [
+    "J('5 factorial')"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Example: `tails`\n",
+    "An example of a paramorphism for lists given in the [\"Bananas...\" paper](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125) is `tails` which returns the list of \"tails\" of a list.\n",
+    "\n",
+    "        [1 2 3] tails\n",
+    "    --------------------\n",
+    "       [[] [3] [2 3]]\n",
+    "    "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "We can build as we go, and we want `F` to run after `G`, so we use pattern `H2`:\n",
+    "\n",
+    "    H2 == c swap [P] [pop] [G [F] dip] primrec"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "We would use:\n",
+    "\n",
+    "    c == []\n",
+    "    F == swons\n",
+    "    G == rest dup\n",
+    "    P == not"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 23,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "define('tails == [] swap [not] [pop] [rest dup [swons] dip] primrec')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 24,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[[] [3] [2 3]]\n"
+     ]
+    }
+   ],
+   "source": [
+    "J('[1 2 3] tails')"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Conclusion: Patterns of Recursion\n",
+    "Our story so far...\n",
+    "\n",
+    "\n",
+    "### Hylo-, Ana-, Cata-\n",
+    "\n",
+    "    H == [P  ] [pop c ] [G          ] [dip F        ] genrec\n",
+    "    A == [P  ] [pop []] [G          ] [dip swap cons] genrec\n",
+    "    C == [not] [pop c ] [uncons swap] [dip F        ] genrec\n",
+    "\n",
+    "### Para-, ?-, ?-\n",
+    "\n",
+    "    P == c  swap [P  ] [pop] [[F        ] dupdip G          ] primrec\n",
+    "    ? == [] swap [P  ] [pop] [[swap cons] dupdip G          ] primrec\n",
+    "    ? == c  swap [not] [pop] [[F        ] dupdip uncons swap] primrec\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Appendix: Fun with Symbols\n",
+    "\n",
+    "    |[ (c, F), (G, P) ]| == (|c, F|) • [(G, P)]\n",
+    "\n",
+    "[\"Bananas, Lenses, & Barbed Wire\"](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125)\n",
+    "\n",
+    "    (|...|)  [(...)]  [<...>]\n",
+    "\n",
+    "I think they are having slightly too much fun with the symbols.  However, \"Too much is always better than not enough.\""
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 2",
+   "language": "python",
+   "name": "python2"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 2
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython2",
+   "version": "2.7.12"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/docs/Recursion_Combinators.md b/docs/Recursion_Combinators.md
new file mode 100644 (file)
index 0000000..97ae948
--- /dev/null
@@ -0,0 +1,525 @@
+
+
+```python
+from notebook_preamble import D, DefinitionWrapper, J, V, define
+```
+
+# Recursive Combinators
+
+This article describes the `genrec` combinator, how to use it, and several generic specializations.
+
+                          [if] [then] [rec1] [rec2] genrec
+    ---------------------------------------------------------------------
+       [if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte
+
+
+From "Recursion Theory and Joy" (j05cmp.html) by Manfred von Thun:
+
+> "The genrec combinator takes four program parameters in addition to
+whatever data parameters it needs. Fourth from the top is an if-part,
+followed by a then-part. If the if-part yields true, then the then-part
+is executed and the combinator terminates. The other two parameters are
+the rec1-part and the rec2-part. If the if-part yields false, the
+rec1-part is executed. Following that the four program parameters and
+the combinator are again pushed onto the stack bundled up in a quoted
+form. Then the rec2-part is executed, where it will find the bundled
+form. Typically it will then execute the bundled form, either with i or
+with app2, or some other combinator."
+
+## Designing Recursive Functions
+The way to design one of these is to fix your base case and 
+test and then treat `R1` and `R2` as an else-part "sandwiching"
+a quotation of the whole function.
+
+For example, given a (general recursive) function `F`:
+
+    F == [I] [T] [R1]   [R2] genrec
+      == [I] [T] [R1 [F] R2] ifte
+
+If the `[I]` predicate is false you must derive `R1` and `R2` from:
+
+    ... R1 [F] R2
+
+Set the stack arguments in front and figure out what `R1` and `R2`
+have to do to apply the quoted `[F]` in the proper way.
+
+## Primitive Recursive Functions
+Primitive recursive functions are those where `R2 == i`.
+
+    P == [I] [T] [R] primrec
+      == [I] [T] [R [P] i] ifte
+      == [I] [T] [R P] ifte
+
+## [Hylomorphism](https://en.wikipedia.org/wiki/Hylomorphism_%28computer_science%29)
+A [hylomorphism](https://en.wikipedia.org/wiki/Hylomorphism_%28computer_science%29) is a recursive function `H :: A -> C` that converts a value of type `A` into a value of type `C` by means of:
+
+- A generator `G :: A -> (B, A)`
+- A combiner `F :: (B, C) -> C`
+- A predicate `P :: A -> Bool` to detect the base case
+- A base case value `c :: C`
+- Recursive calls (zero or more); it has a "call stack in the form of a cons list".
+
+It may be helpful to see this function implemented in imperative Python code.
+
+
+```python
+def hylomorphism(c, F, P, G):
+    '''Return a hylomorphism function H.'''
+
+    def H(a):
+        if P(a):
+            result = c
+        else:
+            b, aa = G(a)
+            result = F(b, H(aa))  # b is stored in the stack frame during recursive call to H().
+        return result
+
+    return H
+```
+
+Cf. ["Bananas, Lenses, & Barbed Wire"](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125)
+
+Note that during evaluation of `H()` the intermediate `b` values are stored in the Python call stack.  This is what is meant by "call stack in the form of a cons list".
+
+## Hylomorphism in Joy
+We can define a combinator `hylomorphism` that will make a hylomorphism combinator `H` from constituent parts.
+
+    H == [P] c [G] [F] hylomorphism
+
+The function `H` is recursive, so we start with `ifte` and set the else-part to
+some function `J` that will contain a quoted copy of `H`.  (The then-part just
+discards the leftover `a` and replaces it with the base case value `c`.)
+
+    H == [P] [pop c] [J] ifte
+
+The else-part `J` gets just the argument `a` on the stack.
+
+    a J
+    a G              The first thing to do is use the generator G
+    aa b             which produces b and a new aa
+    aa b [H] dip     we recur with H on the new aa
+    aa H b F         and run F on the result.
+
+This gives us a definition for `J`.
+
+    J == G [H] dip F
+
+Plug it in and convert to genrec.
+
+    H == [P] [pop c] [G [H] dip F] ifte
+    H == [P] [pop c] [G]   [dip F] genrec
+
+This is the form of a hylomorphism in Joy, which nicely illustrates that
+it is a simple specialization of the general recursion combinator.
+
+    H == [P] c [G] [F] hylomorphism == [P] [pop c] [G] [dip F] genrec
+
+## Derivation of `hylomorphism` combinator
+
+Now we just need to derive a definition that builds the `genrec` arguments
+out of the pieces given to the `hylomorphism` combinator.
+
+       [P]      c  [G]     [F] hylomorphism
+    ------------------------------------------
+       [P] [pop c] [G] [dip F] genrec
+
+Working in reverse:
+
+- Use `swoncat` twice to decouple `[c]` and `[F]`.
+- Use `unit` to dequote `c`.
+- Use `dipd` to untangle `[unit [pop] swoncat]` from the givens.
+
+So:
+
+    H == [P] [pop c]              [G]                  [dip F] genrec
+         [P] [c]    [pop] swoncat [G]        [F] [dip] swoncat genrec
+         [P] c unit [pop] swoncat [G]        [F] [dip] swoncat genrec
+         [P] c [G] [F] [unit [pop] swoncat] dipd [dip] swoncat genrec
+
+At this point all of the arguments (givens) to the hylomorphism are to the left so we have
+a definition for `hylomorphism`:
+
+    hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec
+
+
+```python
+define('hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec')
+```
+
+### Example: Finding [Triangular Numbers](https://en.wikipedia.org/wiki/Triangular_number)
+Let's write a function that, given a positive integer, returns the sum of all positive integers less than that one.  (In this case the types `A`, `B` and `C` are all `int`.)
+
+To sum a range of integers from 0 to *n* - 1:
+
+- `[P]` is `[1 <=]`
+- `c` is `0`
+- `[G]` is `[-- dup]`
+- `[F]` is `[+]`
+
+
+```python
+define('triangular_number == [1 <=] 0 [-- dup] [+] hylomorphism')
+```
+
+Let's try it:
+
+
+```python
+J('5 triangular_number')
+```
+
+    10
+
+
+
+```python
+J('[0 1 2 3 4 5 6] [triangular_number] map')
+```
+
+    [0 0 1 3 6 10 15]
+
+
+## Four Specializations
+There are at least four kinds of recursive combinator, depending on two choices.  The first choice is whether the combiner function `F` should be evaluated during the recursion or pushed into the pending expression to be "collapsed" at the end.  The second choice is whether the combiner needs to operate on the current value of the datastructure or the generator's output, in other words, whether `F` or `G` should run first in the recursive branch.
+
+    H1 ==        [P] [pop c] [G             ] [dip F] genrec
+    H2 == c swap [P] [pop]   [G [F]    dip  ] [i]     genrec
+    H3 ==        [P] [pop c] [  [G] dupdip  ] [dip F] genrec
+    H4 == c swap [P] [pop]   [  [F] dupdip G] [i]     genrec
+
+The working of the generator function `G` differs slightly for each.  Consider the recursive branches:
+
+    ... a G [H1] dip F                w/ a G == a′ b
+    
+    ... c a G [F] dip H2                 a G == b  a′
+    
+    ... a [G] dupdip [H3] dip F          a G == a′
+    
+    ... c a [F] dupdip G H4              a G == a′
+
+The following four sections illustrate how these work, omitting the predicate evaluation.
+
+### `H1`
+
+    H1 == [P] [pop c] [G] [dip F] genrec
+
+Iterate n times.
+
+    ... a  G [H1] dip F
+    ... a′ b [H1] dip F
+    ... a′ H1 b F
+    ... a′ G [H1] dip F b F
+    ... a″ b′ [H1] dip F b F
+    ... a″ H1 b′ F b F
+    ... a″ G [H1] dip F b′ F b F
+    ... a‴ b″ [H1] dip F b′ F b F
+    ... a‴ H1 b″ F b′ F b F
+    ... a‴ pop c b″ F b′ F b F
+    ... c b″ F b′ F b F
+    ... d      b′ F b F
+    ... d′          b F
+    ... d″
+
+This form builds up a pending expression (continuation) that contains the intermediate results along with the pending combiner functions.  When the base case is reached the last term is replaced by the identity value `c` and the continuation "collapses" into the final result using the combiner `F`.
+
+### `H2`
+When you can start with the identity value `c` on the stack and the combiner `F` can operate as you go using the intermediate results immediately rather than queuing them up, use this form.  An important difference is that the generator function must return its results in the reverse order.
+
+    H2 == c swap [P] [pop] [G [F] dip] primrec
+
+    ... c a G  [F] dip H2
+    ... c b a′ [F] dip H2
+    ... c b F a′ H2
+    ... d     a′ H2
+    ... d a′ G  [F] dip H2
+    ... d b′ a″ [F] dip H2
+    ... d b′ F a″ H2
+    ... d′     a″ H2
+    ... d′ a″ G  [F] dip H2
+    ... d′ b″ a‴ [F] dip H2
+    ... d′ b″ F a‴ H2
+    ... d″      a‴ H2
+    ... d″ a‴ pop
+    ... d″
+
+
+### `H3`
+If you examine the traces above you'll see that the combiner `F` only gets to operate on the results of `G`, it never "sees" the first value `a`.  If the combiner and the generator both need to work on the current value then `dup` must be used, and the generator must produce one item instead of two (the b is instead the duplicate of a.)
+
+
+    H3 == [P] [pop c] [[G] dupdip] [dip F] genrec
+
+    ... a [G] dupdip [H3] dip F
+    ... a  G  a      [H3] dip F
+    ... a′    a      [H3] dip F
+    ... a′ H3 a               F
+    ... a′ [G] dupdip [H3] dip F a F
+    ... a′  G  a′     [H3] dip F a F
+    ... a″     a′     [H3] dip F a F
+    ... a″ H3  a′              F a F
+    ... a″ [G] dupdip [H3] dip F a′ F a F
+    ... a″  G    a″   [H3] dip F a′ F a F
+    ... a‴       a″   [H3] dip F a′ F a F
+    ... a‴ H3    a″            F a′ F a F
+    ... a‴ pop c a″ F a′ F a F
+    ...        c a″ F a′ F a F
+    ...        d      a′ F a F
+    ...        d′          a F
+    ...        d″
+
+### `H4`
+And, last but not least, if you can combine as you go, starting with `c`, and the combiner `F` needs to work on the current item, this is the form:
+
+    H4 == c swap [P] [pop] [[F] dupdip G] primrec
+
+    ... c  a  [F] dupdip G H4
+    ... c  a   F  a      G H4
+    ... d         a      G H4
+    ... d  a′              H4
+    ... d  a′ [F] dupdip G H4
+    ... d  a′  F  a′     G H4
+    ... d′        a′     G H4
+    ... d′ a″              H4
+    ... d′ a″ [F] dupdip G H4
+    ... d′ a″  F  a″     G H4
+    ... d″        a″     G H4
+    ... d″ a‴              H4
+    ... d″ a‴ pop
+    ... d″
+
+## Anamorphism
+An anamorphism can be defined as a hylomorphism that uses `[]` for `c` and
+`swons` for `F`.  An anamorphic function builds a list of values.
+
+    A == [P] [] [G] [swons] hylomorphism
+
+### `range` et. al.
+An example of an anamorphism is the `range` function which generates the list of integers from 0 to *n* - 1 given *n*.
+
+Each of the above variations can be used to make four slightly different `range` functions.
+
+#### `range` with `H1`
+    H1 == [P]    [pop c]  [G]      [dip F]     genrec
+       == [0 <=] [pop []] [-- dup] [dip swons] genrec
+
+
+```python
+define('range == [0 <=] [] [-- dup] [swons] hylomorphism')
+```
+
+
+```python
+J('5 range')
+```
+
+    [4 3 2 1 0]
+
+
+#### `range` with `H2`
+    H2 == c  swap [P]    [pop] [G      [F]     dip] primrec
+       == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec
+
+
+```python
+define('range_reverse == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec')
+```
+
+
+```python
+J('5 range_reverse')
+```
+
+    [0 1 2 3 4]
+
+
+#### `range` with `H3`
+    H3 == [P]    [pop c]  [[G]  dupdip] [dip F]     genrec
+       == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec
+
+
+```python
+define('ranger == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec')
+```
+
+
+```python
+J('5 ranger')
+```
+
+    [5 4 3 2 1]
+
+
+#### `range` with `H4`
+    H4 == c  swap [P]    [pop] [[F]     dupdip G ] primrec
+       == [] swap [0 <=] [pop] [[swons] dupdip --] primrec
+
+
+```python
+define('ranger_reverse == [] swap [0 <=] [pop] [[swons] dupdip --] primrec')
+```
+
+
+```python
+J('5 ranger_reverse')
+```
+
+    [1 2 3 4 5]
+
+
+Hopefully this illustrates the workings of the variations.  For more insight you can run the cells using the `V()` function instead of the `J()` function to get a trace of the Joy evaluation.
+
+## Catamorphism
+A catamorphism can be defined as a hylomorphism that uses `[uncons swap]` for `[G]`
+and `[[] =]` (or just `[not]`) for the predicate `[P]`.  A catamorphic function tears down a list term-by-term and makes some new value.
+
+    C == [not] c [uncons swap] [F] hylomorphism
+
+
+```python
+define('swuncons == uncons swap')  # Awkward name.
+```
+
+An example of a catamorphism is the sum function.
+
+    sum == [not] 0 [swuncons] [+] hylomorphism
+
+
+```python
+define('sum == [not] 0 [swuncons] [+] hylomorphism')
+```
+
+
+```python
+J('[5 4 3 2 1] sum')
+```
+
+    15
+
+
+### The `step` combinator
+The `step` combinator will usually be better to use than `catamorphism`.
+
+
+```python
+J('[step] help')
+```
+
+    Run a quoted program on each item in a sequence.
+    ::
+    
+            ... [] [Q] . step
+         -----------------------
+                   ... .
+    
+    
+           ... [a] [Q] . step
+        ------------------------
+                 ... a . Q
+    
+    
+         ... [a b c] [Q] . step
+      ----------------------------------------
+                   ... a . Q [b c] [Q] step
+    
+    The step combinator executes the quotation on each member of the list
+    on top of the stack.
+    
+
+
+
+```python
+define('sum == 0 swap [+] step')
+```
+
+
+```python
+J('[5 4 3 2 1] sum')
+```
+
+    15
+
+
+## Example: Factorial Function
+
+For the Factorial function:
+
+    H4 == c swap [P] [pop] [[F] dupdip G] primrec
+
+With:
+
+    c == 1
+    F == *
+    G == --
+    P == 1 <=
+
+
+```python
+define('factorial == 1 swap [1 <=] [pop] [[*] dupdip --] primrec')
+```
+
+
+```python
+J('5 factorial')
+```
+
+    120
+
+
+## Example: `tails`
+An example of a paramorphism for lists given in the ["Bananas..." paper](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125) is `tails` which returns the list of "tails" of a list.
+
+        [1 2 3] tails
+    --------------------
+       [[] [3] [2 3]]
+    
+
+We can build as we go, and we want `F` to run after `G`, so we use pattern `H2`:
+
+    H2 == c swap [P] [pop] [G [F] dip] primrec
+
+We would use:
+
+    c == []
+    F == swons
+    G == rest dup
+    P == not
+
+
+```python
+define('tails == [] swap [not] [pop] [rest dup [swons] dip] primrec')
+```
+
+
+```python
+J('[1 2 3] tails')
+```
+
+    [[] [3] [2 3]]
+
+
+## Conclusion: Patterns of Recursion
+Our story so far...
+
+
+### Hylo-, Ana-, Cata-
+
+    H == [P  ] [pop c ] [G          ] [dip F        ] genrec
+    A == [P  ] [pop []] [G          ] [dip swap cons] genrec
+    C == [not] [pop c ] [uncons swap] [dip F        ] genrec
+
+### Para-, ?-, ?-
+
+    P == c  swap [P  ] [pop] [[F        ] dupdip G          ] primrec
+    ? == [] swap [P  ] [pop] [[swap cons] dupdip G          ] primrec
+    ? == c  swap [not] [pop] [[F        ] dupdip uncons swap] primrec
+
+
+## Appendix: Fun with Symbols
+
+    |[ (c, F), (G, P) ]| == (|c, F|) • [(G, P)]
+
+["Bananas, Lenses, & Barbed Wire"](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125)
+
+    (|...|)  [(...)]  [<...>]
+
+I think they are having slightly too much fun with the symbols.  However, "Too much is always better than not enough."
diff --git a/docs/Recursion_Combinators.rst b/docs/Recursion_Combinators.rst
new file mode 100644 (file)
index 0000000..b4dc1a7
--- /dev/null
@@ -0,0 +1,695 @@
+
+.. code:: ipython2
+
+    from notebook_preamble import D, DefinitionWrapper, J, V, define
+
+Recursive Combinators
+=====================
+
+This article describes the ``genrec`` combinator, how to use it, and
+several generic specializations.
+
+::
+
+                          [if] [then] [rec1] [rec2] genrec
+    ---------------------------------------------------------------------
+       [if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte
+
+From "Recursion Theory and Joy" (j05cmp.html) by Manfred von Thun:
+
+    "The genrec combinator takes four program parameters in addition to
+    whatever data parameters it needs. Fourth from the top is an
+    if-part, followed by a then-part. If the if-part yields true, then
+    the then-part is executed and the combinator terminates. The other
+    two parameters are the rec1-part and the rec2-part. If the if-part
+    yields false, the rec1-part is executed. Following that the four
+    program parameters and the combinator are again pushed onto the
+    stack bundled up in a quoted form. Then the rec2-part is executed,
+    where it will find the bundled form. Typically it will then execute
+    the bundled form, either with i or with app2, or some other
+    combinator."
+
+Designing Recursive Functions
+-----------------------------
+
+The way to design one of these is to fix your base case and test and
+then treat ``R1`` and ``R2`` as an else-part "sandwiching" a quotation
+of the whole function.
+
+For example, given a (general recursive) function ``F``:
+
+::
+
+    F == [I] [T] [R1]   [R2] genrec
+      == [I] [T] [R1 [F] R2] ifte
+
+If the ``[I]`` predicate is false you must derive ``R1`` and ``R2``
+from:
+
+::
+
+    ... R1 [F] R2
+
+Set the stack arguments in front and figure out what ``R1`` and ``R2``
+have to do to apply the quoted ``[F]`` in the proper way.
+
+Primitive Recursive Functions
+-----------------------------
+
+Primitive recursive functions are those where ``R2 == i``.
+
+::
+
+    P == [I] [T] [R] primrec
+      == [I] [T] [R [P] i] ifte
+      == [I] [T] [R P] ifte
+
+`Hylomorphism <https://en.wikipedia.org/wiki/Hylomorphism_%28computer_science%29>`__
+------------------------------------------------------------------------------------
+
+A
+`hylomorphism <https://en.wikipedia.org/wiki/Hylomorphism_%28computer_science%29>`__
+is a recursive function ``H :: A -> C`` that converts a value of type
+``A`` into a value of type ``C`` by means of:
+
+-  A generator ``G :: A -> (B, A)``
+-  A combiner ``F :: (B, C) -> C``
+-  A predicate ``P :: A -> Bool`` to detect the base case
+-  A base case value ``c :: C``
+-  Recursive calls (zero or more); it has a "call stack in the form of a
+   cons list".
+
+It may be helpful to see this function implemented in imperative Python
+code.
+
+.. code:: ipython2
+
+    def hylomorphism(c, F, P, G):
+        '''Return a hylomorphism function H.'''
+    
+        def H(a):
+            if P(a):
+                result = c
+            else:
+                b, aa = G(a)
+                result = F(b, H(aa))  # b is stored in the stack frame during recursive call to H().
+            return result
+    
+        return H
+
+Cf. `"Bananas, Lenses, & Barbed
+Wire" <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125>`__
+
+Note that during evaluation of ``H()`` the intermediate ``b`` values are
+stored in the Python call stack. This is what is meant by "call stack in
+the form of a cons list".
+
+Hylomorphism in Joy
+-------------------
+
+We can define a combinator ``hylomorphism`` that will make a
+hylomorphism combinator ``H`` from constituent parts.
+
+::
+
+    H == [P] c [G] [F] hylomorphism
+
+The function ``H`` is recursive, so we start with ``ifte`` and set the
+else-part to some function ``J`` that will contain a quoted copy of
+``H``. (The then-part just discards the leftover ``a`` and replaces it
+with the base case value ``c``.)
+
+::
+
+    H == [P] [pop c] [J] ifte
+
+The else-part ``J`` gets just the argument ``a`` on the stack.
+
+::
+
+    a J
+    a G              The first thing to do is use the generator G
+    aa b             which produces b and a new aa
+    aa b [H] dip     we recur with H on the new aa
+    aa H b F         and run F on the result.
+
+This gives us a definition for ``J``.
+
+::
+
+    J == G [H] dip F
+
+Plug it in and convert to genrec.
+
+::
+
+    H == [P] [pop c] [G [H] dip F] ifte
+    H == [P] [pop c] [G]   [dip F] genrec
+
+This is the form of a hylomorphism in Joy, which nicely illustrates that
+it is a simple specialization of the general recursion combinator.
+
+::
+
+    H == [P] c [G] [F] hylomorphism == [P] [pop c] [G] [dip F] genrec
+
+Derivation of ``hylomorphism`` combinator
+-----------------------------------------
+
+Now we just need to derive a definition that builds the ``genrec``
+arguments out of the pieces given to the ``hylomorphism`` combinator.
+
+::
+
+       [P]      c  [G]     [F] hylomorphism
+    ------------------------------------------
+       [P] [pop c] [G] [dip F] genrec
+
+Working in reverse:
+
+-  Use ``swoncat`` twice to decouple ``[c]`` and ``[F]``.
+-  Use ``unit`` to dequote ``c``.
+-  Use ``dipd`` to untangle ``[unit [pop] swoncat]`` from the givens.
+
+So:
+
+::
+
+    H == [P] [pop c]              [G]                  [dip F] genrec
+         [P] [c]    [pop] swoncat [G]        [F] [dip] swoncat genrec
+         [P] c unit [pop] swoncat [G]        [F] [dip] swoncat genrec
+         [P] c [G] [F] [unit [pop] swoncat] dipd [dip] swoncat genrec
+
+At this point all of the arguments (givens) to the hylomorphism are to
+the left so we have a definition for ``hylomorphism``:
+
+::
+
+    hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec
+
+.. code:: ipython2
+
+    define('hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec')
+
+Example: Finding `Triangular Numbers <https://en.wikipedia.org/wiki/Triangular_number>`__
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Let's write a function that, given a positive integer, returns the sum
+of all positive integers less than that one. (In this case the types
+``A``, ``B`` and ``C`` are all ``int``.)
+
+To sum a range of integers from 0 to *n* - 1:
+
+-  ``[P]`` is ``[1 <=]``
+-  ``c`` is ``0``
+-  ``[G]`` is ``[-- dup]``
+-  ``[F]`` is ``[+]``
+
+.. code:: ipython2
+
+    define('triangular_number == [1 <=] 0 [-- dup] [+] hylomorphism')
+
+Let's try it:
+
+.. code:: ipython2
+
+    J('5 triangular_number')
+
+
+.. parsed-literal::
+
+    10
+
+
+.. code:: ipython2
+
+    J('[0 1 2 3 4 5 6] [triangular_number] map')
+
+
+.. parsed-literal::
+
+    [0 0 1 3 6 10 15]
+
+
+Four Specializations
+--------------------
+
+There are at least four kinds of recursive combinator, depending on two
+choices. The first choice is whether the combiner function ``F`` should
+be evaluated during the recursion or pushed into the pending expression
+to be "collapsed" at the end. The second choice is whether the combiner
+needs to operate on the current value of the datastructure or the
+generator's output, in other words, whether ``F`` or ``G`` should run
+first in the recursive branch.
+
+::
+
+    H1 ==        [P] [pop c] [G             ] [dip F] genrec
+    H2 == c swap [P] [pop]   [G [F]    dip  ] [i]     genrec
+    H3 ==        [P] [pop c] [  [G] dupdip  ] [dip F] genrec
+    H4 == c swap [P] [pop]   [  [F] dupdip G] [i]     genrec
+
+The working of the generator function ``G`` differs slightly for each.
+Consider the recursive branches:
+
+::
+
+    ... a G [H1] dip F                w/ a G == a′ b
+
+    ... c a G [F] dip H2                 a G == b  a′
+
+    ... a [G] dupdip [H3] dip F          a G == a′
+
+    ... c a [F] dupdip G H4              a G == a′
+
+The following four sections illustrate how these work, omitting the
+predicate evaluation.
+
+``H1``
+~~~~~~
+
+::
+
+    H1 == [P] [pop c] [G] [dip F] genrec
+
+Iterate n times.
+
+::
+
+    ... a  G [H1] dip F
+    ... a′ b [H1] dip F
+    ... a′ H1 b F
+    ... a′ G [H1] dip F b F
+    ... a″ b′ [H1] dip F b F
+    ... a″ H1 b′ F b F
+    ... a″ G [H1] dip F b′ F b F
+    ... a‴ b″ [H1] dip F b′ F b F
+    ... a‴ H1 b″ F b′ F b F
+    ... a‴ pop c b″ F b′ F b F
+    ... c b″ F b′ F b F
+    ... d      b′ F b F
+    ... d′          b F
+    ... d″
+
+This form builds up a pending expression (continuation) that contains
+the intermediate results along with the pending combiner functions. When
+the base case is reached the last term is replaced by the identity value
+``c`` and the continuation "collapses" into the final result using the
+combiner ``F``.
+
+``H2``
+~~~~~~
+
+When you can start with the identity value ``c`` on the stack and the
+combiner ``F`` can operate as you go using the intermediate results
+immediately rather than queuing them up, use this form. An important
+difference is that the generator function must return its results in the
+reverse order.
+
+::
+
+    H2 == c swap [P] [pop] [G [F] dip] primrec
+
+    ... c a G  [F] dip H2
+    ... c b a′ [F] dip H2
+    ... c b F a′ H2
+    ... d     a′ H2
+    ... d a′ G  [F] dip H2
+    ... d b′ a″ [F] dip H2
+    ... d b′ F a″ H2
+    ... d′     a″ H2
+    ... d′ a″ G  [F] dip H2
+    ... d′ b″ a‴ [F] dip H2
+    ... d′ b″ F a‴ H2
+    ... d″      a‴ H2
+    ... d″ a‴ pop
+    ... d″
+
+``H3``
+~~~~~~
+
+If you examine the traces above you'll see that the combiner ``F`` only
+gets to operate on the results of ``G``, it never "sees" the first value
+``a``. If the combiner and the generator both need to work on the
+current value then ``dup`` must be used, and the generator must produce
+one item instead of two (the b is instead the duplicate of a.)
+
+::
+
+    H3 == [P] [pop c] [[G] dupdip] [dip F] genrec
+
+    ... a [G] dupdip [H3] dip F
+    ... a  G  a      [H3] dip F
+    ... a′    a      [H3] dip F
+    ... a′ H3 a               F
+    ... a′ [G] dupdip [H3] dip F a F
+    ... a′  G  a′     [H3] dip F a F
+    ... a″     a′     [H3] dip F a F
+    ... a″ H3  a′              F a F
+    ... a″ [G] dupdip [H3] dip F a′ F a F
+    ... a″  G    a″   [H3] dip F a′ F a F
+    ... a‴       a″   [H3] dip F a′ F a F
+    ... a‴ H3    a″            F a′ F a F
+    ... a‴ pop c a″ F a′ F a F
+    ...        c a″ F a′ F a F
+    ...        d      a′ F a F
+    ...        d′          a F
+    ...        d″
+
+``H4``
+~~~~~~
+
+And, last but not least, if you can combine as you go, starting with
+``c``, and the combiner ``F`` needs to work on the current item, this is
+the form:
+
+::
+
+    H4 == c swap [P] [pop] [[F] dupdip G] primrec
+
+    ... c  a  [F] dupdip G H4
+    ... c  a   F  a      G H4
+    ... d         a      G H4
+    ... d  a′              H4
+    ... d  a′ [F] dupdip G H4
+    ... d  a′  F  a′     G H4
+    ... d′        a′     G H4
+    ... d′ a″              H4
+    ... d′ a″ [F] dupdip G H4
+    ... d′ a″  F  a″     G H4
+    ... d″        a″     G H4
+    ... d″ a‴              H4
+    ... d″ a‴ pop
+    ... d″
+
+Anamorphism
+-----------
+
+An anamorphism can be defined as a hylomorphism that uses ``[]`` for
+``c`` and ``swons`` for ``F``. An anamorphic function builds a list of
+values.
+
+::
+
+    A == [P] [] [G] [swons] hylomorphism
+
+``range`` et. al.
+~~~~~~~~~~~~~~~~~
+
+An example of an anamorphism is the ``range`` function which generates
+the list of integers from 0 to *n* - 1 given *n*.
+
+Each of the above variations can be used to make four slightly different
+``range`` functions.
+
+``range`` with ``H1``
+^^^^^^^^^^^^^^^^^^^^^
+
+::
+
+    H1 == [P]    [pop c]  [G]      [dip F]     genrec
+       == [0 <=] [pop []] [-- dup] [dip swons] genrec
+
+.. code:: ipython2
+
+    define('range == [0 <=] [] [-- dup] [swons] hylomorphism')
+
+.. code:: ipython2
+
+    J('5 range')
+
+
+.. parsed-literal::
+
+    [4 3 2 1 0]
+
+
+``range`` with ``H2``
+^^^^^^^^^^^^^^^^^^^^^
+
+::
+
+    H2 == c  swap [P]    [pop] [G      [F]     dip] primrec
+       == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec
+
+.. code:: ipython2
+
+    define('range_reverse == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec')
+
+.. code:: ipython2
+
+    J('5 range_reverse')
+
+
+.. parsed-literal::
+
+    [0 1 2 3 4]
+
+
+``range`` with ``H3``
+^^^^^^^^^^^^^^^^^^^^^
+
+::
+
+    H3 == [P]    [pop c]  [[G]  dupdip] [dip F]     genrec
+       == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec
+
+.. code:: ipython2
+
+    define('ranger == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec')
+
+.. code:: ipython2
+
+    J('5 ranger')
+
+
+.. parsed-literal::
+
+    [5 4 3 2 1]
+
+
+``range`` with ``H4``
+^^^^^^^^^^^^^^^^^^^^^
+
+::
+
+    H4 == c  swap [P]    [pop] [[F]     dupdip G ] primrec
+       == [] swap [0 <=] [pop] [[swons] dupdip --] primrec
+
+.. code:: ipython2
+
+    define('ranger_reverse == [] swap [0 <=] [pop] [[swons] dupdip --] primrec')
+
+.. code:: ipython2
+
+    J('5 ranger_reverse')
+
+
+.. parsed-literal::
+
+    [1 2 3 4 5]
+
+
+Hopefully this illustrates the workings of the variations. For more
+insight you can run the cells using the ``V()`` function instead of the
+``J()`` function to get a trace of the Joy evaluation.
+
+Catamorphism
+------------
+
+A catamorphism can be defined as a hylomorphism that uses
+``[uncons swap]`` for ``[G]`` and ``[[] =]`` (or just ``[not]``) for the
+predicate ``[P]``. A catamorphic function tears down a list term-by-term
+and makes some new value.
+
+::
+
+    C == [not] c [uncons swap] [F] hylomorphism
+
+.. code:: ipython2
+
+    define('swuncons == uncons swap')  # Awkward name.
+
+An example of a catamorphism is the sum function.
+
+::
+
+    sum == [not] 0 [swuncons] [+] hylomorphism
+
+.. code:: ipython2
+
+    define('sum == [not] 0 [swuncons] [+] hylomorphism')
+
+.. code:: ipython2
+
+    J('[5 4 3 2 1] sum')
+
+
+.. parsed-literal::
+
+    15
+
+
+The ``step`` combinator
+~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``step`` combinator will usually be better to use than
+``catamorphism``.
+
+.. code:: ipython2
+
+    J('[step] help')
+
+
+.. parsed-literal::
+
+    Run a quoted program on each item in a sequence.
+    ::
+    
+            ... [] [Q] . step
+         -----------------------
+                   ... .
+    
+    
+           ... [a] [Q] . step
+        ------------------------
+                 ... a . Q
+    
+    
+         ... [a b c] [Q] . step
+      ----------------------------------------
+                   ... a . Q [b c] [Q] step
+    
+    The step combinator executes the quotation on each member of the list
+    on top of the stack.
+    
+
+
+.. code:: ipython2
+
+    define('sum == 0 swap [+] step')
+
+.. code:: ipython2
+
+    J('[5 4 3 2 1] sum')
+
+
+.. parsed-literal::
+
+    15
+
+
+Example: Factorial Function
+---------------------------
+
+For the Factorial function:
+
+::
+
+    H4 == c swap [P] [pop] [[F] dupdip G] primrec
+
+With:
+
+::
+
+    c == 1
+    F == *
+    G == --
+    P == 1 <=
+
+.. code:: ipython2
+
+    define('factorial == 1 swap [1 <=] [pop] [[*] dupdip --] primrec')
+
+.. code:: ipython2
+
+    J('5 factorial')
+
+
+.. parsed-literal::
+
+    120
+
+
+Example: ``tails``
+------------------
+
+An example of a paramorphism for lists given in the `"Bananas..."
+paper <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125>`__
+is ``tails`` which returns the list of "tails" of a list.
+
+::
+
+        [1 2 3] tails
+    --------------------
+       [[] [3] [2 3]]
+
+We can build as we go, and we want ``F`` to run after ``G``, so we use
+pattern ``H2``:
+
+::
+
+    H2 == c swap [P] [pop] [G [F] dip] primrec
+
+We would use:
+
+::
+
+    c == []
+    F == swons
+    G == rest dup
+    P == not
+
+.. code:: ipython2
+
+    define('tails == [] swap [not] [pop] [rest dup [swons] dip] primrec')
+
+.. code:: ipython2
+
+    J('[1 2 3] tails')
+
+
+.. parsed-literal::
+
+    [[] [3] [2 3]]
+
+
+Conclusion: Patterns of Recursion
+---------------------------------
+
+Our story so far...
+
+Hylo-, Ana-, Cata-
+~~~~~~~~~~~~~~~~~~
+
+::
+
+    H == [P  ] [pop c ] [G          ] [dip F        ] genrec
+    A == [P  ] [pop []] [G          ] [dip swap cons] genrec
+    C == [not] [pop c ] [uncons swap] [dip F        ] genrec
+
+Para-, ?-, ?-
+~~~~~~~~~~~~~
+
+::
+
+    P == c  swap [P  ] [pop] [[F        ] dupdip G          ] primrec
+    ? == [] swap [P  ] [pop] [[swap cons] dupdip G          ] primrec
+    ? == c  swap [not] [pop] [[F        ] dupdip uncons swap] primrec
+
+Appendix: Fun with Symbols
+--------------------------
+
+::
+
+    |[ (c, F), (G, P) ]| == (|c, F|) • [(G, P)]
+
+`"Bananas, Lenses, & Barbed
+Wire" <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125>`__
+
+::
+
+    (|...|)  [(...)]  [<...>]
+
+I think they are having slightly too much fun with the symbols. However,
+"Too much is always better than not enough."
diff --git a/docs/Types.html b/docs/Types.html
new file mode 100644 (file)
index 0000000..1231e62
--- /dev/null
@@ -0,0 +1,15533 @@
+<!DOCTYPE html>
+<html>
+<head><meta charset="utf-8" />
+<title>Types</title><script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.10/require.min.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
+
+<style type="text/css">
+    /*!
+*
+* Twitter Bootstrap
+*
+*/
+/*!
+ * Bootstrap v3.3.7 (http://getbootstrap.com)
+ * Copyright 2011-2016 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
+html {
+  font-family: sans-serif;
+  -ms-text-size-adjust: 100%;
+  -webkit-text-size-adjust: 100%;
+}
+body {
+  margin: 0;
+}
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+menu,
+nav,
+section,
+summary {
+  display: block;
+}
+audio,
+canvas,
+progress,
+video {
+  display: inline-block;
+  vertical-align: baseline;
+}
+audio:not([controls]) {
+  display: none;
+  height: 0;
+}
+[hidden],
+template {
+  display: none;
+}
+a {
+  background-color: transparent;
+}
+a:active,
+a:hover {
+  outline: 0;
+}
+abbr[title] {
+  border-bottom: 1px dotted;
+}
+b,
+strong {
+  font-weight: bold;
+}
+dfn {
+  font-style: italic;
+}
+h1 {
+  font-size: 2em;
+  margin: 0.67em 0;
+}
+mark {
+  background: #ff0;
+  color: #000;
+}
+small {
+  font-size: 80%;
+}
+sub,
+sup {
+  font-size: 75%;
+  line-height: 0;
+  position: relative;
+  vertical-align: baseline;
+}
+sup {
+  top: -0.5em;
+}
+sub {
+  bottom: -0.25em;
+}
+img {
+  border: 0;
+}
+svg:not(:root) {
+  overflow: hidden;
+}
+figure {
+  margin: 1em 40px;
+}
+hr {
+  box-sizing: content-box;
+  height: 0;
+}
+pre {
+  overflow: auto;
+}
+code,
+kbd,
+pre,
+samp {
+  font-family: monospace, monospace;
+  font-size: 1em;
+}
+button,
+input,
+optgroup,
+select,
+textarea {
+  color: inherit;
+  font: inherit;
+  margin: 0;
+}
+button {
+  overflow: visible;
+}
+button,
+select {
+  text-transform: none;
+}
+button,
+html input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+  -webkit-appearance: button;
+  cursor: pointer;
+}
+button[disabled],
+html input[disabled] {
+  cursor: default;
+}
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+  border: 0;
+  padding: 0;
+}
+input {
+  line-height: normal;
+}
+input[type="checkbox"],
+input[type="radio"] {
+  box-sizing: border-box;
+  padding: 0;
+}
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+  height: auto;
+}
+input[type="search"] {
+  -webkit-appearance: textfield;
+  box-sizing: content-box;
+}
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+  -webkit-appearance: none;
+}
+fieldset {
+  border: 1px solid #c0c0c0;
+  margin: 0 2px;
+  padding: 0.35em 0.625em 0.75em;
+}
+legend {
+  border: 0;
+  padding: 0;
+}
+textarea {
+  overflow: auto;
+}
+optgroup {
+  font-weight: bold;
+}
+table {
+  border-collapse: collapse;
+  border-spacing: 0;
+}
+td,
+th {
+  padding: 0;
+}
+/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */
+@media print {
+  *,
+  *:before,
+  *:after {
+    background: transparent !important;
+    color: #000 !important;
+    box-shadow: none !important;
+    text-shadow: none !important;
+  }
+  a,
+  a:visited {
+    text-decoration: underline;
+  }
+  a[href]:after {
+    content: " (" attr(href) ")";
+  }
+  abbr[title]:after {
+    content: " (" attr(title) ")";
+  }
+  a[href^="#"]:after,
+  a[href^="javascript:"]:after {
+    content: "";
+  }
+  pre,
+  blockquote {
+    border: 1px solid #999;
+    page-break-inside: avoid;
+  }
+  thead {
+    display: table-header-group;
+  }
+  tr,
+  img {
+    page-break-inside: avoid;
+  }
+  img {
+    max-width: 100% !important;
+  }
+  p,
+  h2,
+  h3 {
+    orphans: 3;
+    widows: 3;
+  }
+  h2,
+  h3 {
+    page-break-after: avoid;
+  }
+  .navbar {
+    display: none;
+  }
+  .btn > .caret,
+  .dropup > .btn > .caret {
+    border-top-color: #000 !important;
+  }
+  .label {
+    border: 1px solid #000;
+  }
+  .table {
+    border-collapse: collapse !important;
+  }
+  .table td,
+  .table th {
+    background-color: #fff !important;
+  }
+  .table-bordered th,
+  .table-bordered td {
+    border: 1px solid #ddd !important;
+  }
+}
+@font-face {
+  font-family: 'Glyphicons Halflings';
+  src: url('../components/bootstrap/fonts/glyphicons-halflings-regular.eot');
+  src: url('../components/bootstrap/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../components/bootstrap/fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../components/bootstrap/fonts/glyphicons-halflings-regular.woff') format('woff'), url('../components/bootstrap/fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../components/bootstrap/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
+}
+.glyphicon {
+  position: relative;
+  top: 1px;
+  display: inline-block;
+  font-family: 'Glyphicons Halflings';
+  font-style: normal;
+  font-weight: normal;
+  line-height: 1;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+.glyphicon-asterisk:before {
+  content: "\002a";
+}
+.glyphicon-plus:before {
+  content: "\002b";
+}
+.glyphicon-euro:before,
+.glyphicon-eur:before {
+  content: "\20ac";
+}
+.glyphicon-minus:before {
+  content: "\2212";
+}
+.glyphicon-cloud:before {
+  content: "\2601";
+}
+.glyphicon-envelope:before {
+  content: "\2709";
+}
+.glyphicon-pencil:before {
+  content: "\270f";
+}
+.glyphicon-glass:before {
+  content: "\e001";
+}
+.glyphicon-music:before {
+  content: "\e002";
+}
+.glyphicon-search:before {
+  content: "\e003";
+}
+.glyphicon-heart:before {
+  content: "\e005";
+}
+.glyphicon-star:before {
+  content: "\e006";
+}
+.glyphicon-star-empty:before {
+  content: "\e007";
+}
+.glyphicon-user:before {
+  content: "\e008";
+}
+.glyphicon-film:before {
+  content: "\e009";
+}
+.glyphicon-th-large:before {
+  content: "\e010";
+}
+.glyphicon-th:before {
+  content: "\e011";
+}
+.glyphicon-th-list:before {
+  content: "\e012";
+}
+.glyphicon-ok:before {
+  content: "\e013";
+}
+.glyphicon-remove:before {
+  content: "\e014";
+}
+.glyphicon-zoom-in:before {
+  content: "\e015";
+}
+.glyphicon-zoom-out:before {
+  content: "\e016";
+}
+.glyphicon-off:before {
+  content: "\e017";
+}
+.glyphicon-signal:before {
+  content: "\e018";
+}
+.glyphicon-cog:before {
+  content: "\e019";
+}
+.glyphicon-trash:before {
+  content: "\e020";
+}
+.glyphicon-home:before {
+  content: "\e021";
+}
+.glyphicon-file:before {
+  content: "\e022";
+}
+.glyphicon-time:before {
+  content: "\e023";
+}
+.glyphicon-road:before {
+  content: "\e024";
+}
+.glyphicon-download-alt:before {
+  content: "\e025";
+}
+.glyphicon-download:before {
+  content: "\e026";
+}
+.glyphicon-upload:before {
+  content: "\e027";
+}
+.glyphicon-inbox:before {
+  content: "\e028";
+}
+.glyphicon-play-circle:before {
+  content: "\e029";
+}
+.glyphicon-repeat:before {
+  content: "\e030";
+}
+.glyphicon-refresh:before {
+  content: "\e031";
+}
+.glyphicon-list-alt:before {
+  content: "\e032";
+}
+.glyphicon-lock:before {
+  content: "\e033";
+}
+.glyphicon-flag:before {
+  content: "\e034";
+}
+.glyphicon-headphones:before {
+  content: "\e035";
+}
+.glyphicon-volume-off:before {
+  content: "\e036";
+}
+.glyphicon-volume-down:before {
+  content: "\e037";
+}
+.glyphicon-volume-up:before {
+  content: "\e038";
+}
+.glyphicon-qrcode:before {
+  content: "\e039";
+}
+.glyphicon-barcode:before {
+  content: "\e040";
+}
+.glyphicon-tag:before {
+  content: "\e041";
+}
+.glyphicon-tags:before {
+  content: "\e042";
+}
+.glyphicon-book:before {
+  content: "\e043";
+}
+.glyphicon-bookmark:before {
+  content: "\e044";
+}
+.glyphicon-print:before {
+  content: "\e045";
+}
+.glyphicon-camera:before {
+  content: "\e046";
+}
+.glyphicon-font:before {
+  content: "\e047";
+}
+.glyphicon-bold:before {
+  content: "\e048";
+}
+.glyphicon-italic:before {
+  content: "\e049";
+}
+.glyphicon-text-height:before {
+  content: "\e050";
+}
+.glyphicon-text-width:before {
+  content: "\e051";
+}
+.glyphicon-align-left:before {
+  content: "\e052";
+}
+.glyphicon-align-center:before {
+  content: "\e053";
+}
+.glyphicon-align-right:before {
+  content: "\e054";
+}
+.glyphicon-align-justify:before {
+  content: "\e055";
+}
+.glyphicon-list:before {
+  content: "\e056";
+}
+.glyphicon-indent-left:before {
+  content: "\e057";
+}
+.glyphicon-indent-right:before {
+  content: "\e058";
+}
+.glyphicon-facetime-video:before {
+  content: "\e059";
+}
+.glyphicon-picture:before {
+  content: "\e060";
+}
+.glyphicon-map-marker:before {
+  content: "\e062";
+}
+.glyphicon-adjust:before {
+  content: "\e063";
+}
+.glyphicon-tint:before {
+  content: "\e064";
+}
+.glyphicon-edit:before {
+  content: "\e065";
+}
+.glyphicon-share:before {
+  content: "\e066";
+}
+.glyphicon-check:before {
+  content: "\e067";
+}
+.glyphicon-move:before {
+  content: "\e068";
+}
+.glyphicon-step-backward:before {
+  content: "\e069";
+}
+.glyphicon-fast-backward:before {
+  content: "\e070";
+}
+.glyphicon-backward:before {
+  content: "\e071";
+}
+.glyphicon-play:before {
+  content: "\e072";
+}
+.glyphicon-pause:before {
+  content: "\e073";
+}
+.glyphicon-stop:before {
+  content: "\e074";
+}
+.glyphicon-forward:before {
+  content: "\e075";
+}
+.glyphicon-fast-forward:before {
+  content: "\e076";
+}
+.glyphicon-step-forward:before {
+  content: "\e077";
+}
+.glyphicon-eject:before {
+  content: "\e078";
+}
+.glyphicon-chevron-left:before {
+  content: "\e079";
+}
+.glyphicon-chevron-right:before {
+  content: "\e080";
+}
+.glyphicon-plus-sign:before {
+  content: "\e081";
+}
+.glyphicon-minus-sign:before {
+  content: "\e082";
+}
+.glyphicon-remove-sign:before {
+  content: "\e083";
+}
+.glyphicon-ok-sign:before {
+  content: "\e084";
+}
+.glyphicon-question-sign:before {
+  content: "\e085";
+}
+.glyphicon-info-sign:before {
+  content: "\e086";
+}
+.glyphicon-screenshot:before {
+  content: "\e087";
+}
+.glyphicon-remove-circle:before {
+  content: "\e088";
+}
+.glyphicon-ok-circle:before {
+  content: "\e089";
+}
+.glyphicon-ban-circle:before {
+  content: "\e090";
+}
+.glyphicon-arrow-left:before {
+  content: "\e091";
+}
+.glyphicon-arrow-right:before {
+  content: "\e092";
+}
+.glyphicon-arrow-up:before {
+  content: "\e093";
+}
+.glyphicon-arrow-down:before {
+  content: "\e094";
+}
+.glyphicon-share-alt:before {
+  content: "\e095";
+}
+.glyphicon-resize-full:before {
+  content: "\e096";
+}
+.glyphicon-resize-small:before {
+  content: "\e097";
+}
+.glyphicon-exclamation-sign:before {
+  content: "\e101";
+}
+.glyphicon-gift:before {
+  content: "\e102";
+}
+.glyphicon-leaf:before {
+  content: "\e103";
+}
+.glyphicon-fire:before {
+  content: "\e104";
+}
+.glyphicon-eye-open:before {
+  content: "\e105";
+}
+.glyphicon-eye-close:before {
+  content: "\e106";
+}
+.glyphicon-warning-sign:before {
+  content: "\e107";
+}
+.glyphicon-plane:before {
+  content: "\e108";
+}
+.glyphicon-calendar:before {
+  content: "\e109";
+}
+.glyphicon-random:before {
+  content: "\e110";
+}
+.glyphicon-comment:before {
+  content: "\e111";
+}
+.glyphicon-magnet:before {
+  content: "\e112";
+}
+.glyphicon-chevron-up:before {
+  content: "\e113";
+}
+.glyphicon-chevron-down:before {
+  content: "\e114";
+}
+.glyphicon-retweet:before {
+  content: "\e115";
+}
+.glyphicon-shopping-cart:before {
+  content: "\e116";
+}
+.glyphicon-folder-close:before {
+  content: "\e117";
+}
+.glyphicon-folder-open:before {
+  content: "\e118";
+}
+.glyphicon-resize-vertical:before {
+  content: "\e119";
+}
+.glyphicon-resize-horizontal:before {
+  content: "\e120";
+}
+.glyphicon-hdd:before {
+  content: "\e121";
+}
+.glyphicon-bullhorn:before {
+  content: "\e122";
+}
+.glyphicon-bell:before {
+  content: "\e123";
+}
+.glyphicon-certificate:before {
+  content: "\e124";
+}
+.glyphicon-thumbs-up:before {
+  content: "\e125";
+}
+.glyphicon-thumbs-down:before {
+  content: "\e126";
+}
+.glyphicon-hand-right:before {
+  content: "\e127";
+}
+.glyphicon-hand-left:before {
+  content: "\e128";
+}
+.glyphicon-hand-up:before {
+  content: "\e129";
+}
+.glyphicon-hand-down:before {
+  content: "\e130";
+}
+.glyphicon-circle-arrow-right:before {
+  content: "\e131";
+}
+.glyphicon-circle-arrow-left:before {
+  content: "\e132";
+}
+.glyphicon-circle-arrow-up:before {
+  content: "\e133";
+}
+.glyphicon-circle-arrow-down:before {
+  content: "\e134";
+}
+.glyphicon-globe:before {
+  content: "\e135";
+}
+.glyphicon-wrench:before {
+  content: "\e136";
+}
+.glyphicon-tasks:before {
+  content: "\e137";
+}
+.glyphicon-filter:before {
+  content: "\e138";
+}
+.glyphicon-briefcase:before {
+  content: "\e139";
+}
+.glyphicon-fullscreen:before {
+  content: "\e140";
+}
+.glyphicon-dashboard:before {
+  content: "\e141";
+}
+.glyphicon-paperclip:before {
+  content: "\e142";
+}
+.glyphicon-heart-empty:before {
+  content: "\e143";
+}
+.glyphicon-link:before {
+  content: "\e144";
+}
+.glyphicon-phone:before {
+  content: "\e145";
+}
+.glyphicon-pushpin:before {
+  content: "\e146";
+}
+.glyphicon-usd:before {
+  content: "\e148";
+}
+.glyphicon-gbp:before {
+  content: "\e149";
+}
+.glyphicon-sort:before {
+  content: "\e150";
+}
+.glyphicon-sort-by-alphabet:before {
+  content: "\e151";
+}
+.glyphicon-sort-by-alphabet-alt:before {
+  content: "\e152";
+}
+.glyphicon-sort-by-order:before {
+  content: "\e153";
+}
+.glyphicon-sort-by-order-alt:before {
+  content: "\e154";
+}
+.glyphicon-sort-by-attributes:before {
+  content: "\e155";
+}
+.glyphicon-sort-by-attributes-alt:before {
+  content: "\e156";
+}
+.glyphicon-unchecked:before {
+  content: "\e157";
+}
+.glyphicon-expand:before {
+  content: "\e158";
+}
+.glyphicon-collapse-down:before {
+  content: "\e159";
+}
+.glyphicon-collapse-up:before {
+  content: "\e160";
+}
+.glyphicon-log-in:before {
+  content: "\e161";
+}
+.glyphicon-flash:before {
+  content: "\e162";
+}
+.glyphicon-log-out:before {
+  content: "\e163";
+}
+.glyphicon-new-window:before {
+  content: "\e164";
+}
+.glyphicon-record:before {
+  content: "\e165";
+}
+.glyphicon-save:before {
+  content: "\e166";
+}
+.glyphicon-open:before {
+  content: "\e167";
+}
+.glyphicon-saved:before {
+  content: "\e168";
+}
+.glyphicon-import:before {
+  content: "\e169";
+}
+.glyphicon-export:before {
+  content: "\e170";
+}
+.glyphicon-send:before {
+  content: "\e171";
+}
+.glyphicon-floppy-disk:before {
+  content: "\e172";
+}
+.glyphicon-floppy-saved:before {
+  content: "\e173";
+}
+.glyphicon-floppy-remove:before {
+  content: "\e174";
+}
+.glyphicon-floppy-save:before {
+  content: "\e175";
+}
+.glyphicon-floppy-open:before {
+  content: "\e176";
+}
+.glyphicon-credit-card:before {
+  content: "\e177";
+}
+.glyphicon-transfer:before {
+  content: "\e178";
+}
+.glyphicon-cutlery:before {
+  content: "\e179";
+}
+.glyphicon-header:before {
+  content: "\e180";
+}
+.glyphicon-compressed:before {
+  content: "\e181";
+}
+.glyphicon-earphone:before {
+  content: "\e182";
+}
+.glyphicon-phone-alt:before {
+  content: "\e183";
+}
+.glyphicon-tower:before {
+  content: "\e184";
+}
+.glyphicon-stats:before {
+  content: "\e185";
+}
+.glyphicon-sd-video:before {
+  content: "\e186";
+}
+.glyphicon-hd-video:before {
+  content: "\e187";
+}
+.glyphicon-subtitles:before {
+  content: "\e188";
+}
+.glyphicon-sound-stereo:before {
+  content: "\e189";
+}
+.glyphicon-sound-dolby:before {
+  content: "\e190";
+}
+.glyphicon-sound-5-1:before {
+  content: "\e191";
+}
+.glyphicon-sound-6-1:before {
+  content: "\e192";
+}
+.glyphicon-sound-7-1:before {
+  content: "\e193";
+}
+.glyphicon-copyright-mark:before {
+  content: "\e194";
+}
+.glyphicon-registration-mark:before {
+  content: "\e195";
+}
+.glyphicon-cloud-download:before {
+  content: "\e197";
+}
+.glyphicon-cloud-upload:before {
+  content: "\e198";
+}
+.glyphicon-tree-conifer:before {
+  content: "\e199";
+}
+.glyphicon-tree-deciduous:before {
+  content: "\e200";
+}
+.glyphicon-cd:before {
+  content: "\e201";
+}
+.glyphicon-save-file:before {
+  content: "\e202";
+}
+.glyphicon-open-file:before {
+  content: "\e203";
+}
+.glyphicon-level-up:before {
+  content: "\e204";
+}
+.glyphicon-copy:before {
+  content: "\e205";
+}
+.glyphicon-paste:before {
+  content: "\e206";
+}
+.glyphicon-alert:before {
+  content: "\e209";
+}
+.glyphicon-equalizer:before {
+  content: "\e210";
+}
+.glyphicon-king:before {
+  content: "\e211";
+}
+.glyphicon-queen:before {
+  content: "\e212";
+}
+.glyphicon-pawn:before {
+  content: "\e213";
+}
+.glyphicon-bishop:before {
+  content: "\e214";
+}
+.glyphicon-knight:before {
+  content: "\e215";
+}
+.glyphicon-baby-formula:before {
+  content: "\e216";
+}
+.glyphicon-tent:before {
+  content: "\26fa";
+}
+.glyphicon-blackboard:before {
+  content: "\e218";
+}
+.glyphicon-bed:before {
+  content: "\e219";
+}
+.glyphicon-apple:before {
+  content: "\f8ff";
+}
+.glyphicon-erase:before {
+  content: "\e221";
+}
+.glyphicon-hourglass:before {
+  content: "\231b";
+}
+.glyphicon-lamp:before {
+  content: "\e223";
+}
+.glyphicon-duplicate:before {
+  content: "\e224";
+}
+.glyphicon-piggy-bank:before {
+  content: "\e225";
+}
+.glyphicon-scissors:before {
+  content: "\e226";
+}
+.glyphicon-bitcoin:before {
+  content: "\e227";
+}
+.glyphicon-btc:before {
+  content: "\e227";
+}
+.glyphicon-xbt:before {
+  content: "\e227";
+}
+.glyphicon-yen:before {
+  content: "\00a5";
+}
+.glyphicon-jpy:before {
+  content: "\00a5";
+}
+.glyphicon-ruble:before {
+  content: "\20bd";
+}
+.glyphicon-rub:before {
+  content: "\20bd";
+}
+.glyphicon-scale:before {
+  content: "\e230";
+}
+.glyphicon-ice-lolly:before {
+  content: "\e231";
+}
+.glyphicon-ice-lolly-tasted:before {
+  content: "\e232";
+}
+.glyphicon-education:before {
+  content: "\e233";
+}
+.glyphicon-option-horizontal:before {
+  content: "\e234";
+}
+.glyphicon-option-vertical:before {
+  content: "\e235";
+}
+.glyphicon-menu-hamburger:before {
+  content: "\e236";
+}
+.glyphicon-modal-window:before {
+  content: "\e237";
+}
+.glyphicon-oil:before {
+  content: "\e238";
+}
+.glyphicon-grain:before {
+  content: "\e239";
+}
+.glyphicon-sunglasses:before {
+  content: "\e240";
+}
+.glyphicon-text-size:before {
+  content: "\e241";
+}
+.glyphicon-text-color:before {
+  content: "\e242";
+}
+.glyphicon-text-background:before {
+  content: "\e243";
+}
+.glyphicon-object-align-top:before {
+  content: "\e244";
+}
+.glyphicon-object-align-bottom:before {
+  content: "\e245";
+}
+.glyphicon-object-align-horizontal:before {
+  content: "\e246";
+}
+.glyphicon-object-align-left:before {
+  content: "\e247";
+}
+.glyphicon-object-align-vertical:before {
+  content: "\e248";
+}
+.glyphicon-object-align-right:before {
+  content: "\e249";
+}
+.glyphicon-triangle-right:before {
+  content: "\e250";
+}
+.glyphicon-triangle-left:before {
+  content: "\e251";
+}
+.glyphicon-triangle-bottom:before {
+  content: "\e252";
+}
+.glyphicon-triangle-top:before {
+  content: "\e253";
+}
+.glyphicon-console:before {
+  content: "\e254";
+}
+.glyphicon-superscript:before {
+  content: "\e255";
+}
+.glyphicon-subscript:before {
+  content: "\e256";
+}
+.glyphicon-menu-left:before {
+  content: "\e257";
+}
+.glyphicon-menu-right:before {
+  content: "\e258";
+}
+.glyphicon-menu-down:before {
+  content: "\e259";
+}
+.glyphicon-menu-up:before {
+  content: "\e260";
+}
+* {
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+}
+*:before,
+*:after {
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+}
+html {
+  font-size: 10px;
+  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+body {
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-size: 13px;
+  line-height: 1.42857143;
+  color: #000;
+  background-color: #fff;
+}
+input,
+button,
+select,
+textarea {
+  font-family: inherit;
+  font-size: inherit;
+  line-height: inherit;
+}
+a {
+  color: #337ab7;
+  text-decoration: none;
+}
+a:hover,
+a:focus {
+  color: #23527c;
+  text-decoration: underline;
+}
+a:focus {
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+figure {
+  margin: 0;
+}
+img {
+  vertical-align: middle;
+}
+.img-responsive,
+.thumbnail > img,
+.thumbnail a > img,
+.carousel-inner > .item > img,
+.carousel-inner > .item > a > img {
+  display: block;
+  max-width: 100%;
+  height: auto;
+}
+.img-rounded {
+  border-radius: 3px;
+}
+.img-thumbnail {
+  padding: 4px;
+  line-height: 1.42857143;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-radius: 2px;
+  -webkit-transition: all 0.2s ease-in-out;
+  -o-transition: all 0.2s ease-in-out;
+  transition: all 0.2s ease-in-out;
+  display: inline-block;
+  max-width: 100%;
+  height: auto;
+}
+.img-circle {
+  border-radius: 50%;
+}
+hr {
+  margin-top: 18px;
+  margin-bottom: 18px;
+  border: 0;
+  border-top: 1px solid #eeeeee;
+}
+.sr-only {
+  position: absolute;
+  width: 1px;
+  height: 1px;
+  margin: -1px;
+  padding: 0;
+  overflow: hidden;
+  clip: rect(0, 0, 0, 0);
+  border: 0;
+}
+.sr-only-focusable:active,
+.sr-only-focusable:focus {
+  position: static;
+  width: auto;
+  height: auto;
+  margin: 0;
+  overflow: visible;
+  clip: auto;
+}
+[role="button"] {
+  cursor: pointer;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+.h1,
+.h2,
+.h3,
+.h4,
+.h5,
+.h6 {
+  font-family: inherit;
+  font-weight: 500;
+  line-height: 1.1;
+  color: inherit;
+}
+h1 small,
+h2 small,
+h3 small,
+h4 small,
+h5 small,
+h6 small,
+.h1 small,
+.h2 small,
+.h3 small,
+.h4 small,
+.h5 small,
+.h6 small,
+h1 .small,
+h2 .small,
+h3 .small,
+h4 .small,
+h5 .small,
+h6 .small,
+.h1 .small,
+.h2 .small,
+.h3 .small,
+.h4 .small,
+.h5 .small,
+.h6 .small {
+  font-weight: normal;
+  line-height: 1;
+  color: #777777;
+}
+h1,
+.h1,
+h2,
+.h2,
+h3,
+.h3 {
+  margin-top: 18px;
+  margin-bottom: 9px;
+}
+h1 small,
+.h1 small,
+h2 small,
+.h2 small,
+h3 small,
+.h3 small,
+h1 .small,
+.h1 .small,
+h2 .small,
+.h2 .small,
+h3 .small,
+.h3 .small {
+  font-size: 65%;
+}
+h4,
+.h4,
+h5,
+.h5,
+h6,
+.h6 {
+  margin-top: 9px;
+  margin-bottom: 9px;
+}
+h4 small,
+.h4 small,
+h5 small,
+.h5 small,
+h6 small,
+.h6 small,
+h4 .small,
+.h4 .small,
+h5 .small,
+.h5 .small,
+h6 .small,
+.h6 .small {
+  font-size: 75%;
+}
+h1,
+.h1 {
+  font-size: 33px;
+}
+h2,
+.h2 {
+  font-size: 27px;
+}
+h3,
+.h3 {
+  font-size: 23px;
+}
+h4,
+.h4 {
+  font-size: 17px;
+}
+h5,
+.h5 {
+  font-size: 13px;
+}
+h6,
+.h6 {
+  font-size: 12px;
+}
+p {
+  margin: 0 0 9px;
+}
+.lead {
+  margin-bottom: 18px;
+  font-size: 14px;
+  font-weight: 300;
+  line-height: 1.4;
+}
+@media (min-width: 768px) {
+  .lead {
+    font-size: 19.5px;
+  }
+}
+small,
+.small {
+  font-size: 92%;
+}
+mark,
+.mark {
+  background-color: #fcf8e3;
+  padding: .2em;
+}
+.text-left {
+  text-align: left;
+}
+.text-right {
+  text-align: right;
+}
+.text-center {
+  text-align: center;
+}
+.text-justify {
+  text-align: justify;
+}
+.text-nowrap {
+  white-space: nowrap;
+}
+.text-lowercase {
+  text-transform: lowercase;
+}
+.text-uppercase {
+  text-transform: uppercase;
+}
+.text-capitalize {
+  text-transform: capitalize;
+}
+.text-muted {
+  color: #777777;
+}
+.text-primary {
+  color: #337ab7;
+}
+a.text-primary:hover,
+a.text-primary:focus {
+  color: #286090;
+}
+.text-success {
+  color: #3c763d;
+}
+a.text-success:hover,
+a.text-success:focus {
+  color: #2b542c;
+}
+.text-info {
+  color: #31708f;
+}
+a.text-info:hover,
+a.text-info:focus {
+  color: #245269;
+}
+.text-warning {
+  color: #8a6d3b;
+}
+a.text-warning:hover,
+a.text-warning:focus {
+  color: #66512c;
+}
+.text-danger {
+  color: #a94442;
+}
+a.text-danger:hover,
+a.text-danger:focus {
+  color: #843534;
+}
+.bg-primary {
+  color: #fff;
+  background-color: #337ab7;
+}
+a.bg-primary:hover,
+a.bg-primary:focus {
+  background-color: #286090;
+}
+.bg-success {
+  background-color: #dff0d8;
+}
+a.bg-success:hover,
+a.bg-success:focus {
+  background-color: #c1e2b3;
+}
+.bg-info {
+  background-color: #d9edf7;
+}
+a.bg-info:hover,
+a.bg-info:focus {
+  background-color: #afd9ee;
+}
+.bg-warning {
+  background-color: #fcf8e3;
+}
+a.bg-warning:hover,
+a.bg-warning:focus {
+  background-color: #f7ecb5;
+}
+.bg-danger {
+  background-color: #f2dede;
+}
+a.bg-danger:hover,
+a.bg-danger:focus {
+  background-color: #e4b9b9;
+}
+.page-header {
+  padding-bottom: 8px;
+  margin: 36px 0 18px;
+  border-bottom: 1px solid #eeeeee;
+}
+ul,
+ol {
+  margin-top: 0;
+  margin-bottom: 9px;
+}
+ul ul,
+ol ul,
+ul ol,
+ol ol {
+  margin-bottom: 0;
+}
+.list-unstyled {
+  padding-left: 0;
+  list-style: none;
+}
+.list-inline {
+  padding-left: 0;
+  list-style: none;
+  margin-left: -5px;
+}
+.list-inline > li {
+  display: inline-block;
+  padding-left: 5px;
+  padding-right: 5px;
+}
+dl {
+  margin-top: 0;
+  margin-bottom: 18px;
+}
+dt,
+dd {
+  line-height: 1.42857143;
+}
+dt {
+  font-weight: bold;
+}
+dd {
+  margin-left: 0;
+}
+@media (min-width: 541px) {
+  .dl-horizontal dt {
+    float: left;
+    width: 160px;
+    clear: left;
+    text-align: right;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+  .dl-horizontal dd {
+    margin-left: 180px;
+  }
+}
+abbr[title],
+abbr[data-original-title] {
+  cursor: help;
+  border-bottom: 1px dotted #777777;
+}
+.initialism {
+  font-size: 90%;
+  text-transform: uppercase;
+}
+blockquote {
+  padding: 9px 18px;
+  margin: 0 0 18px;
+  font-size: inherit;
+  border-left: 5px solid #eeeeee;
+}
+blockquote p:last-child,
+blockquote ul:last-child,
+blockquote ol:last-child {
+  margin-bottom: 0;
+}
+blockquote footer,
+blockquote small,
+blockquote .small {
+  display: block;
+  font-size: 80%;
+  line-height: 1.42857143;
+  color: #777777;
+}
+blockquote footer:before,
+blockquote small:before,
+blockquote .small:before {
+  content: '\2014 \00A0';
+}
+.blockquote-reverse,
+blockquote.pull-right {
+  padding-right: 15px;
+  padding-left: 0;
+  border-right: 5px solid #eeeeee;
+  border-left: 0;
+  text-align: right;
+}
+.blockquote-reverse footer:before,
+blockquote.pull-right footer:before,
+.blockquote-reverse small:before,
+blockquote.pull-right small:before,
+.blockquote-reverse .small:before,
+blockquote.pull-right .small:before {
+  content: '';
+}
+.blockquote-reverse footer:after,
+blockquote.pull-right footer:after,
+.blockquote-reverse small:after,
+blockquote.pull-right small:after,
+.blockquote-reverse .small:after,
+blockquote.pull-right .small:after {
+  content: '\00A0 \2014';
+}
+address {
+  margin-bottom: 18px;
+  font-style: normal;
+  line-height: 1.42857143;
+}
+code,
+kbd,
+pre,
+samp {
+  font-family: monospace;
+}
+code {
+  padding: 2px 4px;
+  font-size: 90%;
+  color: #c7254e;
+  background-color: #f9f2f4;
+  border-radius: 2px;
+}
+kbd {
+  padding: 2px 4px;
+  font-size: 90%;
+  color: #888;
+  background-color: transparent;
+  border-radius: 1px;
+  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);
+}
+kbd kbd {
+  padding: 0;
+  font-size: 100%;
+  font-weight: bold;
+  box-shadow: none;
+}
+pre {
+  display: block;
+  padding: 8.5px;
+  margin: 0 0 9px;
+  font-size: 12px;
+  line-height: 1.42857143;
+  word-break: break-all;
+  word-wrap: break-word;
+  color: #333333;
+  background-color: #f5f5f5;
+  border: 1px solid #ccc;
+  border-radius: 2px;
+}
+pre code {
+  padding: 0;
+  font-size: inherit;
+  color: inherit;
+  white-space: pre-wrap;
+  background-color: transparent;
+  border-radius: 0;
+}
+.pre-scrollable {
+  max-height: 340px;
+  overflow-y: scroll;
+}
+.container {
+  margin-right: auto;
+  margin-left: auto;
+  padding-left: 0px;
+  padding-right: 0px;
+}
+@media (min-width: 768px) {
+  .container {
+    width: 768px;
+  }
+}
+@media (min-width: 992px) {
+  .container {
+    width: 940px;
+  }
+}
+@media (min-width: 1200px) {
+  .container {
+    width: 1140px;
+  }
+}
+.container-fluid {
+  margin-right: auto;
+  margin-left: auto;
+  padding-left: 0px;
+  padding-right: 0px;
+}
+.row {
+  margin-left: 0px;
+  margin-right: 0px;
+}
+.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {
+  position: relative;
+  min-height: 1px;
+  padding-left: 0px;
+  padding-right: 0px;
+}
+.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {
+  float: left;
+}
+.col-xs-12 {
+  width: 100%;
+}
+.col-xs-11 {
+  width: 91.66666667%;
+}
+.col-xs-10 {
+  width: 83.33333333%;
+}
+.col-xs-9 {
+  width: 75%;
+}
+.col-xs-8 {
+  width: 66.66666667%;
+}
+.col-xs-7 {
+  width: 58.33333333%;
+}
+.col-xs-6 {
+  width: 50%;
+}
+.col-xs-5 {
+  width: 41.66666667%;
+}
+.col-xs-4 {
+  width: 33.33333333%;
+}
+.col-xs-3 {
+  width: 25%;
+}
+.col-xs-2 {
+  width: 16.66666667%;
+}
+.col-xs-1 {
+  width: 8.33333333%;
+}
+.col-xs-pull-12 {
+  right: 100%;
+}
+.col-xs-pull-11 {
+  right: 91.66666667%;
+}
+.col-xs-pull-10 {
+  right: 83.33333333%;
+}
+.col-xs-pull-9 {
+  right: 75%;
+}
+.col-xs-pull-8 {
+  right: 66.66666667%;
+}
+.col-xs-pull-7 {
+  right: 58.33333333%;
+}
+.col-xs-pull-6 {
+  right: 50%;
+}
+.col-xs-pull-5 {
+  right: 41.66666667%;
+}
+.col-xs-pull-4 {
+  right: 33.33333333%;
+}
+.col-xs-pull-3 {
+  right: 25%;
+}
+.col-xs-pull-2 {
+  right: 16.66666667%;
+}
+.col-xs-pull-1 {
+  right: 8.33333333%;
+}
+.col-xs-pull-0 {
+  right: auto;
+}
+.col-xs-push-12 {
+  left: 100%;
+}
+.col-xs-push-11 {
+  left: 91.66666667%;
+}
+.col-xs-push-10 {
+  left: 83.33333333%;
+}
+.col-xs-push-9 {
+  left: 75%;
+}
+.col-xs-push-8 {
+  left: 66.66666667%;
+}
+.col-xs-push-7 {
+  left: 58.33333333%;
+}
+.col-xs-push-6 {
+  left: 50%;
+}
+.col-xs-push-5 {
+  left: 41.66666667%;
+}
+.col-xs-push-4 {
+  left: 33.33333333%;
+}
+.col-xs-push-3 {
+  left: 25%;
+}
+.col-xs-push-2 {
+  left: 16.66666667%;
+}
+.col-xs-push-1 {
+  left: 8.33333333%;
+}
+.col-xs-push-0 {
+  left: auto;
+}
+.col-xs-offset-12 {
+  margin-left: 100%;
+}
+.col-xs-offset-11 {
+  margin-left: 91.66666667%;
+}
+.col-xs-offset-10 {
+  margin-left: 83.33333333%;
+}
+.col-xs-offset-9 {
+  margin-left: 75%;
+}
+.col-xs-offset-8 {
+  margin-left: 66.66666667%;
+}
+.col-xs-offset-7 {
+  margin-left: 58.33333333%;
+}
+.col-xs-offset-6 {
+  margin-left: 50%;
+}
+.col-xs-offset-5 {
+  margin-left: 41.66666667%;
+}
+.col-xs-offset-4 {
+  margin-left: 33.33333333%;
+}
+.col-xs-offset-3 {
+  margin-left: 25%;
+}
+.col-xs-offset-2 {
+  margin-left: 16.66666667%;
+}
+.col-xs-offset-1 {
+  margin-left: 8.33333333%;
+}
+.col-xs-offset-0 {
+  margin-left: 0%;
+}
+@media (min-width: 768px) {
+  .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {
+    float: left;
+  }
+  .col-sm-12 {
+    width: 100%;
+  }
+  .col-sm-11 {
+    width: 91.66666667%;
+  }
+  .col-sm-10 {
+    width: 83.33333333%;
+  }
+  .col-sm-9 {
+    width: 75%;
+  }
+  .col-sm-8 {
+    width: 66.66666667%;
+  }
+  .col-sm-7 {
+    width: 58.33333333%;
+  }
+  .col-sm-6 {
+    width: 50%;
+  }
+  .col-sm-5 {
+    width: 41.66666667%;
+  }
+  .col-sm-4 {
+    width: 33.33333333%;
+  }
+  .col-sm-3 {
+    width: 25%;
+  }
+  .col-sm-2 {
+    width: 16.66666667%;
+  }
+  .col-sm-1 {
+    width: 8.33333333%;
+  }
+  .col-sm-pull-12 {
+    right: 100%;
+  }
+  .col-sm-pull-11 {
+    right: 91.66666667%;
+  }
+  .col-sm-pull-10 {
+    right: 83.33333333%;
+  }
+  .col-sm-pull-9 {
+    right: 75%;
+  }
+  .col-sm-pull-8 {
+    right: 66.66666667%;
+  }
+  .col-sm-pull-7 {
+    right: 58.33333333%;
+  }
+  .col-sm-pull-6 {
+    right: 50%;
+  }
+  .col-sm-pull-5 {
+    right: 41.66666667%;
+  }
+  .col-sm-pull-4 {
+    right: 33.33333333%;
+  }
+  .col-sm-pull-3 {
+    right: 25%;
+  }
+  .col-sm-pull-2 {
+    right: 16.66666667%;
+  }
+  .col-sm-pull-1 {
+    right: 8.33333333%;
+  }
+  .col-sm-pull-0 {
+    right: auto;
+  }
+  .col-sm-push-12 {
+    left: 100%;
+  }
+  .col-sm-push-11 {
+    left: 91.66666667%;
+  }
+  .col-sm-push-10 {
+    left: 83.33333333%;
+  }
+  .col-sm-push-9 {
+    left: 75%;
+  }
+  .col-sm-push-8 {
+    left: 66.66666667%;
+  }
+  .col-sm-push-7 {
+    left: 58.33333333%;
+  }
+  .col-sm-push-6 {
+    left: 50%;
+  }
+  .col-sm-push-5 {
+    left: 41.66666667%;
+  }
+  .col-sm-push-4 {
+    left: 33.33333333%;
+  }
+  .col-sm-push-3 {
+    left: 25%;
+  }
+  .col-sm-push-2 {
+    left: 16.66666667%;
+  }
+  .col-sm-push-1 {
+    left: 8.33333333%;
+  }
+  .col-sm-push-0 {
+    left: auto;
+  }
+  .col-sm-offset-12 {
+    margin-left: 100%;
+  }
+  .col-sm-offset-11 {
+    margin-left: 91.66666667%;
+  }
+  .col-sm-offset-10 {
+    margin-left: 83.33333333%;
+  }
+  .col-sm-offset-9 {
+    margin-left: 75%;
+  }
+  .col-sm-offset-8 {
+    margin-left: 66.66666667%;
+  }
+  .col-sm-offset-7 {
+    margin-left: 58.33333333%;
+  }
+  .col-sm-offset-6 {
+    margin-left: 50%;
+  }
+  .col-sm-offset-5 {
+    margin-left: 41.66666667%;
+  }
+  .col-sm-offset-4 {
+    margin-left: 33.33333333%;
+  }
+  .col-sm-offset-3 {
+    margin-left: 25%;
+  }
+  .col-sm-offset-2 {
+    margin-left: 16.66666667%;
+  }
+  .col-sm-offset-1 {
+    margin-left: 8.33333333%;
+  }
+  .col-sm-offset-0 {
+    margin-left: 0%;
+  }
+}
+@media (min-width: 992px) {
+  .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {
+    float: left;
+  }
+  .col-md-12 {
+    width: 100%;
+  }
+  .col-md-11 {
+    width: 91.66666667%;
+  }
+  .col-md-10 {
+    width: 83.33333333%;
+  }
+  .col-md-9 {
+    width: 75%;
+  }
+  .col-md-8 {
+    width: 66.66666667%;
+  }
+  .col-md-7 {
+    width: 58.33333333%;
+  }
+  .col-md-6 {
+    width: 50%;
+  }
+  .col-md-5 {
+    width: 41.66666667%;
+  }
+  .col-md-4 {
+    width: 33.33333333%;
+  }
+  .col-md-3 {
+    width: 25%;
+  }
+  .col-md-2 {
+    width: 16.66666667%;
+  }
+  .col-md-1 {
+    width: 8.33333333%;
+  }
+  .col-md-pull-12 {
+    right: 100%;
+  }
+  .col-md-pull-11 {
+    right: 91.66666667%;
+  }
+  .col-md-pull-10 {
+    right: 83.33333333%;
+  }
+  .col-md-pull-9 {
+    right: 75%;
+  }
+  .col-md-pull-8 {
+    right: 66.66666667%;
+  }
+  .col-md-pull-7 {
+    right: 58.33333333%;
+  }
+  .col-md-pull-6 {
+    right: 50%;
+  }
+  .col-md-pull-5 {
+    right: 41.66666667%;
+  }
+  .col-md-pull-4 {
+    right: 33.33333333%;
+  }
+  .col-md-pull-3 {
+    right: 25%;
+  }
+  .col-md-pull-2 {
+    right: 16.66666667%;
+  }
+  .col-md-pull-1 {
+    right: 8.33333333%;
+  }
+  .col-md-pull-0 {
+    right: auto;
+  }
+  .col-md-push-12 {
+    left: 100%;
+  }
+  .col-md-push-11 {
+    left: 91.66666667%;
+  }
+  .col-md-push-10 {
+    left: 83.33333333%;
+  }
+  .col-md-push-9 {
+    left: 75%;
+  }
+  .col-md-push-8 {
+    left: 66.66666667%;
+  }
+  .col-md-push-7 {
+    left: 58.33333333%;
+  }
+  .col-md-push-6 {
+    left: 50%;
+  }
+  .col-md-push-5 {
+    left: 41.66666667%;
+  }
+  .col-md-push-4 {
+    left: 33.33333333%;
+  }
+  .col-md-push-3 {
+    left: 25%;
+  }
+  .col-md-push-2 {
+    left: 16.66666667%;
+  }
+  .col-md-push-1 {
+    left: 8.33333333%;
+  }
+  .col-md-push-0 {
+    left: auto;
+  }
+  .col-md-offset-12 {
+    margin-left: 100%;
+  }
+  .col-md-offset-11 {
+    margin-left: 91.66666667%;
+  }
+  .col-md-offset-10 {
+    margin-left: 83.33333333%;
+  }
+  .col-md-offset-9 {
+    margin-left: 75%;
+  }
+  .col-md-offset-8 {
+    margin-left: 66.66666667%;
+  }
+  .col-md-offset-7 {
+    margin-left: 58.33333333%;
+  }
+  .col-md-offset-6 {
+    margin-left: 50%;
+  }
+  .col-md-offset-5 {
+    margin-left: 41.66666667%;
+  }
+  .col-md-offset-4 {
+    margin-left: 33.33333333%;
+  }
+  .col-md-offset-3 {
+    margin-left: 25%;
+  }
+  .col-md-offset-2 {
+    margin-left: 16.66666667%;
+  }
+  .col-md-offset-1 {
+    margin-left: 8.33333333%;
+  }
+  .col-md-offset-0 {
+    margin-left: 0%;
+  }
+}
+@media (min-width: 1200px) {
+  .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {
+    float: left;
+  }
+  .col-lg-12 {
+    width: 100%;
+  }
+  .col-lg-11 {
+    width: 91.66666667%;
+  }
+  .col-lg-10 {
+    width: 83.33333333%;
+  }
+  .col-lg-9 {
+    width: 75%;
+  }
+  .col-lg-8 {
+    width: 66.66666667%;
+  }
+  .col-lg-7 {
+    width: 58.33333333%;
+  }
+  .col-lg-6 {
+    width: 50%;
+  }
+  .col-lg-5 {
+    width: 41.66666667%;
+  }
+  .col-lg-4 {
+    width: 33.33333333%;
+  }
+  .col-lg-3 {
+    width: 25%;
+  }
+  .col-lg-2 {
+    width: 16.66666667%;
+  }
+  .col-lg-1 {
+    width: 8.33333333%;
+  }
+  .col-lg-pull-12 {
+    right: 100%;
+  }
+  .col-lg-pull-11 {
+    right: 91.66666667%;
+  }
+  .col-lg-pull-10 {
+    right: 83.33333333%;
+  }
+  .col-lg-pull-9 {
+    right: 75%;
+  }
+  .col-lg-pull-8 {
+    right: 66.66666667%;
+  }
+  .col-lg-pull-7 {
+    right: 58.33333333%;
+  }
+  .col-lg-pull-6 {
+    right: 50%;
+  }
+  .col-lg-pull-5 {
+    right: 41.66666667%;
+  }
+  .col-lg-pull-4 {
+    right: 33.33333333%;
+  }
+  .col-lg-pull-3 {
+    right: 25%;
+  }
+  .col-lg-pull-2 {
+    right: 16.66666667%;
+  }
+  .col-lg-pull-1 {
+    right: 8.33333333%;
+  }
+  .col-lg-pull-0 {
+    right: auto;
+  }
+  .col-lg-push-12 {
+    left: 100%;
+  }
+  .col-lg-push-11 {
+    left: 91.66666667%;
+  }
+  .col-lg-push-10 {
+    left: 83.33333333%;
+  }
+  .col-lg-push-9 {
+    left: 75%;
+  }
+  .col-lg-push-8 {
+    left: 66.66666667%;
+  }
+  .col-lg-push-7 {
+    left: 58.33333333%;
+  }
+  .col-lg-push-6 {
+    left: 50%;
+  }
+  .col-lg-push-5 {
+    left: 41.66666667%;
+  }
+  .col-lg-push-4 {
+    left: 33.33333333%;
+  }
+  .col-lg-push-3 {
+    left: 25%;
+  }
+  .col-lg-push-2 {
+    left: 16.66666667%;
+  }
+  .col-lg-push-1 {
+    left: 8.33333333%;
+  }
+  .col-lg-push-0 {
+    left: auto;
+  }
+  .col-lg-offset-12 {
+    margin-left: 100%;
+  }
+  .col-lg-offset-11 {
+    margin-left: 91.66666667%;
+  }
+  .col-lg-offset-10 {
+    margin-left: 83.33333333%;
+  }
+  .col-lg-offset-9 {
+    margin-left: 75%;
+  }
+  .col-lg-offset-8 {
+    margin-left: 66.66666667%;
+  }
+  .col-lg-offset-7 {
+    margin-left: 58.33333333%;
+  }
+  .col-lg-offset-6 {
+    margin-left: 50%;
+  }
+  .col-lg-offset-5 {
+    margin-left: 41.66666667%;
+  }
+  .col-lg-offset-4 {
+    margin-left: 33.33333333%;
+  }
+  .col-lg-offset-3 {
+    margin-left: 25%;
+  }
+  .col-lg-offset-2 {
+    margin-left: 16.66666667%;
+  }
+  .col-lg-offset-1 {
+    margin-left: 8.33333333%;
+  }
+  .col-lg-offset-0 {
+    margin-left: 0%;
+  }
+}
+table {
+  background-color: transparent;
+}
+caption {
+  padding-top: 8px;
+  padding-bottom: 8px;
+  color: #777777;
+  text-align: left;
+}
+th {
+  text-align: left;
+}
+.table {
+  width: 100%;
+  max-width: 100%;
+  margin-bottom: 18px;
+}
+.table > thead > tr > th,
+.table > tbody > tr > th,
+.table > tfoot > tr > th,
+.table > thead > tr > td,
+.table > tbody > tr > td,
+.table > tfoot > tr > td {
+  padding: 8px;
+  line-height: 1.42857143;
+  vertical-align: top;
+  border-top: 1px solid #ddd;
+}
+.table > thead > tr > th {
+  vertical-align: bottom;
+  border-bottom: 2px solid #ddd;
+}
+.table > caption + thead > tr:first-child > th,
+.table > colgroup + thead > tr:first-child > th,
+.table > thead:first-child > tr:first-child > th,
+.table > caption + thead > tr:first-child > td,
+.table > colgroup + thead > tr:first-child > td,
+.table > thead:first-child > tr:first-child > td {
+  border-top: 0;
+}
+.table > tbody + tbody {
+  border-top: 2px solid #ddd;
+}
+.table .table {
+  background-color: #fff;
+}
+.table-condensed > thead > tr > th,
+.table-condensed > tbody > tr > th,
+.table-condensed > tfoot > tr > th,
+.table-condensed > thead > tr > td,
+.table-condensed > tbody > tr > td,
+.table-condensed > tfoot > tr > td {
+  padding: 5px;
+}
+.table-bordered {
+  border: 1px solid #ddd;
+}
+.table-bordered > thead > tr > th,
+.table-bordered > tbody > tr > th,
+.table-bordered > tfoot > tr > th,
+.table-bordered > thead > tr > td,
+.table-bordered > tbody > tr > td,
+.table-bordered > tfoot > tr > td {
+  border: 1px solid #ddd;
+}
+.table-bordered > thead > tr > th,
+.table-bordered > thead > tr > td {
+  border-bottom-width: 2px;
+}
+.table-striped > tbody > tr:nth-of-type(odd) {
+  background-color: #f9f9f9;
+}
+.table-hover > tbody > tr:hover {
+  background-color: #f5f5f5;
+}
+table col[class*="col-"] {
+  position: static;
+  float: none;
+  display: table-column;
+}
+table td[class*="col-"],
+table th[class*="col-"] {
+  position: static;
+  float: none;
+  display: table-cell;
+}
+.table > thead > tr > td.active,
+.table > tbody > tr > td.active,
+.table > tfoot > tr > td.active,
+.table > thead > tr > th.active,
+.table > tbody > tr > th.active,
+.table > tfoot > tr > th.active,
+.table > thead > tr.active > td,
+.table > tbody > tr.active > td,
+.table > tfoot > tr.active > td,
+.table > thead > tr.active > th,
+.table > tbody > tr.active > th,
+.table > tfoot > tr.active > th {
+  background-color: #f5f5f5;
+}
+.table-hover > tbody > tr > td.active:hover,
+.table-hover > tbody > tr > th.active:hover,
+.table-hover > tbody > tr.active:hover > td,
+.table-hover > tbody > tr:hover > .active,
+.table-hover > tbody > tr.active:hover > th {
+  background-color: #e8e8e8;
+}
+.table > thead > tr > td.success,
+.table > tbody > tr > td.success,
+.table > tfoot > tr > td.success,
+.table > thead > tr > th.success,
+.table > tbody > tr > th.success,
+.table > tfoot > tr > th.success,
+.table > thead > tr.success > td,
+.table > tbody > tr.success > td,
+.table > tfoot > tr.success > td,
+.table > thead > tr.success > th,
+.table > tbody > tr.success > th,
+.table > tfoot > tr.success > th {
+  background-color: #dff0d8;
+}
+.table-hover > tbody > tr > td.success:hover,
+.table-hover > tbody > tr > th.success:hover,
+.table-hover > tbody > tr.success:hover > td,
+.table-hover > tbody > tr:hover > .success,
+.table-hover > tbody > tr.success:hover > th {
+  background-color: #d0e9c6;
+}
+.table > thead > tr > td.info,
+.table > tbody > tr > td.info,
+.table > tfoot > tr > td.info,
+.table > thead > tr > th.info,
+.table > tbody > tr > th.info,
+.table > tfoot > tr > th.info,
+.table > thead > tr.info > td,
+.table > tbody > tr.info > td,
+.table > tfoot > tr.info > td,
+.table > thead > tr.info > th,
+.table > tbody > tr.info > th,
+.table > tfoot > tr.info > th {
+  background-color: #d9edf7;
+}
+.table-hover > tbody > tr > td.info:hover,
+.table-hover > tbody > tr > th.info:hover,
+.table-hover > tbody > tr.info:hover > td,
+.table-hover > tbody > tr:hover > .info,
+.table-hover > tbody > tr.info:hover > th {
+  background-color: #c4e3f3;
+}
+.table > thead > tr > td.warning,
+.table > tbody > tr > td.warning,
+.table > tfoot > tr > td.warning,
+.table > thead > tr > th.warning,
+.table > tbody > tr > th.warning,
+.table > tfoot > tr > th.warning,
+.table > thead > tr.warning > td,
+.table > tbody > tr.warning > td,
+.table > tfoot > tr.warning > td,
+.table > thead > tr.warning > th,
+.table > tbody > tr.warning > th,
+.table > tfoot > tr.warning > th {
+  background-color: #fcf8e3;
+}
+.table-hover > tbody > tr > td.warning:hover,
+.table-hover > tbody > tr > th.warning:hover,
+.table-hover > tbody > tr.warning:hover > td,
+.table-hover > tbody > tr:hover > .warning,
+.table-hover > tbody > tr.warning:hover > th {
+  background-color: #faf2cc;
+}
+.table > thead > tr > td.danger,
+.table > tbody > tr > td.danger,
+.table > tfoot > tr > td.danger,
+.table > thead > tr > th.danger,
+.table > tbody > tr > th.danger,
+.table > tfoot > tr > th.danger,
+.table > thead > tr.danger > td,
+.table > tbody > tr.danger > td,
+.table > tfoot > tr.danger > td,
+.table > thead > tr.danger > th,
+.table > tbody > tr.danger > th,
+.table > tfoot > tr.danger > th {
+  background-color: #f2dede;
+}
+.table-hover > tbody > tr > td.danger:hover,
+.table-hover > tbody > tr > th.danger:hover,
+.table-hover > tbody > tr.danger:hover > td,
+.table-hover > tbody > tr:hover > .danger,
+.table-hover > tbody > tr.danger:hover > th {
+  background-color: #ebcccc;
+}
+.table-responsive {
+  overflow-x: auto;
+  min-height: 0.01%;
+}
+@media screen and (max-width: 767px) {
+  .table-responsive {
+    width: 100%;
+    margin-bottom: 13.5px;
+    overflow-y: hidden;
+    -ms-overflow-style: -ms-autohiding-scrollbar;
+    border: 1px solid #ddd;
+  }
+  .table-responsive > .table {
+    margin-bottom: 0;
+  }
+  .table-responsive > .table > thead > tr > th,
+  .table-responsive > .table > tbody > tr > th,
+  .table-responsive > .table > tfoot > tr > th,
+  .table-responsive > .table > thead > tr > td,
+  .table-responsive > .table > tbody > tr > td,
+  .table-responsive > .table > tfoot > tr > td {
+    white-space: nowrap;
+  }
+  .table-responsive > .table-bordered {
+    border: 0;
+  }
+  .table-responsive > .table-bordered > thead > tr > th:first-child,
+  .table-responsive > .table-bordered > tbody > tr > th:first-child,
+  .table-responsive > .table-bordered > tfoot > tr > th:first-child,
+  .table-responsive > .table-bordered > thead > tr > td:first-child,
+  .table-responsive > .table-bordered > tbody > tr > td:first-child,
+  .table-responsive > .table-bordered > tfoot > tr > td:first-child {
+    border-left: 0;
+  }
+  .table-responsive > .table-bordered > thead > tr > th:last-child,
+  .table-responsive > .table-bordered > tbody > tr > th:last-child,
+  .table-responsive > .table-bordered > tfoot > tr > th:last-child,
+  .table-responsive > .table-bordered > thead > tr > td:last-child,
+  .table-responsive > .table-bordered > tbody > tr > td:last-child,
+  .table-responsive > .table-bordered > tfoot > tr > td:last-child {
+    border-right: 0;
+  }
+  .table-responsive > .table-bordered > tbody > tr:last-child > th,
+  .table-responsive > .table-bordered > tfoot > tr:last-child > th,
+  .table-responsive > .table-bordered > tbody > tr:last-child > td,
+  .table-responsive > .table-bordered > tfoot > tr:last-child > td {
+    border-bottom: 0;
+  }
+}
+fieldset {
+  padding: 0;
+  margin: 0;
+  border: 0;
+  min-width: 0;
+}
+legend {
+  display: block;
+  width: 100%;
+  padding: 0;
+  margin-bottom: 18px;
+  font-size: 19.5px;
+  line-height: inherit;
+  color: #333333;
+  border: 0;
+  border-bottom: 1px solid #e5e5e5;
+}
+label {
+  display: inline-block;
+  max-width: 100%;
+  margin-bottom: 5px;
+  font-weight: bold;
+}
+input[type="search"] {
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+}
+input[type="radio"],
+input[type="checkbox"] {
+  margin: 4px 0 0;
+  margin-top: 1px \9;
+  line-height: normal;
+}
+input[type="file"] {
+  display: block;
+}
+input[type="range"] {
+  display: block;
+  width: 100%;
+}
+select[multiple],
+select[size] {
+  height: auto;
+}
+input[type="file"]:focus,
+input[type="radio"]:focus,
+input[type="checkbox"]:focus {
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+output {
+  display: block;
+  padding-top: 7px;
+  font-size: 13px;
+  line-height: 1.42857143;
+  color: #555555;
+}
+.form-control {
+  display: block;
+  width: 100%;
+  height: 32px;
+  padding: 6px 12px;
+  font-size: 13px;
+  line-height: 1.42857143;
+  color: #555555;
+  background-color: #fff;
+  background-image: none;
+  border: 1px solid #ccc;
+  border-radius: 2px;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+  -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+  transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+}
+.form-control:focus {
+  border-color: #66afe9;
+  outline: 0;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
+  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
+}
+.form-control::-moz-placeholder {
+  color: #999;
+  opacity: 1;
+}
+.form-control:-ms-input-placeholder {
+  color: #999;
+}
+.form-control::-webkit-input-placeholder {
+  color: #999;
+}
+.form-control::-ms-expand {
+  border: 0;
+  background-color: transparent;
+}
+.form-control[disabled],
+.form-control[readonly],
+fieldset[disabled] .form-control {
+  background-color: #eeeeee;
+  opacity: 1;
+}
+.form-control[disabled],
+fieldset[disabled] .form-control {
+  cursor: not-allowed;
+}
+textarea.form-control {
+  height: auto;
+}
+input[type="search"] {
+  -webkit-appearance: none;
+}
+@media screen and (-webkit-min-device-pixel-ratio: 0) {
+  input[type="date"].form-control,
+  input[type="time"].form-control,
+  input[type="datetime-local"].form-control,
+  input[type="month"].form-control {
+    line-height: 32px;
+  }
+  input[type="date"].input-sm,
+  input[type="time"].input-sm,
+  input[type="datetime-local"].input-sm,
+  input[type="month"].input-sm,
+  .input-group-sm input[type="date"],
+  .input-group-sm input[type="time"],
+  .input-group-sm input[type="datetime-local"],
+  .input-group-sm input[type="month"] {
+    line-height: 30px;
+  }
+  input[type="date"].input-lg,
+  input[type="time"].input-lg,
+  input[type="datetime-local"].input-lg,
+  input[type="month"].input-lg,
+  .input-group-lg input[type="date"],
+  .input-group-lg input[type="time"],
+  .input-group-lg input[type="datetime-local"],
+  .input-group-lg input[type="month"] {
+    line-height: 45px;
+  }
+}
+.form-group {
+  margin-bottom: 15px;
+}
+.radio,
+.checkbox {
+  position: relative;
+  display: block;
+  margin-top: 10px;
+  margin-bottom: 10px;
+}
+.radio label,
+.checkbox label {
+  min-height: 18px;
+  padding-left: 20px;
+  margin-bottom: 0;
+  font-weight: normal;
+  cursor: pointer;
+}
+.radio input[type="radio"],
+.radio-inline input[type="radio"],
+.checkbox input[type="checkbox"],
+.checkbox-inline input[type="checkbox"] {
+  position: absolute;
+  margin-left: -20px;
+  margin-top: 4px \9;
+}
+.radio + .radio,
+.checkbox + .checkbox {
+  margin-top: -5px;
+}
+.radio-inline,
+.checkbox-inline {
+  position: relative;
+  display: inline-block;
+  padding-left: 20px;
+  margin-bottom: 0;
+  vertical-align: middle;
+  font-weight: normal;
+  cursor: pointer;
+}
+.radio-inline + .radio-inline,
+.checkbox-inline + .checkbox-inline {
+  margin-top: 0;
+  margin-left: 10px;
+}
+input[type="radio"][disabled],
+input[type="checkbox"][disabled],
+input[type="radio"].disabled,
+input[type="checkbox"].disabled,
+fieldset[disabled] input[type="radio"],
+fieldset[disabled] input[type="checkbox"] {
+  cursor: not-allowed;
+}
+.radio-inline.disabled,
+.checkbox-inline.disabled,
+fieldset[disabled] .radio-inline,
+fieldset[disabled] .checkbox-inline {
+  cursor: not-allowed;
+}
+.radio.disabled label,
+.checkbox.disabled label,
+fieldset[disabled] .radio label,
+fieldset[disabled] .checkbox label {
+  cursor: not-allowed;
+}
+.form-control-static {
+  padding-top: 7px;
+  padding-bottom: 7px;
+  margin-bottom: 0;
+  min-height: 31px;
+}
+.form-control-static.input-lg,
+.form-control-static.input-sm {
+  padding-left: 0;
+  padding-right: 0;
+}
+.input-sm {
+  height: 30px;
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 1px;
+}
+select.input-sm {
+  height: 30px;
+  line-height: 30px;
+}
+textarea.input-sm,
+select[multiple].input-sm {
+  height: auto;
+}
+.form-group-sm .form-control {
+  height: 30px;
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 1px;
+}
+.form-group-sm select.form-control {
+  height: 30px;
+  line-height: 30px;
+}
+.form-group-sm textarea.form-control,
+.form-group-sm select[multiple].form-control {
+  height: auto;
+}
+.form-group-sm .form-control-static {
+  height: 30px;
+  min-height: 30px;
+  padding: 6px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+}
+.input-lg {
+  height: 45px;
+  padding: 10px 16px;
+  font-size: 17px;
+  line-height: 1.3333333;
+  border-radius: 3px;
+}
+select.input-lg {
+  height: 45px;
+  line-height: 45px;
+}
+textarea.input-lg,
+select[multiple].input-lg {
+  height: auto;
+}
+.form-group-lg .form-control {
+  height: 45px;
+  padding: 10px 16px;
+  font-size: 17px;
+  line-height: 1.3333333;
+  border-radius: 3px;
+}
+.form-group-lg select.form-control {
+  height: 45px;
+  line-height: 45px;
+}
+.form-group-lg textarea.form-control,
+.form-group-lg select[multiple].form-control {
+  height: auto;
+}
+.form-group-lg .form-control-static {
+  height: 45px;
+  min-height: 35px;
+  padding: 11px 16px;
+  font-size: 17px;
+  line-height: 1.3333333;
+}
+.has-feedback {
+  position: relative;
+}
+.has-feedback .form-control {
+  padding-right: 40px;
+}
+.form-control-feedback {
+  position: absolute;
+  top: 0;
+  right: 0;
+  z-index: 2;
+  display: block;
+  width: 32px;
+  height: 32px;
+  line-height: 32px;
+  text-align: center;
+  pointer-events: none;
+}
+.input-lg + .form-control-feedback,
+.input-group-lg + .form-control-feedback,
+.form-group-lg .form-control + .form-control-feedback {
+  width: 45px;
+  height: 45px;
+  line-height: 45px;
+}
+.input-sm + .form-control-feedback,
+.input-group-sm + .form-control-feedback,
+.form-group-sm .form-control + .form-control-feedback {
+  width: 30px;
+  height: 30px;
+  line-height: 30px;
+}
+.has-success .help-block,
+.has-success .control-label,
+.has-success .radio,
+.has-success .checkbox,
+.has-success .radio-inline,
+.has-success .checkbox-inline,
+.has-success.radio label,
+.has-success.checkbox label,
+.has-success.radio-inline label,
+.has-success.checkbox-inline label {
+  color: #3c763d;
+}
+.has-success .form-control {
+  border-color: #3c763d;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+}
+.has-success .form-control:focus {
+  border-color: #2b542c;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
+}
+.has-success .input-group-addon {
+  color: #3c763d;
+  border-color: #3c763d;
+  background-color: #dff0d8;
+}
+.has-success .form-control-feedback {
+  color: #3c763d;
+}
+.has-warning .help-block,
+.has-warning .control-label,
+.has-warning .radio,
+.has-warning .checkbox,
+.has-warning .radio-inline,
+.has-warning .checkbox-inline,
+.has-warning.radio label,
+.has-warning.checkbox label,
+.has-warning.radio-inline label,
+.has-warning.checkbox-inline label {
+  color: #8a6d3b;
+}
+.has-warning .form-control {
+  border-color: #8a6d3b;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+}
+.has-warning .form-control:focus {
+  border-color: #66512c;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;
+}
+.has-warning .input-group-addon {
+  color: #8a6d3b;
+  border-color: #8a6d3b;
+  background-color: #fcf8e3;
+}
+.has-warning .form-control-feedback {
+  color: #8a6d3b;
+}
+.has-error .help-block,
+.has-error .control-label,
+.has-error .radio,
+.has-error .checkbox,
+.has-error .radio-inline,
+.has-error .checkbox-inline,
+.has-error.radio label,
+.has-error.checkbox label,
+.has-error.radio-inline label,
+.has-error.checkbox-inline label {
+  color: #a94442;
+}
+.has-error .form-control {
+  border-color: #a94442;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+}
+.has-error .form-control:focus {
+  border-color: #843534;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
+}
+.has-error .input-group-addon {
+  color: #a94442;
+  border-color: #a94442;
+  background-color: #f2dede;
+}
+.has-error .form-control-feedback {
+  color: #a94442;
+}
+.has-feedback label ~ .form-control-feedback {
+  top: 23px;
+}
+.has-feedback label.sr-only ~ .form-control-feedback {
+  top: 0;
+}
+.help-block {
+  display: block;
+  margin-top: 5px;
+  margin-bottom: 10px;
+  color: #404040;
+}
+@media (min-width: 768px) {
+  .form-inline .form-group {
+    display: inline-block;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .form-inline .form-control {
+    display: inline-block;
+    width: auto;
+    vertical-align: middle;
+  }
+  .form-inline .form-control-static {
+    display: inline-block;
+  }
+  .form-inline .input-group {
+    display: inline-table;
+    vertical-align: middle;
+  }
+  .form-inline .input-group .input-group-addon,
+  .form-inline .input-group .input-group-btn,
+  .form-inline .input-group .form-control {
+    width: auto;
+  }
+  .form-inline .input-group > .form-control {
+    width: 100%;
+  }
+  .form-inline .control-label {
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .form-inline .radio,
+  .form-inline .checkbox {
+    display: inline-block;
+    margin-top: 0;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .form-inline .radio label,
+  .form-inline .checkbox label {
+    padding-left: 0;
+  }
+  .form-inline .radio input[type="radio"],
+  .form-inline .checkbox input[type="checkbox"] {
+    position: relative;
+    margin-left: 0;
+  }
+  .form-inline .has-feedback .form-control-feedback {
+    top: 0;
+  }
+}
+.form-horizontal .radio,
+.form-horizontal .checkbox,
+.form-horizontal .radio-inline,
+.form-horizontal .checkbox-inline {
+  margin-top: 0;
+  margin-bottom: 0;
+  padding-top: 7px;
+}
+.form-horizontal .radio,
+.form-horizontal .checkbox {
+  min-height: 25px;
+}
+.form-horizontal .form-group {
+  margin-left: 0px;
+  margin-right: 0px;
+}
+@media (min-width: 768px) {
+  .form-horizontal .control-label {
+    text-align: right;
+    margin-bottom: 0;
+    padding-top: 7px;
+  }
+}
+.form-horizontal .has-feedback .form-control-feedback {
+  right: 0px;
+}
+@media (min-width: 768px) {
+  .form-horizontal .form-group-lg .control-label {
+    padding-top: 11px;
+    font-size: 17px;
+  }
+}
+@media (min-width: 768px) {
+  .form-horizontal .form-group-sm .control-label {
+    padding-top: 6px;
+    font-size: 12px;
+  }
+}
+.btn {
+  display: inline-block;
+  margin-bottom: 0;
+  font-weight: normal;
+  text-align: center;
+  vertical-align: middle;
+  touch-action: manipulation;
+  cursor: pointer;
+  background-image: none;
+  border: 1px solid transparent;
+  white-space: nowrap;
+  padding: 6px 12px;
+  font-size: 13px;
+  line-height: 1.42857143;
+  border-radius: 2px;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+}
+.btn:focus,
+.btn:active:focus,
+.btn.active:focus,
+.btn.focus,
+.btn:active.focus,
+.btn.active.focus {
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+.btn:hover,
+.btn:focus,
+.btn.focus {
+  color: #333;
+  text-decoration: none;
+}
+.btn:active,
+.btn.active {
+  outline: 0;
+  background-image: none;
+  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+}
+.btn.disabled,
+.btn[disabled],
+fieldset[disabled] .btn {
+  cursor: not-allowed;
+  opacity: 0.65;
+  filter: alpha(opacity=65);
+  -webkit-box-shadow: none;
+  box-shadow: none;
+}
+a.btn.disabled,
+fieldset[disabled] a.btn {
+  pointer-events: none;
+}
+.btn-default {
+  color: #333;
+  background-color: #fff;
+  border-color: #ccc;
+}
+.btn-default:focus,
+.btn-default.focus {
+  color: #333;
+  background-color: #e6e6e6;
+  border-color: #8c8c8c;
+}
+.btn-default:hover {
+  color: #333;
+  background-color: #e6e6e6;
+  border-color: #adadad;
+}
+.btn-default:active,
+.btn-default.active,
+.open > .dropdown-toggle.btn-default {
+  color: #333;
+  background-color: #e6e6e6;
+  border-color: #adadad;
+}
+.btn-default:active:hover,
+.btn-default.active:hover,
+.open > .dropdown-toggle.btn-default:hover,
+.btn-default:active:focus,
+.btn-default.active:focus,
+.open > .dropdown-toggle.btn-default:focus,
+.btn-default:active.focus,
+.btn-default.active.focus,
+.open > .dropdown-toggle.btn-default.focus {
+  color: #333;
+  background-color: #d4d4d4;
+  border-color: #8c8c8c;
+}
+.btn-default:active,
+.btn-default.active,
+.open > .dropdown-toggle.btn-default {
+  background-image: none;
+}
+.btn-default.disabled:hover,
+.btn-default[disabled]:hover,
+fieldset[disabled] .btn-default:hover,
+.btn-default.disabled:focus,
+.btn-default[disabled]:focus,
+fieldset[disabled] .btn-default:focus,
+.btn-default.disabled.focus,
+.btn-default[disabled].focus,
+fieldset[disabled] .btn-default.focus {
+  background-color: #fff;
+  border-color: #ccc;
+}
+.btn-default .badge {
+  color: #fff;
+  background-color: #333;
+}
+.btn-primary {
+  color: #fff;
+  background-color: #337ab7;
+  border-color: #2e6da4;
+}
+.btn-primary:focus,
+.btn-primary.focus {
+  color: #fff;
+  background-color: #286090;
+  border-color: #122b40;
+}
+.btn-primary:hover {
+  color: #fff;
+  background-color: #286090;
+  border-color: #204d74;
+}
+.btn-primary:active,
+.btn-primary.active,
+.open > .dropdown-toggle.btn-primary {
+  color: #fff;
+  background-color: #286090;
+  border-color: #204d74;
+}
+.btn-primary:active:hover,
+.btn-primary.active:hover,
+.open > .dropdown-toggle.btn-primary:hover,
+.btn-primary:active:focus,
+.btn-primary.active:focus,
+.open > .dropdown-toggle.btn-primary:focus,
+.btn-primary:active.focus,
+.btn-primary.active.focus,
+.open > .dropdown-toggle.btn-primary.focus {
+  color: #fff;
+  background-color: #204d74;
+  border-color: #122b40;
+}
+.btn-primary:active,
+.btn-primary.active,
+.open > .dropdown-toggle.btn-primary {
+  background-image: none;
+}
+.btn-primary.disabled:hover,
+.btn-primary[disabled]:hover,
+fieldset[disabled] .btn-primary:hover,
+.btn-primary.disabled:focus,
+.btn-primary[disabled]:focus,
+fieldset[disabled] .btn-primary:focus,
+.btn-primary.disabled.focus,
+.btn-primary[disabled].focus,
+fieldset[disabled] .btn-primary.focus {
+  background-color: #337ab7;
+  border-color: #2e6da4;
+}
+.btn-primary .badge {
+  color: #337ab7;
+  background-color: #fff;
+}
+.btn-success {
+  color: #fff;
+  background-color: #5cb85c;
+  border-color: #4cae4c;
+}
+.btn-success:focus,
+.btn-success.focus {
+  color: #fff;
+  background-color: #449d44;
+  border-color: #255625;
+}
+.btn-success:hover {
+  color: #fff;
+  background-color: #449d44;
+  border-color: #398439;
+}
+.btn-success:active,
+.btn-success.active,
+.open > .dropdown-toggle.btn-success {
+  color: #fff;
+  background-color: #449d44;
+  border-color: #398439;
+}
+.btn-success:active:hover,
+.btn-success.active:hover,
+.open > .dropdown-toggle.btn-success:hover,
+.btn-success:active:focus,
+.btn-success.active:focus,
+.open > .dropdown-toggle.btn-success:focus,
+.btn-success:active.focus,
+.btn-success.active.focus,
+.open > .dropdown-toggle.btn-success.focus {
+  color: #fff;
+  background-color: #398439;
+  border-color: #255625;
+}
+.btn-success:active,
+.btn-success.active,
+.open > .dropdown-toggle.btn-success {
+  background-image: none;
+}
+.btn-success.disabled:hover,
+.btn-success[disabled]:hover,
+fieldset[disabled] .btn-success:hover,
+.btn-success.disabled:focus,
+.btn-success[disabled]:focus,
+fieldset[disabled] .btn-success:focus,
+.btn-success.disabled.focus,
+.btn-success[disabled].focus,
+fieldset[disabled] .btn-success.focus {
+  background-color: #5cb85c;
+  border-color: #4cae4c;
+}
+.btn-success .badge {
+  color: #5cb85c;
+  background-color: #fff;
+}
+.btn-info {
+  color: #fff;
+  background-color: #5bc0de;
+  border-color: #46b8da;
+}
+.btn-info:focus,
+.btn-info.focus {
+  color: #fff;
+  background-color: #31b0d5;
+  border-color: #1b6d85;
+}
+.btn-info:hover {
+  color: #fff;
+  background-color: #31b0d5;
+  border-color: #269abc;
+}
+.btn-info:active,
+.btn-info.active,
+.open > .dropdown-toggle.btn-info {
+  color: #fff;
+  background-color: #31b0d5;
+  border-color: #269abc;
+}
+.btn-info:active:hover,
+.btn-info.active:hover,
+.open > .dropdown-toggle.btn-info:hover,
+.btn-info:active:focus,
+.btn-info.active:focus,
+.open > .dropdown-toggle.btn-info:focus,
+.btn-info:active.focus,
+.btn-info.active.focus,
+.open > .dropdown-toggle.btn-info.focus {
+  color: #fff;
+  background-color: #269abc;
+  border-color: #1b6d85;
+}
+.btn-info:active,
+.btn-info.active,
+.open > .dropdown-toggle.btn-info {
+  background-image: none;
+}
+.btn-info.disabled:hover,
+.btn-info[disabled]:hover,
+fieldset[disabled] .btn-info:hover,
+.btn-info.disabled:focus,
+.btn-info[disabled]:focus,
+fieldset[disabled] .btn-info:focus,
+.btn-info.disabled.focus,
+.btn-info[disabled].focus,
+fieldset[disabled] .btn-info.focus {
+  background-color: #5bc0de;
+  border-color: #46b8da;
+}
+.btn-info .badge {
+  color: #5bc0de;
+  background-color: #fff;
+}
+.btn-warning {
+  color: #fff;
+  background-color: #f0ad4e;
+  border-color: #eea236;
+}
+.btn-warning:focus,
+.btn-warning.focus {
+  color: #fff;
+  background-color: #ec971f;
+  border-color: #985f0d;
+}
+.btn-warning:hover {
+  color: #fff;
+  background-color: #ec971f;
+  border-color: #d58512;
+}
+.btn-warning:active,
+.btn-warning.active,
+.open > .dropdown-toggle.btn-warning {
+  color: #fff;
+  background-color: #ec971f;
+  border-color: #d58512;
+}
+.btn-warning:active:hover,
+.btn-warning.active:hover,
+.open > .dropdown-toggle.btn-warning:hover,
+.btn-warning:active:focus,
+.btn-warning.active:focus,
+.open > .dropdown-toggle.btn-warning:focus,
+.btn-warning:active.focus,
+.btn-warning.active.focus,
+.open > .dropdown-toggle.btn-warning.focus {
+  color: #fff;
+  background-color: #d58512;
+  border-color: #985f0d;
+}
+.btn-warning:active,
+.btn-warning.active,
+.open > .dropdown-toggle.btn-warning {
+  background-image: none;
+}
+.btn-warning.disabled:hover,
+.btn-warning[disabled]:hover,
+fieldset[disabled] .btn-warning:hover,
+.btn-warning.disabled:focus,
+.btn-warning[disabled]:focus,
+fieldset[disabled] .btn-warning:focus,
+.btn-warning.disabled.focus,
+.btn-warning[disabled].focus,
+fieldset[disabled] .btn-warning.focus {
+  background-color: #f0ad4e;
+  border-color: #eea236;
+}
+.btn-warning .badge {
+  color: #f0ad4e;
+  background-color: #fff;
+}
+.btn-danger {
+  color: #fff;
+  background-color: #d9534f;
+  border-color: #d43f3a;
+}
+.btn-danger:focus,
+.btn-danger.focus {
+  color: #fff;
+  background-color: #c9302c;
+  border-color: #761c19;
+}
+.btn-danger:hover {
+  color: #fff;
+  background-color: #c9302c;
+  border-color: #ac2925;
+}
+.btn-danger:active,
+.btn-danger.active,
+.open > .dropdown-toggle.btn-danger {
+  color: #fff;
+  background-color: #c9302c;
+  border-color: #ac2925;
+}
+.btn-danger:active:hover,
+.btn-danger.active:hover,
+.open > .dropdown-toggle.btn-danger:hover,
+.btn-danger:active:focus,
+.btn-danger.active:focus,
+.open > .dropdown-toggle.btn-danger:focus,
+.btn-danger:active.focus,
+.btn-danger.active.focus,
+.open > .dropdown-toggle.btn-danger.focus {
+  color: #fff;
+  background-color: #ac2925;
+  border-color: #761c19;
+}
+.btn-danger:active,
+.btn-danger.active,
+.open > .dropdown-toggle.btn-danger {
+  background-image: none;
+}
+.btn-danger.disabled:hover,
+.btn-danger[disabled]:hover,
+fieldset[disabled] .btn-danger:hover,
+.btn-danger.disabled:focus,
+.btn-danger[disabled]:focus,
+fieldset[disabled] .btn-danger:focus,
+.btn-danger.disabled.focus,
+.btn-danger[disabled].focus,
+fieldset[disabled] .btn-danger.focus {
+  background-color: #d9534f;
+  border-color: #d43f3a;
+}
+.btn-danger .badge {
+  color: #d9534f;
+  background-color: #fff;
+}
+.btn-link {
+  color: #337ab7;
+  font-weight: normal;
+  border-radius: 0;
+}
+.btn-link,
+.btn-link:active,
+.btn-link.active,
+.btn-link[disabled],
+fieldset[disabled] .btn-link {
+  background-color: transparent;
+  -webkit-box-shadow: none;
+  box-shadow: none;
+}
+.btn-link,
+.btn-link:hover,
+.btn-link:focus,
+.btn-link:active {
+  border-color: transparent;
+}
+.btn-link:hover,
+.btn-link:focus {
+  color: #23527c;
+  text-decoration: underline;
+  background-color: transparent;
+}
+.btn-link[disabled]:hover,
+fieldset[disabled] .btn-link:hover,
+.btn-link[disabled]:focus,
+fieldset[disabled] .btn-link:focus {
+  color: #777777;
+  text-decoration: none;
+}
+.btn-lg,
+.btn-group-lg > .btn {
+  padding: 10px 16px;
+  font-size: 17px;
+  line-height: 1.3333333;
+  border-radius: 3px;
+}
+.btn-sm,
+.btn-group-sm > .btn {
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 1px;
+}
+.btn-xs,
+.btn-group-xs > .btn {
+  padding: 1px 5px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 1px;
+}
+.btn-block {
+  display: block;
+  width: 100%;
+}
+.btn-block + .btn-block {
+  margin-top: 5px;
+}
+input[type="submit"].btn-block,
+input[type="reset"].btn-block,
+input[type="button"].btn-block {
+  width: 100%;
+}
+.fade {
+  opacity: 0;
+  -webkit-transition: opacity 0.15s linear;
+  -o-transition: opacity 0.15s linear;
+  transition: opacity 0.15s linear;
+}
+.fade.in {
+  opacity: 1;
+}
+.collapse {
+  display: none;
+}
+.collapse.in {
+  display: block;
+}
+tr.collapse.in {
+  display: table-row;
+}
+tbody.collapse.in {
+  display: table-row-group;
+}
+.collapsing {
+  position: relative;
+  height: 0;
+  overflow: hidden;
+  -webkit-transition-property: height, visibility;
+  transition-property: height, visibility;
+  -webkit-transition-duration: 0.35s;
+  transition-duration: 0.35s;
+  -webkit-transition-timing-function: ease;
+  transition-timing-function: ease;
+}
+.caret {
+  display: inline-block;
+  width: 0;
+  height: 0;
+  margin-left: 2px;
+  vertical-align: middle;
+  border-top: 4px dashed;
+  border-top: 4px solid \9;
+  border-right: 4px solid transparent;
+  border-left: 4px solid transparent;
+}
+.dropup,
+.dropdown {
+  position: relative;
+}
+.dropdown-toggle:focus {
+  outline: 0;
+}
+.dropdown-menu {
+  position: absolute;
+  top: 100%;
+  left: 0;
+  z-index: 1000;
+  display: none;
+  float: left;
+  min-width: 160px;
+  padding: 5px 0;
+  margin: 2px 0 0;
+  list-style: none;
+  font-size: 13px;
+  text-align: left;
+  background-color: #fff;
+  border: 1px solid #ccc;
+  border: 1px solid rgba(0, 0, 0, 0.15);
+  border-radius: 2px;
+  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+  background-clip: padding-box;
+}
+.dropdown-menu.pull-right {
+  right: 0;
+  left: auto;
+}
+.dropdown-menu .divider {
+  height: 1px;
+  margin: 8px 0;
+  overflow: hidden;
+  background-color: #e5e5e5;
+}
+.dropdown-menu > li > a {
+  display: block;
+  padding: 3px 20px;
+  clear: both;
+  font-weight: normal;
+  line-height: 1.42857143;
+  color: #333333;
+  white-space: nowrap;
+}
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus {
+  text-decoration: none;
+  color: #262626;
+  background-color: #f5f5f5;
+}
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+  color: #fff;
+  text-decoration: none;
+  outline: 0;
+  background-color: #337ab7;
+}
+.dropdown-menu > .disabled > a,
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+  color: #777777;
+}
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+  text-decoration: none;
+  background-color: transparent;
+  background-image: none;
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  cursor: not-allowed;
+}
+.open > .dropdown-menu {
+  display: block;
+}
+.open > a {
+  outline: 0;
+}
+.dropdown-menu-right {
+  left: auto;
+  right: 0;
+}
+.dropdown-menu-left {
+  left: 0;
+  right: auto;
+}
+.dropdown-header {
+  display: block;
+  padding: 3px 20px;
+  font-size: 12px;
+  line-height: 1.42857143;
+  color: #777777;
+  white-space: nowrap;
+}
+.dropdown-backdrop {
+  position: fixed;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  top: 0;
+  z-index: 990;
+}
+.pull-right > .dropdown-menu {
+  right: 0;
+  left: auto;
+}
+.dropup .caret,
+.navbar-fixed-bottom .dropdown .caret {
+  border-top: 0;
+  border-bottom: 4px dashed;
+  border-bottom: 4px solid \9;
+  content: "";
+}
+.dropup .dropdown-menu,
+.navbar-fixed-bottom .dropdown .dropdown-menu {
+  top: auto;
+  bottom: 100%;
+  margin-bottom: 2px;
+}
+@media (min-width: 541px) {
+  .navbar-right .dropdown-menu {
+    left: auto;
+    right: 0;
+  }
+  .navbar-right .dropdown-menu-left {
+    left: 0;
+    right: auto;
+  }
+}
+.btn-group,
+.btn-group-vertical {
+  position: relative;
+  display: inline-block;
+  vertical-align: middle;
+}
+.btn-group > .btn,
+.btn-group-vertical > .btn {
+  position: relative;
+  float: left;
+}
+.btn-group > .btn:hover,
+.btn-group-vertical > .btn:hover,
+.btn-group > .btn:focus,
+.btn-group-vertical > .btn:focus,
+.btn-group > .btn:active,
+.btn-group-vertical > .btn:active,
+.btn-group > .btn.active,
+.btn-group-vertical > .btn.active {
+  z-index: 2;
+}
+.btn-group .btn + .btn,
+.btn-group .btn + .btn-group,
+.btn-group .btn-group + .btn,
+.btn-group .btn-group + .btn-group {
+  margin-left: -1px;
+}
+.btn-toolbar {
+  margin-left: -5px;
+}
+.btn-toolbar .btn,
+.btn-toolbar .btn-group,
+.btn-toolbar .input-group {
+  float: left;
+}
+.btn-toolbar > .btn,
+.btn-toolbar > .btn-group,
+.btn-toolbar > .input-group {
+  margin-left: 5px;
+}
+.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {
+  border-radius: 0;
+}
+.btn-group > .btn:first-child {
+  margin-left: 0;
+}
+.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {
+  border-bottom-right-radius: 0;
+  border-top-right-radius: 0;
+}
+.btn-group > .btn:last-child:not(:first-child),
+.btn-group > .dropdown-toggle:not(:first-child) {
+  border-bottom-left-radius: 0;
+  border-top-left-radius: 0;
+}
+.btn-group > .btn-group {
+  float: left;
+}
+.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {
+  border-radius: 0;
+}
+.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,
+.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
+  border-bottom-right-radius: 0;
+  border-top-right-radius: 0;
+}
+.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {
+  border-bottom-left-radius: 0;
+  border-top-left-radius: 0;
+}
+.btn-group .dropdown-toggle:active,
+.btn-group.open .dropdown-toggle {
+  outline: 0;
+}
+.btn-group > .btn + .dropdown-toggle {
+  padding-left: 8px;
+  padding-right: 8px;
+}
+.btn-group > .btn-lg + .dropdown-toggle {
+  padding-left: 12px;
+  padding-right: 12px;
+}
+.btn-group.open .dropdown-toggle {
+  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+}
+.btn-group.open .dropdown-toggle.btn-link {
+  -webkit-box-shadow: none;
+  box-shadow: none;
+}
+.btn .caret {
+  margin-left: 0;
+}
+.btn-lg .caret {
+  border-width: 5px 5px 0;
+  border-bottom-width: 0;
+}
+.dropup .btn-lg .caret {
+  border-width: 0 5px 5px;
+}
+.btn-group-vertical > .btn,
+.btn-group-vertical > .btn-group,
+.btn-group-vertical > .btn-group > .btn {
+  display: block;
+  float: none;
+  width: 100%;
+  max-width: 100%;
+}
+.btn-group-vertical > .btn-group > .btn {
+  float: none;
+}
+.btn-group-vertical > .btn + .btn,
+.btn-group-vertical > .btn + .btn-group,
+.btn-group-vertical > .btn-group + .btn,
+.btn-group-vertical > .btn-group + .btn-group {
+  margin-top: -1px;
+  margin-left: 0;
+}
+.btn-group-vertical > .btn:not(:first-child):not(:last-child) {
+  border-radius: 0;
+}
+.btn-group-vertical > .btn:first-child:not(:last-child) {
+  border-top-right-radius: 2px;
+  border-top-left-radius: 2px;
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.btn-group-vertical > .btn:last-child:not(:first-child) {
+  border-top-right-radius: 0;
+  border-top-left-radius: 0;
+  border-bottom-right-radius: 2px;
+  border-bottom-left-radius: 2px;
+}
+.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {
+  border-radius: 0;
+}
+.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,
+.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {
+  border-top-right-radius: 0;
+  border-top-left-radius: 0;
+}
+.btn-group-justified {
+  display: table;
+  width: 100%;
+  table-layout: fixed;
+  border-collapse: separate;
+}
+.btn-group-justified > .btn,
+.btn-group-justified > .btn-group {
+  float: none;
+  display: table-cell;
+  width: 1%;
+}
+.btn-group-justified > .btn-group .btn {
+  width: 100%;
+}
+.btn-group-justified > .btn-group .dropdown-menu {
+  left: auto;
+}
+[data-toggle="buttons"] > .btn input[type="radio"],
+[data-toggle="buttons"] > .btn-group > .btn input[type="radio"],
+[data-toggle="buttons"] > .btn input[type="checkbox"],
+[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] {
+  position: absolute;
+  clip: rect(0, 0, 0, 0);
+  pointer-events: none;
+}
+.input-group {
+  position: relative;
+  display: table;
+  border-collapse: separate;
+}
+.input-group[class*="col-"] {
+  float: none;
+  padding-left: 0;
+  padding-right: 0;
+}
+.input-group .form-control {
+  position: relative;
+  z-index: 2;
+  float: left;
+  width: 100%;
+  margin-bottom: 0;
+}
+.input-group .form-control:focus {
+  z-index: 3;
+}
+.input-group-lg > .form-control,
+.input-group-lg > .input-group-addon,
+.input-group-lg > .input-group-btn > .btn {
+  height: 45px;
+  padding: 10px 16px;
+  font-size: 17px;
+  line-height: 1.3333333;
+  border-radius: 3px;
+}
+select.input-group-lg > .form-control,
+select.input-group-lg > .input-group-addon,
+select.input-group-lg > .input-group-btn > .btn {
+  height: 45px;
+  line-height: 45px;
+}
+textarea.input-group-lg > .form-control,
+textarea.input-group-lg > .input-group-addon,
+textarea.input-group-lg > .input-group-btn > .btn,
+select[multiple].input-group-lg > .form-control,
+select[multiple].input-group-lg > .input-group-addon,
+select[multiple].input-group-lg > .input-group-btn > .btn {
+  height: auto;
+}
+.input-group-sm > .form-control,
+.input-group-sm > .input-group-addon,
+.input-group-sm > .input-group-btn > .btn {
+  height: 30px;
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 1px;
+}
+select.input-group-sm > .form-control,
+select.input-group-sm > .input-group-addon,
+select.input-group-sm > .input-group-btn > .btn {
+  height: 30px;
+  line-height: 30px;
+}
+textarea.input-group-sm > .form-control,
+textarea.input-group-sm > .input-group-addon,
+textarea.input-group-sm > .input-group-btn > .btn,
+select[multiple].input-group-sm > .form-control,
+select[multiple].input-group-sm > .input-group-addon,
+select[multiple].input-group-sm > .input-group-btn > .btn {
+  height: auto;
+}
+.input-group-addon,
+.input-group-btn,
+.input-group .form-control {
+  display: table-cell;
+}
+.input-group-addon:not(:first-child):not(:last-child),
+.input-group-btn:not(:first-child):not(:last-child),
+.input-group .form-control:not(:first-child):not(:last-child) {
+  border-radius: 0;
+}
+.input-group-addon,
+.input-group-btn {
+  width: 1%;
+  white-space: nowrap;
+  vertical-align: middle;
+}
+.input-group-addon {
+  padding: 6px 12px;
+  font-size: 13px;
+  font-weight: normal;
+  line-height: 1;
+  color: #555555;
+  text-align: center;
+  background-color: #eeeeee;
+  border: 1px solid #ccc;
+  border-radius: 2px;
+}
+.input-group-addon.input-sm {
+  padding: 5px 10px;
+  font-size: 12px;
+  border-radius: 1px;
+}
+.input-group-addon.input-lg {
+  padding: 10px 16px;
+  font-size: 17px;
+  border-radius: 3px;
+}
+.input-group-addon input[type="radio"],
+.input-group-addon input[type="checkbox"] {
+  margin-top: 0;
+}
+.input-group .form-control:first-child,
+.input-group-addon:first-child,
+.input-group-btn:first-child > .btn,
+.input-group-btn:first-child > .btn-group > .btn,
+.input-group-btn:first-child > .dropdown-toggle,
+.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),
+.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {
+  border-bottom-right-radius: 0;
+  border-top-right-radius: 0;
+}
+.input-group-addon:first-child {
+  border-right: 0;
+}
+.input-group .form-control:last-child,
+.input-group-addon:last-child,
+.input-group-btn:last-child > .btn,
+.input-group-btn:last-child > .btn-group > .btn,
+.input-group-btn:last-child > .dropdown-toggle,
+.input-group-btn:first-child > .btn:not(:first-child),
+.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {
+  border-bottom-left-radius: 0;
+  border-top-left-radius: 0;
+}
+.input-group-addon:last-child {
+  border-left: 0;
+}
+.input-group-btn {
+  position: relative;
+  font-size: 0;
+  white-space: nowrap;
+}
+.input-group-btn > .btn {
+  position: relative;
+}
+.input-group-btn > .btn + .btn {
+  margin-left: -1px;
+}
+.input-group-btn > .btn:hover,
+.input-group-btn > .btn:focus,
+.input-group-btn > .btn:active {
+  z-index: 2;
+}
+.input-group-btn:first-child > .btn,
+.input-group-btn:first-child > .btn-group {
+  margin-right: -1px;
+}
+.input-group-btn:last-child > .btn,
+.input-group-btn:last-child > .btn-group {
+  z-index: 2;
+  margin-left: -1px;
+}
+.nav {
+  margin-bottom: 0;
+  padding-left: 0;
+  list-style: none;
+}
+.nav > li {
+  position: relative;
+  display: block;
+}
+.nav > li > a {
+  position: relative;
+  display: block;
+  padding: 10px 15px;
+}
+.nav > li > a:hover,
+.nav > li > a:focus {
+  text-decoration: none;
+  background-color: #eeeeee;
+}
+.nav > li.disabled > a {
+  color: #777777;
+}
+.nav > li.disabled > a:hover,
+.nav > li.disabled > a:focus {
+  color: #777777;
+  text-decoration: none;
+  background-color: transparent;
+  cursor: not-allowed;
+}
+.nav .open > a,
+.nav .open > a:hover,
+.nav .open > a:focus {
+  background-color: #eeeeee;
+  border-color: #337ab7;
+}
+.nav .nav-divider {
+  height: 1px;
+  margin: 8px 0;
+  overflow: hidden;
+  background-color: #e5e5e5;
+}
+.nav > li > a > img {
+  max-width: none;
+}
+.nav-tabs {
+  border-bottom: 1px solid #ddd;
+}
+.nav-tabs > li {
+  float: left;
+  margin-bottom: -1px;
+}
+.nav-tabs > li > a {
+  margin-right: 2px;
+  line-height: 1.42857143;
+  border: 1px solid transparent;
+  border-radius: 2px 2px 0 0;
+}
+.nav-tabs > li > a:hover {
+  border-color: #eeeeee #eeeeee #ddd;
+}
+.nav-tabs > li.active > a,
+.nav-tabs > li.active > a:hover,
+.nav-tabs > li.active > a:focus {
+  color: #555555;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-bottom-color: transparent;
+  cursor: default;
+}
+.nav-tabs.nav-justified {
+  width: 100%;
+  border-bottom: 0;
+}
+.nav-tabs.nav-justified > li {
+  float: none;
+}
+.nav-tabs.nav-justified > li > a {
+  text-align: center;
+  margin-bottom: 5px;
+}
+.nav-tabs.nav-justified > .dropdown .dropdown-menu {
+  top: auto;
+  left: auto;
+}
+@media (min-width: 768px) {
+  .nav-tabs.nav-justified > li {
+    display: table-cell;
+    width: 1%;
+  }
+  .nav-tabs.nav-justified > li > a {
+    margin-bottom: 0;
+  }
+}
+.nav-tabs.nav-justified > li > a {
+  margin-right: 0;
+  border-radius: 2px;
+}
+.nav-tabs.nav-justified > .active > a,
+.nav-tabs.nav-justified > .active > a:hover,
+.nav-tabs.nav-justified > .active > a:focus {
+  border: 1px solid #ddd;
+}
+@media (min-width: 768px) {
+  .nav-tabs.nav-justified > li > a {
+    border-bottom: 1px solid #ddd;
+    border-radius: 2px 2px 0 0;
+  }
+  .nav-tabs.nav-justified > .active > a,
+  .nav-tabs.nav-justified > .active > a:hover,
+  .nav-tabs.nav-justified > .active > a:focus {
+    border-bottom-color: #fff;
+  }
+}
+.nav-pills > li {
+  float: left;
+}
+.nav-pills > li > a {
+  border-radius: 2px;
+}
+.nav-pills > li + li {
+  margin-left: 2px;
+}
+.nav-pills > li.active > a,
+.nav-pills > li.active > a:hover,
+.nav-pills > li.active > a:focus {
+  color: #fff;
+  background-color: #337ab7;
+}
+.nav-stacked > li {
+  float: none;
+}
+.nav-stacked > li + li {
+  margin-top: 2px;
+  margin-left: 0;
+}
+.nav-justified {
+  width: 100%;
+}
+.nav-justified > li {
+  float: none;
+}
+.nav-justified > li > a {
+  text-align: center;
+  margin-bottom: 5px;
+}
+.nav-justified > .dropdown .dropdown-menu {
+  top: auto;
+  left: auto;
+}
+@media (min-width: 768px) {
+  .nav-justified > li {
+    display: table-cell;
+    width: 1%;
+  }
+  .nav-justified > li > a {
+    margin-bottom: 0;
+  }
+}
+.nav-tabs-justified {
+  border-bottom: 0;
+}
+.nav-tabs-justified > li > a {
+  margin-right: 0;
+  border-radius: 2px;
+}
+.nav-tabs-justified > .active > a,
+.nav-tabs-justified > .active > a:hover,
+.nav-tabs-justified > .active > a:focus {
+  border: 1px solid #ddd;
+}
+@media (min-width: 768px) {
+  .nav-tabs-justified > li > a {
+    border-bottom: 1px solid #ddd;
+    border-radius: 2px 2px 0 0;
+  }
+  .nav-tabs-justified > .active > a,
+  .nav-tabs-justified > .active > a:hover,
+  .nav-tabs-justified > .active > a:focus {
+    border-bottom-color: #fff;
+  }
+}
+.tab-content > .tab-pane {
+  display: none;
+}
+.tab-content > .active {
+  display: block;
+}
+.nav-tabs .dropdown-menu {
+  margin-top: -1px;
+  border-top-right-radius: 0;
+  border-top-left-radius: 0;
+}
+.navbar {
+  position: relative;
+  min-height: 30px;
+  margin-bottom: 18px;
+  border: 1px solid transparent;
+}
+@media (min-width: 541px) {
+  .navbar {
+    border-radius: 2px;
+  }
+}
+@media (min-width: 541px) {
+  .navbar-header {
+    float: left;
+  }
+}
+.navbar-collapse {
+  overflow-x: visible;
+  padding-right: 0px;
+  padding-left: 0px;
+  border-top: 1px solid transparent;
+  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);
+  -webkit-overflow-scrolling: touch;
+}
+.navbar-collapse.in {
+  overflow-y: auto;
+}
+@media (min-width: 541px) {
+  .navbar-collapse {
+    width: auto;
+    border-top: 0;
+    box-shadow: none;
+  }
+  .navbar-collapse.collapse {
+    display: block !important;
+    height: auto !important;
+    padding-bottom: 0;
+    overflow: visible !important;
+  }
+  .navbar-collapse.in {
+    overflow-y: visible;
+  }
+  .navbar-fixed-top .navbar-collapse,
+  .navbar-static-top .navbar-collapse,
+  .navbar-fixed-bottom .navbar-collapse {
+    padding-left: 0;
+    padding-right: 0;
+  }
+}
+.navbar-fixed-top .navbar-collapse,
+.navbar-fixed-bottom .navbar-collapse {
+  max-height: 340px;
+}
+@media (max-device-width: 540px) and (orientation: landscape) {
+  .navbar-fixed-top .navbar-collapse,
+  .navbar-fixed-bottom .navbar-collapse {
+    max-height: 200px;
+  }
+}
+.container > .navbar-header,
+.container-fluid > .navbar-header,
+.container > .navbar-collapse,
+.container-fluid > .navbar-collapse {
+  margin-right: 0px;
+  margin-left: 0px;
+}
+@media (min-width: 541px) {
+  .container > .navbar-header,
+  .container-fluid > .navbar-header,
+  .container > .navbar-collapse,
+  .container-fluid > .navbar-collapse {
+    margin-right: 0;
+    margin-left: 0;
+  }
+}
+.navbar-static-top {
+  z-index: 1000;
+  border-width: 0 0 1px;
+}
+@media (min-width: 541px) {
+  .navbar-static-top {
+    border-radius: 0;
+  }
+}
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+  position: fixed;
+  right: 0;
+  left: 0;
+  z-index: 1030;
+}
+@media (min-width: 541px) {
+  .navbar-fixed-top,
+  .navbar-fixed-bottom {
+    border-radius: 0;
+  }
+}
+.navbar-fixed-top {
+  top: 0;
+  border-width: 0 0 1px;
+}
+.navbar-fixed-bottom {
+  bottom: 0;
+  margin-bottom: 0;
+  border-width: 1px 0 0;
+}
+.navbar-brand {
+  float: left;
+  padding: 6px 0px;
+  font-size: 17px;
+  line-height: 18px;
+  height: 30px;
+}
+.navbar-brand:hover,
+.navbar-brand:focus {
+  text-decoration: none;
+}
+.navbar-brand > img {
+  display: block;
+}
+@media (min-width: 541px) {
+  .navbar > .container .navbar-brand,
+  .navbar > .container-fluid .navbar-brand {
+    margin-left: 0px;
+  }
+}
+.navbar-toggle {
+  position: relative;
+  float: right;
+  margin-right: 0px;
+  padding: 9px 10px;
+  margin-top: -2px;
+  margin-bottom: -2px;
+  background-color: transparent;
+  background-image: none;
+  border: 1px solid transparent;
+  border-radius: 2px;
+}
+.navbar-toggle:focus {
+  outline: 0;
+}
+.navbar-toggle .icon-bar {
+  display: block;
+  width: 22px;
+  height: 2px;
+  border-radius: 1px;
+}
+.navbar-toggle .icon-bar + .icon-bar {
+  margin-top: 4px;
+}
+@media (min-width: 541px) {
+  .navbar-toggle {
+    display: none;
+  }
+}
+.navbar-nav {
+  margin: 3px 0px;
+}
+.navbar-nav > li > a {
+  padding-top: 10px;
+  padding-bottom: 10px;
+  line-height: 18px;
+}
+@media (max-width: 540px) {
+  .navbar-nav .open .dropdown-menu {
+    position: static;
+    float: none;
+    width: auto;
+    margin-top: 0;
+    background-color: transparent;
+    border: 0;
+    box-shadow: none;
+  }
+  .navbar-nav .open .dropdown-menu > li > a,
+  .navbar-nav .open .dropdown-menu .dropdown-header {
+    padding: 5px 15px 5px 25px;
+  }
+  .navbar-nav .open .dropdown-menu > li > a {
+    line-height: 18px;
+  }
+  .navbar-nav .open .dropdown-menu > li > a:hover,
+  .navbar-nav .open .dropdown-menu > li > a:focus {
+    background-image: none;
+  }
+}
+@media (min-width: 541px) {
+  .navbar-nav {
+    float: left;
+    margin: 0;
+  }
+  .navbar-nav > li {
+    float: left;
+  }
+  .navbar-nav > li > a {
+    padding-top: 6px;
+    padding-bottom: 6px;
+  }
+}
+.navbar-form {
+  margin-left: 0px;
+  margin-right: 0px;
+  padding: 10px 0px;
+  border-top: 1px solid transparent;
+  border-bottom: 1px solid transparent;
+  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+  margin-top: -1px;
+  margin-bottom: -1px;
+}
+@media (min-width: 768px) {
+  .navbar-form .form-group {
+    display: inline-block;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .navbar-form .form-control {
+    display: inline-block;
+    width: auto;
+    vertical-align: middle;
+  }
+  .navbar-form .form-control-static {
+    display: inline-block;
+  }
+  .navbar-form .input-group {
+    display: inline-table;
+    vertical-align: middle;
+  }
+  .navbar-form .input-group .input-group-addon,
+  .navbar-form .input-group .input-group-btn,
+  .navbar-form .input-group .form-control {
+    width: auto;
+  }
+  .navbar-form .input-group > .form-control {
+    width: 100%;
+  }
+  .navbar-form .control-label {
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .navbar-form .radio,
+  .navbar-form .checkbox {
+    display: inline-block;
+    margin-top: 0;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .navbar-form .radio label,
+  .navbar-form .checkbox label {
+    padding-left: 0;
+  }
+  .navbar-form .radio input[type="radio"],
+  .navbar-form .checkbox input[type="checkbox"] {
+    position: relative;
+    margin-left: 0;
+  }
+  .navbar-form .has-feedback .form-control-feedback {
+    top: 0;
+  }
+}
+@media (max-width: 540px) {
+  .navbar-form .form-group {
+    margin-bottom: 5px;
+  }
+  .navbar-form .form-group:last-child {
+    margin-bottom: 0;
+  }
+}
+@media (min-width: 541px) {
+  .navbar-form {
+    width: auto;
+    border: 0;
+    margin-left: 0;
+    margin-right: 0;
+    padding-top: 0;
+    padding-bottom: 0;
+    -webkit-box-shadow: none;
+    box-shadow: none;
+  }
+}
+.navbar-nav > li > .dropdown-menu {
+  margin-top: 0;
+  border-top-right-radius: 0;
+  border-top-left-radius: 0;
+}
+.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {
+  margin-bottom: 0;
+  border-top-right-radius: 2px;
+  border-top-left-radius: 2px;
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.navbar-btn {
+  margin-top: -1px;
+  margin-bottom: -1px;
+}
+.navbar-btn.btn-sm {
+  margin-top: 0px;
+  margin-bottom: 0px;
+}
+.navbar-btn.btn-xs {
+  margin-top: 4px;
+  margin-bottom: 4px;
+}
+.navbar-text {
+  margin-top: 6px;
+  margin-bottom: 6px;
+}
+@media (min-width: 541px) {
+  .navbar-text {
+    float: left;
+    margin-left: 0px;
+    margin-right: 0px;
+  }
+}
+@media (min-width: 541px) {
+  .navbar-left {
+    float: left !important;
+    float: left;
+  }
+  .navbar-right {
+    float: right !important;
+    float: right;
+    margin-right: 0px;
+  }
+  .navbar-right ~ .navbar-right {
+    margin-right: 0;
+  }
+}
+.navbar-default {
+  background-color: #f8f8f8;
+  border-color: #e7e7e7;
+}
+.navbar-default .navbar-brand {
+  color: #777;
+}
+.navbar-default .navbar-brand:hover,
+.navbar-default .navbar-brand:focus {
+  color: #5e5e5e;
+  background-color: transparent;
+}
+.navbar-default .navbar-text {
+  color: #777;
+}
+.navbar-default .navbar-nav > li > a {
+  color: #777;
+}
+.navbar-default .navbar-nav > li > a:hover,
+.navbar-default .navbar-nav > li > a:focus {
+  color: #333;
+  background-color: transparent;
+}
+.navbar-default .navbar-nav > .active > a,
+.navbar-default .navbar-nav > .active > a:hover,
+.navbar-default .navbar-nav > .active > a:focus {
+  color: #555;
+  background-color: #e7e7e7;
+}
+.navbar-default .navbar-nav > .disabled > a,
+.navbar-default .navbar-nav > .disabled > a:hover,
+.navbar-default .navbar-nav > .disabled > a:focus {
+  color: #ccc;
+  background-color: transparent;
+}
+.navbar-default .navbar-toggle {
+  border-color: #ddd;
+}
+.navbar-default .navbar-toggle:hover,
+.navbar-default .navbar-toggle:focus {
+  background-color: #ddd;
+}
+.navbar-default .navbar-toggle .icon-bar {
+  background-color: #888;
+}
+.navbar-default .navbar-collapse,
+.navbar-default .navbar-form {
+  border-color: #e7e7e7;
+}
+.navbar-default .navbar-nav > .open > a,
+.navbar-default .navbar-nav > .open > a:hover,
+.navbar-default .navbar-nav > .open > a:focus {
+  background-color: #e7e7e7;
+  color: #555;
+}
+@media (max-width: 540px) {
+  .navbar-default .navbar-nav .open .dropdown-menu > li > a {
+    color: #777;
+  }
+  .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,
+  .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {
+    color: #333;
+    background-color: transparent;
+  }
+  .navbar-default .navbar-nav .open .dropdown-menu > .active > a,
+  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,
+  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {
+    color: #555;
+    background-color: #e7e7e7;
+  }
+  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,
+  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,
+  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {
+    color: #ccc;
+    background-color: transparent;
+  }
+}
+.navbar-default .navbar-link {
+  color: #777;
+}
+.navbar-default .navbar-link:hover {
+  color: #333;
+}
+.navbar-default .btn-link {
+  color: #777;
+}
+.navbar-default .btn-link:hover,
+.navbar-default .btn-link:focus {
+  color: #333;
+}
+.navbar-default .btn-link[disabled]:hover,
+fieldset[disabled] .navbar-default .btn-link:hover,
+.navbar-default .btn-link[disabled]:focus,
+fieldset[disabled] .navbar-default .btn-link:focus {
+  color: #ccc;
+}
+.navbar-inverse {
+  background-color: #222;
+  border-color: #080808;
+}
+.navbar-inverse .navbar-brand {
+  color: #9d9d9d;
+}
+.navbar-inverse .navbar-brand:hover,
+.navbar-inverse .navbar-brand:focus {
+  color: #fff;
+  background-color: transparent;
+}
+.navbar-inverse .navbar-text {
+  color: #9d9d9d;
+}
+.navbar-inverse .navbar-nav > li > a {
+  color: #9d9d9d;
+}
+.navbar-inverse .navbar-nav > li > a:hover,
+.navbar-inverse .navbar-nav > li > a:focus {
+  color: #fff;
+  background-color: transparent;
+}
+.navbar-inverse .navbar-nav > .active > a,
+.navbar-inverse .navbar-nav > .active > a:hover,
+.navbar-inverse .navbar-nav > .active > a:focus {
+  color: #fff;
+  background-color: #080808;
+}
+.navbar-inverse .navbar-nav > .disabled > a,
+.navbar-inverse .navbar-nav > .disabled > a:hover,
+.navbar-inverse .navbar-nav > .disabled > a:focus {
+  color: #444;
+  background-color: transparent;
+}
+.navbar-inverse .navbar-toggle {
+  border-color: #333;
+}
+.navbar-inverse .navbar-toggle:hover,
+.navbar-inverse .navbar-toggle:focus {
+  background-color: #333;
+}
+.navbar-inverse .navbar-toggle .icon-bar {
+  background-color: #fff;
+}
+.navbar-inverse .navbar-collapse,
+.navbar-inverse .navbar-form {
+  border-color: #101010;
+}
+.navbar-inverse .navbar-nav > .open > a,
+.navbar-inverse .navbar-nav > .open > a:hover,
+.navbar-inverse .navbar-nav > .open > a:focus {
+  background-color: #080808;
+  color: #fff;
+}
+@media (max-width: 540px) {
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {
+    border-color: #080808;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu .divider {
+    background-color: #080808;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {
+    color: #9d9d9d;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {
+    color: #fff;
+    background-color: transparent;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {
+    color: #fff;
+    background-color: #080808;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {
+    color: #444;
+    background-color: transparent;
+  }
+}
+.navbar-inverse .navbar-link {
+  color: #9d9d9d;
+}
+.navbar-inverse .navbar-link:hover {
+  color: #fff;
+}
+.navbar-inverse .btn-link {
+  color: #9d9d9d;
+}
+.navbar-inverse .btn-link:hover,
+.navbar-inverse .btn-link:focus {
+  color: #fff;
+}
+.navbar-inverse .btn-link[disabled]:hover,
+fieldset[disabled] .navbar-inverse .btn-link:hover,
+.navbar-inverse .btn-link[disabled]:focus,
+fieldset[disabled] .navbar-inverse .btn-link:focus {
+  color: #444;
+}
+.breadcrumb {
+  padding: 8px 15px;
+  margin-bottom: 18px;
+  list-style: none;
+  background-color: #f5f5f5;
+  border-radius: 2px;
+}
+.breadcrumb > li {
+  display: inline-block;
+}
+.breadcrumb > li + li:before {
+  content: "/\00a0";
+  padding: 0 5px;
+  color: #5e5e5e;
+}
+.breadcrumb > .active {
+  color: #777777;
+}
+.pagination {
+  display: inline-block;
+  padding-left: 0;
+  margin: 18px 0;
+  border-radius: 2px;
+}
+.pagination > li {
+  display: inline;
+}
+.pagination > li > a,
+.pagination > li > span {
+  position: relative;
+  float: left;
+  padding: 6px 12px;
+  line-height: 1.42857143;
+  text-decoration: none;
+  color: #337ab7;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  margin-left: -1px;
+}
+.pagination > li:first-child > a,
+.pagination > li:first-child > span {
+  margin-left: 0;
+  border-bottom-left-radius: 2px;
+  border-top-left-radius: 2px;
+}
+.pagination > li:last-child > a,
+.pagination > li:last-child > span {
+  border-bottom-right-radius: 2px;
+  border-top-right-radius: 2px;
+}
+.pagination > li > a:hover,
+.pagination > li > span:hover,
+.pagination > li > a:focus,
+.pagination > li > span:focus {
+  z-index: 2;
+  color: #23527c;
+  background-color: #eeeeee;
+  border-color: #ddd;
+}
+.pagination > .active > a,
+.pagination > .active > span,
+.pagination > .active > a:hover,
+.pagination > .active > span:hover,
+.pagination > .active > a:focus,
+.pagination > .active > span:focus {
+  z-index: 3;
+  color: #fff;
+  background-color: #337ab7;
+  border-color: #337ab7;
+  cursor: default;
+}
+.pagination > .disabled > span,
+.pagination > .disabled > span:hover,
+.pagination > .disabled > span:focus,
+.pagination > .disabled > a,
+.pagination > .disabled > a:hover,
+.pagination > .disabled > a:focus {
+  color: #777777;
+  background-color: #fff;
+  border-color: #ddd;
+  cursor: not-allowed;
+}
+.pagination-lg > li > a,
+.pagination-lg > li > span {
+  padding: 10px 16px;
+  font-size: 17px;
+  line-height: 1.3333333;
+}
+.pagination-lg > li:first-child > a,
+.pagination-lg > li:first-child > span {
+  border-bottom-left-radius: 3px;
+  border-top-left-radius: 3px;
+}
+.pagination-lg > li:last-child > a,
+.pagination-lg > li:last-child > span {
+  border-bottom-right-radius: 3px;
+  border-top-right-radius: 3px;
+}
+.pagination-sm > li > a,
+.pagination-sm > li > span {
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+}
+.pagination-sm > li:first-child > a,
+.pagination-sm > li:first-child > span {
+  border-bottom-left-radius: 1px;
+  border-top-left-radius: 1px;
+}
+.pagination-sm > li:last-child > a,
+.pagination-sm > li:last-child > span {
+  border-bottom-right-radius: 1px;
+  border-top-right-radius: 1px;
+}
+.pager {
+  padding-left: 0;
+  margin: 18px 0;
+  list-style: none;
+  text-align: center;
+}
+.pager li {
+  display: inline;
+}
+.pager li > a,
+.pager li > span {
+  display: inline-block;
+  padding: 5px 14px;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-radius: 15px;
+}
+.pager li > a:hover,
+.pager li > a:focus {
+  text-decoration: none;
+  background-color: #eeeeee;
+}
+.pager .next > a,
+.pager .next > span {
+  float: right;
+}
+.pager .previous > a,
+.pager .previous > span {
+  float: left;
+}
+.pager .disabled > a,
+.pager .disabled > a:hover,
+.pager .disabled > a:focus,
+.pager .disabled > span {
+  color: #777777;
+  background-color: #fff;
+  cursor: not-allowed;
+}
+.label {
+  display: inline;
+  padding: .2em .6em .3em;
+  font-size: 75%;
+  font-weight: bold;
+  line-height: 1;
+  color: #fff;
+  text-align: center;
+  white-space: nowrap;
+  vertical-align: baseline;
+  border-radius: .25em;
+}
+a.label:hover,
+a.label:focus {
+  color: #fff;
+  text-decoration: none;
+  cursor: pointer;
+}
+.label:empty {
+  display: none;
+}
+.btn .label {
+  position: relative;
+  top: -1px;
+}
+.label-default {
+  background-color: #777777;
+}
+.label-default[href]:hover,
+.label-default[href]:focus {
+  background-color: #5e5e5e;
+}
+.label-primary {
+  background-color: #337ab7;
+}
+.label-primary[href]:hover,
+.label-primary[href]:focus {
+  background-color: #286090;
+}
+.label-success {
+  background-color: #5cb85c;
+}
+.label-success[href]:hover,
+.label-success[href]:focus {
+  background-color: #449d44;
+}
+.label-info {
+  background-color: #5bc0de;
+}
+.label-info[href]:hover,
+.label-info[href]:focus {
+  background-color: #31b0d5;
+}
+.label-warning {
+  background-color: #f0ad4e;
+}
+.label-warning[href]:hover,
+.label-warning[href]:focus {
+  background-color: #ec971f;
+}
+.label-danger {
+  background-color: #d9534f;
+}
+.label-danger[href]:hover,
+.label-danger[href]:focus {
+  background-color: #c9302c;
+}
+.badge {
+  display: inline-block;
+  min-width: 10px;
+  padding: 3px 7px;
+  font-size: 12px;
+  font-weight: bold;
+  color: #fff;
+  line-height: 1;
+  vertical-align: middle;
+  white-space: nowrap;
+  text-align: center;
+  background-color: #777777;
+  border-radius: 10px;
+}
+.badge:empty {
+  display: none;
+}
+.btn .badge {
+  position: relative;
+  top: -1px;
+}
+.btn-xs .badge,
+.btn-group-xs > .btn .badge {
+  top: 0;
+  padding: 1px 5px;
+}
+a.badge:hover,
+a.badge:focus {
+  color: #fff;
+  text-decoration: none;
+  cursor: pointer;
+}
+.list-group-item.active > .badge,
+.nav-pills > .active > a > .badge {
+  color: #337ab7;
+  background-color: #fff;
+}
+.list-group-item > .badge {
+  float: right;
+}
+.list-group-item > .badge + .badge {
+  margin-right: 5px;
+}
+.nav-pills > li > a > .badge {
+  margin-left: 3px;
+}
+.jumbotron {
+  padding-top: 30px;
+  padding-bottom: 30px;
+  margin-bottom: 30px;
+  color: inherit;
+  background-color: #eeeeee;
+}
+.jumbotron h1,
+.jumbotron .h1 {
+  color: inherit;
+}
+.jumbotron p {
+  margin-bottom: 15px;
+  font-size: 20px;
+  font-weight: 200;
+}
+.jumbotron > hr {
+  border-top-color: #d5d5d5;
+}
+.container .jumbotron,
+.container-fluid .jumbotron {
+  border-radius: 3px;
+  padding-left: 0px;
+  padding-right: 0px;
+}
+.jumbotron .container {
+  max-width: 100%;
+}
+@media screen and (min-width: 768px) {
+  .jumbotron {
+    padding-top: 48px;
+    padding-bottom: 48px;
+  }
+  .container .jumbotron,
+  .container-fluid .jumbotron {
+    padding-left: 60px;
+    padding-right: 60px;
+  }
+  .jumbotron h1,
+  .jumbotron .h1 {
+    font-size: 59px;
+  }
+}
+.thumbnail {
+  display: block;
+  padding: 4px;
+  margin-bottom: 18px;
+  line-height: 1.42857143;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-radius: 2px;
+  -webkit-transition: border 0.2s ease-in-out;
+  -o-transition: border 0.2s ease-in-out;
+  transition: border 0.2s ease-in-out;
+}
+.thumbnail > img,
+.thumbnail a > img {
+  margin-left: auto;
+  margin-right: auto;
+}
+a.thumbnail:hover,
+a.thumbnail:focus,
+a.thumbnail.active {
+  border-color: #337ab7;
+}
+.thumbnail .caption {
+  padding: 9px;
+  color: #000;
+}
+.alert {
+  padding: 15px;
+  margin-bottom: 18px;
+  border: 1px solid transparent;
+  border-radius: 2px;
+}
+.alert h4 {
+  margin-top: 0;
+  color: inherit;
+}
+.alert .alert-link {
+  font-weight: bold;
+}
+.alert > p,
+.alert > ul {
+  margin-bottom: 0;
+}
+.alert > p + p {
+  margin-top: 5px;
+}
+.alert-dismissable,
+.alert-dismissible {
+  padding-right: 35px;
+}
+.alert-dismissable .close,
+.alert-dismissible .close {
+  position: relative;
+  top: -2px;
+  right: -21px;
+  color: inherit;
+}
+.alert-success {
+  background-color: #dff0d8;
+  border-color: #d6e9c6;
+  color: #3c763d;
+}
+.alert-success hr {
+  border-top-color: #c9e2b3;
+}
+.alert-success .alert-link {
+  color: #2b542c;
+}
+.alert-info {
+  background-color: #d9edf7;
+  border-color: #bce8f1;
+  color: #31708f;
+}
+.alert-info hr {
+  border-top-color: #a6e1ec;
+}
+.alert-info .alert-link {
+  color: #245269;
+}
+.alert-warning {
+  background-color: #fcf8e3;
+  border-color: #faebcc;
+  color: #8a6d3b;
+}
+.alert-warning hr {
+  border-top-color: #f7e1b5;
+}
+.alert-warning .alert-link {
+  color: #66512c;
+}
+.alert-danger {
+  background-color: #f2dede;
+  border-color: #ebccd1;
+  color: #a94442;
+}
+.alert-danger hr {
+  border-top-color: #e4b9c0;
+}
+.alert-danger .alert-link {
+  color: #843534;
+}
+@-webkit-keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+@keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+.progress {
+  overflow: hidden;
+  height: 18px;
+  margin-bottom: 18px;
+  background-color: #f5f5f5;
+  border-radius: 2px;
+  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+}
+.progress-bar {
+  float: left;
+  width: 0%;
+  height: 100%;
+  font-size: 12px;
+  line-height: 18px;
+  color: #fff;
+  text-align: center;
+  background-color: #337ab7;
+  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+  -webkit-transition: width 0.6s ease;
+  -o-transition: width 0.6s ease;
+  transition: width 0.6s ease;
+}
+.progress-striped .progress-bar,
+.progress-bar-striped {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-size: 40px 40px;
+}
+.progress.active .progress-bar,
+.progress-bar.active {
+  -webkit-animation: progress-bar-stripes 2s linear infinite;
+  -o-animation: progress-bar-stripes 2s linear infinite;
+  animation: progress-bar-stripes 2s linear infinite;
+}
+.progress-bar-success {
+  background-color: #5cb85c;
+}
+.progress-striped .progress-bar-success {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+.progress-bar-info {
+  background-color: #5bc0de;
+}
+.progress-striped .progress-bar-info {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+.progress-bar-warning {
+  background-color: #f0ad4e;
+}
+.progress-striped .progress-bar-warning {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+.progress-bar-danger {
+  background-color: #d9534f;
+}
+.progress-striped .progress-bar-danger {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+.media {
+  margin-top: 15px;
+}
+.media:first-child {
+  margin-top: 0;
+}
+.media,
+.media-body {
+  zoom: 1;
+  overflow: hidden;
+}
+.media-body {
+  width: 10000px;
+}
+.media-object {
+  display: block;
+}
+.media-object.img-thumbnail {
+  max-width: none;
+}
+.media-right,
+.media > .pull-right {
+  padding-left: 10px;
+}
+.media-left,
+.media > .pull-left {
+  padding-right: 10px;
+}
+.media-left,
+.media-right,
+.media-body {
+  display: table-cell;
+  vertical-align: top;
+}
+.media-middle {
+  vertical-align: middle;
+}
+.media-bottom {
+  vertical-align: bottom;
+}
+.media-heading {
+  margin-top: 0;
+  margin-bottom: 5px;
+}
+.media-list {
+  padding-left: 0;
+  list-style: none;
+}
+.list-group {
+  margin-bottom: 20px;
+  padding-left: 0;
+}
+.list-group-item {
+  position: relative;
+  display: block;
+  padding: 10px 15px;
+  margin-bottom: -1px;
+  background-color: #fff;
+  border: 1px solid #ddd;
+}
+.list-group-item:first-child {
+  border-top-right-radius: 2px;
+  border-top-left-radius: 2px;
+}
+.list-group-item:last-child {
+  margin-bottom: 0;
+  border-bottom-right-radius: 2px;
+  border-bottom-left-radius: 2px;
+}
+a.list-group-item,
+button.list-group-item {
+  color: #555;
+}
+a.list-group-item .list-group-item-heading,
+button.list-group-item .list-group-item-heading {
+  color: #333;
+}
+a.list-group-item:hover,
+button.list-group-item:hover,
+a.list-group-item:focus,
+button.list-group-item:focus {
+  text-decoration: none;
+  color: #555;
+  background-color: #f5f5f5;
+}
+button.list-group-item {
+  width: 100%;
+  text-align: left;
+}
+.list-group-item.disabled,
+.list-group-item.disabled:hover,
+.list-group-item.disabled:focus {
+  background-color: #eeeeee;
+  color: #777777;
+  cursor: not-allowed;
+}
+.list-group-item.disabled .list-group-item-heading,
+.list-group-item.disabled:hover .list-group-item-heading,
+.list-group-item.disabled:focus .list-group-item-heading {
+  color: inherit;
+}
+.list-group-item.disabled .list-group-item-text,
+.list-group-item.disabled:hover .list-group-item-text,
+.list-group-item.disabled:focus .list-group-item-text {
+  color: #777777;
+}
+.list-group-item.active,
+.list-group-item.active:hover,
+.list-group-item.active:focus {
+  z-index: 2;
+  color: #fff;
+  background-color: #337ab7;
+  border-color: #337ab7;
+}
+.list-group-item.active .list-group-item-heading,
+.list-group-item.active:hover .list-group-item-heading,
+.list-group-item.active:focus .list-group-item-heading,
+.list-group-item.active .list-group-item-heading > small,
+.list-group-item.active:hover .list-group-item-heading > small,
+.list-group-item.active:focus .list-group-item-heading > small,
+.list-group-item.active .list-group-item-heading > .small,
+.list-group-item.active:hover .list-group-item-heading > .small,
+.list-group-item.active:focus .list-group-item-heading > .small {
+  color: inherit;
+}
+.list-group-item.active .list-group-item-text,
+.list-group-item.active:hover .list-group-item-text,
+.list-group-item.active:focus .list-group-item-text {
+  color: #c7ddef;
+}
+.list-group-item-success {
+  color: #3c763d;
+  background-color: #dff0d8;
+}
+a.list-group-item-success,
+button.list-group-item-success {
+  color: #3c763d;
+}
+a.list-group-item-success .list-group-item-heading,
+button.list-group-item-success .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-success:hover,
+button.list-group-item-success:hover,
+a.list-group-item-success:focus,
+button.list-group-item-success:focus {
+  color: #3c763d;
+  background-color: #d0e9c6;
+}
+a.list-group-item-success.active,
+button.list-group-item-success.active,
+a.list-group-item-success.active:hover,
+button.list-group-item-success.active:hover,
+a.list-group-item-success.active:focus,
+button.list-group-item-success.active:focus {
+  color: #fff;
+  background-color: #3c763d;
+  border-color: #3c763d;
+}
+.list-group-item-info {
+  color: #31708f;
+  background-color: #d9edf7;
+}
+a.list-group-item-info,
+button.list-group-item-info {
+  color: #31708f;
+}
+a.list-group-item-info .list-group-item-heading,
+button.list-group-item-info .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-info:hover,
+button.list-group-item-info:hover,
+a.list-group-item-info:focus,
+button.list-group-item-info:focus {
+  color: #31708f;
+  background-color: #c4e3f3;
+}
+a.list-group-item-info.active,
+button.list-group-item-info.active,
+a.list-group-item-info.active:hover,
+button.list-group-item-info.active:hover,
+a.list-group-item-info.active:focus,
+button.list-group-item-info.active:focus {
+  color: #fff;
+  background-color: #31708f;
+  border-color: #31708f;
+}
+.list-group-item-warning {
+  color: #8a6d3b;
+  background-color: #fcf8e3;
+}
+a.list-group-item-warning,
+button.list-group-item-warning {
+  color: #8a6d3b;
+}
+a.list-group-item-warning .list-group-item-heading,
+button.list-group-item-warning .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-warning:hover,
+button.list-group-item-warning:hover,
+a.list-group-item-warning:focus,
+button.list-group-item-warning:focus {
+  color: #8a6d3b;
+  background-color: #faf2cc;
+}
+a.list-group-item-warning.active,
+button.list-group-item-warning.active,
+a.list-group-item-warning.active:hover,
+button.list-group-item-warning.active:hover,
+a.list-group-item-warning.active:focus,
+button.list-group-item-warning.active:focus {
+  color: #fff;
+  background-color: #8a6d3b;
+  border-color: #8a6d3b;
+}
+.list-group-item-danger {
+  color: #a94442;
+  background-color: #f2dede;
+}
+a.list-group-item-danger,
+button.list-group-item-danger {
+  color: #a94442;
+}
+a.list-group-item-danger .list-group-item-heading,
+button.list-group-item-danger .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-danger:hover,
+button.list-group-item-danger:hover,
+a.list-group-item-danger:focus,
+button.list-group-item-danger:focus {
+  color: #a94442;
+  background-color: #ebcccc;
+}
+a.list-group-item-danger.active,
+button.list-group-item-danger.active,
+a.list-group-item-danger.active:hover,
+button.list-group-item-danger.active:hover,
+a.list-group-item-danger.active:focus,
+button.list-group-item-danger.active:focus {
+  color: #fff;
+  background-color: #a94442;
+  border-color: #a94442;
+}
+.list-group-item-heading {
+  margin-top: 0;
+  margin-bottom: 5px;
+}
+.list-group-item-text {
+  margin-bottom: 0;
+  line-height: 1.3;
+}
+.panel {
+  margin-bottom: 18px;
+  background-color: #fff;
+  border: 1px solid transparent;
+  border-radius: 2px;
+  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
+  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
+}
+.panel-body {
+  padding: 15px;
+}
+.panel-heading {
+  padding: 10px 15px;
+  border-bottom: 1px solid transparent;
+  border-top-right-radius: 1px;
+  border-top-left-radius: 1px;
+}
+.panel-heading > .dropdown .dropdown-toggle {
+  color: inherit;
+}
+.panel-title {
+  margin-top: 0;
+  margin-bottom: 0;
+  font-size: 15px;
+  color: inherit;
+}
+.panel-title > a,
+.panel-title > small,
+.panel-title > .small,
+.panel-title > small > a,
+.panel-title > .small > a {
+  color: inherit;
+}
+.panel-footer {
+  padding: 10px 15px;
+  background-color: #f5f5f5;
+  border-top: 1px solid #ddd;
+  border-bottom-right-radius: 1px;
+  border-bottom-left-radius: 1px;
+}
+.panel > .list-group,
+.panel > .panel-collapse > .list-group {
+  margin-bottom: 0;
+}
+.panel > .list-group .list-group-item,
+.panel > .panel-collapse > .list-group .list-group-item {
+  border-width: 1px 0;
+  border-radius: 0;
+}
+.panel > .list-group:first-child .list-group-item:first-child,
+.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {
+  border-top: 0;
+  border-top-right-radius: 1px;
+  border-top-left-radius: 1px;
+}
+.panel > .list-group:last-child .list-group-item:last-child,
+.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {
+  border-bottom: 0;
+  border-bottom-right-radius: 1px;
+  border-bottom-left-radius: 1px;
+}
+.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {
+  border-top-right-radius: 0;
+  border-top-left-radius: 0;
+}
+.panel-heading + .list-group .list-group-item:first-child {
+  border-top-width: 0;
+}
+.list-group + .panel-footer {
+  border-top-width: 0;
+}
+.panel > .table,
+.panel > .table-responsive > .table,
+.panel > .panel-collapse > .table {
+  margin-bottom: 0;
+}
+.panel > .table caption,
+.panel > .table-responsive > .table caption,
+.panel > .panel-collapse > .table caption {
+  padding-left: 15px;
+  padding-right: 15px;
+}
+.panel > .table:first-child,
+.panel > .table-responsive:first-child > .table:first-child {
+  border-top-right-radius: 1px;
+  border-top-left-radius: 1px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {
+  border-top-left-radius: 1px;
+  border-top-right-radius: 1px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,
+.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {
+  border-top-left-radius: 1px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,
+.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {
+  border-top-right-radius: 1px;
+}
+.panel > .table:last-child,
+.panel > .table-responsive:last-child > .table:last-child {
+  border-bottom-right-radius: 1px;
+  border-bottom-left-radius: 1px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {
+  border-bottom-left-radius: 1px;
+  border-bottom-right-radius: 1px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
+.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {
+  border-bottom-left-radius: 1px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
+.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {
+  border-bottom-right-radius: 1px;
+}
+.panel > .panel-body + .table,
+.panel > .panel-body + .table-responsive,
+.panel > .table + .panel-body,
+.panel > .table-responsive + .panel-body {
+  border-top: 1px solid #ddd;
+}
+.panel > .table > tbody:first-child > tr:first-child th,
+.panel > .table > tbody:first-child > tr:first-child td {
+  border-top: 0;
+}
+.panel > .table-bordered,
+.panel > .table-responsive > .table-bordered {
+  border: 0;
+}
+.panel > .table-bordered > thead > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,
+.panel > .table-bordered > tbody > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,
+.panel > .table-bordered > tfoot > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,
+.panel > .table-bordered > thead > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,
+.panel > .table-bordered > tbody > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,
+.panel > .table-bordered > tfoot > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {
+  border-left: 0;
+}
+.panel > .table-bordered > thead > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,
+.panel > .table-bordered > tbody > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,
+.panel > .table-bordered > tfoot > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,
+.panel > .table-bordered > thead > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,
+.panel > .table-bordered > tbody > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,
+.panel > .table-bordered > tfoot > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {
+  border-right: 0;
+}
+.panel > .table-bordered > thead > tr:first-child > td,
+.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,
+.panel > .table-bordered > tbody > tr:first-child > td,
+.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,
+.panel > .table-bordered > thead > tr:first-child > th,
+.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,
+.panel > .table-bordered > tbody > tr:first-child > th,
+.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {
+  border-bottom: 0;
+}
+.panel > .table-bordered > tbody > tr:last-child > td,
+.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,
+.panel > .table-bordered > tfoot > tr:last-child > td,
+.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,
+.panel > .table-bordered > tbody > tr:last-child > th,
+.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,
+.panel > .table-bordered > tfoot > tr:last-child > th,
+.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {
+  border-bottom: 0;
+}
+.panel > .table-responsive {
+  border: 0;
+  margin-bottom: 0;
+}
+.panel-group {
+  margin-bottom: 18px;
+}
+.panel-group .panel {
+  margin-bottom: 0;
+  border-radius: 2px;
+}
+.panel-group .panel + .panel {
+  margin-top: 5px;
+}
+.panel-group .panel-heading {
+  border-bottom: 0;
+}
+.panel-group .panel-heading + .panel-collapse > .panel-body,
+.panel-group .panel-heading + .panel-collapse > .list-group {
+  border-top: 1px solid #ddd;
+}
+.panel-group .panel-footer {
+  border-top: 0;
+}
+.panel-group .panel-footer + .panel-collapse .panel-body {
+  border-bottom: 1px solid #ddd;
+}
+.panel-default {
+  border-color: #ddd;
+}
+.panel-default > .panel-heading {
+  color: #333333;
+  background-color: #f5f5f5;
+  border-color: #ddd;
+}
+.panel-default > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #ddd;
+}
+.panel-default > .panel-heading .badge {
+  color: #f5f5f5;
+  background-color: #333333;
+}
+.panel-default > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #ddd;
+}
+.panel-primary {
+  border-color: #337ab7;
+}
+.panel-primary > .panel-heading {
+  color: #fff;
+  background-color: #337ab7;
+  border-color: #337ab7;
+}
+.panel-primary > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #337ab7;
+}
+.panel-primary > .panel-heading .badge {
+  color: #337ab7;
+  background-color: #fff;
+}
+.panel-primary > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #337ab7;
+}
+.panel-success {
+  border-color: #d6e9c6;
+}
+.panel-success > .panel-heading {
+  color: #3c763d;
+  background-color: #dff0d8;
+  border-color: #d6e9c6;
+}
+.panel-success > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #d6e9c6;
+}
+.panel-success > .panel-heading .badge {
+  color: #dff0d8;
+  background-color: #3c763d;
+}
+.panel-success > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #d6e9c6;
+}
+.panel-info {
+  border-color: #bce8f1;
+}
+.panel-info > .panel-heading {
+  color: #31708f;
+  background-color: #d9edf7;
+  border-color: #bce8f1;
+}
+.panel-info > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #bce8f1;
+}
+.panel-info > .panel-heading .badge {
+  color: #d9edf7;
+  background-color: #31708f;
+}
+.panel-info > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #bce8f1;
+}
+.panel-warning {
+  border-color: #faebcc;
+}
+.panel-warning > .panel-heading {
+  color: #8a6d3b;
+  background-color: #fcf8e3;
+  border-color: #faebcc;
+}
+.panel-warning > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #faebcc;
+}
+.panel-warning > .panel-heading .badge {
+  color: #fcf8e3;
+  background-color: #8a6d3b;
+}
+.panel-warning > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #faebcc;
+}
+.panel-danger {
+  border-color: #ebccd1;
+}
+.panel-danger > .panel-heading {
+  color: #a94442;
+  background-color: #f2dede;
+  border-color: #ebccd1;
+}
+.panel-danger > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #ebccd1;
+}
+.panel-danger > .panel-heading .badge {
+  color: #f2dede;
+  background-color: #a94442;
+}
+.panel-danger > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #ebccd1;
+}
+.embed-responsive {
+  position: relative;
+  display: block;
+  height: 0;
+  padding: 0;
+  overflow: hidden;
+}
+.embed-responsive .embed-responsive-item,
+.embed-responsive iframe,
+.embed-responsive embed,
+.embed-responsive object,
+.embed-responsive video {
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  height: 100%;
+  width: 100%;
+  border: 0;
+}
+.embed-responsive-16by9 {
+  padding-bottom: 56.25%;
+}
+.embed-responsive-4by3 {
+  padding-bottom: 75%;
+}
+.well {
+  min-height: 20px;
+  padding: 19px;
+  margin-bottom: 20px;
+  background-color: #f5f5f5;
+  border: 1px solid #e3e3e3;
+  border-radius: 2px;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+}
+.well blockquote {
+  border-color: #ddd;
+  border-color: rgba(0, 0, 0, 0.15);
+}
+.well-lg {
+  padding: 24px;
+  border-radius: 3px;
+}
+.well-sm {
+  padding: 9px;
+  border-radius: 1px;
+}
+.close {
+  float: right;
+  font-size: 19.5px;
+  font-weight: bold;
+  line-height: 1;
+  color: #000;
+  text-shadow: 0 1px 0 #fff;
+  opacity: 0.2;
+  filter: alpha(opacity=20);
+}
+.close:hover,
+.close:focus {
+  color: #000;
+  text-decoration: none;
+  cursor: pointer;
+  opacity: 0.5;
+  filter: alpha(opacity=50);
+}
+button.close {
+  padding: 0;
+  cursor: pointer;
+  background: transparent;
+  border: 0;
+  -webkit-appearance: none;
+}
+.modal-open {
+  overflow: hidden;
+}
+.modal {
+  display: none;
+  overflow: hidden;
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 1050;
+  -webkit-overflow-scrolling: touch;
+  outline: 0;
+}
+.modal.fade .modal-dialog {
+  -webkit-transform: translate(0, -25%);
+  -ms-transform: translate(0, -25%);
+  -o-transform: translate(0, -25%);
+  transform: translate(0, -25%);
+  -webkit-transition: -webkit-transform 0.3s ease-out;
+  -moz-transition: -moz-transform 0.3s ease-out;
+  -o-transition: -o-transform 0.3s ease-out;
+  transition: transform 0.3s ease-out;
+}
+.modal.in .modal-dialog {
+  -webkit-transform: translate(0, 0);
+  -ms-transform: translate(0, 0);
+  -o-transform: translate(0, 0);
+  transform: translate(0, 0);
+}
+.modal-open .modal {
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+.modal-dialog {
+  position: relative;
+  width: auto;
+  margin: 10px;
+}
+.modal-content {
+  position: relative;
+  background-color: #fff;
+  border: 1px solid #999;
+  border: 1px solid rgba(0, 0, 0, 0.2);
+  border-radius: 3px;
+  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
+  box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
+  background-clip: padding-box;
+  outline: 0;
+}
+.modal-backdrop {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 1040;
+  background-color: #000;
+}
+.modal-backdrop.fade {
+  opacity: 0;
+  filter: alpha(opacity=0);
+}
+.modal-backdrop.in {
+  opacity: 0.5;
+  filter: alpha(opacity=50);
+}
+.modal-header {
+  padding: 15px;
+  border-bottom: 1px solid #e5e5e5;
+}
+.modal-header .close {
+  margin-top: -2px;
+}
+.modal-title {
+  margin: 0;
+  line-height: 1.42857143;
+}
+.modal-body {
+  position: relative;
+  padding: 15px;
+}
+.modal-footer {
+  padding: 15px;
+  text-align: right;
+  border-top: 1px solid #e5e5e5;
+}
+.modal-footer .btn + .btn {
+  margin-left: 5px;
+  margin-bottom: 0;
+}
+.modal-footer .btn-group .btn + .btn {
+  margin-left: -1px;
+}
+.modal-footer .btn-block + .btn-block {
+  margin-left: 0;
+}
+.modal-scrollbar-measure {
+  position: absolute;
+  top: -9999px;
+  width: 50px;
+  height: 50px;
+  overflow: scroll;
+}
+@media (min-width: 768px) {
+  .modal-dialog {
+    width: 600px;
+    margin: 30px auto;
+  }
+  .modal-content {
+    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
+    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
+  }
+  .modal-sm {
+    width: 300px;
+  }
+}
+@media (min-width: 992px) {
+  .modal-lg {
+    width: 900px;
+  }
+}
+.tooltip {
+  position: absolute;
+  z-index: 1070;
+  display: block;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-style: normal;
+  font-weight: normal;
+  letter-spacing: normal;
+  line-break: auto;
+  line-height: 1.42857143;
+  text-align: left;
+  text-align: start;
+  text-decoration: none;
+  text-shadow: none;
+  text-transform: none;
+  white-space: normal;
+  word-break: normal;
+  word-spacing: normal;
+  word-wrap: normal;
+  font-size: 12px;
+  opacity: 0;
+  filter: alpha(opacity=0);
+}
+.tooltip.in {
+  opacity: 0.9;
+  filter: alpha(opacity=90);
+}
+.tooltip.top {
+  margin-top: -3px;
+  padding: 5px 0;
+}
+.tooltip.right {
+  margin-left: 3px;
+  padding: 0 5px;
+}
+.tooltip.bottom {
+  margin-top: 3px;
+  padding: 5px 0;
+}
+.tooltip.left {
+  margin-left: -3px;
+  padding: 0 5px;
+}
+.tooltip-inner {
+  max-width: 200px;
+  padding: 3px 8px;
+  color: #fff;
+  text-align: center;
+  background-color: #000;
+  border-radius: 2px;
+}
+.tooltip-arrow {
+  position: absolute;
+  width: 0;
+  height: 0;
+  border-color: transparent;
+  border-style: solid;
+}
+.tooltip.top .tooltip-arrow {
+  bottom: 0;
+  left: 50%;
+  margin-left: -5px;
+  border-width: 5px 5px 0;
+  border-top-color: #000;
+}
+.tooltip.top-left .tooltip-arrow {
+  bottom: 0;
+  right: 5px;
+  margin-bottom: -5px;
+  border-width: 5px 5px 0;
+  border-top-color: #000;
+}
+.tooltip.top-right .tooltip-arrow {
+  bottom: 0;
+  left: 5px;
+  margin-bottom: -5px;
+  border-width: 5px 5px 0;
+  border-top-color: #000;
+}
+.tooltip.right .tooltip-arrow {
+  top: 50%;
+  left: 0;
+  margin-top: -5px;
+  border-width: 5px 5px 5px 0;
+  border-right-color: #000;
+}
+.tooltip.left .tooltip-arrow {
+  top: 50%;
+  right: 0;
+  margin-top: -5px;
+  border-width: 5px 0 5px 5px;
+  border-left-color: #000;
+}
+.tooltip.bottom .tooltip-arrow {
+  top: 0;
+  left: 50%;
+  margin-left: -5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000;
+}
+.tooltip.bottom-left .tooltip-arrow {
+  top: 0;
+  right: 5px;
+  margin-top: -5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000;
+}
+.tooltip.bottom-right .tooltip-arrow {
+  top: 0;
+  left: 5px;
+  margin-top: -5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000;
+}
+.popover {
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: 1060;
+  display: none;
+  max-width: 276px;
+  padding: 1px;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-style: normal;
+  font-weight: normal;
+  letter-spacing: normal;
+  line-break: auto;
+  line-height: 1.42857143;
+  text-align: left;
+  text-align: start;
+  text-decoration: none;
+  text-shadow: none;
+  text-transform: none;
+  white-space: normal;
+  word-break: normal;
+  word-spacing: normal;
+  word-wrap: normal;
+  font-size: 13px;
+  background-color: #fff;
+  background-clip: padding-box;
+  border: 1px solid #ccc;
+  border: 1px solid rgba(0, 0, 0, 0.2);
+  border-radius: 3px;
+  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+}
+.popover.top {
+  margin-top: -10px;
+}
+.popover.right {
+  margin-left: 10px;
+}
+.popover.bottom {
+  margin-top: 10px;
+}
+.popover.left {
+  margin-left: -10px;
+}
+.popover-title {
+  margin: 0;
+  padding: 8px 14px;
+  font-size: 13px;
+  background-color: #f7f7f7;
+  border-bottom: 1px solid #ebebeb;
+  border-radius: 2px 2px 0 0;
+}
+.popover-content {
+  padding: 9px 14px;
+}
+.popover > .arrow,
+.popover > .arrow:after {
+  position: absolute;
+  display: block;
+  width: 0;
+  height: 0;
+  border-color: transparent;
+  border-style: solid;
+}
+.popover > .arrow {
+  border-width: 11px;
+}
+.popover > .arrow:after {
+  border-width: 10px;
+  content: "";
+}
+.popover.top > .arrow {
+  left: 50%;
+  margin-left: -11px;
+  border-bottom-width: 0;
+  border-top-color: #999999;
+  border-top-color: rgba(0, 0, 0, 0.25);
+  bottom: -11px;
+}
+.popover.top > .arrow:after {
+  content: " ";
+  bottom: 1px;
+  margin-left: -10px;
+  border-bottom-width: 0;
+  border-top-color: #fff;
+}
+.popover.right > .arrow {
+  top: 50%;
+  left: -11px;
+  margin-top: -11px;
+  border-left-width: 0;
+  border-right-color: #999999;
+  border-right-color: rgba(0, 0, 0, 0.25);
+}
+.popover.right > .arrow:after {
+  content: " ";
+  left: 1px;
+  bottom: -10px;
+  border-left-width: 0;
+  border-right-color: #fff;
+}
+.popover.bottom > .arrow {
+  left: 50%;
+  margin-left: -11px;
+  border-top-width: 0;
+  border-bottom-color: #999999;
+  border-bottom-color: rgba(0, 0, 0, 0.25);
+  top: -11px;
+}
+.popover.bottom > .arrow:after {
+  content: " ";
+  top: 1px;
+  margin-left: -10px;
+  border-top-width: 0;
+  border-bottom-color: #fff;
+}
+.popover.left > .arrow {
+  top: 50%;
+  right: -11px;
+  margin-top: -11px;
+  border-right-width: 0;
+  border-left-color: #999999;
+  border-left-color: rgba(0, 0, 0, 0.25);
+}
+.popover.left > .arrow:after {
+  content: " ";
+  right: 1px;
+  border-right-width: 0;
+  border-left-color: #fff;
+  bottom: -10px;
+}
+.carousel {
+  position: relative;
+}
+.carousel-inner {
+  position: relative;
+  overflow: hidden;
+  width: 100%;
+}
+.carousel-inner > .item {
+  display: none;
+  position: relative;
+  -webkit-transition: 0.6s ease-in-out left;
+  -o-transition: 0.6s ease-in-out left;
+  transition: 0.6s ease-in-out left;
+}
+.carousel-inner > .item > img,
+.carousel-inner > .item > a > img {
+  line-height: 1;
+}
+@media all and (transform-3d), (-webkit-transform-3d) {
+  .carousel-inner > .item {
+    -webkit-transition: -webkit-transform 0.6s ease-in-out;
+    -moz-transition: -moz-transform 0.6s ease-in-out;
+    -o-transition: -o-transform 0.6s ease-in-out;
+    transition: transform 0.6s ease-in-out;
+    -webkit-backface-visibility: hidden;
+    -moz-backface-visibility: hidden;
+    backface-visibility: hidden;
+    -webkit-perspective: 1000px;
+    -moz-perspective: 1000px;
+    perspective: 1000px;
+  }
+  .carousel-inner > .item.next,
+  .carousel-inner > .item.active.right {
+    -webkit-transform: translate3d(100%, 0, 0);
+    transform: translate3d(100%, 0, 0);
+    left: 0;
+  }
+  .carousel-inner > .item.prev,
+  .carousel-inner > .item.active.left {
+    -webkit-transform: translate3d(-100%, 0, 0);
+    transform: translate3d(-100%, 0, 0);
+    left: 0;
+  }
+  .carousel-inner > .item.next.left,
+  .carousel-inner > .item.prev.right,
+  .carousel-inner > .item.active {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+    left: 0;
+  }
+}
+.carousel-inner > .active,
+.carousel-inner > .next,
+.carousel-inner > .prev {
+  display: block;
+}
+.carousel-inner > .active {
+  left: 0;
+}
+.carousel-inner > .next,
+.carousel-inner > .prev {
+  position: absolute;
+  top: 0;
+  width: 100%;
+}
+.carousel-inner > .next {
+  left: 100%;
+}
+.carousel-inner > .prev {
+  left: -100%;
+}
+.carousel-inner > .next.left,
+.carousel-inner > .prev.right {
+  left: 0;
+}
+.carousel-inner > .active.left {
+  left: -100%;
+}
+.carousel-inner > .active.right {
+  left: 100%;
+}
+.carousel-control {
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  width: 15%;
+  opacity: 0.5;
+  filter: alpha(opacity=50);
+  font-size: 20px;
+  color: #fff;
+  text-align: center;
+  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
+  background-color: rgba(0, 0, 0, 0);
+}
+.carousel-control.left {
+  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);
+  background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);
+  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);
+  background-repeat: repeat-x;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);
+}
+.carousel-control.right {
+  left: auto;
+  right: 0;
+  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);
+  background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);
+  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);
+  background-repeat: repeat-x;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);
+}
+.carousel-control:hover,
+.carousel-control:focus {
+  outline: 0;
+  color: #fff;
+  text-decoration: none;
+  opacity: 0.9;
+  filter: alpha(opacity=90);
+}
+.carousel-control .icon-prev,
+.carousel-control .icon-next,
+.carousel-control .glyphicon-chevron-left,
+.carousel-control .glyphicon-chevron-right {
+  position: absolute;
+  top: 50%;
+  margin-top: -10px;
+  z-index: 5;
+  display: inline-block;
+}
+.carousel-control .icon-prev,
+.carousel-control .glyphicon-chevron-left {
+  left: 50%;
+  margin-left: -10px;
+}
+.carousel-control .icon-next,
+.carousel-control .glyphicon-chevron-right {
+  right: 50%;
+  margin-right: -10px;
+}
+.carousel-control .icon-prev,
+.carousel-control .icon-next {
+  width: 20px;
+  height: 20px;
+  line-height: 1;
+  font-family: serif;
+}
+.carousel-control .icon-prev:before {
+  content: '\2039';
+}
+.carousel-control .icon-next:before {
+  content: '\203a';
+}
+.carousel-indicators {
+  position: absolute;
+  bottom: 10px;
+  left: 50%;
+  z-index: 15;
+  width: 60%;
+  margin-left: -30%;
+  padding-left: 0;
+  list-style: none;
+  text-align: center;
+}
+.carousel-indicators li {
+  display: inline-block;
+  width: 10px;
+  height: 10px;
+  margin: 1px;
+  text-indent: -999px;
+  border: 1px solid #fff;
+  border-radius: 10px;
+  cursor: pointer;
+  background-color: #000 \9;
+  background-color: rgba(0, 0, 0, 0);
+}
+.carousel-indicators .active {
+  margin: 0;
+  width: 12px;
+  height: 12px;
+  background-color: #fff;
+}
+.carousel-caption {
+  position: absolute;
+  left: 15%;
+  right: 15%;
+  bottom: 20px;
+  z-index: 10;
+  padding-top: 20px;
+  padding-bottom: 20px;
+  color: #fff;
+  text-align: center;
+  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
+}
+.carousel-caption .btn {
+  text-shadow: none;
+}
+@media screen and (min-width: 768px) {
+  .carousel-control .glyphicon-chevron-left,
+  .carousel-control .glyphicon-chevron-right,
+  .carousel-control .icon-prev,
+  .carousel-control .icon-next {
+    width: 30px;
+    height: 30px;
+    margin-top: -10px;
+    font-size: 30px;
+  }
+  .carousel-control .glyphicon-chevron-left,
+  .carousel-control .icon-prev {
+    margin-left: -10px;
+  }
+  .carousel-control .glyphicon-chevron-right,
+  .carousel-control .icon-next {
+    margin-right: -10px;
+  }
+  .carousel-caption {
+    left: 20%;
+    right: 20%;
+    padding-bottom: 30px;
+  }
+  .carousel-indicators {
+    bottom: 20px;
+  }
+}
+.clearfix:before,
+.clearfix:after,
+.dl-horizontal dd:before,
+.dl-horizontal dd:after,
+.container:before,
+.container:after,
+.container-fluid:before,
+.container-fluid:after,
+.row:before,
+.row:after,
+.form-horizontal .form-group:before,
+.form-horizontal .form-group:after,
+.btn-toolbar:before,
+.btn-toolbar:after,
+.btn-group-vertical > .btn-group:before,
+.btn-group-vertical > .btn-group:after,
+.nav:before,
+.nav:after,
+.navbar:before,
+.navbar:after,
+.navbar-header:before,
+.navbar-header:after,
+.navbar-collapse:before,
+.navbar-collapse:after,
+.pager:before,
+.pager:after,
+.panel-body:before,
+.panel-body:after,
+.modal-header:before,
+.modal-header:after,
+.modal-footer:before,
+.modal-footer:after,
+.item_buttons:before,
+.item_buttons:after {
+  content: " ";
+  display: table;
+}
+.clearfix:after,
+.dl-horizontal dd:after,
+.container:after,
+.container-fluid:after,
+.row:after,
+.form-horizontal .form-group:after,
+.btn-toolbar:after,
+.btn-group-vertical > .btn-group:after,
+.nav:after,
+.navbar:after,
+.navbar-header:after,
+.navbar-collapse:after,
+.pager:after,
+.panel-body:after,
+.modal-header:after,
+.modal-footer:after,
+.item_buttons:after {
+  clear: both;
+}
+.center-block {
+  display: block;
+  margin-left: auto;
+  margin-right: auto;
+}
+.pull-right {
+  float: right !important;
+}
+.pull-left {
+  float: left !important;
+}
+.hide {
+  display: none !important;
+}
+.show {
+  display: block !important;
+}
+.invisible {
+  visibility: hidden;
+}
+.text-hide {
+  font: 0/0 a;
+  color: transparent;
+  text-shadow: none;
+  background-color: transparent;
+  border: 0;
+}
+.hidden {
+  display: none !important;
+}
+.affix {
+  position: fixed;
+}
+@-ms-viewport {
+  width: device-width;
+}
+.visible-xs,
+.visible-sm,
+.visible-md,
+.visible-lg {
+  display: none !important;
+}
+.visible-xs-block,
+.visible-xs-inline,
+.visible-xs-inline-block,
+.visible-sm-block,
+.visible-sm-inline,
+.visible-sm-inline-block,
+.visible-md-block,
+.visible-md-inline,
+.visible-md-inline-block,
+.visible-lg-block,
+.visible-lg-inline,
+.visible-lg-inline-block {
+  display: none !important;
+}
+@media (max-width: 767px) {
+  .visible-xs {
+    display: block !important;
+  }
+  table.visible-xs {
+    display: table !important;
+  }
+  tr.visible-xs {
+    display: table-row !important;
+  }
+  th.visible-xs,
+  td.visible-xs {
+    display: table-cell !important;
+  }
+}
+@media (max-width: 767px) {
+  .visible-xs-block {
+    display: block !important;
+  }
+}
+@media (max-width: 767px) {
+  .visible-xs-inline {
+    display: inline !important;
+  }
+}
+@media (max-width: 767px) {
+  .visible-xs-inline-block {
+    display: inline-block !important;
+  }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm {
+    display: block !important;
+  }
+  table.visible-sm {
+    display: table !important;
+  }
+  tr.visible-sm {
+    display: table-row !important;
+  }
+  th.visible-sm,
+  td.visible-sm {
+    display: table-cell !important;
+  }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm-block {
+    display: block !important;
+  }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm-inline {
+    display: inline !important;
+  }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm-inline-block {
+    display: inline-block !important;
+  }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md {
+    display: block !important;
+  }
+  table.visible-md {
+    display: table !important;
+  }
+  tr.visible-md {
+    display: table-row !important;
+  }
+  th.visible-md,
+  td.visible-md {
+    display: table-cell !important;
+  }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md-block {
+    display: block !important;
+  }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md-inline {
+    display: inline !important;
+  }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md-inline-block {
+    display: inline-block !important;
+  }
+}
+@media (min-width: 1200px) {
+  .visible-lg {
+    display: block !important;
+  }
+  table.visible-lg {
+    display: table !important;
+  }
+  tr.visible-lg {
+    display: table-row !important;
+  }
+  th.visible-lg,
+  td.visible-lg {
+    display: table-cell !important;
+  }
+}
+@media (min-width: 1200px) {
+  .visible-lg-block {
+    display: block !important;
+  }
+}
+@media (min-width: 1200px) {
+  .visible-lg-inline {
+    display: inline !important;
+  }
+}
+@media (min-width: 1200px) {
+  .visible-lg-inline-block {
+    display: inline-block !important;
+  }
+}
+@media (max-width: 767px) {
+  .hidden-xs {
+    display: none !important;
+  }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+  .hidden-sm {
+    display: none !important;
+  }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+  .hidden-md {
+    display: none !important;
+  }
+}
+@media (min-width: 1200px) {
+  .hidden-lg {
+    display: none !important;
+  }
+}
+.visible-print {
+  display: none !important;
+}
+@media print {
+  .visible-print {
+    display: block !important;
+  }
+  table.visible-print {
+    display: table !important;
+  }
+  tr.visible-print {
+    display: table-row !important;
+  }
+  th.visible-print,
+  td.visible-print {
+    display: table-cell !important;
+  }
+}
+.visible-print-block {
+  display: none !important;
+}
+@media print {
+  .visible-print-block {
+    display: block !important;
+  }
+}
+.visible-print-inline {
+  display: none !important;
+}
+@media print {
+  .visible-print-inline {
+    display: inline !important;
+  }
+}
+.visible-print-inline-block {
+  display: none !important;
+}
+@media print {
+  .visible-print-inline-block {
+    display: inline-block !important;
+  }
+}
+@media print {
+  .hidden-print {
+    display: none !important;
+  }
+}
+/*!
+*
+* Font Awesome
+*
+*/
+/*!
+ *  Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome
+ *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
+ */
+/* FONT PATH
+ * -------------------------- */
+@font-face {
+  font-family: 'FontAwesome';
+  src: url('../components/font-awesome/fonts/fontawesome-webfont.eot?v=4.2.0');
+  src: url('../components/font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.2.0') format('embedded-opentype'), url('../components/font-awesome/fonts/fontawesome-webfont.woff?v=4.2.0') format('woff'), url('../components/font-awesome/fonts/fontawesome-webfont.ttf?v=4.2.0') format('truetype'), url('../components/font-awesome/fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular') format('svg');
+  font-weight: normal;
+  font-style: normal;
+}
+.fa {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+/* makes the font 33% larger relative to the icon container */
+.fa-lg {
+  font-size: 1.33333333em;
+  line-height: 0.75em;
+  vertical-align: -15%;
+}
+.fa-2x {
+  font-size: 2em;
+}
+.fa-3x {
+  font-size: 3em;
+}
+.fa-4x {
+  font-size: 4em;
+}
+.fa-5x {
+  font-size: 5em;
+}
+.fa-fw {
+  width: 1.28571429em;
+  text-align: center;
+}
+.fa-ul {
+  padding-left: 0;
+  margin-left: 2.14285714em;
+  list-style-type: none;
+}
+.fa-ul > li {
+  position: relative;
+}
+.fa-li {
+  position: absolute;
+  left: -2.14285714em;
+  width: 2.14285714em;
+  top: 0.14285714em;
+  text-align: center;
+}
+.fa-li.fa-lg {
+  left: -1.85714286em;
+}
+.fa-border {
+  padding: .2em .25em .15em;
+  border: solid 0.08em #eee;
+  border-radius: .1em;
+}
+.pull-right {
+  float: right;
+}
+.pull-left {
+  float: left;
+}
+.fa.pull-left {
+  margin-right: .3em;
+}
+.fa.pull-right {
+  margin-left: .3em;
+}
+.fa-spin {
+  -webkit-animation: fa-spin 2s infinite linear;
+  animation: fa-spin 2s infinite linear;
+}
+@-webkit-keyframes fa-spin {
+  0% {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+  100% {
+    -webkit-transform: rotate(359deg);
+    transform: rotate(359deg);
+  }
+}
+@keyframes fa-spin {
+  0% {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+  100% {
+    -webkit-transform: rotate(359deg);
+    transform: rotate(359deg);
+  }
+}
+.fa-rotate-90 {
+  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
+  -webkit-transform: rotate(90deg);
+  -ms-transform: rotate(90deg);
+  transform: rotate(90deg);
+}
+.fa-rotate-180 {
+  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
+  -webkit-transform: rotate(180deg);
+  -ms-transform: rotate(180deg);
+  transform: rotate(180deg);
+}
+.fa-rotate-270 {
+  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
+  -webkit-transform: rotate(270deg);
+  -ms-transform: rotate(270deg);
+  transform: rotate(270deg);
+}
+.fa-flip-horizontal {
+  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);
+  -webkit-transform: scale(-1, 1);
+  -ms-transform: scale(-1, 1);
+  transform: scale(-1, 1);
+}
+.fa-flip-vertical {
+  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);
+  -webkit-transform: scale(1, -1);
+  -ms-transform: scale(1, -1);
+  transform: scale(1, -1);
+}
+:root .fa-rotate-90,
+:root .fa-rotate-180,
+:root .fa-rotate-270,
+:root .fa-flip-horizontal,
+:root .fa-flip-vertical {
+  filter: none;
+}
+.fa-stack {
+  position: relative;
+  display: inline-block;
+  width: 2em;
+  height: 2em;
+  line-height: 2em;
+  vertical-align: middle;
+}
+.fa-stack-1x,
+.fa-stack-2x {
+  position: absolute;
+  left: 0;
+  width: 100%;
+  text-align: center;
+}
+.fa-stack-1x {
+  line-height: inherit;
+}
+.fa-stack-2x {
+  font-size: 2em;
+}
+.fa-inverse {
+  color: #fff;
+}
+/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
+   readers do not read off random characters that represent icons */
+.fa-glass:before {
+  content: "\f000";
+}
+.fa-music:before {
+  content: "\f001";
+}
+.fa-search:before {
+  content: "\f002";
+}
+.fa-envelope-o:before {
+  content: "\f003";
+}
+.fa-heart:before {
+  content: "\f004";
+}
+.fa-star:before {
+  content: "\f005";
+}
+.fa-star-o:before {
+  content: "\f006";
+}
+.fa-user:before {
+  content: "\f007";
+}
+.fa-film:before {
+  content: "\f008";
+}
+.fa-th-large:before {
+  content: "\f009";
+}
+.fa-th:before {
+  content: "\f00a";
+}
+.fa-th-list:before {
+  content: "\f00b";
+}
+.fa-check:before {
+  content: "\f00c";
+}
+.fa-remove:before,
+.fa-close:before,
+.fa-times:before {
+  content: "\f00d";
+}
+.fa-search-plus:before {
+  content: "\f00e";
+}
+.fa-search-minus:before {
+  content: "\f010";
+}
+.fa-power-off:before {
+  content: "\f011";
+}
+.fa-signal:before {
+  content: "\f012";
+}
+.fa-gear:before,
+.fa-cog:before {
+  content: "\f013";
+}
+.fa-trash-o:before {
+  content: "\f014";
+}
+.fa-home:before {
+  content: "\f015";
+}
+.fa-file-o:before {
+  content: "\f016";
+}
+.fa-clock-o:before {
+  content: "\f017";
+}
+.fa-road:before {
+  content: "\f018";
+}
+.fa-download:before {
+  content: "\f019";
+}
+.fa-arrow-circle-o-down:before {
+  content: "\f01a";
+}
+.fa-arrow-circle-o-up:before {
+  content: "\f01b";
+}
+.fa-inbox:before {
+  content: "\f01c";
+}
+.fa-play-circle-o:before {
+  content: "\f01d";
+}
+.fa-rotate-right:before,
+.fa-repeat:before {
+  content: "\f01e";
+}
+.fa-refresh:before {
+  content: "\f021";
+}
+.fa-list-alt:before {
+  content: "\f022";
+}
+.fa-lock:before {
+  content: "\f023";
+}
+.fa-flag:before {
+  content: "\f024";
+}
+.fa-headphones:before {
+  content: "\f025";
+}
+.fa-volume-off:before {
+  content: "\f026";
+}
+.fa-volume-down:before {
+  content: "\f027";
+}
+.fa-volume-up:before {
+  content: "\f028";
+}
+.fa-qrcode:before {
+  content: "\f029";
+}
+.fa-barcode:before {
+  content: "\f02a";
+}
+.fa-tag:before {
+  content: "\f02b";
+}
+.fa-tags:before {
+  content: "\f02c";
+}
+.fa-book:before {
+  content: "\f02d";
+}
+.fa-bookmark:before {
+  content: "\f02e";
+}
+.fa-print:before {
+  content: "\f02f";
+}
+.fa-camera:before {
+  content: "\f030";
+}
+.fa-font:before {
+  content: "\f031";
+}
+.fa-bold:before {
+  content: "\f032";
+}
+.fa-italic:before {
+  content: "\f033";
+}
+.fa-text-height:before {
+  content: "\f034";
+}
+.fa-text-width:before {
+  content: "\f035";
+}
+.fa-align-left:before {
+  content: "\f036";
+}
+.fa-align-center:before {
+  content: "\f037";
+}
+.fa-align-right:before {
+  content: "\f038";
+}
+.fa-align-justify:before {
+  content: "\f039";
+}
+.fa-list:before {
+  content: "\f03a";
+}
+.fa-dedent:before,
+.fa-outdent:before {
+  content: "\f03b";
+}
+.fa-indent:before {
+  content: "\f03c";
+}
+.fa-video-camera:before {
+  content: "\f03d";
+}
+.fa-photo:before,
+.fa-image:before,
+.fa-picture-o:before {
+  content: "\f03e";
+}
+.fa-pencil:before {
+  content: "\f040";
+}
+.fa-map-marker:before {
+  content: "\f041";
+}
+.fa-adjust:before {
+  content: "\f042";
+}
+.fa-tint:before {
+  content: "\f043";
+}
+.fa-edit:before,
+.fa-pencil-square-o:before {
+  content: "\f044";
+}
+.fa-share-square-o:before {
+  content: "\f045";
+}
+.fa-check-square-o:before {
+  content: "\f046";
+}
+.fa-arrows:before {
+  content: "\f047";
+}
+.fa-step-backward:before {
+  content: "\f048";
+}
+.fa-fast-backward:before {
+  content: "\f049";
+}
+.fa-backward:before {
+  content: "\f04a";
+}
+.fa-play:before {
+  content: "\f04b";
+}
+.fa-pause:before {
+  content: "\f04c";
+}
+.fa-stop:before {
+  content: "\f04d";
+}
+.fa-forward:before {
+  content: "\f04e";
+}
+.fa-fast-forward:before {
+  content: "\f050";
+}
+.fa-step-forward:before {
+  content: "\f051";
+}
+.fa-eject:before {
+  content: "\f052";
+}
+.fa-chevron-left:before {
+  content: "\f053";
+}
+.fa-chevron-right:before {
+  content: "\f054";
+}
+.fa-plus-circle:before {
+  content: "\f055";
+}
+.fa-minus-circle:before {
+  content: "\f056";
+}
+.fa-times-circle:before {
+  content: "\f057";
+}
+.fa-check-circle:before {
+  content: "\f058";
+}
+.fa-question-circle:before {
+  content: "\f059";
+}
+.fa-info-circle:before {
+  content: "\f05a";
+}
+.fa-crosshairs:before {
+  content: "\f05b";
+}
+.fa-times-circle-o:before {
+  content: "\f05c";
+}
+.fa-check-circle-o:before {
+  content: "\f05d";
+}
+.fa-ban:before {
+  content: "\f05e";
+}
+.fa-arrow-left:before {
+  content: "\f060";
+}
+.fa-arrow-right:before {
+  content: "\f061";
+}
+.fa-arrow-up:before {
+  content: "\f062";
+}
+.fa-arrow-down:before {
+  content: "\f063";
+}
+.fa-mail-forward:before,
+.fa-share:before {
+  content: "\f064";
+}
+.fa-expand:before {
+  content: "\f065";
+}
+.fa-compress:before {
+  content: "\f066";
+}
+.fa-plus:before {
+  content: "\f067";
+}
+.fa-minus:before {
+  content: "\f068";
+}
+.fa-asterisk:before {
+  content: "\f069";
+}
+.fa-exclamation-circle:before {
+  content: "\f06a";
+}
+.fa-gift:before {
+  content: "\f06b";
+}
+.fa-leaf:before {
+  content: "\f06c";
+}
+.fa-fire:before {
+  content: "\f06d";
+}
+.fa-eye:before {
+  content: "\f06e";
+}
+.fa-eye-slash:before {
+  content: "\f070";
+}
+.fa-warning:before,
+.fa-exclamation-triangle:before {
+  content: "\f071";
+}
+.fa-plane:before {
+  content: "\f072";
+}
+.fa-calendar:before {
+  content: "\f073";
+}
+.fa-random:before {
+  content: "\f074";
+}
+.fa-comment:before {
+  content: "\f075";
+}
+.fa-magnet:before {
+  content: "\f076";
+}
+.fa-chevron-up:before {
+  content: "\f077";
+}
+.fa-chevron-down:before {
+  content: "\f078";
+}
+.fa-retweet:before {
+  content: "\f079";
+}
+.fa-shopping-cart:before {
+  content: "\f07a";
+}
+.fa-folder:before {
+  content: "\f07b";
+}
+.fa-folder-open:before {
+  content: "\f07c";
+}
+.fa-arrows-v:before {
+  content: "\f07d";
+}
+.fa-arrows-h:before {
+  content: "\f07e";
+}
+.fa-bar-chart-o:before,
+.fa-bar-chart:before {
+  content: "\f080";
+}
+.fa-twitter-square:before {
+  content: "\f081";
+}
+.fa-facebook-square:before {
+  content: "\f082";
+}
+.fa-camera-retro:before {
+  content: "\f083";
+}
+.fa-key:before {
+  content: "\f084";
+}
+.fa-gears:before,
+.fa-cogs:before {
+  content: "\f085";
+}
+.fa-comments:before {
+  content: "\f086";
+}
+.fa-thumbs-o-up:before {
+  content: "\f087";
+}
+.fa-thumbs-o-down:before {
+  content: "\f088";
+}
+.fa-star-half:before {
+  content: "\f089";
+}
+.fa-heart-o:before {
+  content: "\f08a";
+}
+.fa-sign-out:before {
+  content: "\f08b";
+}
+.fa-linkedin-square:before {
+  content: "\f08c";
+}
+.fa-thumb-tack:before {
+  content: "\f08d";
+}
+.fa-external-link:before {
+  content: "\f08e";
+}
+.fa-sign-in:before {
+  content: "\f090";
+}
+.fa-trophy:before {
+  content: "\f091";
+}
+.fa-github-square:before {
+  content: "\f092";
+}
+.fa-upload:before {
+  content: "\f093";
+}
+.fa-lemon-o:before {
+  content: "\f094";
+}
+.fa-phone:before {
+  content: "\f095";
+}
+.fa-square-o:before {
+  content: "\f096";
+}
+.fa-bookmark-o:before {
+  content: "\f097";
+}
+.fa-phone-square:before {
+  content: "\f098";
+}
+.fa-twitter:before {
+  content: "\f099";
+}
+.fa-facebook:before {
+  content: "\f09a";
+}
+.fa-github:before {
+  content: "\f09b";
+}
+.fa-unlock:before {
+  content: "\f09c";
+}
+.fa-credit-card:before {
+  content: "\f09d";
+}
+.fa-rss:before {
+  content: "\f09e";
+}
+.fa-hdd-o:before {
+  content: "\f0a0";
+}
+.fa-bullhorn:before {
+  content: "\f0a1";
+}
+.fa-bell:before {
+  content: "\f0f3";
+}
+.fa-certificate:before {
+  content: "\f0a3";
+}
+.fa-hand-o-right:before {
+  content: "\f0a4";
+}
+.fa-hand-o-left:before {
+  content: "\f0a5";
+}
+.fa-hand-o-up:before {
+  content: "\f0a6";
+}
+.fa-hand-o-down:before {
+  content: "\f0a7";
+}
+.fa-arrow-circle-left:before {
+  content: "\f0a8";
+}
+.fa-arrow-circle-right:before {
+  content: "\f0a9";
+}
+.fa-arrow-circle-up:before {
+  content: "\f0aa";
+}
+.fa-arrow-circle-down:before {
+  content: "\f0ab";
+}
+.fa-globe:before {
+  content: "\f0ac";
+}
+.fa-wrench:before {
+  content: "\f0ad";
+}
+.fa-tasks:before {
+  content: "\f0ae";
+}
+.fa-filter:before {
+  content: "\f0b0";
+}
+.fa-briefcase:before {
+  content: "\f0b1";
+}
+.fa-arrows-alt:before {
+  content: "\f0b2";
+}
+.fa-group:before,
+.fa-users:before {
+  content: "\f0c0";
+}
+.fa-chain:before,
+.fa-link:before {
+  content: "\f0c1";
+}
+.fa-cloud:before {
+  content: "\f0c2";
+}
+.fa-flask:before {
+  content: "\f0c3";
+}
+.fa-cut:before,
+.fa-scissors:before {
+  content: "\f0c4";
+}
+.fa-copy:before,
+.fa-files-o:before {
+  content: "\f0c5";
+}
+.fa-paperclip:before {
+  content: "\f0c6";
+}
+.fa-save:before,
+.fa-floppy-o:before {
+  content: "\f0c7";
+}
+.fa-square:before {
+  content: "\f0c8";
+}
+.fa-navicon:before,
+.fa-reorder:before,
+.fa-bars:before {
+  content: "\f0c9";
+}
+.fa-list-ul:before {
+  content: "\f0ca";
+}
+.fa-list-ol:before {
+  content: "\f0cb";
+}
+.fa-strikethrough:before {
+  content: "\f0cc";
+}
+.fa-underline:before {
+  content: "\f0cd";
+}
+.fa-table:before {
+  content: "\f0ce";
+}
+.fa-magic:before {
+  content: "\f0d0";
+}
+.fa-truck:before {
+  content: "\f0d1";
+}
+.fa-pinterest:before {
+  content: "\f0d2";
+}
+.fa-pinterest-square:before {
+  content: "\f0d3";
+}
+.fa-google-plus-square:before {
+  content: "\f0d4";
+}
+.fa-google-plus:before {
+  content: "\f0d5";
+}
+.fa-money:before {
+  content: "\f0d6";
+}
+.fa-caret-down:before {
+  content: "\f0d7";
+}
+.fa-caret-up:before {
+  content: "\f0d8";
+}
+.fa-caret-left:before {
+  content: "\f0d9";
+}
+.fa-caret-right:before {
+  content: "\f0da";
+}
+.fa-columns:before {
+  content: "\f0db";
+}
+.fa-unsorted:before,
+.fa-sort:before {
+  content: "\f0dc";
+}
+.fa-sort-down:before,
+.fa-sort-desc:before {
+  content: "\f0dd";
+}
+.fa-sort-up:before,
+.fa-sort-asc:before {
+  content: "\f0de";
+}
+.fa-envelope:before {
+  content: "\f0e0";
+}
+.fa-linkedin:before {
+  content: "\f0e1";
+}
+.fa-rotate-left:before,
+.fa-undo:before {
+  content: "\f0e2";
+}
+.fa-legal:before,
+.fa-gavel:before {
+  content: "\f0e3";
+}
+.fa-dashboard:before,
+.fa-tachometer:before {
+  content: "\f0e4";
+}
+.fa-comment-o:before {
+  content: "\f0e5";
+}
+.fa-comments-o:before {
+  content: "\f0e6";
+}
+.fa-flash:before,
+.fa-bolt:before {
+  content: "\f0e7";
+}
+.fa-sitemap:before {
+  content: "\f0e8";
+}
+.fa-umbrella:before {
+  content: "\f0e9";
+}
+.fa-paste:before,
+.fa-clipboard:before {
+  content: "\f0ea";
+}
+.fa-lightbulb-o:before {
+  content: "\f0eb";
+}
+.fa-exchange:before {
+  content: "\f0ec";
+}
+.fa-cloud-download:before {
+  content: "\f0ed";
+}
+.fa-cloud-upload:before {
+  content: "\f0ee";
+}
+.fa-user-md:before {
+  content: "\f0f0";
+}
+.fa-stethoscope:before {
+  content: "\f0f1";
+}
+.fa-suitcase:before {
+  content: "\f0f2";
+}
+.fa-bell-o:before {
+  content: "\f0a2";
+}
+.fa-coffee:before {
+  content: "\f0f4";
+}
+.fa-cutlery:before {
+  content: "\f0f5";
+}
+.fa-file-text-o:before {
+  content: "\f0f6";
+}
+.fa-building-o:before {
+  content: "\f0f7";
+}
+.fa-hospital-o:before {
+  content: "\f0f8";
+}
+.fa-ambulance:before {
+  content: "\f0f9";
+}
+.fa-medkit:before {
+  content: "\f0fa";
+}
+.fa-fighter-jet:before {
+  content: "\f0fb";
+}
+.fa-beer:before {
+  content: "\f0fc";
+}
+.fa-h-square:before {
+  content: "\f0fd";
+}
+.fa-plus-square:before {
+  content: "\f0fe";
+}
+.fa-angle-double-left:before {
+  content: "\f100";
+}
+.fa-angle-double-right:before {
+  content: "\f101";
+}
+.fa-angle-double-up:before {
+  content: "\f102";
+}
+.fa-angle-double-down:before {
+  content: "\f103";
+}
+.fa-angle-left:before {
+  content: "\f104";
+}
+.fa-angle-right:before {
+  content: "\f105";
+}
+.fa-angle-up:before {
+  content: "\f106";
+}
+.fa-angle-down:before {
+  content: "\f107";
+}
+.fa-desktop:before {
+  content: "\f108";
+}
+.fa-laptop:before {
+  content: "\f109";
+}
+.fa-tablet:before {
+  content: "\f10a";
+}
+.fa-mobile-phone:before,
+.fa-mobile:before {
+  content: "\f10b";
+}
+.fa-circle-o:before {
+  content: "\f10c";
+}
+.fa-quote-left:before {
+  content: "\f10d";
+}
+.fa-quote-right:before {
+  content: "\f10e";
+}
+.fa-spinner:before {
+  content: "\f110";
+}
+.fa-circle:before {
+  content: "\f111";
+}
+.fa-mail-reply:before,
+.fa-reply:before {
+  content: "\f112";
+}
+.fa-github-alt:before {
+  content: "\f113";
+}
+.fa-folder-o:before {
+  content: "\f114";
+}
+.fa-folder-open-o:before {
+  content: "\f115";
+}
+.fa-smile-o:before {
+  content: "\f118";
+}
+.fa-frown-o:before {
+  content: "\f119";
+}
+.fa-meh-o:before {
+  content: "\f11a";
+}
+.fa-gamepad:before {
+  content: "\f11b";
+}
+.fa-keyboard-o:before {
+  content: "\f11c";
+}
+.fa-flag-o:before {
+  content: "\f11d";
+}
+.fa-flag-checkered:before {
+  content: "\f11e";
+}
+.fa-terminal:before {
+  content: "\f120";
+}
+.fa-code:before {
+  content: "\f121";
+}
+.fa-mail-reply-all:before,
+.fa-reply-all:before {
+  content: "\f122";
+}
+.fa-star-half-empty:before,
+.fa-star-half-full:before,
+.fa-star-half-o:before {
+  content: "\f123";
+}
+.fa-location-arrow:before {
+  content: "\f124";
+}
+.fa-crop:before {
+  content: "\f125";
+}
+.fa-code-fork:before {
+  content: "\f126";
+}
+.fa-unlink:before,
+.fa-chain-broken:before {
+  content: "\f127";
+}
+.fa-question:before {
+  content: "\f128";
+}
+.fa-info:before {
+  content: "\f129";
+}
+.fa-exclamation:before {
+  content: "\f12a";
+}
+.fa-superscript:before {
+  content: "\f12b";
+}
+.fa-subscript:before {
+  content: "\f12c";
+}
+.fa-eraser:before {
+  content: "\f12d";
+}
+.fa-puzzle-piece:before {
+  content: "\f12e";
+}
+.fa-microphone:before {
+  content: "\f130";
+}
+.fa-microphone-slash:before {
+  content: "\f131";
+}
+.fa-shield:before {
+  content: "\f132";
+}
+.fa-calendar-o:before {
+  content: "\f133";
+}
+.fa-fire-extinguisher:before {
+  content: "\f134";
+}
+.fa-rocket:before {
+  content: "\f135";
+}
+.fa-maxcdn:before {
+  content: "\f136";
+}
+.fa-chevron-circle-left:before {
+  content: "\f137";
+}
+.fa-chevron-circle-right:before {
+  content: "\f138";
+}
+.fa-chevron-circle-up:before {
+  content: "\f139";
+}
+.fa-chevron-circle-down:before {
+  content: "\f13a";
+}
+.fa-html5:before {
+  content: "\f13b";
+}
+.fa-css3:before {
+  content: "\f13c";
+}
+.fa-anchor:before {
+  content: "\f13d";
+}
+.fa-unlock-alt:before {
+  content: "\f13e";
+}
+.fa-bullseye:before {
+  content: "\f140";
+}
+.fa-ellipsis-h:before {
+  content: "\f141";
+}
+.fa-ellipsis-v:before {
+  content: "\f142";
+}
+.fa-rss-square:before {
+  content: "\f143";
+}
+.fa-play-circle:before {
+  content: "\f144";
+}
+.fa-ticket:before {
+  content: "\f145";
+}
+.fa-minus-square:before {
+  content: "\f146";
+}
+.fa-minus-square-o:before {
+  content: "\f147";
+}
+.fa-level-up:before {
+  content: "\f148";
+}
+.fa-level-down:before {
+  content: "\f149";
+}
+.fa-check-square:before {
+  content: "\f14a";
+}
+.fa-pencil-square:before {
+  content: "\f14b";
+}
+.fa-external-link-square:before {
+  content: "\f14c";
+}
+.fa-share-square:before {
+  content: "\f14d";
+}
+.fa-compass:before {
+  content: "\f14e";
+}
+.fa-toggle-down:before,
+.fa-caret-square-o-down:before {
+  content: "\f150";
+}
+.fa-toggle-up:before,
+.fa-caret-square-o-up:before {
+  content: "\f151";
+}
+.fa-toggle-right:before,
+.fa-caret-square-o-right:before {
+  content: "\f152";
+}
+.fa-euro:before,
+.fa-eur:before {
+  content: "\f153";
+}
+.fa-gbp:before {
+  content: "\f154";
+}
+.fa-dollar:before,
+.fa-usd:before {
+  content: "\f155";
+}
+.fa-rupee:before,
+.fa-inr:before {
+  content: "\f156";
+}
+.fa-cny:before,
+.fa-rmb:before,
+.fa-yen:before,
+.fa-jpy:before {
+  content: "\f157";
+}
+.fa-ruble:before,
+.fa-rouble:before,
+.fa-rub:before {
+  content: "\f158";
+}
+.fa-won:before,
+.fa-krw:before {
+  content: "\f159";
+}
+.fa-bitcoin:before,
+.fa-btc:before {
+  content: "\f15a";
+}
+.fa-file:before {
+  content: "\f15b";
+}
+.fa-file-text:before {
+  content: "\f15c";
+}
+.fa-sort-alpha-asc:before {
+  content: "\f15d";
+}
+.fa-sort-alpha-desc:before {
+  content: "\f15e";
+}
+.fa-sort-amount-asc:before {
+  content: "\f160";
+}
+.fa-sort-amount-desc:before {
+  content: "\f161";
+}
+.fa-sort-numeric-asc:before {
+  content: "\f162";
+}
+.fa-sort-numeric-desc:before {
+  content: "\f163";
+}
+.fa-thumbs-up:before {
+  content: "\f164";
+}
+.fa-thumbs-down:before {
+  content: "\f165";
+}
+.fa-youtube-square:before {
+  content: "\f166";
+}
+.fa-youtube:before {
+  content: "\f167";
+}
+.fa-xing:before {
+  content: "\f168";
+}
+.fa-xing-square:before {
+  content: "\f169";
+}
+.fa-youtube-play:before {
+  content: "\f16a";
+}
+.fa-dropbox:before {
+  content: "\f16b";
+}
+.fa-stack-overflow:before {
+  content: "\f16c";
+}
+.fa-instagram:before {
+  content: "\f16d";
+}
+.fa-flickr:before {
+  content: "\f16e";
+}
+.fa-adn:before {
+  content: "\f170";
+}
+.fa-bitbucket:before {
+  content: "\f171";
+}
+.fa-bitbucket-square:before {
+  content: "\f172";
+}
+.fa-tumblr:before {
+  content: "\f173";
+}
+.fa-tumblr-square:before {
+  content: "\f174";
+}
+.fa-long-arrow-down:before {
+  content: "\f175";
+}
+.fa-long-arrow-up:before {
+  content: "\f176";
+}
+.fa-long-arrow-left:before {
+  content: "\f177";
+}
+.fa-long-arrow-right:before {
+  content: "\f178";
+}
+.fa-apple:before {
+  content: "\f179";
+}
+.fa-windows:before {
+  content: "\f17a";
+}
+.fa-android:before {
+  content: "\f17b";
+}
+.fa-linux:before {
+  content: "\f17c";
+}
+.fa-dribbble:before {
+  content: "\f17d";
+}
+.fa-skype:before {
+  content: "\f17e";
+}
+.fa-foursquare:before {
+  content: "\f180";
+}
+.fa-trello:before {
+  content: "\f181";
+}
+.fa-female:before {
+  content: "\f182";
+}
+.fa-male:before {
+  content: "\f183";
+}
+.fa-gittip:before {
+  content: "\f184";
+}
+.fa-sun-o:before {
+  content: "\f185";
+}
+.fa-moon-o:before {
+  content: "\f186";
+}
+.fa-archive:before {
+  content: "\f187";
+}
+.fa-bug:before {
+  content: "\f188";
+}
+.fa-vk:before {
+  content: "\f189";
+}
+.fa-weibo:before {
+  content: "\f18a";
+}
+.fa-renren:before {
+  content: "\f18b";
+}
+.fa-pagelines:before {
+  content: "\f18c";
+}
+.fa-stack-exchange:before {
+  content: "\f18d";
+}
+.fa-arrow-circle-o-right:before {
+  content: "\f18e";
+}
+.fa-arrow-circle-o-left:before {
+  content: "\f190";
+}
+.fa-toggle-left:before,
+.fa-caret-square-o-left:before {
+  content: "\f191";
+}
+.fa-dot-circle-o:before {
+  content: "\f192";
+}
+.fa-wheelchair:before {
+  content: "\f193";
+}
+.fa-vimeo-square:before {
+  content: "\f194";
+}
+.fa-turkish-lira:before,
+.fa-try:before {
+  content: "\f195";
+}
+.fa-plus-square-o:before {
+  content: "\f196";
+}
+.fa-space-shuttle:before {
+  content: "\f197";
+}
+.fa-slack:before {
+  content: "\f198";
+}
+.fa-envelope-square:before {
+  content: "\f199";
+}
+.fa-wordpress:before {
+  content: "\f19a";
+}
+.fa-openid:before {
+  content: "\f19b";
+}
+.fa-institution:before,
+.fa-bank:before,
+.fa-university:before {
+  content: "\f19c";
+}
+.fa-mortar-board:before,
+.fa-graduation-cap:before {
+  content: "\f19d";
+}
+.fa-yahoo:before {
+  content: "\f19e";
+}
+.fa-google:before {
+  content: "\f1a0";
+}
+.fa-reddit:before {
+  content: "\f1a1";
+}
+.fa-reddit-square:before {
+  content: "\f1a2";
+}
+.fa-stumbleupon-circle:before {
+  content: "\f1a3";
+}
+.fa-stumbleupon:before {
+  content: "\f1a4";
+}
+.fa-delicious:before {
+  content: "\f1a5";
+}
+.fa-digg:before {
+  content: "\f1a6";
+}
+.fa-pied-piper:before {
+  content: "\f1a7";
+}
+.fa-pied-piper-alt:before {
+  content: "\f1a8";
+}
+.fa-drupal:before {
+  content: "\f1a9";
+}
+.fa-joomla:before {
+  content: "\f1aa";
+}
+.fa-language:before {
+  content: "\f1ab";
+}
+.fa-fax:before {
+  content: "\f1ac";
+}
+.fa-building:before {
+  content: "\f1ad";
+}
+.fa-child:before {
+  content: "\f1ae";
+}
+.fa-paw:before {
+  content: "\f1b0";
+}
+.fa-spoon:before {
+  content: "\f1b1";
+}
+.fa-cube:before {
+  content: "\f1b2";
+}
+.fa-cubes:before {
+  content: "\f1b3";
+}
+.fa-behance:before {
+  content: "\f1b4";
+}
+.fa-behance-square:before {
+  content: "\f1b5";
+}
+.fa-steam:before {
+  content: "\f1b6";
+}
+.fa-steam-square:before {
+  content: "\f1b7";
+}
+.fa-recycle:before {
+  content: "\f1b8";
+}
+.fa-automobile:before,
+.fa-car:before {
+  content: "\f1b9";
+}
+.fa-cab:before,
+.fa-taxi:before {
+  content: "\f1ba";
+}
+.fa-tree:before {
+  content: "\f1bb";
+}
+.fa-spotify:before {
+  content: "\f1bc";
+}
+.fa-deviantart:before {
+  content: "\f1bd";
+}
+.fa-soundcloud:before {
+  content: "\f1be";
+}
+.fa-database:before {
+  content: "\f1c0";
+}
+.fa-file-pdf-o:before {
+  content: "\f1c1";
+}
+.fa-file-word-o:before {
+  content: "\f1c2";
+}
+.fa-file-excel-o:before {
+  content: "\f1c3";
+}
+.fa-file-powerpoint-o:before {
+  content: "\f1c4";
+}
+.fa-file-photo-o:before,
+.fa-file-picture-o:before,
+.fa-file-image-o:before {
+  content: "\f1c5";
+}
+.fa-file-zip-o:before,
+.fa-file-archive-o:before {
+  content: "\f1c6";
+}
+.fa-file-sound-o:before,
+.fa-file-audio-o:before {
+  content: "\f1c7";
+}
+.fa-file-movie-o:before,
+.fa-file-video-o:before {
+  content: "\f1c8";
+}
+.fa-file-code-o:before {
+  content: "\f1c9";
+}
+.fa-vine:before {
+  content: "\f1ca";
+}
+.fa-codepen:before {
+  content: "\f1cb";
+}
+.fa-jsfiddle:before {
+  content: "\f1cc";
+}
+.fa-life-bouy:before,
+.fa-life-buoy:before,
+.fa-life-saver:before,
+.fa-support:before,
+.fa-life-ring:before {
+  content: "\f1cd";
+}
+.fa-circle-o-notch:before {
+  content: "\f1ce";
+}
+.fa-ra:before,
+.fa-rebel:before {
+  content: "\f1d0";
+}
+.fa-ge:before,
+.fa-empire:before {
+  content: "\f1d1";
+}
+.fa-git-square:before {
+  content: "\f1d2";
+}
+.fa-git:before {
+  content: "\f1d3";
+}
+.fa-hacker-news:before {
+  content: "\f1d4";
+}
+.fa-tencent-weibo:before {
+  content: "\f1d5";
+}
+.fa-qq:before {
+  content: "\f1d6";
+}
+.fa-wechat:before,
+.fa-weixin:before {
+  content: "\f1d7";
+}
+.fa-send:before,
+.fa-paper-plane:before {
+  content: "\f1d8";
+}
+.fa-send-o:before,
+.fa-paper-plane-o:before {
+  content: "\f1d9";
+}
+.fa-history:before {
+  content: "\f1da";
+}
+.fa-circle-thin:before {
+  content: "\f1db";
+}
+.fa-header:before {
+  content: "\f1dc";
+}
+.fa-paragraph:before {
+  content: "\f1dd";
+}
+.fa-sliders:before {
+  content: "\f1de";
+}
+.fa-share-alt:before {
+  content: "\f1e0";
+}
+.fa-share-alt-square:before {
+  content: "\f1e1";
+}
+.fa-bomb:before {
+  content: "\f1e2";
+}
+.fa-soccer-ball-o:before,
+.fa-futbol-o:before {
+  content: "\f1e3";
+}
+.fa-tty:before {
+  content: "\f1e4";
+}
+.fa-binoculars:before {
+  content: "\f1e5";
+}
+.fa-plug:before {
+  content: "\f1e6";
+}
+.fa-slideshare:before {
+  content: "\f1e7";
+}
+.fa-twitch:before {
+  content: "\f1e8";
+}
+.fa-yelp:before {
+  content: "\f1e9";
+}
+.fa-newspaper-o:before {
+  content: "\f1ea";
+}
+.fa-wifi:before {
+  content: "\f1eb";
+}
+.fa-calculator:before {
+  content: "\f1ec";
+}
+.fa-paypal:before {
+  content: "\f1ed";
+}
+.fa-google-wallet:before {
+  content: "\f1ee";
+}
+.fa-cc-visa:before {
+  content: "\f1f0";
+}
+.fa-cc-mastercard:before {
+  content: "\f1f1";
+}
+.fa-cc-discover:before {
+  content: "\f1f2";
+}
+.fa-cc-amex:before {
+  content: "\f1f3";
+}
+.fa-cc-paypal:before {
+  content: "\f1f4";
+}
+.fa-cc-stripe:before {
+  content: "\f1f5";
+}
+.fa-bell-slash:before {
+  content: "\f1f6";
+}
+.fa-bell-slash-o:before {
+  content: "\f1f7";
+}
+.fa-trash:before {
+  content: "\f1f8";
+}
+.fa-copyright:before {
+  content: "\f1f9";
+}
+.fa-at:before {
+  content: "\f1fa";
+}
+.fa-eyedropper:before {
+  content: "\f1fb";
+}
+.fa-paint-brush:before {
+  content: "\f1fc";
+}
+.fa-birthday-cake:before {
+  content: "\f1fd";
+}
+.fa-area-chart:before {
+  content: "\f1fe";
+}
+.fa-pie-chart:before {
+  content: "\f200";
+}
+.fa-line-chart:before {
+  content: "\f201";
+}
+.fa-lastfm:before {
+  content: "\f202";
+}
+.fa-lastfm-square:before {
+  content: "\f203";
+}
+.fa-toggle-off:before {
+  content: "\f204";
+}
+.fa-toggle-on:before {
+  content: "\f205";
+}
+.fa-bicycle:before {
+  content: "\f206";
+}
+.fa-bus:before {
+  content: "\f207";
+}
+.fa-ioxhost:before {
+  content: "\f208";
+}
+.fa-angellist:before {
+  content: "\f209";
+}
+.fa-cc:before {
+  content: "\f20a";
+}
+.fa-shekel:before,
+.fa-sheqel:before,
+.fa-ils:before {
+  content: "\f20b";
+}
+.fa-meanpath:before {
+  content: "\f20c";
+}
+/*!
+*
+* IPython base
+*
+*/
+.modal.fade .modal-dialog {
+  -webkit-transform: translate(0, 0);
+  -ms-transform: translate(0, 0);
+  -o-transform: translate(0, 0);
+  transform: translate(0, 0);
+}
+code {
+  color: #000;
+}
+pre {
+  font-size: inherit;
+  line-height: inherit;
+}
+label {
+  font-weight: normal;
+}
+/* Make the page background atleast 100% the height of the view port */
+/* Make the page itself atleast 70% the height of the view port */
+.border-box-sizing {
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+}
+.corner-all {
+  border-radius: 2px;
+}
+.no-padding {
+  padding: 0px;
+}
+/* Flexible box model classes */
+/* Taken from Alex Russell http://infrequently.org/2009/08/css-3-progress/ */
+/* This file is a compatability layer.  It allows the usage of flexible box 
+model layouts accross multiple browsers, including older browsers.  The newest,
+universal implementation of the flexible box model is used when available (see
+`Modern browsers` comments below).  Browsers that are known to implement this 
+new spec completely include:
+
+    Firefox 28.0+
+    Chrome 29.0+
+    Internet Explorer 11+ 
+    Opera 17.0+
+
+Browsers not listed, including Safari, are supported via the styling under the
+`Old browsers` comments below.
+*/
+.hbox {
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: horizontal;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: horizontal;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: horizontal;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: row;
+  align-items: stretch;
+}
+.hbox > * {
+  /* Old browsers */
+  -webkit-box-flex: 0;
+  -moz-box-flex: 0;
+  box-flex: 0;
+  /* Modern browsers */
+  flex: none;
+}
+.vbox {
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: vertical;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: vertical;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: column;
+  align-items: stretch;
+}
+.vbox > * {
+  /* Old browsers */
+  -webkit-box-flex: 0;
+  -moz-box-flex: 0;
+  box-flex: 0;
+  /* Modern browsers */
+  flex: none;
+}
+.hbox.reverse,
+.vbox.reverse,
+.reverse {
+  /* Old browsers */
+  -webkit-box-direction: reverse;
+  -moz-box-direction: reverse;
+  box-direction: reverse;
+  /* Modern browsers */
+  flex-direction: row-reverse;
+}
+.hbox.box-flex0,
+.vbox.box-flex0,
+.box-flex0 {
+  /* Old browsers */
+  -webkit-box-flex: 0;
+  -moz-box-flex: 0;
+  box-flex: 0;
+  /* Modern browsers */
+  flex: none;
+  width: auto;
+}
+.hbox.box-flex1,
+.vbox.box-flex1,
+.box-flex1 {
+  /* Old browsers */
+  -webkit-box-flex: 1;
+  -moz-box-flex: 1;
+  box-flex: 1;
+  /* Modern browsers */
+  flex: 1;
+}
+.hbox.box-flex,
+.vbox.box-flex,
+.box-flex {
+  /* Old browsers */
+  /* Old browsers */
+  -webkit-box-flex: 1;
+  -moz-box-flex: 1;
+  box-flex: 1;
+  /* Modern browsers */
+  flex: 1;
+}
+.hbox.box-flex2,
+.vbox.box-flex2,
+.box-flex2 {
+  /* Old browsers */
+  -webkit-box-flex: 2;
+  -moz-box-flex: 2;
+  box-flex: 2;
+  /* Modern browsers */
+  flex: 2;
+}
+.box-group1 {
+  /*  Deprecated */
+  -webkit-box-flex-group: 1;
+  -moz-box-flex-group: 1;
+  box-flex-group: 1;
+}
+.box-group2 {
+  /* Deprecated */
+  -webkit-box-flex-group: 2;
+  -moz-box-flex-group: 2;
+  box-flex-group: 2;
+}
+.hbox.start,
+.vbox.start,
+.start {
+  /* Old browsers */
+  -webkit-box-pack: start;
+  -moz-box-pack: start;
+  box-pack: start;
+  /* Modern browsers */
+  justify-content: flex-start;
+}
+.hbox.end,
+.vbox.end,
+.end {
+  /* Old browsers */
+  -webkit-box-pack: end;
+  -moz-box-pack: end;
+  box-pack: end;
+  /* Modern browsers */
+  justify-content: flex-end;
+}
+.hbox.center,
+.vbox.center,
+.center {
+  /* Old browsers */
+  -webkit-box-pack: center;
+  -moz-box-pack: center;
+  box-pack: center;
+  /* Modern browsers */
+  justify-content: center;
+}
+.hbox.baseline,
+.vbox.baseline,
+.baseline {
+  /* Old browsers */
+  -webkit-box-pack: baseline;
+  -moz-box-pack: baseline;
+  box-pack: baseline;
+  /* Modern browsers */
+  justify-content: baseline;
+}
+.hbox.stretch,
+.vbox.stretch,
+.stretch {
+  /* Old browsers */
+  -webkit-box-pack: stretch;
+  -moz-box-pack: stretch;
+  box-pack: stretch;
+  /* Modern browsers */
+  justify-content: stretch;
+}
+.hbox.align-start,
+.vbox.align-start,
+.align-start {
+  /* Old browsers */
+  -webkit-box-align: start;
+  -moz-box-align: start;
+  box-align: start;
+  /* Modern browsers */
+  align-items: flex-start;
+}
+.hbox.align-end,
+.vbox.align-end,
+.align-end {
+  /* Old browsers */
+  -webkit-box-align: end;
+  -moz-box-align: end;
+  box-align: end;
+  /* Modern browsers */
+  align-items: flex-end;
+}
+.hbox.align-center,
+.vbox.align-center,
+.align-center {
+  /* Old browsers */
+  -webkit-box-align: center;
+  -moz-box-align: center;
+  box-align: center;
+  /* Modern browsers */
+  align-items: center;
+}
+.hbox.align-baseline,
+.vbox.align-baseline,
+.align-baseline {
+  /* Old browsers */
+  -webkit-box-align: baseline;
+  -moz-box-align: baseline;
+  box-align: baseline;
+  /* Modern browsers */
+  align-items: baseline;
+}
+.hbox.align-stretch,
+.vbox.align-stretch,
+.align-stretch {
+  /* Old browsers */
+  -webkit-box-align: stretch;
+  -moz-box-align: stretch;
+  box-align: stretch;
+  /* Modern browsers */
+  align-items: stretch;
+}
+div.error {
+  margin: 2em;
+  text-align: center;
+}
+div.error > h1 {
+  font-size: 500%;
+  line-height: normal;
+}
+div.error > p {
+  font-size: 200%;
+  line-height: normal;
+}
+div.traceback-wrapper {
+  text-align: left;
+  max-width: 800px;
+  margin: auto;
+}
+/**
+ * Primary styles
+ *
+ * Author: Jupyter Development Team
+ */
+body {
+  background-color: #fff;
+  /* This makes sure that the body covers the entire window and needs to
+       be in a different element than the display: box in wrapper below */
+  position: absolute;
+  left: 0px;
+  right: 0px;
+  top: 0px;
+  bottom: 0px;
+  overflow: visible;
+}
+body > #header {
+  /* Initially hidden to prevent FLOUC */
+  display: none;
+  background-color: #fff;
+  /* Display over codemirror */
+  position: relative;
+  z-index: 100;
+}
+body > #header #header-container {
+  padding-bottom: 5px;
+  padding-top: 5px;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+}
+body > #header .header-bar {
+  width: 100%;
+  height: 1px;
+  background: #e7e7e7;
+  margin-bottom: -1px;
+}
+@media print {
+  body > #header {
+    display: none !important;
+  }
+}
+#header-spacer {
+  width: 100%;
+  visibility: hidden;
+}
+@media print {
+  #header-spacer {
+    display: none;
+  }
+}
+#ipython_notebook {
+  padding-left: 0px;
+  padding-top: 1px;
+  padding-bottom: 1px;
+}
+@media (max-width: 991px) {
+  #ipython_notebook {
+    margin-left: 10px;
+  }
+}
+[dir="rtl"] #ipython_notebook {
+  float: right !important;
+}
+#noscript {
+  width: auto;
+  padding-top: 16px;
+  padding-bottom: 16px;
+  text-align: center;
+  font-size: 22px;
+  color: red;
+  font-weight: bold;
+}
+#ipython_notebook img {
+  height: 28px;
+}
+#site {
+  width: 100%;
+  display: none;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+  overflow: auto;
+}
+@media print {
+  #site {
+    height: auto !important;
+  }
+}
+/* Smaller buttons */
+.ui-button .ui-button-text {
+  padding: 0.2em 0.8em;
+  font-size: 77%;
+}
+input.ui-button {
+  padding: 0.3em 0.9em;
+}
+span#login_widget {
+  float: right;
+}
+span#login_widget > .button,
+#logout {
+  color: #333;
+  background-color: #fff;
+  border-color: #ccc;
+}
+span#login_widget > .button:focus,
+#logout:focus,
+span#login_widget > .button.focus,
+#logout.focus {
+  color: #333;
+  background-color: #e6e6e6;
+  border-color: #8c8c8c;
+}
+span#login_widget > .button:hover,
+#logout:hover {
+  color: #333;
+  background-color: #e6e6e6;
+  border-color: #adadad;
+}
+span#login_widget > .button:active,
+#logout:active,
+span#login_widget > .button.active,
+#logout.active,
+.open > .dropdown-togglespan#login_widget > .button,
+.open > .dropdown-toggle#logout {
+  color: #333;
+  background-color: #e6e6e6;
+  border-color: #adadad;
+}
+span#login_widget > .button:active:hover,
+#logout:active:hover,
+span#login_widget > .button.active:hover,
+#logout.active:hover,
+.open > .dropdown-togglespan#login_widget > .button:hover,
+.open > .dropdown-toggle#logout:hover,
+span#login_widget > .button:active:focus,
+#logout:active:focus,
+span#login_widget > .button.active:focus,
+#logout.active:focus,
+.open > .dropdown-togglespan#login_widget > .button:focus,
+.open > .dropdown-toggle#logout:focus,
+span#login_widget > .button:active.focus,
+#logout:active.focus,
+span#login_widget > .button.active.focus,
+#logout.active.focus,
+.open > .dropdown-togglespan#login_widget > .button.focus,
+.open > .dropdown-toggle#logout.focus {
+  color: #333;
+  background-color: #d4d4d4;
+  border-color: #8c8c8c;
+}
+span#login_widget > .button:active,
+#logout:active,
+span#login_widget > .button.active,
+#logout.active,
+.open > .dropdown-togglespan#login_widget > .button,
+.open > .dropdown-toggle#logout {
+  background-image: none;
+}
+span#login_widget > .button.disabled:hover,
+#logout.disabled:hover,
+span#login_widget > .button[disabled]:hover,
+#logout[disabled]:hover,
+fieldset[disabled] span#login_widget > .button:hover,
+fieldset[disabled] #logout:hover,
+span#login_widget > .button.disabled:focus,
+#logout.disabled:focus,
+span#login_widget > .button[disabled]:focus,
+#logout[disabled]:focus,
+fieldset[disabled] span#login_widget > .button:focus,
+fieldset[disabled] #logout:focus,
+span#login_widget > .button.disabled.focus,
+#logout.disabled.focus,
+span#login_widget > .button[disabled].focus,
+#logout[disabled].focus,
+fieldset[disabled] span#login_widget > .button.focus,
+fieldset[disabled] #logout.focus {
+  background-color: #fff;
+  border-color: #ccc;
+}
+span#login_widget > .button .badge,
+#logout .badge {
+  color: #fff;
+  background-color: #333;
+}
+.nav-header {
+  text-transform: none;
+}
+#header > span {
+  margin-top: 10px;
+}
+.modal_stretch .modal-dialog {
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: vertical;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: vertical;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: column;
+  align-items: stretch;
+  min-height: 80vh;
+}
+.modal_stretch .modal-dialog .modal-body {
+  max-height: calc(100vh - 200px);
+  overflow: auto;
+  flex: 1;
+}
+@media (min-width: 768px) {
+  .modal .modal-dialog {
+    width: 700px;
+  }
+}
+@media (min-width: 768px) {
+  select.form-control {
+    margin-left: 12px;
+    margin-right: 12px;
+  }
+}
+/*!
+*
+* IPython auth
+*
+*/
+.center-nav {
+  display: inline-block;
+  margin-bottom: -4px;
+}
+/*!
+*
+* IPython tree view
+*
+*/
+/* We need an invisible input field on top of the sentense*/
+/* "Drag file onto the list ..." */
+.alternate_upload {
+  background-color: none;
+  display: inline;
+}
+.alternate_upload.form {
+  padding: 0;
+  margin: 0;
+}
+.alternate_upload input.fileinput {
+  text-align: center;
+  vertical-align: middle;
+  display: inline;
+  opacity: 0;
+  z-index: 2;
+  width: 12ex;
+  margin-right: -12ex;
+}
+.alternate_upload .btn-upload {
+  height: 22px;
+}
+/**
+ * Primary styles
+ *
+ * Author: Jupyter Development Team
+ */
+[dir="rtl"] #tabs li {
+  float: right;
+}
+ul#tabs {
+  margin-bottom: 4px;
+}
+[dir="rtl"] ul#tabs {
+  margin-right: 0px;
+}
+ul#tabs a {
+  padding-top: 6px;
+  padding-bottom: 4px;
+}
+ul.breadcrumb a:focus,
+ul.breadcrumb a:hover {
+  text-decoration: none;
+}
+ul.breadcrumb i.icon-home {
+  font-size: 16px;
+  margin-right: 4px;
+}
+ul.breadcrumb span {
+  color: #5e5e5e;
+}
+.list_toolbar {
+  padding: 4px 0 4px 0;
+  vertical-align: middle;
+}
+.list_toolbar .tree-buttons {
+  padding-top: 1px;
+}
+[dir="rtl"] .list_toolbar .tree-buttons {
+  float: left !important;
+}
+[dir="rtl"] .list_toolbar .pull-right {
+  padding-top: 1px;
+  float: left !important;
+}
+[dir="rtl"] .list_toolbar .pull-left {
+  float: right !important;
+}
+.dynamic-buttons {
+  padding-top: 3px;
+  display: inline-block;
+}
+.list_toolbar [class*="span"] {
+  min-height: 24px;
+}
+.list_header {
+  font-weight: bold;
+  background-color: #EEE;
+}
+.list_placeholder {
+  font-weight: bold;
+  padding-top: 4px;
+  padding-bottom: 4px;
+  padding-left: 7px;
+  padding-right: 7px;
+}
+.list_container {
+  margin-top: 4px;
+  margin-bottom: 20px;
+  border: 1px solid #ddd;
+  border-radius: 2px;
+}
+.list_container > div {
+  border-bottom: 1px solid #ddd;
+}
+.list_container > div:hover .list-item {
+  background-color: red;
+}
+.list_container > div:last-child {
+  border: none;
+}
+.list_item:hover .list_item {
+  background-color: #ddd;
+}
+.list_item a {
+  text-decoration: none;
+}
+.list_item:hover {
+  background-color: #fafafa;
+}
+.list_header > div,
+.list_item > div {
+  padding-top: 4px;
+  padding-bottom: 4px;
+  padding-left: 7px;
+  padding-right: 7px;
+  line-height: 22px;
+}
+.list_header > div input,
+.list_item > div input {
+  margin-right: 7px;
+  margin-left: 14px;
+  vertical-align: baseline;
+  line-height: 22px;
+  position: relative;
+  top: -1px;
+}
+.list_header > div .item_link,
+.list_item > div .item_link {
+  margin-left: -1px;
+  vertical-align: baseline;
+  line-height: 22px;
+}
+.new-file input[type=checkbox] {
+  visibility: hidden;
+}
+.item_name {
+  line-height: 22px;
+  height: 24px;
+}
+.item_icon {
+  font-size: 14px;
+  color: #5e5e5e;
+  margin-right: 7px;
+  margin-left: 7px;
+  line-height: 22px;
+  vertical-align: baseline;
+}
+.item_buttons {
+  line-height: 1em;
+  margin-left: -5px;
+}
+.item_buttons .btn,
+.item_buttons .btn-group,
+.item_buttons .input-group {
+  float: left;
+}
+.item_buttons > .btn,
+.item_buttons > .btn-group,
+.item_buttons > .input-group {
+  margin-left: 5px;
+}
+.item_buttons .btn {
+  min-width: 13ex;
+}
+.item_buttons .running-indicator {
+  padding-top: 4px;
+  color: #5cb85c;
+}
+.item_buttons .kernel-name {
+  padding-top: 4px;
+  color: #5bc0de;
+  margin-right: 7px;
+  float: left;
+}
+.toolbar_info {
+  height: 24px;
+  line-height: 24px;
+}
+.list_item input:not([type=checkbox]) {
+  padding-top: 3px;
+  padding-bottom: 3px;
+  height: 22px;
+  line-height: 14px;
+  margin: 0px;
+}
+.highlight_text {
+  color: blue;
+}
+#project_name {
+  display: inline-block;
+  padding-left: 7px;
+  margin-left: -2px;
+}
+#project_name > .breadcrumb {
+  padding: 0px;
+  margin-bottom: 0px;
+  background-color: transparent;
+  font-weight: bold;
+}
+#tree-selector {
+  padding-right: 0px;
+}
+[dir="rtl"] #tree-selector a {
+  float: right;
+}
+#button-select-all {
+  min-width: 50px;
+}
+#select-all {
+  margin-left: 7px;
+  margin-right: 2px;
+}
+.menu_icon {
+  margin-right: 2px;
+}
+.tab-content .row {
+  margin-left: 0px;
+  margin-right: 0px;
+}
+.folder_icon:before {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  content: "\f114";
+}
+.folder_icon:before.pull-left {
+  margin-right: .3em;
+}
+.folder_icon:before.pull-right {
+  margin-left: .3em;
+}
+.notebook_icon:before {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  content: "\f02d";
+  position: relative;
+  top: -1px;
+}
+.notebook_icon:before.pull-left {
+  margin-right: .3em;
+}
+.notebook_icon:before.pull-right {
+  margin-left: .3em;
+}
+.running_notebook_icon:before {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  content: "\f02d";
+  position: relative;
+  top: -1px;
+  color: #5cb85c;
+}
+.running_notebook_icon:before.pull-left {
+  margin-right: .3em;
+}
+.running_notebook_icon:before.pull-right {
+  margin-left: .3em;
+}
+.file_icon:before {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  content: "\f016";
+  position: relative;
+  top: -2px;
+}
+.file_icon:before.pull-left {
+  margin-right: .3em;
+}
+.file_icon:before.pull-right {
+  margin-left: .3em;
+}
+#notebook_toolbar .pull-right {
+  padding-top: 0px;
+  margin-right: -1px;
+}
+ul#new-menu {
+  left: auto;
+  right: 0;
+}
+[dir="rtl"] #new-menu {
+  text-align: right;
+}
+.kernel-menu-icon {
+  padding-right: 12px;
+  width: 24px;
+  content: "\f096";
+}
+.kernel-menu-icon:before {
+  content: "\f096";
+}
+.kernel-menu-icon-current:before {
+  content: "\f00c";
+}
+#tab_content {
+  padding-top: 20px;
+}
+#running .panel-group .panel {
+  margin-top: 3px;
+  margin-bottom: 1em;
+}
+#running .panel-group .panel .panel-heading {
+  background-color: #EEE;
+  padding-top: 4px;
+  padding-bottom: 4px;
+  padding-left: 7px;
+  padding-right: 7px;
+  line-height: 22px;
+}
+#running .panel-group .panel .panel-heading a:focus,
+#running .panel-group .panel .panel-heading a:hover {
+  text-decoration: none;
+}
+#running .panel-group .panel .panel-body {
+  padding: 0px;
+}
+#running .panel-group .panel .panel-body .list_container {
+  margin-top: 0px;
+  margin-bottom: 0px;
+  border: 0px;
+  border-radius: 0px;
+}
+#running .panel-group .panel .panel-body .list_container .list_item {
+  border-bottom: 1px solid #ddd;
+}
+#running .panel-group .panel .panel-body .list_container .list_item:last-child {
+  border-bottom: 0px;
+}
+[dir="rtl"] #running .col-sm-8 {
+  float: right !important;
+}
+.delete-button {
+  display: none;
+}
+.duplicate-button {
+  display: none;
+}
+.rename-button {
+  display: none;
+}
+.shutdown-button {
+  display: none;
+}
+.dynamic-instructions {
+  display: inline-block;
+  padding-top: 4px;
+}
+/*!
+*
+* IPython text editor webapp
+*
+*/
+.selected-keymap i.fa {
+  padding: 0px 5px;
+}
+.selected-keymap i.fa:before {
+  content: "\f00c";
+}
+#mode-menu {
+  overflow: auto;
+  max-height: 20em;
+}
+.edit_app #header {
+  -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+  box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+}
+.edit_app #menubar .navbar {
+  /* Use a negative 1 bottom margin, so the border overlaps the border of the
+    header */
+  margin-bottom: -1px;
+}
+.dirty-indicator {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  width: 20px;
+}
+.dirty-indicator.pull-left {
+  margin-right: .3em;
+}
+.dirty-indicator.pull-right {
+  margin-left: .3em;
+}
+.dirty-indicator-dirty {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  width: 20px;
+}
+.dirty-indicator-dirty.pull-left {
+  margin-right: .3em;
+}
+.dirty-indicator-dirty.pull-right {
+  margin-left: .3em;
+}
+.dirty-indicator-clean {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  width: 20px;
+}
+.dirty-indicator-clean.pull-left {
+  margin-right: .3em;
+}
+.dirty-indicator-clean.pull-right {
+  margin-left: .3em;
+}
+.dirty-indicator-clean:before {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  content: "\f00c";
+}
+.dirty-indicator-clean:before.pull-left {
+  margin-right: .3em;
+}
+.dirty-indicator-clean:before.pull-right {
+  margin-left: .3em;
+}
+#filename {
+  font-size: 16pt;
+  display: table;
+  padding: 0px 5px;
+}
+#current-mode {
+  padding-left: 5px;
+  padding-right: 5px;
+}
+#texteditor-backdrop {
+  padding-top: 20px;
+  padding-bottom: 20px;
+}
+@media not print {
+  #texteditor-backdrop {
+    background-color: #EEE;
+  }
+}
+@media print {
+  #texteditor-backdrop #texteditor-container .CodeMirror-gutter,
+  #texteditor-backdrop #texteditor-container .CodeMirror-gutters {
+    background-color: #fff;
+  }
+}
+@media not print {
+  #texteditor-backdrop #texteditor-container .CodeMirror-gutter,
+  #texteditor-backdrop #texteditor-container .CodeMirror-gutters {
+    background-color: #fff;
+  }
+}
+@media not print {
+  #texteditor-backdrop #texteditor-container {
+    padding: 0px;
+    background-color: #fff;
+    -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+    box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+  }
+}
+/*!
+*
+* IPython notebook
+*
+*/
+/* CSS font colors for translated ANSI colors. */
+.ansibold {
+  font-weight: bold;
+}
+/* use dark versions for foreground, to improve visibility */
+.ansiblack {
+  color: black;
+}
+.ansired {
+  color: darkred;
+}
+.ansigreen {
+  color: darkgreen;
+}
+.ansiyellow {
+  color: #c4a000;
+}
+.ansiblue {
+  color: darkblue;
+}
+.ansipurple {
+  color: darkviolet;
+}
+.ansicyan {
+  color: steelblue;
+}
+.ansigray {
+  color: gray;
+}
+/* and light for background, for the same reason */
+.ansibgblack {
+  background-color: black;
+}
+.ansibgred {
+  background-color: red;
+}
+.ansibggreen {
+  background-color: green;
+}
+.ansibgyellow {
+  background-color: yellow;
+}
+.ansibgblue {
+  background-color: blue;
+}
+.ansibgpurple {
+  background-color: magenta;
+}
+.ansibgcyan {
+  background-color: cyan;
+}
+.ansibggray {
+  background-color: gray;
+}
+div.cell {
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: vertical;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: vertical;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: column;
+  align-items: stretch;
+  border-radius: 2px;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+  border-width: 1px;
+  border-style: solid;
+  border-color: transparent;
+  width: 100%;
+  padding: 5px;
+  /* This acts as a spacer between cells, that is outside the border */
+  margin: 0px;
+  outline: none;
+  border-left-width: 1px;
+  padding-left: 5px;
+  background: linear-gradient(to right, transparent -40px, transparent 1px, transparent 1px, transparent 100%);
+}
+div.cell.jupyter-soft-selected {
+  border-left-color: #90CAF9;
+  border-left-color: #E3F2FD;
+  border-left-width: 1px;
+  padding-left: 5px;
+  border-right-color: #E3F2FD;
+  border-right-width: 1px;
+  background: #E3F2FD;
+}
+@media print {
+  div.cell.jupyter-soft-selected {
+    border-color: transparent;
+  }
+}
+div.cell.selected {
+  border-color: #ababab;
+  border-left-width: 0px;
+  padding-left: 6px;
+  background: linear-gradient(to right, #42A5F5 -40px, #42A5F5 5px, transparent 5px, transparent 100%);
+}
+@media print {
+  div.cell.selected {
+    border-color: transparent;
+  }
+}
+div.cell.selected.jupyter-soft-selected {
+  border-left-width: 0;
+  padding-left: 6px;
+  background: linear-gradient(to right, #42A5F5 -40px, #42A5F5 7px, #E3F2FD 7px, #E3F2FD 100%);
+}
+.edit_mode div.cell.selected {
+  border-color: #66BB6A;
+  border-left-width: 0px;
+  padding-left: 6px;
+  background: linear-gradient(to right, #66BB6A -40px, #66BB6A 5px, transparent 5px, transparent 100%);
+}
+@media print {
+  .edit_mode div.cell.selected {
+    border-color: transparent;
+  }
+}
+.prompt {
+  /* This needs to be wide enough for 3 digit prompt numbers: In[100]: */
+  min-width: 14ex;
+  /* This padding is tuned to match the padding on the CodeMirror editor. */
+  padding: 0.4em;
+  margin: 0px;
+  font-family: monospace;
+  text-align: right;
+  /* This has to match that of the the CodeMirror class line-height below */
+  line-height: 1.21429em;
+  /* Don't highlight prompt number selection */
+  -webkit-touch-callout: none;
+  -webkit-user-select: none;
+  -khtml-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+  /* Use default cursor */
+  cursor: default;
+}
+@media (max-width: 540px) {
+  .prompt {
+    text-align: left;
+  }
+}
+div.inner_cell {
+  min-width: 0;
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: vertical;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: vertical;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: column;
+  align-items: stretch;
+  /* Old browsers */
+  -webkit-box-flex: 1;
+  -moz-box-flex: 1;
+  box-flex: 1;
+  /* Modern browsers */
+  flex: 1;
+}
+/* input_area and input_prompt must match in top border and margin for alignment */
+div.input_area {
+  border: 1px solid #cfcfcf;
+  border-radius: 2px;
+  background: #f7f7f7;
+  line-height: 1.21429em;
+}
+/* This is needed so that empty prompt areas can collapse to zero height when there
+   is no content in the output_subarea and the prompt. The main purpose of this is
+   to make sure that empty JavaScript output_subareas have no height. */
+div.prompt:empty {
+  padding-top: 0;
+  padding-bottom: 0;
+}
+div.unrecognized_cell {
+  padding: 5px 5px 5px 0px;
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: horizontal;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: horizontal;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: horizontal;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: row;
+  align-items: stretch;
+}
+div.unrecognized_cell .inner_cell {
+  border-radius: 2px;
+  padding: 5px;
+  font-weight: bold;
+  color: red;
+  border: 1px solid #cfcfcf;
+  background: #eaeaea;
+}
+div.unrecognized_cell .inner_cell a {
+  color: inherit;
+  text-decoration: none;
+}
+div.unrecognized_cell .inner_cell a:hover {
+  color: inherit;
+  text-decoration: none;
+}
+@media (max-width: 540px) {
+  div.unrecognized_cell > div.prompt {
+    display: none;
+  }
+}
+div.code_cell {
+  /* avoid page breaking on code cells when printing */
+}
+@media print {
+  div.code_cell {
+    page-break-inside: avoid;
+  }
+}
+/* any special styling for code cells that are currently running goes here */
+div.input {
+  page-break-inside: avoid;
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: horizontal;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: horizontal;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: horizontal;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: row;
+  align-items: stretch;
+}
+@media (max-width: 540px) {
+  div.input {
+    /* Old browsers */
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+    -webkit-box-align: stretch;
+    display: -moz-box;
+    -moz-box-orient: vertical;
+    -moz-box-align: stretch;
+    display: box;
+    box-orient: vertical;
+    box-align: stretch;
+    /* Modern browsers */
+    display: flex;
+    flex-direction: column;
+    align-items: stretch;
+  }
+}
+/* input_area and input_prompt must match in top border and margin for alignment */
+div.input_prompt {
+  color: #303F9F;
+  border-top: 1px solid transparent;
+}
+div.input_area > div.highlight {
+  margin: 0.4em;
+  border: none;
+  padding: 0px;
+  background-color: transparent;
+}
+div.input_area > div.highlight > pre {
+  margin: 0px;
+  border: none;
+  padding: 0px;
+  background-color: transparent;
+}
+/* The following gets added to the <head> if it is detected that the user has a
+ * monospace font with inconsistent normal/bold/italic height.  See
+ * notebookmain.js.  Such fonts will have keywords vertically offset with
+ * respect to the rest of the text.  The user should select a better font.
+ * See: https://github.com/ipython/ipython/issues/1503
+ *
+ * .CodeMirror span {
+ *      vertical-align: bottom;
+ * }
+ */
+.CodeMirror {
+  line-height: 1.21429em;
+  /* Changed from 1em to our global default */
+  font-size: 14px;
+  height: auto;
+  /* Changed to auto to autogrow */
+  background: none;
+  /* Changed from white to allow our bg to show through */
+}
+.CodeMirror-scroll {
+  /*  The CodeMirror docs are a bit fuzzy on if overflow-y should be hidden or visible.*/
+  /*  We have found that if it is visible, vertical scrollbars appear with font size changes.*/
+  overflow-y: hidden;
+  overflow-x: auto;
+}
+.CodeMirror-lines {
+  /* In CM2, this used to be 0.4em, but in CM3 it went to 4px. We need the em value because */
+  /* we have set a different line-height and want this to scale with that. */
+  padding: 0.4em;
+}
+.CodeMirror-linenumber {
+  padding: 0 8px 0 4px;
+}
+.CodeMirror-gutters {
+  border-bottom-left-radius: 2px;
+  border-top-left-radius: 2px;
+}
+.CodeMirror pre {
+  /* In CM3 this went to 4px from 0 in CM2. We need the 0 value because of how we size */
+  /* .CodeMirror-lines */
+  padding: 0;
+  border: 0;
+  border-radius: 0;
+}
+/*
+
+Original style from softwaremaniacs.org (c) Ivan Sagalaev <Maniac@SoftwareManiacs.Org>
+Adapted from GitHub theme
+
+*/
+.highlight-base {
+  color: #000;
+}
+.highlight-variable {
+  color: #000;
+}
+.highlight-variable-2 {
+  color: #1a1a1a;
+}
+.highlight-variable-3 {
+  color: #333333;
+}
+.highlight-string {
+  color: #BA2121;
+}
+.highlight-comment {
+  color: #408080;
+  font-style: italic;
+}
+.highlight-number {
+  color: #080;
+}
+.highlight-atom {
+  color: #88F;
+}
+.highlight-keyword {
+  color: #008000;
+  font-weight: bold;
+}
+.highlight-builtin {
+  color: #008000;
+}
+.highlight-error {
+  color: #f00;
+}
+.highlight-operator {
+  color: #AA22FF;
+  font-weight: bold;
+}
+.highlight-meta {
+  color: #AA22FF;
+}
+/* previously not defined, copying from default codemirror */
+.highlight-def {
+  color: #00f;
+}
+.highlight-string-2 {
+  color: #f50;
+}
+.highlight-qualifier {
+  color: #555;
+}
+.highlight-bracket {
+  color: #997;
+}
+.highlight-tag {
+  color: #170;
+}
+.highlight-attribute {
+  color: #00c;
+}
+.highlight-header {
+  color: blue;
+}
+.highlight-quote {
+  color: #090;
+}
+.highlight-link {
+  color: #00c;
+}
+/* apply the same style to codemirror */
+.cm-s-ipython span.cm-keyword {
+  color: #008000;
+  font-weight: bold;
+}
+.cm-s-ipython span.cm-atom {
+  color: #88F;
+}
+.cm-s-ipython span.cm-number {
+  color: #080;
+}
+.cm-s-ipython span.cm-def {
+  color: #00f;
+}
+.cm-s-ipython span.cm-variable {
+  color: #000;
+}
+.cm-s-ipython span.cm-operator {
+  color: #AA22FF;
+  font-weight: bold;
+}
+.cm-s-ipython span.cm-variable-2 {
+  color: #1a1a1a;
+}
+.cm-s-ipython span.cm-variable-3 {
+  color: #333333;
+}
+.cm-s-ipython span.cm-comment {
+  color: #408080;
+  font-style: italic;
+}
+.cm-s-ipython span.cm-string {
+  color: #BA2121;
+}
+.cm-s-ipython span.cm-string-2 {
+  color: #f50;
+}
+.cm-s-ipython span.cm-meta {
+  color: #AA22FF;
+}
+.cm-s-ipython span.cm-qualifier {
+  color: #555;
+}
+.cm-s-ipython span.cm-builtin {
+  color: #008000;
+}
+.cm-s-ipython span.cm-bracket {
+  color: #997;
+}
+.cm-s-ipython span.cm-tag {
+  color: #170;
+}
+.cm-s-ipython span.cm-attribute {
+  color: #00c;
+}
+.cm-s-ipython span.cm-header {
+  color: blue;
+}
+.cm-s-ipython span.cm-quote {
+  color: #090;
+}
+.cm-s-ipython span.cm-link {
+  color: #00c;
+}
+.cm-s-ipython span.cm-error {
+  color: #f00;
+}
+.cm-s-ipython span.cm-tab {
+  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=);
+  background-position: right;
+  background-repeat: no-repeat;
+}
+div.output_wrapper {
+  /* this position must be relative to enable descendents to be absolute within it */
+  position: relative;
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: vertical;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: vertical;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: column;
+  align-items: stretch;
+  z-index: 1;
+}
+/* class for the output area when it should be height-limited */
+div.output_scroll {
+  /* ideally, this would be max-height, but FF barfs all over that */
+  height: 24em;
+  /* FF needs this *and the wrapper* to specify full width, or it will shrinkwrap */
+  width: 100%;
+  overflow: auto;
+  border-radius: 2px;
+  -webkit-box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.8);
+  box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.8);
+  display: block;
+}
+/* output div while it is collapsed */
+div.output_collapsed {
+  margin: 0px;
+  padding: 0px;
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: vertical;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: vertical;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: column;
+  align-items: stretch;
+}
+div.out_prompt_overlay {
+  height: 100%;
+  padding: 0px 0.4em;
+  position: absolute;
+  border-radius: 2px;
+}
+div.out_prompt_overlay:hover {
+  /* use inner shadow to get border that is computed the same on WebKit/FF */
+  -webkit-box-shadow: inset 0 0 1px #000;
+  box-shadow: inset 0 0 1px #000;
+  background: rgba(240, 240, 240, 0.5);
+}
+div.output_prompt {
+  color: #D84315;
+}
+/* This class is the outer container of all output sections. */
+div.output_area {
+  padding: 0px;
+  page-break-inside: avoid;
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: horizontal;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: horizontal;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: horizontal;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: row;
+  align-items: stretch;
+}
+div.output_area .MathJax_Display {
+  text-align: left !important;
+}
+div.output_area .rendered_html table {
+  margin-left: 0;
+  margin-right: 0;
+}
+div.output_area .rendered_html img {
+  margin-left: 0;
+  margin-right: 0;
+}
+div.output_area img,
+div.output_area svg {
+  max-width: 100%;
+  height: auto;
+}
+div.output_area img.unconfined,
+div.output_area svg.unconfined {
+  max-width: none;
+}
+/* This is needed to protect the pre formating from global settings such
+   as that of bootstrap */
+.output {
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: vertical;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: vertical;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: column;
+  align-items: stretch;
+}
+@media (max-width: 540px) {
+  div.output_area {
+    /* Old browsers */
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+    -webkit-box-align: stretch;
+    display: -moz-box;
+    -moz-box-orient: vertical;
+    -moz-box-align: stretch;
+    display: box;
+    box-orient: vertical;
+    box-align: stretch;
+    /* Modern browsers */
+    display: flex;
+    flex-direction: column;
+    align-items: stretch;
+  }
+}
+div.output_area pre {
+  margin: 0;
+  padding: 0;
+  border: 0;
+  vertical-align: baseline;
+  color: black;
+  background-color: transparent;
+  border-radius: 0;
+}
+/* This class is for the output subarea inside the output_area and after
+   the prompt div. */
+div.output_subarea {
+  overflow-x: auto;
+  padding: 0.4em;
+  /* Old browsers */
+  -webkit-box-flex: 1;
+  -moz-box-flex: 1;
+  box-flex: 1;
+  /* Modern browsers */
+  flex: 1;
+  max-width: calc(100% - 14ex);
+}
+div.output_scroll div.output_subarea {
+  overflow-x: visible;
+}
+/* The rest of the output_* classes are for special styling of the different
+   output types */
+/* all text output has this class: */
+div.output_text {
+  text-align: left;
+  color: #000;
+  /* This has to match that of the the CodeMirror class line-height below */
+  line-height: 1.21429em;
+}
+/* stdout/stderr are 'text' as well as 'stream', but execute_result/error are *not* streams */
+div.output_stderr {
+  background: #fdd;
+  /* very light red background for stderr */
+}
+div.output_latex {
+  text-align: left;
+}
+/* Empty output_javascript divs should have no height */
+div.output_javascript:empty {
+  padding: 0;
+}
+.js-error {
+  color: darkred;
+}
+/* raw_input styles */
+div.raw_input_container {
+  line-height: 1.21429em;
+  padding-top: 5px;
+}
+pre.raw_input_prompt {
+  /* nothing needed here. */
+}
+input.raw_input {
+  font-family: monospace;
+  font-size: inherit;
+  color: inherit;
+  width: auto;
+  /* make sure input baseline aligns with prompt */
+  vertical-align: baseline;
+  /* padding + margin = 0.5em between prompt and cursor */
+  padding: 0em 0.25em;
+  margin: 0em 0.25em;
+}
+input.raw_input:focus {
+  box-shadow: none;
+}
+p.p-space {
+  margin-bottom: 10px;
+}
+div.output_unrecognized {
+  padding: 5px;
+  font-weight: bold;
+  color: red;
+}
+div.output_unrecognized a {
+  color: inherit;
+  text-decoration: none;
+}
+div.output_unrecognized a:hover {
+  color: inherit;
+  text-decoration: none;
+}
+.rendered_html {
+  color: #000;
+  /* any extras will just be numbers: */
+}
+.rendered_html em {
+  font-style: italic;
+}
+.rendered_html strong {
+  font-weight: bold;
+}
+.rendered_html u {
+  text-decoration: underline;
+}
+.rendered_html :link {
+  text-decoration: underline;
+}
+.rendered_html :visited {
+  text-decoration: underline;
+}
+.rendered_html h1 {
+  font-size: 185.7%;
+  margin: 1.08em 0 0 0;
+  font-weight: bold;
+  line-height: 1.0;
+}
+.rendered_html h2 {
+  font-size: 157.1%;
+  margin: 1.27em 0 0 0;
+  font-weight: bold;
+  line-height: 1.0;
+}
+.rendered_html h3 {
+  font-size: 128.6%;
+  margin: 1.55em 0 0 0;
+  font-weight: bold;
+  line-height: 1.0;
+}
+.rendered_html h4 {
+  font-size: 100%;
+  margin: 2em 0 0 0;
+  font-weight: bold;
+  line-height: 1.0;
+}
+.rendered_html h5 {
+  font-size: 100%;
+  margin: 2em 0 0 0;
+  font-weight: bold;
+  line-height: 1.0;
+  font-style: italic;
+}
+.rendered_html h6 {
+  font-size: 100%;
+  margin: 2em 0 0 0;
+  font-weight: bold;
+  line-height: 1.0;
+  font-style: italic;
+}
+.rendered_html h1:first-child {
+  margin-top: 0.538em;
+}
+.rendered_html h2:first-child {
+  margin-top: 0.636em;
+}
+.rendered_html h3:first-child {
+  margin-top: 0.777em;
+}
+.rendered_html h4:first-child {
+  margin-top: 1em;
+}
+.rendered_html h5:first-child {
+  margin-top: 1em;
+}
+.rendered_html h6:first-child {
+  margin-top: 1em;
+}
+.rendered_html ul {
+  list-style: disc;
+  margin: 0em 2em;
+  padding-left: 0px;
+}
+.rendered_html ul ul {
+  list-style: square;
+  margin: 0em 2em;
+}
+.rendered_html ul ul ul {
+  list-style: circle;
+  margin: 0em 2em;
+}
+.rendered_html ol {
+  list-style: decimal;
+  margin: 0em 2em;
+  padding-left: 0px;
+}
+.rendered_html ol ol {
+  list-style: upper-alpha;
+  margin: 0em 2em;
+}
+.rendered_html ol ol ol {
+  list-style: lower-alpha;
+  margin: 0em 2em;
+}
+.rendered_html ol ol ol ol {
+  list-style: lower-roman;
+  margin: 0em 2em;
+}
+.rendered_html ol ol ol ol ol {
+  list-style: decimal;
+  margin: 0em 2em;
+}
+.rendered_html * + ul {
+  margin-top: 1em;
+}
+.rendered_html * + ol {
+  margin-top: 1em;
+}
+.rendered_html hr {
+  color: black;
+  background-color: black;
+}
+.rendered_html pre {
+  margin: 1em 2em;
+}
+.rendered_html pre,
+.rendered_html code {
+  border: 0;
+  background-color: #fff;
+  color: #000;
+  font-size: 100%;
+  padding: 0px;
+}
+.rendered_html blockquote {
+  margin: 1em 2em;
+}
+.rendered_html table {
+  margin-left: auto;
+  margin-right: auto;
+  border: 1px solid black;
+  border-collapse: collapse;
+}
+.rendered_html tr,
+.rendered_html th,
+.rendered_html td {
+  border: 1px solid black;
+  border-collapse: collapse;
+  margin: 1em 2em;
+}
+.rendered_html td,
+.rendered_html th {
+  text-align: left;
+  vertical-align: middle;
+  padding: 4px;
+}
+.rendered_html th {
+  font-weight: bold;
+}
+.rendered_html * + table {
+  margin-top: 1em;
+}
+.rendered_html p {
+  text-align: left;
+}
+.rendered_html * + p {
+  margin-top: 1em;
+}
+.rendered_html img {
+  display: block;
+  margin-left: auto;
+  margin-right: auto;
+}
+.rendered_html * + img {
+  margin-top: 1em;
+}
+.rendered_html img,
+.rendered_html svg {
+  max-width: 100%;
+  height: auto;
+}
+.rendered_html img.unconfined,
+.rendered_html svg.unconfined {
+  max-width: none;
+}
+div.text_cell {
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: horizontal;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: horizontal;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: horizontal;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: row;
+  align-items: stretch;
+}
+@media (max-width: 540px) {
+  div.text_cell > div.prompt {
+    display: none;
+  }
+}
+div.text_cell_render {
+  /*font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;*/
+  outline: none;
+  resize: none;
+  width: inherit;
+  border-style: none;
+  padding: 0.5em 0.5em 0.5em 0.4em;
+  color: #000;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+}
+a.anchor-link:link {
+  text-decoration: none;
+  padding: 0px 20px;
+  visibility: hidden;
+}
+h1:hover .anchor-link,
+h2:hover .anchor-link,
+h3:hover .anchor-link,
+h4:hover .anchor-link,
+h5:hover .anchor-link,
+h6:hover .anchor-link {
+  visibility: visible;
+}
+.text_cell.rendered .input_area {
+  display: none;
+}
+.text_cell.rendered .rendered_html {
+  overflow-x: auto;
+  overflow-y: hidden;
+}
+.text_cell.unrendered .text_cell_render {
+  display: none;
+}
+.cm-header-1,
+.cm-header-2,
+.cm-header-3,
+.cm-header-4,
+.cm-header-5,
+.cm-header-6 {
+  font-weight: bold;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+}
+.cm-header-1 {
+  font-size: 185.7%;
+}
+.cm-header-2 {
+  font-size: 157.1%;
+}
+.cm-header-3 {
+  font-size: 128.6%;
+}
+.cm-header-4 {
+  font-size: 110%;
+}
+.cm-header-5 {
+  font-size: 100%;
+  font-style: italic;
+}
+.cm-header-6 {
+  font-size: 100%;
+  font-style: italic;
+}
+/*!
+*
+* IPython notebook webapp
+*
+*/
+@media (max-width: 767px) {
+  .notebook_app {
+    padding-left: 0px;
+    padding-right: 0px;
+  }
+}
+#ipython-main-app {
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+  height: 100%;
+}
+div#notebook_panel {
+  margin: 0px;
+  padding: 0px;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+  height: 100%;
+}
+div#notebook {
+  font-size: 14px;
+  line-height: 20px;
+  overflow-y: hidden;
+  overflow-x: auto;
+  width: 100%;
+  /* This spaces the page away from the edge of the notebook area */
+  padding-top: 20px;
+  margin: 0px;
+  outline: none;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+  min-height: 100%;
+}
+@media not print {
+  #notebook-container {
+    padding: 15px;
+    background-color: #fff;
+    min-height: 0;
+    -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+    box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+  }
+}
+@media print {
+  #notebook-container {
+    width: 100%;
+  }
+}
+div.ui-widget-content {
+  border: 1px solid #ababab;
+  outline: none;
+}
+pre.dialog {
+  background-color: #f7f7f7;
+  border: 1px solid #ddd;
+  border-radius: 2px;
+  padding: 0.4em;
+  padding-left: 2em;
+}
+p.dialog {
+  padding: 0.2em;
+}
+/* Word-wrap output correctly.  This is the CSS3 spelling, though Firefox seems
+   to not honor it correctly.  Webkit browsers (Chrome, rekonq, Safari) do.
+ */
+pre,
+code,
+kbd,
+samp {
+  white-space: pre-wrap;
+}
+#fonttest {
+  font-family: monospace;
+}
+p {
+  margin-bottom: 0;
+}
+.end_space {
+  min-height: 100px;
+  transition: height .2s ease;
+}
+.notebook_app > #header {
+  -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+  box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+}
+@media not print {
+  .notebook_app {
+    background-color: #EEE;
+  }
+}
+kbd {
+  border-style: solid;
+  border-width: 1px;
+  box-shadow: none;
+  margin: 2px;
+  padding-left: 2px;
+  padding-right: 2px;
+  padding-top: 1px;
+  padding-bottom: 1px;
+}
+/* CSS for the cell toolbar */
+.celltoolbar {
+  border: thin solid #CFCFCF;
+  border-bottom: none;
+  background: #EEE;
+  border-radius: 2px 2px 0px 0px;
+  width: 100%;
+  height: 29px;
+  padding-right: 4px;
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: horizontal;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: horizontal;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: horizontal;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: row;
+  align-items: stretch;
+  /* Old browsers */
+  -webkit-box-pack: end;
+  -moz-box-pack: end;
+  box-pack: end;
+  /* Modern browsers */
+  justify-content: flex-end;
+  display: -webkit-flex;
+}
+@media print {
+  .celltoolbar {
+    display: none;
+  }
+}
+.ctb_hideshow {
+  display: none;
+  vertical-align: bottom;
+}
+/* ctb_show is added to the ctb_hideshow div to show the cell toolbar.
+   Cell toolbars are only shown when the ctb_global_show class is also set.
+*/
+.ctb_global_show .ctb_show.ctb_hideshow {
+  display: block;
+}
+.ctb_global_show .ctb_show + .input_area,
+.ctb_global_show .ctb_show + div.text_cell_input,
+.ctb_global_show .ctb_show ~ div.text_cell_render {
+  border-top-right-radius: 0px;
+  border-top-left-radius: 0px;
+}
+.ctb_global_show .ctb_show ~ div.text_cell_render {
+  border: 1px solid #cfcfcf;
+}
+.celltoolbar {
+  font-size: 87%;
+  padding-top: 3px;
+}
+.celltoolbar select {
+  display: block;
+  width: 100%;
+  height: 32px;
+  padding: 6px 12px;
+  font-size: 13px;
+  line-height: 1.42857143;
+  color: #555555;
+  background-color: #fff;
+  background-image: none;
+  border: 1px solid #ccc;
+  border-radius: 2px;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+  -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+  transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+  height: 30px;
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 1px;
+  width: inherit;
+  font-size: inherit;
+  height: 22px;
+  padding: 0px;
+  display: inline-block;
+}
+.celltoolbar select:focus {
+  border-color: #66afe9;
+  outline: 0;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
+  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
+}
+.celltoolbar select::-moz-placeholder {
+  color: #999;
+  opacity: 1;
+}
+.celltoolbar select:-ms-input-placeholder {
+  color: #999;
+}
+.celltoolbar select::-webkit-input-placeholder {
+  color: #999;
+}
+.celltoolbar select::-ms-expand {
+  border: 0;
+  background-color: transparent;
+}
+.celltoolbar select[disabled],
+.celltoolbar select[readonly],
+fieldset[disabled] .celltoolbar select {
+  background-color: #eeeeee;
+  opacity: 1;
+}
+.celltoolbar select[disabled],
+fieldset[disabled] .celltoolbar select {
+  cursor: not-allowed;
+}
+textarea.celltoolbar select {
+  height: auto;
+}
+select.celltoolbar select {
+  height: 30px;
+  line-height: 30px;
+}
+textarea.celltoolbar select,
+select[multiple].celltoolbar select {
+  height: auto;
+}
+.celltoolbar label {
+  margin-left: 5px;
+  margin-right: 5px;
+}
+.completions {
+  position: absolute;
+  z-index: 110;
+  overflow: hidden;
+  border: 1px solid #ababab;
+  border-radius: 2px;
+  -webkit-box-shadow: 0px 6px 10px -1px #adadad;
+  box-shadow: 0px 6px 10px -1px #adadad;
+  line-height: 1;
+}
+.completions select {
+  background: white;
+  outline: none;
+  border: none;
+  padding: 0px;
+  margin: 0px;
+  overflow: auto;
+  font-family: monospace;
+  font-size: 110%;
+  color: #000;
+  width: auto;
+}
+.completions select option.context {
+  color: #286090;
+}
+#kernel_logo_widget {
+  float: right !important;
+  float: right;
+}
+#kernel_logo_widget .current_kernel_logo {
+  display: none;
+  margin-top: -1px;
+  margin-bottom: -1px;
+  width: 32px;
+  height: 32px;
+}
+#menubar {
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+  margin-top: 1px;
+}
+#menubar .navbar {
+  border-top: 1px;
+  border-radius: 0px 0px 2px 2px;
+  margin-bottom: 0px;
+}
+#menubar .navbar-toggle {
+  float: left;
+  padding-top: 7px;
+  padding-bottom: 7px;
+  border: none;
+}
+#menubar .navbar-collapse {
+  clear: left;
+}
+.nav-wrapper {
+  border-bottom: 1px solid #e7e7e7;
+}
+i.menu-icon {
+  padding-top: 4px;
+}
+ul#help_menu li a {
+  overflow: hidden;
+  padding-right: 2.2em;
+}
+ul#help_menu li a i {
+  margin-right: -1.2em;
+}
+.dropdown-submenu {
+  position: relative;
+}
+.dropdown-submenu > .dropdown-menu {
+  top: 0;
+  left: 100%;
+  margin-top: -6px;
+  margin-left: -1px;
+}
+.dropdown-submenu:hover > .dropdown-menu {
+  display: block;
+}
+.dropdown-submenu > a:after {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  display: block;
+  content: "\f0da";
+  float: right;
+  color: #333333;
+  margin-top: 2px;
+  margin-right: -10px;
+}
+.dropdown-submenu > a:after.pull-left {
+  margin-right: .3em;
+}
+.dropdown-submenu > a:after.pull-right {
+  margin-left: .3em;
+}
+.dropdown-submenu:hover > a:after {
+  color: #262626;
+}
+.dropdown-submenu.pull-left {
+  float: none;
+}
+.dropdown-submenu.pull-left > .dropdown-menu {
+  left: -100%;
+  margin-left: 10px;
+}
+#notification_area {
+  float: right !important;
+  float: right;
+  z-index: 10;
+}
+.indicator_area {
+  float: right !important;
+  float: right;
+  color: #777;
+  margin-left: 5px;
+  margin-right: 5px;
+  width: 11px;
+  z-index: 10;
+  text-align: center;
+  width: auto;
+}
+#kernel_indicator {
+  float: right !important;
+  float: right;
+  color: #777;
+  margin-left: 5px;
+  margin-right: 5px;
+  width: 11px;
+  z-index: 10;
+  text-align: center;
+  width: auto;
+  border-left: 1px solid;
+}
+#kernel_indicator .kernel_indicator_name {
+  padding-left: 5px;
+  padding-right: 5px;
+}
+#modal_indicator {
+  float: right !important;
+  float: right;
+  color: #777;
+  margin-left: 5px;
+  margin-right: 5px;
+  width: 11px;
+  z-index: 10;
+  text-align: center;
+  width: auto;
+}
+#readonly-indicator {
+  float: right !important;
+  float: right;
+  color: #777;
+  margin-left: 5px;
+  margin-right: 5px;
+  width: 11px;
+  z-index: 10;
+  text-align: center;
+  width: auto;
+  margin-top: 2px;
+  margin-bottom: 0px;
+  margin-left: 0px;
+  margin-right: 0px;
+  display: none;
+}
+.modal_indicator:before {
+  width: 1.28571429em;
+  text-align: center;
+}
+.edit_mode .modal_indicator:before {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  content: "\f040";
+}
+.edit_mode .modal_indicator:before.pull-left {
+  margin-right: .3em;
+}
+.edit_mode .modal_indicator:before.pull-right {
+  margin-left: .3em;
+}
+.command_mode .modal_indicator:before {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  content: ' ';
+}
+.command_mode .modal_indicator:before.pull-left {
+  margin-right: .3em;
+}
+.command_mode .modal_indicator:before.pull-right {
+  margin-left: .3em;
+}
+.kernel_idle_icon:before {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  content: "\f10c";
+}
+.kernel_idle_icon:before.pull-left {
+  margin-right: .3em;
+}
+.kernel_idle_icon:before.pull-right {
+  margin-left: .3em;
+}
+.kernel_busy_icon:before {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  content: "\f111";
+}
+.kernel_busy_icon:before.pull-left {
+  margin-right: .3em;
+}
+.kernel_busy_icon:before.pull-right {
+  margin-left: .3em;
+}
+.kernel_dead_icon:before {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  content: "\f1e2";
+}
+.kernel_dead_icon:before.pull-left {
+  margin-right: .3em;
+}
+.kernel_dead_icon:before.pull-right {
+  margin-left: .3em;
+}
+.kernel_disconnected_icon:before {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  content: "\f127";
+}
+.kernel_disconnected_icon:before.pull-left {
+  margin-right: .3em;
+}
+.kernel_disconnected_icon:before.pull-right {
+  margin-left: .3em;
+}
+.notification_widget {
+  color: #777;
+  z-index: 10;
+  background: rgba(240, 240, 240, 0.5);
+  margin-right: 4px;
+  color: #333;
+  background-color: #fff;
+  border-color: #ccc;
+}
+.notification_widget:focus,
+.notification_widget.focus {
+  color: #333;
+  background-color: #e6e6e6;
+  border-color: #8c8c8c;
+}
+.notification_widget:hover {
+  color: #333;
+  background-color: #e6e6e6;
+  border-color: #adadad;
+}
+.notification_widget:active,
+.notification_widget.active,
+.open > .dropdown-toggle.notification_widget {
+  color: #333;
+  background-color: #e6e6e6;
+  border-color: #adadad;
+}
+.notification_widget:active:hover,
+.notification_widget.active:hover,
+.open > .dropdown-toggle.notification_widget:hover,
+.notification_widget:active:focus,
+.notification_widget.active:focus,
+.open > .dropdown-toggle.notification_widget:focus,
+.notification_widget:active.focus,
+.notification_widget.active.focus,
+.open > .dropdown-toggle.notification_widget.focus {
+  color: #333;
+  background-color: #d4d4d4;
+  border-color: #8c8c8c;
+}
+.notification_widget:active,
+.notification_widget.active,
+.open > .dropdown-toggle.notification_widget {
+  background-image: none;
+}
+.notification_widget.disabled:hover,
+.notification_widget[disabled]:hover,
+fieldset[disabled] .notification_widget:hover,
+.notification_widget.disabled:focus,
+.notification_widget[disabled]:focus,
+fieldset[disabled] .notification_widget:focus,
+.notification_widget.disabled.focus,
+.notification_widget[disabled].focus,
+fieldset[disabled] .notification_widget.focus {
+  background-color: #fff;
+  border-color: #ccc;
+}
+.notification_widget .badge {
+  color: #fff;
+  background-color: #333;
+}
+.notification_widget.warning {
+  color: #fff;
+  background-color: #f0ad4e;
+  border-color: #eea236;
+}
+.notification_widget.warning:focus,
+.notification_widget.warning.focus {
+  color: #fff;
+  background-color: #ec971f;
+  border-color: #985f0d;
+}
+.notification_widget.warning:hover {
+  color: #fff;
+  background-color: #ec971f;
+  border-color: #d58512;
+}
+.notification_widget.warning:active,
+.notification_widget.warning.active,
+.open > .dropdown-toggle.notification_widget.warning {
+  color: #fff;
+  background-color: #ec971f;
+  border-color: #d58512;
+}
+.notification_widget.warning:active:hover,
+.notification_widget.warning.active:hover,
+.open > .dropdown-toggle.notification_widget.warning:hover,
+.notification_widget.warning:active:focus,
+.notification_widget.warning.active:focus,
+.open > .dropdown-toggle.notification_widget.warning:focus,
+.notification_widget.warning:active.focus,
+.notification_widget.warning.active.focus,
+.open > .dropdown-toggle.notification_widget.warning.focus {
+  color: #fff;
+  background-color: #d58512;
+  border-color: #985f0d;
+}
+.notification_widget.warning:active,
+.notification_widget.warning.active,
+.open > .dropdown-toggle.notification_widget.warning {
+  background-image: none;
+}
+.notification_widget.warning.disabled:hover,
+.notification_widget.warning[disabled]:hover,
+fieldset[disabled] .notification_widget.warning:hover,
+.notification_widget.warning.disabled:focus,
+.notification_widget.warning[disabled]:focus,
+fieldset[disabled] .notification_widget.warning:focus,
+.notification_widget.warning.disabled.focus,
+.notification_widget.warning[disabled].focus,
+fieldset[disabled] .notification_widget.warning.focus {
+  background-color: #f0ad4e;
+  border-color: #eea236;
+}
+.notification_widget.warning .badge {
+  color: #f0ad4e;
+  background-color: #fff;
+}
+.notification_widget.success {
+  color: #fff;
+  background-color: #5cb85c;
+  border-color: #4cae4c;
+}
+.notification_widget.success:focus,
+.notification_widget.success.focus {
+  color: #fff;
+  background-color: #449d44;
+  border-color: #255625;
+}
+.notification_widget.success:hover {
+  color: #fff;
+  background-color: #449d44;
+  border-color: #398439;
+}
+.notification_widget.success:active,
+.notification_widget.success.active,
+.open > .dropdown-toggle.notification_widget.success {
+  color: #fff;
+  background-color: #449d44;
+  border-color: #398439;
+}
+.notification_widget.success:active:hover,
+.notification_widget.success.active:hover,
+.open > .dropdown-toggle.notification_widget.success:hover,
+.notification_widget.success:active:focus,
+.notification_widget.success.active:focus,
+.open > .dropdown-toggle.notification_widget.success:focus,
+.notification_widget.success:active.focus,
+.notification_widget.success.active.focus,
+.open > .dropdown-toggle.notification_widget.success.focus {
+  color: #fff;
+  background-color: #398439;
+  border-color: #255625;
+}
+.notification_widget.success:active,
+.notification_widget.success.active,
+.open > .dropdown-toggle.notification_widget.success {
+  background-image: none;
+}
+.notification_widget.success.disabled:hover,
+.notification_widget.success[disabled]:hover,
+fieldset[disabled] .notification_widget.success:hover,
+.notification_widget.success.disabled:focus,
+.notification_widget.success[disabled]:focus,
+fieldset[disabled] .notification_widget.success:focus,
+.notification_widget.success.disabled.focus,
+.notification_widget.success[disabled].focus,
+fieldset[disabled] .notification_widget.success.focus {
+  background-color: #5cb85c;
+  border-color: #4cae4c;
+}
+.notification_widget.success .badge {
+  color: #5cb85c;
+  background-color: #fff;
+}
+.notification_widget.info {
+  color: #fff;
+  background-color: #5bc0de;
+  border-color: #46b8da;
+}
+.notification_widget.info:focus,
+.notification_widget.info.focus {
+  color: #fff;
+  background-color: #31b0d5;
+  border-color: #1b6d85;
+}
+.notification_widget.info:hover {
+  color: #fff;
+  background-color: #31b0d5;
+  border-color: #269abc;
+}
+.notification_widget.info:active,
+.notification_widget.info.active,
+.open > .dropdown-toggle.notification_widget.info {
+  color: #fff;
+  background-color: #31b0d5;
+  border-color: #269abc;
+}
+.notification_widget.info:active:hover,
+.notification_widget.info.active:hover,
+.open > .dropdown-toggle.notification_widget.info:hover,
+.notification_widget.info:active:focus,
+.notification_widget.info.active:focus,
+.open > .dropdown-toggle.notification_widget.info:focus,
+.notification_widget.info:active.focus,
+.notification_widget.info.active.focus,
+.open > .dropdown-toggle.notification_widget.info.focus {
+  color: #fff;
+  background-color: #269abc;
+  border-color: #1b6d85;
+}
+.notification_widget.info:active,
+.notification_widget.info.active,
+.open > .dropdown-toggle.notification_widget.info {
+  background-image: none;
+}
+.notification_widget.info.disabled:hover,
+.notification_widget.info[disabled]:hover,
+fieldset[disabled] .notification_widget.info:hover,
+.notification_widget.info.disabled:focus,
+.notification_widget.info[disabled]:focus,
+fieldset[disabled] .notification_widget.info:focus,
+.notification_widget.info.disabled.focus,
+.notification_widget.info[disabled].focus,
+fieldset[disabled] .notification_widget.info.focus {
+  background-color: #5bc0de;
+  border-color: #46b8da;
+}
+.notification_widget.info .badge {
+  color: #5bc0de;
+  background-color: #fff;
+}
+.notification_widget.danger {
+  color: #fff;
+  background-color: #d9534f;
+  border-color: #d43f3a;
+}
+.notification_widget.danger:focus,
+.notification_widget.danger.focus {
+  color: #fff;
+  background-color: #c9302c;
+  border-color: #761c19;
+}
+.notification_widget.danger:hover {
+  color: #fff;
+  background-color: #c9302c;
+  border-color: #ac2925;
+}
+.notification_widget.danger:active,
+.notification_widget.danger.active,
+.open > .dropdown-toggle.notification_widget.danger {
+  color: #fff;
+  background-color: #c9302c;
+  border-color: #ac2925;
+}
+.notification_widget.danger:active:hover,
+.notification_widget.danger.active:hover,
+.open > .dropdown-toggle.notification_widget.danger:hover,
+.notification_widget.danger:active:focus,
+.notification_widget.danger.active:focus,
+.open > .dropdown-toggle.notification_widget.danger:focus,
+.notification_widget.danger:active.focus,
+.notification_widget.danger.active.focus,
+.open > .dropdown-toggle.notification_widget.danger.focus {
+  color: #fff;
+  background-color: #ac2925;
+  border-color: #761c19;
+}
+.notification_widget.danger:active,
+.notification_widget.danger.active,
+.open > .dropdown-toggle.notification_widget.danger {
+  background-image: none;
+}
+.notification_widget.danger.disabled:hover,
+.notification_widget.danger[disabled]:hover,
+fieldset[disabled] .notification_widget.danger:hover,
+.notification_widget.danger.disabled:focus,
+.notification_widget.danger[disabled]:focus,
+fieldset[disabled] .notification_widget.danger:focus,
+.notification_widget.danger.disabled.focus,
+.notification_widget.danger[disabled].focus,
+fieldset[disabled] .notification_widget.danger.focus {
+  background-color: #d9534f;
+  border-color: #d43f3a;
+}
+.notification_widget.danger .badge {
+  color: #d9534f;
+  background-color: #fff;
+}
+div#pager {
+  background-color: #fff;
+  font-size: 14px;
+  line-height: 20px;
+  overflow: hidden;
+  display: none;
+  position: fixed;
+  bottom: 0px;
+  width: 100%;
+  max-height: 50%;
+  padding-top: 8px;
+  -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+  box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+  /* Display over codemirror */
+  z-index: 100;
+  /* Hack which prevents jquery ui resizable from changing top. */
+  top: auto !important;
+}
+div#pager pre {
+  line-height: 1.21429em;
+  color: #000;
+  background-color: #f7f7f7;
+  padding: 0.4em;
+}
+div#pager #pager-button-area {
+  position: absolute;
+  top: 8px;
+  right: 20px;
+}
+div#pager #pager-contents {
+  position: relative;
+  overflow: auto;
+  width: 100%;
+  height: 100%;
+}
+div#pager #pager-contents #pager-container {
+  position: relative;
+  padding: 15px 0px;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+}
+div#pager .ui-resizable-handle {
+  top: 0px;
+  height: 8px;
+  background: #f7f7f7;
+  border-top: 1px solid #cfcfcf;
+  border-bottom: 1px solid #cfcfcf;
+  /* This injects handle bars (a short, wide = symbol) for 
+        the resize handle. */
+}
+div#pager .ui-resizable-handle::after {
+  content: '';
+  top: 2px;
+  left: 50%;
+  height: 3px;
+  width: 30px;
+  margin-left: -15px;
+  position: absolute;
+  border-top: 1px solid #cfcfcf;
+}
+.quickhelp {
+  /* Old browsers */
+  display: -webkit-box;
+  -webkit-box-orient: horizontal;
+  -webkit-box-align: stretch;
+  display: -moz-box;
+  -moz-box-orient: horizontal;
+  -moz-box-align: stretch;
+  display: box;
+  box-orient: horizontal;
+  box-align: stretch;
+  /* Modern browsers */
+  display: flex;
+  flex-direction: row;
+  align-items: stretch;
+  line-height: 1.8em;
+}
+.shortcut_key {
+  display: inline-block;
+  width: 21ex;
+  text-align: right;
+  font-family: monospace;
+}
+.shortcut_descr {
+  display: inline-block;
+  /* Old browsers */
+  -webkit-box-flex: 1;
+  -moz-box-flex: 1;
+  box-flex: 1;
+  /* Modern browsers */
+  flex: 1;
+}
+span.save_widget {
+  margin-top: 6px;
+}
+span.save_widget span.filename {
+  height: 1em;
+  line-height: 1em;
+  padding: 3px;
+  margin-left: 16px;
+  border: none;
+  font-size: 146.5%;
+  border-radius: 2px;
+}
+span.save_widget span.filename:hover {
+  background-color: #e6e6e6;
+}
+span.checkpoint_status,
+span.autosave_status {
+  font-size: small;
+}
+@media (max-width: 767px) {
+  span.save_widget {
+    font-size: small;
+  }
+  span.checkpoint_status,
+  span.autosave_status {
+    display: none;
+  }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+  span.checkpoint_status {
+    display: none;
+  }
+  span.autosave_status {
+    font-size: x-small;
+  }
+}
+.toolbar {
+  padding: 0px;
+  margin-left: -5px;
+  margin-top: 2px;
+  margin-bottom: 5px;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+}
+.toolbar select,
+.toolbar label {
+  width: auto;
+  vertical-align: middle;
+  margin-right: 2px;
+  margin-bottom: 0px;
+  display: inline;
+  font-size: 92%;
+  margin-left: 0.3em;
+  margin-right: 0.3em;
+  padding: 0px;
+  padding-top: 3px;
+}
+.toolbar .btn {
+  padding: 2px 8px;
+}
+.toolbar .btn-group {
+  margin-top: 0px;
+  margin-left: 5px;
+}
+#maintoolbar {
+  margin-bottom: -3px;
+  margin-top: -8px;
+  border: 0px;
+  min-height: 27px;
+  margin-left: 0px;
+  padding-top: 11px;
+  padding-bottom: 3px;
+}
+#maintoolbar .navbar-text {
+  float: none;
+  vertical-align: middle;
+  text-align: right;
+  margin-left: 5px;
+  margin-right: 0px;
+  margin-top: 0px;
+}
+.select-xs {
+  height: 24px;
+}
+.pulse,
+.dropdown-menu > li > a.pulse,
+li.pulse > a.dropdown-toggle,
+li.pulse.open > a.dropdown-toggle {
+  background-color: #F37626;
+  color: white;
+}
+/**
+ * Primary styles
+ *
+ * Author: Jupyter Development Team
+ */
+/** WARNING IF YOU ARE EDITTING THIS FILE, if this is a .css file, It has a lot
+ * of chance of beeing generated from the ../less/[samename].less file, you can
+ * try to get back the less file by reverting somme commit in history
+ **/
+/*
+ * We'll try to get something pretty, so we
+ * have some strange css to have the scroll bar on
+ * the left with fix button on the top right of the tooltip
+ */
+@-moz-keyframes fadeOut {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+  }
+}
+@-webkit-keyframes fadeOut {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+  }
+}
+@-moz-keyframes fadeIn {
+  from {
+    opacity: 0;
+  }
+  to {
+    opacity: 1;
+  }
+}
+@-webkit-keyframes fadeIn {
+  from {
+    opacity: 0;
+  }
+  to {
+    opacity: 1;
+  }
+}
+/*properties of tooltip after "expand"*/
+.bigtooltip {
+  overflow: auto;
+  height: 200px;
+  -webkit-transition-property: height;
+  -webkit-transition-duration: 500ms;
+  -moz-transition-property: height;
+  -moz-transition-duration: 500ms;
+  transition-property: height;
+  transition-duration: 500ms;
+}
+/*properties of tooltip before "expand"*/
+.smalltooltip {
+  -webkit-transition-property: height;
+  -webkit-transition-duration: 500ms;
+  -moz-transition-property: height;
+  -moz-transition-duration: 500ms;
+  transition-property: height;
+  transition-duration: 500ms;
+  text-overflow: ellipsis;
+  overflow: hidden;
+  height: 80px;
+}
+.tooltipbuttons {
+  position: absolute;
+  padding-right: 15px;
+  top: 0px;
+  right: 0px;
+}
+.tooltiptext {
+  /*avoid the button to overlap on some docstring*/
+  padding-right: 30px;
+}
+.ipython_tooltip {
+  max-width: 700px;
+  /*fade-in animation when inserted*/
+  -webkit-animation: fadeOut 400ms;
+  -moz-animation: fadeOut 400ms;
+  animation: fadeOut 400ms;
+  -webkit-animation: fadeIn 400ms;
+  -moz-animation: fadeIn 400ms;
+  animation: fadeIn 400ms;
+  vertical-align: middle;
+  background-color: #f7f7f7;
+  overflow: visible;
+  border: #ababab 1px solid;
+  outline: none;
+  padding: 3px;
+  margin: 0px;
+  padding-left: 7px;
+  font-family: monospace;
+  min-height: 50px;
+  -moz-box-shadow: 0px 6px 10px -1px #adadad;
+  -webkit-box-shadow: 0px 6px 10px -1px #adadad;
+  box-shadow: 0px 6px 10px -1px #adadad;
+  border-radius: 2px;
+  position: absolute;
+  z-index: 1000;
+}
+.ipython_tooltip a {
+  float: right;
+}
+.ipython_tooltip .tooltiptext pre {
+  border: 0;
+  border-radius: 0;
+  font-size: 100%;
+  background-color: #f7f7f7;
+}
+.pretooltiparrow {
+  left: 0px;
+  margin: 0px;
+  top: -16px;
+  width: 40px;
+  height: 16px;
+  overflow: hidden;
+  position: absolute;
+}
+.pretooltiparrow:before {
+  background-color: #f7f7f7;
+  border: 1px #ababab solid;
+  z-index: 11;
+  content: "";
+  position: absolute;
+  left: 15px;
+  top: 10px;
+  width: 25px;
+  height: 25px;
+  -webkit-transform: rotate(45deg);
+  -moz-transform: rotate(45deg);
+  -ms-transform: rotate(45deg);
+  -o-transform: rotate(45deg);
+}
+ul.typeahead-list i {
+  margin-left: -10px;
+  width: 18px;
+}
+ul.typeahead-list {
+  max-height: 80vh;
+  overflow: auto;
+}
+ul.typeahead-list > li > a {
+  /** Firefox bug **/
+  /* see https://github.com/jupyter/notebook/issues/559 */
+  white-space: normal;
+}
+.cmd-palette .modal-body {
+  padding: 7px;
+}
+.cmd-palette form {
+  background: white;
+}
+.cmd-palette input {
+  outline: none;
+}
+.no-shortcut {
+  display: none;
+}
+.command-shortcut:before {
+  content: "(command)";
+  padding-right: 3px;
+  color: #777777;
+}
+.edit-shortcut:before {
+  content: "(edit)";
+  padding-right: 3px;
+  color: #777777;
+}
+#find-and-replace #replace-preview .match,
+#find-and-replace #replace-preview .insert {
+  background-color: #BBDEFB;
+  border-color: #90CAF9;
+  border-style: solid;
+  border-width: 1px;
+  border-radius: 0px;
+}
+#find-and-replace #replace-preview .replace .match {
+  background-color: #FFCDD2;
+  border-color: #EF9A9A;
+  border-radius: 0px;
+}
+#find-and-replace #replace-preview .replace .insert {
+  background-color: #C8E6C9;
+  border-color: #A5D6A7;
+  border-radius: 0px;
+}
+#find-and-replace #replace-preview {
+  max-height: 60vh;
+  overflow: auto;
+}
+#find-and-replace #replace-preview pre {
+  padding: 5px 10px;
+}
+.terminal-app {
+  background: #EEE;
+}
+.terminal-app #header {
+  background: #fff;
+  -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+  box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
+}
+.terminal-app .terminal {
+  width: 100%;
+  float: left;
+  font-family: monospace;
+  color: white;
+  background: black;
+  padding: 0.4em;
+  border-radius: 2px;
+  -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.4);
+  box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.4);
+}
+.terminal-app .terminal,
+.terminal-app .terminal dummy-screen {
+  line-height: 1em;
+  font-size: 14px;
+}
+.terminal-app .terminal .xterm-rows {
+  padding: 10px;
+}
+.terminal-app .terminal-cursor {
+  color: black;
+  background: white;
+}
+.terminal-app #terminado-container {
+  margin-top: 20px;
+}
+/*# sourceMappingURL=style.min.css.map */
+    </style>
+<style type="text/css">
+    .highlight .hll { background-color: #ffffcc }
+.highlight  { background: #f8f8f8; }
+.highlight .c { color: #408080; font-style: italic } /* Comment */
+.highlight .err { border: 1px solid #FF0000 } /* Error */
+.highlight .k { color: #008000; font-weight: bold } /* Keyword */
+.highlight .o { color: #666666 } /* Operator */
+.highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */
+.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #BC7A00 } /* Comment.Preproc */
+.highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */
+.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */
+.highlight .gd { color: #A00000 } /* Generic.Deleted */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #FF0000 } /* Generic.Error */
+.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.highlight .gi { color: #00A000 } /* Generic.Inserted */
+.highlight .go { color: #888888 } /* Generic.Output */
+.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.highlight .gt { color: #0044DD } /* Generic.Traceback */
+.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #008000 } /* Keyword.Pseudo */
+.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #B00040 } /* Keyword.Type */
+.highlight .m { color: #666666 } /* Literal.Number */
+.highlight .s { color: #BA2121 } /* Literal.String */
+.highlight .na { color: #7D9029 } /* Name.Attribute */
+.highlight .nb { color: #008000 } /* Name.Builtin */
+.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
+.highlight .no { color: #880000 } /* Name.Constant */
+.highlight .nd { color: #AA22FF } /* Name.Decorator */
+.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
+.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #0000FF } /* Name.Function */
+.highlight .nl { color: #A0A000 } /* Name.Label */
+.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
+.highlight .nv { color: #19177C } /* Name.Variable */
+.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mb { color: #666666 } /* Literal.Number.Bin */
+.highlight .mf { color: #666666 } /* Literal.Number.Float */
+.highlight .mh { color: #666666 } /* Literal.Number.Hex */
+.highlight .mi { color: #666666 } /* Literal.Number.Integer */
+.highlight .mo { color: #666666 } /* Literal.Number.Oct */
+.highlight .sa { color: #BA2121 } /* Literal.String.Affix */
+.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
+.highlight .sc { color: #BA2121 } /* Literal.String.Char */
+.highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */
+.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
+.highlight .s2 { color: #BA2121 } /* Literal.String.Double */
+.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
+.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.highlight .sx { color: #008000 } /* Literal.String.Other */
+.highlight .sr { color: #BB6688 } /* Literal.String.Regex */
+.highlight .s1 { color: #BA2121 } /* Literal.String.Single */
+.highlight .ss { color: #19177C } /* Literal.String.Symbol */
+.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
+.highlight .fm { color: #0000FF } /* Name.Function.Magic */
+.highlight .vc { color: #19177C } /* Name.Variable.Class */
+.highlight .vg { color: #19177C } /* Name.Variable.Global */
+.highlight .vi { color: #19177C } /* Name.Variable.Instance */
+.highlight .vm { color: #19177C } /* Name.Variable.Magic */
+.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
+    </style>
+<style type="text/css">
+    
+/* Temporary definitions which will become obsolete with Notebook release 5.0 */
+.ansi-black-fg { color: #3E424D; }
+.ansi-black-bg { background-color: #3E424D; }
+.ansi-black-intense-fg { color: #282C36; }
+.ansi-black-intense-bg { background-color: #282C36; }
+.ansi-red-fg { color: #E75C58; }
+.ansi-red-bg { background-color: #E75C58; }
+.ansi-red-intense-fg { color: #B22B31; }
+.ansi-red-intense-bg { background-color: #B22B31; }
+.ansi-green-fg { color: #00A250; }
+.ansi-green-bg { background-color: #00A250; }
+.ansi-green-intense-fg { color: #007427; }
+.ansi-green-intense-bg { background-color: #007427; }
+.ansi-yellow-fg { color: #DDB62B; }
+.ansi-yellow-bg { background-color: #DDB62B; }
+.ansi-yellow-intense-fg { color: #B27D12; }
+.ansi-yellow-intense-bg { background-color: #B27D12; }
+.ansi-blue-fg { color: #208FFB; }
+.ansi-blue-bg { background-color: #208FFB; }
+.ansi-blue-intense-fg { color: #0065CA; }
+.ansi-blue-intense-bg { background-color: #0065CA; }
+.ansi-magenta-fg { color: #D160C4; }
+.ansi-magenta-bg { background-color: #D160C4; }
+.ansi-magenta-intense-fg { color: #A03196; }
+.ansi-magenta-intense-bg { background-color: #A03196; }
+.ansi-cyan-fg { color: #60C6C8; }
+.ansi-cyan-bg { background-color: #60C6C8; }
+.ansi-cyan-intense-fg { color: #258F8F; }
+.ansi-cyan-intense-bg { background-color: #258F8F; }
+.ansi-white-fg { color: #C5C1B4; }
+.ansi-white-bg { background-color: #C5C1B4; }
+.ansi-white-intense-fg { color: #A1A6B2; }
+.ansi-white-intense-bg { background-color: #A1A6B2; }
+
+.ansi-bold { font-weight: bold; }
+
+    </style>
+
+
+<style type="text/css">
+/* Overrides of notebook CSS for static HTML export */
+body {
+  overflow: visible;
+  padding: 8px;
+}
+
+div#notebook {
+  overflow: visible;
+  border-top: none;
+}@media print {
+  div.cell {
+    display: block;
+    page-break-inside: avoid;
+  } 
+  div.output_wrapper { 
+    display: block;
+    page-break-inside: avoid; 
+  }
+  div.output { 
+    display: block;
+    page-break-inside: avoid; 
+  }
+}
+</style>
+
+<!-- Custom stylesheet, it must be in the same directory as the html file -->
+<link rel="stylesheet" href="custom.css">
+
+<!-- Loading mathjax macro -->
+<!-- Load mathjax -->
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS_HTML"></script>
+    <!-- MathJax configuration -->
+    <script type="text/x-mathjax-config">
+    MathJax.Hub.Config({
+        tex2jax: {
+            inlineMath: [ ['$','$'], ["\\(","\\)"] ],
+            displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
+            processEscapes: true,
+            processEnvironments: true
+        },
+        // Center justify equations in code and markdown cells. Elsewhere
+        // we use CSS to left justify single line equations in code cells.
+        displayAlign: 'center',
+        "HTML-CSS": {
+            styles: {'.MathJax_Display': {"margin": 0}},
+            linebreaks: { automatic: true }
+        }
+    });
+    </script>
+    <!-- End of mathjax configuration --></head>
+<body>
+  <div tabindex="-1" id="notebook" class="border-box-sizing">
+    <div class="container" id="notebook-container">
+
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h1 id="Type-Inference">Type Inference<a class="anchor-link" href="#Type-Inference">&#182;</a></h1>
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h2 id="P&#246;ial's-Rules">P&#246;ial's Rules<a class="anchor-link" href="#P&#246;ial's-Rules">&#182;</a></h2><p><a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.212.6026">"Typing Tools for Typeless Stack Languages" by Jaanus Pöial</a></p>
+
+<pre><code>@INPROCEEDINGS{Pöial06typingtools,
+    author = {Jaanus Pöial},
+    title = {Typing tools for typeless stack languages},
+    booktitle = {In 23rd Euro-Forth Conference},
+    year = {2006},
+    pages = {40--46}
+}</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="First-Rule">First Rule<a class="anchor-link" href="#First-Rule">&#182;</a></h3><p>This rule deals with functions (and literals) that put items on the stack <code>(-- d)</code>:</p>
+
+<pre><code>   (a -- b)∘(-- d)
+---------------------
+     (a -- b d)</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="Second-Rule">Second Rule<a class="anchor-link" href="#Second-Rule">&#182;</a></h3><p>This rule deals with functions that consume items from the stack <code>(a --)</code>:</p>
+
+<pre><code>   (a --)∘(c -- d)
+---------------------
+     (c a -- d)</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="Third-Rule">Third Rule<a class="anchor-link" href="#Third-Rule">&#182;</a></h3><p>The third rule is actually two rules.  These two rules deal with composing functions when the second one will consume one of items the first one produces.  The two types must be <em>unified</em> or a type conflict declared.</p>
+
+<pre><code>   (a -- b t[i])∘(c u[j] -- d)   t &lt;= u (t is subtype of u)
+-------------------------------
+   (a -- b     )∘(c      -- d)   t[i] == t[k] == u[j]
+                                         ^
+
+   (a -- b t[i])∘(c u[j] -- d)   u &lt;= t (u is subtype of t)
+-------------------------------
+   (a -- b     )∘(c      -- d)   t[i] == u[k] == u[j]</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h2 id="Examples">Examples<a class="anchor-link" href="#Examples">&#182;</a></h2><p>Let's work through some examples by hand to develop an intuition for the algorithm.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>There's a function in one of the other notebooks.</p>
+
+<pre><code>F == pop swap roll&lt; rest rest cons cons
+
+</code></pre>
+<p>It's all "stack chatter" and list manipulation so we should be able to deduce its type.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="Stack-Effect-Comments">Stack Effect Comments<a class="anchor-link" href="#Stack-Effect-Comments">&#182;</a></h3><p>Joy function types will be represented by Forth-style stack effect comments.  I'm going to use numbers instead of names to keep track of the stack arguments.  (A little bit like <a href="https://en.wikipedia.org/wiki/De_Bruijn_index">De Bruijn index</a>, at least it reminds me of them):</p>
+
+<pre><code>pop (1 --)
+
+swap (1 2 -- 2 1)
+
+roll&lt; (1 2 3 -- 2 3 1)
+
+</code></pre>
+<p>These commands alter the stack but don't "look at" the values so these numbers represent an "Any type".</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="pop-swap"><code>pop swap</code><a class="anchor-link" href="#pop-swap">&#182;</a></h3>
+<pre><code>(1 --) (1 2 -- 2 1)
+
+</code></pre>
+<p>Here we encounter a complication. The argument numbers need to be made unique among both sides.   For this let's change <code>pop</code> to use 0:</p>
+
+<pre><code>(0 --) (1 2 -- 2 1)
+
+</code></pre>
+<p>Following the second rule:</p>
+
+<pre><code>(1 2 0 -- 2 1)</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="pop&#8728;swap-roll&lt;"><code>pop&#8728;swap roll&lt;</code><a class="anchor-link" href="#pop&#8728;swap-roll&lt;">&#182;</a></h3>
+<pre><code>(1 2 0 -- 2 1) (1 2 3 -- 2 3 1)
+
+</code></pre>
+<p>Let's re-label them:</p>
+
+<pre><code>(1a 2a 0a -- 2a 1a) (1b 2b 3b -- 2b 3b 1b)</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>Now we follow the rules.</p>
+<p>We must unify <code>1a</code> and <code>3b</code>, and <code>2a</code> and <code>2b</code>, replacing the terms in the forms:</p>
+
+<pre><code>(1a 2a 0a -- 2a 1a) (1b 2b 3b -- 2b 3b 1b)
+                                            w/  {1a: 3b}
+(3b 2a 0a -- 2a   ) (1b 2b    -- 2b 3b 1b)
+                                            w/  {2a: 2b}
+(3b 2b 0a --      ) (1b       -- 2b 3b 1b)
+
+</code></pre>
+<p>Here we must apply the second rule:</p>
+
+<pre><code>   (3b 2b 0a --) (1b -- 2b 3b 1b)
+-----------------------------------
+     (1b 3b 2b 0a -- 2b 3b 1b)
+
+</code></pre>
+<p>Now we de-label the type, uh, labels:</p>
+
+<pre><code>(1b 3b 2b 0a -- 2b 3b 1b)
+
+w/ {
+    1b: 1,
+    3b: 2,
+    2b: 3,
+    0a: 0,
+    }
+
+(1 2 3 0 -- 3 2 1)
+
+</code></pre>
+<p>And now we have the stack effect comment for <code>pop∘swap∘roll&lt;</code>.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="Compiling-pop&#8728;swap&#8728;roll&lt;">Compiling <code>pop&#8728;swap&#8728;roll&lt;</code><a class="anchor-link" href="#Compiling-pop&#8728;swap&#8728;roll&lt;">&#182;</a></h3><p>The simplest way to "compile" this function would be something like:</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[1]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">poswrd</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">e</span><span class="p">,</span> <span class="n">d</span><span class="p">):</span>
+    <span class="k">return</span> <span class="n">roll_down</span><span class="p">(</span><span class="o">*</span><span class="n">swap</span><span class="p">(</span><span class="o">*</span><span class="n">pop</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">e</span><span class="p">,</span> <span class="n">d</span><span class="p">)))</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>However, internally this function would still be allocating tuples (stack cells) and doing other unnecesssary work.</p>
+<p>Looking ahead for a moment, from the stack effect comment:</p>
+
+<pre><code>(1 2 3 0 -- 3 2 1)
+
+</code></pre>
+<p>We should be able to directly write out a Python function like:</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[2]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">poswrd</span><span class="p">(</span><span class="n">stack</span><span class="p">):</span>
+    <span class="p">(</span><span class="n">_</span><span class="p">,</span> <span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="n">stack</span><span class="p">))))</span> <span class="o">=</span> <span class="n">stack</span>
+    <span class="k">return</span> <span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">stack</span><span class="p">)))</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>This eliminates the internal work of the first version.  Because this function only rearranges the stack and doesn't do any actual processing on the stack items themselves all the information needed to implement it is in the stack effect comment.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="Functions-on-Lists">Functions on Lists<a class="anchor-link" href="#Functions-on-Lists">&#182;</a></h3><p>These are slightly tricky.</p>
+
+<pre><code>rest ( [1 ...] -- [...] )
+
+cons ( 1 [...] -- [1 ...] )</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="pop&#8728;swap&#8728;roll&lt;-rest"><code>pop&#8728;swap&#8728;roll&lt; rest</code><a class="anchor-link" href="#pop&#8728;swap&#8728;roll&lt;-rest">&#182;</a></h3>
+<pre><code>(1 2 3 0 -- 3 2 1) ([1 ...] -- [...])
+
+</code></pre>
+<p>Re-label (instead of adding left and right tags I'm just taking the next available index number for the right-side stack effect comment):</p>
+
+<pre><code>(1 2 3 0 -- 3 2 1) ([4 ...] -- [...])
+
+</code></pre>
+<p>Unify and update:</p>
+
+<pre><code>(1       2 3 0 -- 3 2 1) ([4 ...] -- [...])
+                                             w/ {1: [4 ...]}
+([4 ...] 2 3 0 -- 3 2  ) (        -- [...])
+
+</code></pre>
+<p>Apply the first rule:</p>
+
+<pre><code>   ([4 ...] 2 3 0 -- 3 2) (-- [...])
+---------------------------------------
+     ([4 ...] 2 3 0 -- 3 2 [...])
+
+</code></pre>
+<p>And there we are.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="pop&#8728;swap&#8728;roll&lt;&#8728;rest-rest"><code>pop&#8728;swap&#8728;roll&lt;&#8728;rest rest</code><a class="anchor-link" href="#pop&#8728;swap&#8728;roll&lt;&#8728;rest-rest">&#182;</a></h3><p>Let's do it again.</p>
+
+<pre><code>([4 ...] 2 3 0 -- 3 2 [...]) ([1 ...] -- [...])
+
+</code></pre>
+<p>Re-label (the tails of the lists on each side each get their own label):</p>
+
+<pre><code>([4 .0.] 2 3 0 -- 3 2 [.0.]) ([5 .1.] -- [.1.])
+
+</code></pre>
+<p>Unify and update (note the opening square brackets have been omited in the substitution dict, this is deliberate and I'll explain below):</p>
+
+<pre><code>([4 .0.]   2 3 0 -- 3 2 [.0.]  ) ([5 .1.] -- [.1.])
+                                                    w/ { .0.] : 5 .1.] }
+([4 5 .1.] 2 3 0 -- 3 2 [5 .1.]) ([5 .1.] -- [.1.])</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>How do we find <code>.0.]</code> in <code>[4 .0.]</code> and replace it with <code>5 .1.]</code> getting the result <code>[4 5 .1.]</code>?  This might seem hard, but because the underlying structure of the Joy list is a cons-list in Python it's actually pretty easy.  I'll explain below.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>Next we unify and find our two terms are the same already: <code>[5 .1.]</code>:</p>
+
+<pre><code>([4 5 .1.] 2 3 0 -- 3 2 [5 .1.]) ([5 .1.] -- [.1.])
+
+</code></pre>
+<p>Giving us:</p>
+
+<pre><code>([4 5 .1.] 2 3 0 -- 3 2) (-- [.1.])
+
+</code></pre>
+<p>From here we apply the first rule and get:</p>
+
+<pre><code>([4 5 .1.] 2 3 0 -- 3 2 [.1.])
+
+</code></pre>
+<p>Cleaning up the labels:</p>
+
+<pre><code>([4 5 ...] 2 3 1 -- 3 2 [...])
+
+</code></pre>
+<p>This is the stack effect of <code>pop∘swap∘roll&lt;∘rest∘rest</code>.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="pop&#8728;swap&#8728;roll&lt;&#8728;rest&#8728;rest-cons"><code>pop&#8728;swap&#8728;roll&lt;&#8728;rest&#8728;rest cons</code><a class="anchor-link" href="#pop&#8728;swap&#8728;roll&lt;&#8728;rest&#8728;rest-cons">&#182;</a></h3>
+<pre><code>([4 5 ...] 2 3 1 -- 3 2 [...]) (1 [...] -- [1 ...])
+
+</code></pre>
+<p>Re-label:</p>
+
+<pre><code>([4 5 .1.] 2 3 1 -- 3 2 [.1.]) (6 [.2.] -- [6 .2.])
+
+</code></pre>
+<p>Unify:</p>
+
+<pre><code>([4 5 .1.] 2 3 1 -- 3 2 [.1.]) (6 [.2.] -- [6 .2.])
+                                                     w/ { .1.] : .2.] }
+([4 5 .2.] 2 3 1 -- 3 2      ) (6       -- [6 .2.])
+                                                     w/ {2: 6}
+([4 5 .2.] 6 3 1 -- 3        ) (        -- [6 .2.])
+
+</code></pre>
+<p>First rule:</p>
+
+<pre><code>([4 5 .2.] 6 3 1 -- 3 [6 .2.])
+
+</code></pre>
+<p>Re-label:</p>
+
+<pre><code>([4 5 ...] 2 3 1 -- 3 [2 ...])
+
+</code></pre>
+<p>Done.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="pop&#8728;swap&#8728;roll&lt;&#8728;rest&#8728;rest&#8728;cons-cons"><code>pop&#8728;swap&#8728;roll&lt;&#8728;rest&#8728;rest&#8728;cons cons</code><a class="anchor-link" href="#pop&#8728;swap&#8728;roll&lt;&#8728;rest&#8728;rest&#8728;cons-cons">&#182;</a></h3><p>One more time.</p>
+
+<pre><code>([4 5 ...] 2 3 1 -- 3 [2 ...]) (1 [...] -- [1 ...])
+
+</code></pre>
+<p>Re-label:</p>
+
+<pre><code>([4 5 .1.] 2 3 1 -- 3 [2 .1.]) (6 [.2.] -- [6 .2.])
+
+</code></pre>
+<p>Unify:</p>
+
+<pre><code>([4 5 .1.] 2 3 1 -- 3 [2 .1.]) (6 [.2.] -- [6 .2.]  )
+                                                       w/ { .2.] : 2 .1.] }
+([4 5 .1.] 2 3 1 -- 3        ) (6       -- [6 2 .1.])
+                                                       w/ {3: 6}
+([4 5 .1.] 2 6 1 --          ) (        -- [6 2 .1.])
+
+</code></pre>
+<p>First or second rule:</p>
+
+<pre><code>([4 5 .1.] 2 6 1 -- [6 2 .1.])
+
+</code></pre>
+<p>Clean up the labels:</p>
+
+<pre><code>([4 5 ...] 2 3 1 -- [3 2 ...])
+
+</code></pre>
+<p>And there you have it, the stack effect for <code>pop∘swap∘roll&lt;∘rest∘rest∘cons∘cons</code>.</p>
+
+<pre><code>([4 5 ...] 2 3 1 -- [3 2 ...])</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>From this stack effect comment it should be possible to construct the following Python code:</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[3]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">F</span><span class="p">(</span><span class="n">stack</span><span class="p">):</span>
+    <span class="p">(</span><span class="n">_</span><span class="p">,</span> <span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="p">((</span><span class="n">a</span><span class="p">,</span> <span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="n">S0</span><span class="p">)),</span> <span class="n">stack</span><span class="p">))))</span> <span class="o">=</span> <span class="n">stack</span>
+    <span class="k">return</span> <span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="n">S0</span><span class="p">)),</span> <span class="n">stack</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h2 id="Implementation">Implementation<a class="anchor-link" href="#Implementation">&#182;</a></h2>
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="Representing-Stack-Effect-Comments-in-Python">Representing Stack Effect Comments in Python<a class="anchor-link" href="#Representing-Stack-Effect-Comments-in-Python">&#182;</a></h3><p>I'm going to use pairs of tuples of type descriptors, which will be integers or tuples of type descriptors:</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[4]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">roll_dn</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
+
+<span class="n">pop</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,),</span> <span class="p">()</span>
+
+<span class="n">swap</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="compose()"><code>compose()</code><a class="anchor-link" href="#compose()">&#182;</a></h3>
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[5]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">compose</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">g</span><span class="p">):</span>
+
+    <span class="p">(</span><span class="n">f_in</span><span class="p">,</span> <span class="n">f_out</span><span class="p">),</span> <span class="p">(</span><span class="n">g_in</span><span class="p">,</span> <span class="n">g_out</span><span class="p">)</span> <span class="o">=</span> <span class="n">f</span><span class="p">,</span> <span class="n">g</span>
+
+    <span class="c1"># First rule.</span>
+    <span class="c1">#</span>
+    <span class="c1">#       (a -- b) (-- d)</span>
+    <span class="c1">#    ---------------------</span>
+    <span class="c1">#         (a -- b d)</span>
+
+    <span class="k">if</span> <span class="ow">not</span> <span class="n">g_in</span><span class="p">:</span>
+
+        <span class="n">fg_in</span><span class="p">,</span> <span class="n">fg_out</span> <span class="o">=</span> <span class="n">f_in</span><span class="p">,</span> <span class="n">f_out</span> <span class="o">+</span> <span class="n">g_out</span>
+
+    <span class="c1"># Second rule.</span>
+    <span class="c1">#</span>
+    <span class="c1">#       (a --) (c -- d)</span>
+    <span class="c1">#    ---------------------</span>
+    <span class="c1">#         (c a -- d)</span>
+
+    <span class="k">elif</span> <span class="ow">not</span> <span class="n">f_out</span><span class="p">:</span>
+
+        <span class="n">fg_in</span><span class="p">,</span> <span class="n">fg_out</span> <span class="o">=</span> <span class="n">g_in</span> <span class="o">+</span> <span class="n">f_in</span><span class="p">,</span> <span class="n">g_out</span>
+
+    <span class="k">else</span><span class="p">:</span> <span class="c1"># Unify, update, recur.</span>
+
+        <span class="n">fo</span><span class="p">,</span> <span class="n">gi</span> <span class="o">=</span> <span class="n">f_out</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">g_in</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
+
+        <span class="n">s</span> <span class="o">=</span> <span class="n">unify</span><span class="p">(</span><span class="n">gi</span><span class="p">,</span> <span class="n">fo</span><span class="p">)</span>
+
+        <span class="k">if</span> <span class="n">s</span> <span class="o">==</span> <span class="bp">False</span><span class="p">:</span>  <span class="c1"># s can also be the empty dict, which is ok.</span>
+            <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="s1">&#39;Cannot unify </span><span class="si">%r</span><span class="s1"> and </span><span class="si">%r</span><span class="s1">.&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">fo</span><span class="p">,</span> <span class="n">gi</span><span class="p">))</span>
+
+        <span class="n">f_g</span> <span class="o">=</span> <span class="p">(</span><span class="n">f_in</span><span class="p">,</span> <span class="n">f_out</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">]),</span> <span class="p">(</span><span class="n">g_in</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">g_out</span><span class="p">)</span>
+
+        <span class="k">if</span> <span class="n">s</span><span class="p">:</span> <span class="n">f_g</span> <span class="o">=</span> <span class="n">update</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">f_g</span><span class="p">)</span>
+
+        <span class="n">fg_in</span><span class="p">,</span> <span class="n">fg_out</span> <span class="o">=</span> <span class="n">compose</span><span class="p">(</span><span class="o">*</span><span class="n">f_g</span><span class="p">)</span>
+
+    <span class="k">return</span> <span class="n">fg_in</span><span class="p">,</span> <span class="n">fg_out</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="unify()"><code>unify()</code><a class="anchor-link" href="#unify()">&#182;</a></h3>
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[6]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">unify</span><span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">s</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
+    <span class="k">if</span> <span class="n">s</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
+        <span class="n">s</span> <span class="o">=</span> <span class="p">{}</span>
+
+    <span class="k">if</span> <span class="n">u</span> <span class="o">==</span> <span class="n">v</span><span class="p">:</span>
+        <span class="k">return</span> <span class="n">s</span>
+
+    <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
+        <span class="n">s</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="n">v</span>
+        <span class="k">return</span> <span class="n">s</span>
+
+    <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
+        <span class="n">s</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">u</span>
+        <span class="k">return</span> <span class="n">s</span>
+
+    <span class="k">return</span> <span class="bp">False</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="update()"><code>update()</code><a class="anchor-link" href="#update()">&#182;</a></h3>
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[7]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">update</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">term</span><span class="p">):</span>
+    <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">term</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">):</span>
+        <span class="k">return</span> <span class="n">s</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">term</span><span class="p">,</span> <span class="n">term</span><span class="p">)</span>
+    <span class="k">return</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">update</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">inner</span><span class="p">)</span> <span class="k">for</span> <span class="n">inner</span> <span class="ow">in</span> <span class="n">term</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="relabel()"><code>relabel()</code><a class="anchor-link" href="#relabel()">&#182;</a></h3>
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[8]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">relabel</span><span class="p">(</span><span class="n">left</span><span class="p">,</span> <span class="n">right</span><span class="p">):</span>
+    <span class="k">return</span> <span class="n">left</span><span class="p">,</span> <span class="n">_1000</span><span class="p">(</span><span class="n">right</span><span class="p">)</span>
+
+<span class="k">def</span> <span class="nf">_1000</span><span class="p">(</span><span class="n">right</span><span class="p">):</span>
+    <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">right</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">):</span>
+        <span class="k">return</span> <span class="mi">1000</span> <span class="o">+</span> <span class="n">right</span>
+    <span class="k">return</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">_1000</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">right</span><span class="p">)</span>
+
+<span class="n">relabel</span><span class="p">(</span><span class="n">pop</span><span class="p">,</span> <span class="n">swap</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt output_prompt">Out[8]:</div>
+
+
+
+
+<div class="output_text output_subarea output_execute_result">
+<pre>(((1,), ()), ((1001, 1002), (1002, 1001)))</pre>
+</div>
+
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="delabel()"><code>delabel()</code><a class="anchor-link" href="#delabel()">&#182;</a></h3>
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[9]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">delabel</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
+    <span class="n">s</span> <span class="o">=</span> <span class="p">{</span><span class="n">u</span><span class="p">:</span> <span class="n">i</span> <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">u</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="nb">sorted</span><span class="p">(</span><span class="n">_unique</span><span class="p">(</span><span class="n">f</span><span class="p">)))}</span>
+    <span class="k">return</span> <span class="n">update</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">f</span><span class="p">)</span>
+
+<span class="k">def</span> <span class="nf">_unique</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">seen</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
+    <span class="k">if</span> <span class="n">seen</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
+        <span class="n">seen</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
+    <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">):</span>
+        <span class="n">seen</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
+    <span class="k">else</span><span class="p">:</span>
+        <span class="k">for</span> <span class="n">inner</span> <span class="ow">in</span> <span class="n">f</span><span class="p">:</span>
+            <span class="n">_unique</span><span class="p">(</span><span class="n">inner</span><span class="p">,</span> <span class="n">seen</span><span class="p">)</span>
+    <span class="k">return</span> <span class="n">seen</span>
+
+<span class="n">delabel</span><span class="p">(</span><span class="n">relabel</span><span class="p">(</span><span class="n">pop</span><span class="p">,</span> <span class="n">swap</span><span class="p">))</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt output_prompt">Out[9]:</div>
+
+
+
+
+<div class="output_text output_subarea output_execute_result">
+<pre>(((0,), ()), ((1, 2), (2, 1)))</pre>
+</div>
+
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="C()"><code>C()</code><a class="anchor-link" href="#C()">&#182;</a></h3><p>At last we put it all together in a function <code>C()</code> that accepts two stack effect comments and returns their composition (or raises and exception if they can't be composed due to type conflicts.)</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[10]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">C</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">g</span><span class="p">):</span>
+    <span class="n">f</span><span class="p">,</span> <span class="n">g</span> <span class="o">=</span> <span class="n">relabel</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">g</span><span class="p">)</span>
+    <span class="n">fg</span> <span class="o">=</span> <span class="n">compose</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">g</span><span class="p">)</span>
+    <span class="k">return</span> <span class="n">delabel</span><span class="p">(</span><span class="n">fg</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>Let's try it out.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[11]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">C</span><span class="p">(</span><span class="n">pop</span><span class="p">,</span> <span class="n">swap</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt output_prompt">Out[11]:</div>
+
+
+
+
+<div class="output_text output_subarea output_execute_result">
+<pre>((1, 2, 0), (2, 1))</pre>
+</div>
+
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[12]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">C</span><span class="p">(</span><span class="n">C</span><span class="p">(</span><span class="n">pop</span><span class="p">,</span> <span class="n">swap</span><span class="p">),</span> <span class="n">roll_dn</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt output_prompt">Out[12]:</div>
+
+
+
+
+<div class="output_text output_subarea output_execute_result">
+<pre>((3, 1, 2, 0), (2, 1, 3))</pre>
+</div>
+
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[13]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">C</span><span class="p">(</span><span class="n">swap</span><span class="p">,</span> <span class="n">roll_dn</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt output_prompt">Out[13]:</div>
+
+
+
+
+<div class="output_text output_subarea output_execute_result">
+<pre>((2, 0, 1), (1, 0, 2))</pre>
+</div>
+
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[14]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">C</span><span class="p">(</span><span class="n">pop</span><span class="p">,</span> <span class="n">C</span><span class="p">(</span><span class="n">swap</span><span class="p">,</span> <span class="n">roll_dn</span><span class="p">))</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt output_prompt">Out[14]:</div>
+
+
+
+
+<div class="output_text output_subarea output_execute_result">
+<pre>((3, 1, 2, 0), (2, 1, 3))</pre>
+</div>
+
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[15]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">poswrd</span> <span class="o">=</span> <span class="nb">reduce</span><span class="p">(</span><span class="n">C</span><span class="p">,</span> <span class="p">(</span><span class="n">pop</span><span class="p">,</span> <span class="n">swap</span><span class="p">,</span> <span class="n">roll_dn</span><span class="p">))</span>
+<span class="n">poswrd</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt output_prompt">Out[15]:</div>
+
+
+
+
+<div class="output_text output_subarea output_execute_result">
+<pre>((3, 1, 2, 0), (2, 1, 3))</pre>
+</div>
+
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="List-Functions">List Functions<a class="anchor-link" href="#List-Functions">&#182;</a></h3><p>Here's that trick to represent functions like <code>rest</code> and <code>cons</code> that manipulate lists.  We use a cons-list of tuples and give the tails their own numbers.  Then everything above already works.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[16]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">rest</span> <span class="o">=</span> <span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">),),</span> <span class="p">(</span><span class="mi">2</span><span class="p">,)</span>
+
+<span class="n">cons</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">),)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[17]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">C</span><span class="p">(</span><span class="n">poswrd</span><span class="p">,</span> <span class="n">rest</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt output_prompt">Out[17]:</div>
+
+
+
+
+<div class="output_text output_subarea output_execute_result">
+<pre>(((3, 4), 1, 2, 0), (2, 1, 4))</pre>
+</div>
+
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>Compare this to the stack effect comment we wrote above:</p>
+
+<pre><code>((  (3, 4), 1, 2, 0 ), ( 2, 1,   4  ))
+(   [4 ...] 2  3  0  --  3  2  [...])
+
+</code></pre>
+<p>The translation table, if you will, would be:</p>
+
+<pre><code>{
+3: 4,
+4: ...],
+1: 2,
+2: 3,
+0: 0,
+}</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[18]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">F</span> <span class="o">=</span> <span class="nb">reduce</span><span class="p">(</span><span class="n">C</span><span class="p">,</span> <span class="p">(</span><span class="n">pop</span><span class="p">,</span> <span class="n">swap</span><span class="p">,</span> <span class="n">roll_dn</span><span class="p">,</span> <span class="n">rest</span><span class="p">,</span> <span class="n">rest</span><span class="p">,</span> <span class="n">cons</span><span class="p">,</span> <span class="n">cons</span><span class="p">))</span>
+
+<span class="n">F</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt output_prompt">Out[18]:</div>
+
+
+
+
+<div class="output_text output_subarea output_execute_result">
+<pre>(((3, (4, 5)), 1, 2, 0), ((2, (1, 5)),))</pre>
+</div>
+
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>Compare with the stack effect comment and you can see it works fine:</p>
+
+<pre><code>([4 5 ...] 2 3 1 -- [3 2 ...])</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="Dealing-with-cons-and-uncons">Dealing with <code>cons</code> and <code>uncons</code><a class="anchor-link" href="#Dealing-with-cons-and-uncons">&#182;</a></h3><p>However, if we try to compose e.g. <code>cons</code> and <code>uncons</code> it won't work:</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[19]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">uncons</span> <span class="o">=</span> <span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">),),</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[20]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">try</span><span class="p">:</span>
+    <span class="n">C</span><span class="p">(</span><span class="n">cons</span><span class="p">,</span> <span class="n">uncons</span><span class="p">)</span>
+<span class="k">except</span> <span class="ne">Exception</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span>
+    <span class="k">print</span> <span class="n">e</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>Cannot unify (1, 2) and (1001, 1002).
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h4 id="unify()-version-2"><code>unify()</code> version 2<a class="anchor-link" href="#unify()-version-2">&#182;</a></h4><p>The problem is that the <code>unify()</code> function as written doesn't handle the case when both terms are tuples.  We just have to add a clause to deal with this recursively:</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[21]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">unify</span><span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">s</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
+    <span class="k">if</span> <span class="n">s</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
+        <span class="n">s</span> <span class="o">=</span> <span class="p">{}</span>
+    <span class="k">else</span><span class="p">:</span>
+        <span class="n">u</span> <span class="o">=</span> <span class="n">update</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">u</span><span class="p">)</span>
+        <span class="n">v</span> <span class="o">=</span> <span class="n">update</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span>
+
+    <span class="k">if</span> <span class="n">u</span> <span class="o">==</span> <span class="n">v</span><span class="p">:</span>
+        <span class="k">return</span> <span class="n">s</span>
+
+    <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
+        <span class="n">s</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="n">v</span>
+        <span class="k">return</span> <span class="n">s</span>
+
+    <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
+        <span class="n">s</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">u</span>
+        <span class="k">return</span> <span class="n">s</span>
+
+    <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">)</span> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">):</span>
+        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">u</span><span class="p">)</span> <span class="o">!=</span> <span class="nb">len</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">2</span><span class="p">:</span>
+            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="nb">repr</span><span class="p">((</span><span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">)))</span>
+        <span class="k">for</span> <span class="n">uu</span><span class="p">,</span> <span class="n">vv</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">):</span>
+            <span class="n">s</span> <span class="o">=</span> <span class="n">unify</span><span class="p">(</span><span class="n">uu</span><span class="p">,</span> <span class="n">vv</span><span class="p">,</span> <span class="n">s</span><span class="p">)</span>
+            <span class="k">if</span> <span class="n">s</span> <span class="o">==</span> <span class="bp">False</span><span class="p">:</span> <span class="c1"># (instead of a substitution dict.)</span>
+                <span class="k">break</span>
+        <span class="k">return</span> <span class="n">s</span>
+    <span class="k">return</span> <span class="bp">False</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[22]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">C</span><span class="p">(</span><span class="n">cons</span><span class="p">,</span> <span class="n">uncons</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt output_prompt">Out[22]:</div>
+
+
+
+
+<div class="output_text output_subarea output_execute_result">
+<pre>((0, 1), (0, 1))</pre>
+</div>
+
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h2 id="Compiling">Compiling<a class="anchor-link" href="#Compiling">&#182;</a></h2><p>Now consider the Python function we would like to derive:</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[23]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">F_python</span><span class="p">(</span><span class="n">stack</span><span class="p">):</span>
+    <span class="p">(</span><span class="n">_</span><span class="p">,</span> <span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="p">((</span><span class="n">a</span><span class="p">,</span> <span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="n">S0</span><span class="p">)),</span> <span class="n">stack</span><span class="p">))))</span> <span class="o">=</span> <span class="n">stack</span>
+    <span class="k">return</span> <span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="n">S0</span><span class="p">)),</span> <span class="n">stack</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>And compare it to the input stack effect comment tuple we just computed:</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[24]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">F</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt output_prompt">Out[24]:</div>
+
+
+
+
+<div class="output_text output_subarea output_execute_result">
+<pre>((3, (4, 5)), 1, 2, 0)</pre>
+</div>
+
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>The stack-de-structuring tuple has nearly the same form as our input stack effect comment tuple, just in the reverse order:</p>
+
+<pre><code>(_, (d, (c, ((a, (b, S0)), stack))))
+
+</code></pre>
+<p>Remove the punctuation:</p>
+
+<pre><code> _   d   c   (a, (b, S0))
+
+</code></pre>
+<p>Reverse the order and compare:</p>
+
+<pre><code> (a, (b, S0))   c   d   _
+((3, (4, 5 )),  1,  2,  0)
+
+</code></pre>
+<p>Eh?</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>And the return tuple</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[25]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">F</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt output_prompt">Out[25]:</div>
+
+
+
+
+<div class="output_text output_subarea output_execute_result">
+<pre>((2, (1, 5)),)</pre>
+</div>
+
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>is similar to the output stack effect comment tuple:</p>
+
+<pre><code>((d, (c, S0)), stack)
+((2, (1, 5 )),      )
+
+</code></pre>
+<p>This should make it pretty easy to write a Python function that accepts the stack effect comment tuples and returns a new Python function (either as a string of code or a function object ready to use) that performs the semantics of that Joy function (described by the stack effect.)</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="Python-Identifiers">Python Identifiers<a class="anchor-link" href="#Python-Identifiers">&#182;</a></h3><p>We want to substitute Python identifiers for the integers.  I'm going to repurpose <code>joy.parser.Symbol</code> class for this:</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[26]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">defaultdict</span>
+<span class="kn">from</span> <span class="nn">joy.parser</span> <span class="kn">import</span> <span class="n">Symbol</span>
+
+
+<span class="k">def</span> <span class="nf">_names_for</span><span class="p">():</span>
+    <span class="n">I</span> <span class="o">=</span> <span class="nb">iter</span><span class="p">(</span><span class="nb">xrange</span><span class="p">(</span><span class="mi">1000</span><span class="p">))</span>
+    <span class="k">return</span> <span class="k">lambda</span><span class="p">:</span> <span class="n">Symbol</span><span class="p">(</span><span class="s1">&#39;a</span><span class="si">%i</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="nb">next</span><span class="p">(</span><span class="n">I</span><span class="p">))</span>
+
+
+<span class="k">def</span> <span class="nf">identifiers</span><span class="p">(</span><span class="n">term</span><span class="p">,</span> <span class="n">s</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
+    <span class="k">if</span> <span class="n">s</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
+        <span class="n">s</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="n">_names_for</span><span class="p">())</span>
+    <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">term</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
+        <span class="k">return</span> <span class="n">s</span><span class="p">[</span><span class="n">term</span><span class="p">]</span>
+    <span class="k">return</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">identifiers</span><span class="p">(</span><span class="n">inner</span><span class="p">,</span> <span class="n">s</span><span class="p">)</span> <span class="k">for</span> <span class="n">inner</span> <span class="ow">in</span> <span class="n">term</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="doc_from_stack_effect()"><code>doc_from_stack_effect()</code><a class="anchor-link" href="#doc_from_stack_effect()">&#182;</a></h3><p>As a convenience I've implemented a function to convert the Python stack effect comment tuples to reasonable text format.  There are some details in how this code works that related to stuff later in the notebook, so you should skip it for now and read it later if you're interested.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[27]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">doc_from_stack_effect</span><span class="p">(</span><span class="n">inputs</span><span class="p">,</span> <span class="n">outputs</span><span class="p">):</span>
+    <span class="k">return</span> <span class="s1">&#39;(</span><span class="si">%s</span><span class="s1">--</span><span class="si">%s</span><span class="s1">)&#39;</span> <span class="o">%</span> <span class="p">(</span>
+        <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">map</span><span class="p">(</span><span class="n">_to_str</span><span class="p">,</span> <span class="n">inputs</span> <span class="o">+</span> <span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">,))),</span>
+        <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">map</span><span class="p">(</span><span class="n">_to_str</span><span class="p">,</span> <span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">,)</span> <span class="o">+</span> <span class="n">outputs</span><span class="p">))</span>
+    <span class="p">)</span>
+
+
+<span class="k">def</span> <span class="nf">_to_str</span><span class="p">(</span><span class="n">term</span><span class="p">):</span>
+    <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">term</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">):</span>
+        <span class="k">try</span><span class="p">:</span>
+            <span class="n">t</span> <span class="o">=</span> <span class="n">term</span><span class="o">.</span><span class="n">prefix</span> <span class="o">==</span> <span class="s1">&#39;s&#39;</span>
+        <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
+            <span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">term</span><span class="p">)</span>
+        <span class="k">return</span> <span class="s1">&#39;[.</span><span class="si">%i</span><span class="s1">.]&#39;</span> <span class="o">%</span> <span class="n">term</span><span class="o">.</span><span class="n">number</span> <span class="k">if</span> <span class="n">t</span> <span class="k">else</span> <span class="nb">str</span><span class="p">(</span><span class="n">term</span><span class="p">)</span>
+
+    <span class="n">a</span> <span class="o">=</span> <span class="p">[]</span>
+    <span class="k">while</span> <span class="n">term</span> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">term</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">):</span>
+        <span class="n">item</span><span class="p">,</span> <span class="n">term</span> <span class="o">=</span> <span class="n">term</span>
+        <span class="n">a</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">_to_str</span><span class="p">(</span><span class="n">item</span><span class="p">))</span>
+
+    <span class="k">try</span><span class="p">:</span>
+        <span class="n">n</span> <span class="o">=</span> <span class="n">term</span><span class="o">.</span><span class="n">number</span>
+    <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
+        <span class="n">n</span> <span class="o">=</span> <span class="n">term</span>
+    <span class="k">else</span><span class="p">:</span>
+        <span class="k">if</span> <span class="n">term</span><span class="o">.</span><span class="n">prefix</span> <span class="o">!=</span> <span class="s1">&#39;s&#39;</span><span class="p">:</span>
+            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s1">&#39;Stack label: </span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">term</span><span class="p">,))</span>
+
+    <span class="n">a</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39;.</span><span class="si">%s</span><span class="s1">.&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">n</span><span class="p">,))</span>
+    <span class="k">return</span> <span class="s1">&#39;[</span><span class="si">%s</span><span class="s1">]&#39;</span> <span class="o">%</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="compile_()"><code>compile_()</code><a class="anchor-link" href="#compile_()">&#182;</a></h3><p>Now we can write a compiler function to emit Python source code.  (The underscore suffix distiguishes it from the built-in <code>compile()</code> function.)</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[28]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">compile_</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">f</span><span class="p">,</span> <span class="n">doc</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
+    <span class="k">if</span> <span class="n">doc</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
+        <span class="n">doc</span> <span class="o">=</span> <span class="n">doc_from_stack_effect</span><span class="p">(</span><span class="o">*</span><span class="n">f</span><span class="p">)</span>
+    <span class="n">inputs</span><span class="p">,</span> <span class="n">outputs</span> <span class="o">=</span> <span class="n">identifiers</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
+    <span class="n">i</span> <span class="o">=</span> <span class="n">o</span> <span class="o">=</span> <span class="n">Symbol</span><span class="p">(</span><span class="s1">&#39;stack&#39;</span><span class="p">)</span>
+    <span class="k">for</span> <span class="n">term</span> <span class="ow">in</span> <span class="n">inputs</span><span class="p">:</span>
+        <span class="n">i</span> <span class="o">=</span> <span class="n">term</span><span class="p">,</span> <span class="n">i</span>
+    <span class="k">for</span> <span class="n">term</span> <span class="ow">in</span> <span class="n">outputs</span><span class="p">:</span>
+        <span class="n">o</span> <span class="o">=</span> <span class="n">term</span><span class="p">,</span> <span class="n">o</span>
+    <span class="k">return</span> <span class="s1">&#39;&#39;&#39;def </span><span class="si">%s</span><span class="s1">(stack):</span>
+<span class="s1">    &quot;&quot;&quot;</span><span class="si">%s</span><span class="s1">&quot;&quot;&quot;</span>
+<span class="s1">    </span><span class="si">%s</span><span class="s1"> = stack</span>
+<span class="s1">    return </span><span class="si">%s</span><span class="s1">&#39;&#39;&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">doc</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">o</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>Here it is in action:</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[29]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">source</span> <span class="o">=</span> <span class="n">compile_</span><span class="p">(</span><span class="s1">&#39;F&#39;</span><span class="p">,</span> <span class="n">F</span><span class="p">)</span>
+
+<span class="k">print</span> <span class="n">source</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>def F(stack):
+    &#34;&#34;&#34;([3 4 .5.] 1 2 0 -- [2 1 .5.])&#34;&#34;&#34;
+    (a5, (a4, (a3, ((a0, (a1, a2)), stack)))) = stack
+    return ((a4, (a3, a2)), stack)
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>Compare:</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[30]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">F_python</span><span class="p">(</span><span class="n">stack</span><span class="p">):</span>
+    <span class="p">(</span><span class="n">_</span><span class="p">,</span> <span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="p">((</span><span class="n">a</span><span class="p">,</span> <span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="n">S0</span><span class="p">)),</span> <span class="n">stack</span><span class="p">))))</span> <span class="o">=</span> <span class="n">stack</span>
+    <span class="k">return</span> <span class="p">((</span><span class="n">d</span><span class="p">,</span> <span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="n">S0</span><span class="p">)),</span> <span class="n">stack</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>Next steps:</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[31]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">L</span> <span class="o">=</span> <span class="p">{}</span>
+
+<span class="nb">eval</span><span class="p">(</span><span class="nb">compile</span><span class="p">(</span><span class="n">source</span><span class="p">,</span> <span class="s1">&#39;__main__&#39;</span><span class="p">,</span> <span class="s1">&#39;single&#39;</span><span class="p">),</span> <span class="p">{},</span> <span class="n">L</span><span class="p">)</span>
+
+<span class="n">L</span><span class="p">[</span><span class="s1">&#39;F&#39;</span><span class="p">]</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt output_prompt">Out[31]:</div>
+
+
+
+
+<div class="output_text output_subarea output_execute_result">
+<pre>&lt;function F&gt;</pre>
+</div>
+
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>Let's try it out:</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[32]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="kn">from</span> <span class="nn">notebook_preamble</span> <span class="kn">import</span> <span class="n">D</span><span class="p">,</span> <span class="n">J</span><span class="p">,</span> <span class="n">V</span>
+<span class="kn">from</span> <span class="nn">joy.library</span> <span class="kn">import</span> <span class="n">SimpleFunctionWrapper</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[33]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">D</span><span class="p">[</span><span class="s1">&#39;F&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">SimpleFunctionWrapper</span><span class="p">(</span><span class="n">L</span><span class="p">[</span><span class="s1">&#39;F&#39;</span><span class="p">])</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[34]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">&#39;[4 5 ...] 2 3 1 F&#39;</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>[3 2 ...]
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>With this, we have a partial Joy compiler that works on the subset of Joy functions that manipulate stacks (both what I call "stack chatter" and the ones that manipulate stacks on the stack.)</p>
+<p>I'm probably going to modify the definition wrapper code to detect definitions that can be compiled by this partial compiler and do it automatically.  It might be a reasonable idea to detect sequences of compilable functions in definitions that have uncompilable functions in them and just compile those.  However, if your library is well-factored this might be less helpful.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="Compiling-Library-Functions">Compiling Library Functions<a class="anchor-link" href="#Compiling-Library-Functions">&#182;</a></h3><p>We can use <code>compile_()</code> to generate many primitives in the library from their stack effect comments:</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[35]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">defs</span><span class="p">():</span>
+
+    <span class="n">roll_down</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
+
+    <span class="n">roll_up</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
+
+    <span class="n">pop</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,),</span> <span class="p">()</span>
+
+    <span class="n">swap</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
+
+    <span class="n">rest</span> <span class="o">=</span> <span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">),),</span> <span class="p">(</span><span class="mi">2</span><span class="p">,)</span>
+    
+    <span class="n">rrest</span> <span class="o">=</span> <span class="n">C</span><span class="p">(</span><span class="n">rest</span><span class="p">,</span> <span class="n">rest</span><span class="p">)</span>
+
+    <span class="n">cons</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">),)</span>
+
+    <span class="n">uncons</span> <span class="o">=</span> <span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">),),</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
+    
+    <span class="n">swons</span> <span class="o">=</span> <span class="n">C</span><span class="p">(</span><span class="n">swap</span><span class="p">,</span> <span class="n">cons</span><span class="p">)</span>
+
+    <span class="k">return</span> <span class="nb">locals</span><span class="p">()</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[36]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">for</span> <span class="n">name</span><span class="p">,</span> <span class="n">stack_effect_comment</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">defs</span><span class="p">()</span><span class="o">.</span><span class="n">items</span><span class="p">()):</span>
+    <span class="k">print</span>
+    <span class="k">print</span> <span class="n">compile_</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">stack_effect_comment</span><span class="p">)</span>
+    <span class="k">print</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>
+def cons(stack):
+    &#34;&#34;&#34;(1 2 -- [1 .2.])&#34;&#34;&#34;
+    (a1, (a0, stack)) = stack
+    return ((a0, a1), stack)
+
+
+def pop(stack):
+    &#34;&#34;&#34;(1 --)&#34;&#34;&#34;
+    (a0, stack) = stack
+    return stack
+
+
+def rest(stack):
+    &#34;&#34;&#34;([1 .2.] -- 2)&#34;&#34;&#34;
+    ((a0, a1), stack) = stack
+    return (a1, stack)
+
+
+def roll_down(stack):
+    &#34;&#34;&#34;(1 2 3 -- 2 3 1)&#34;&#34;&#34;
+    (a2, (a1, (a0, stack))) = stack
+    return (a0, (a2, (a1, stack)))
+
+
+def roll_up(stack):
+    &#34;&#34;&#34;(1 2 3 -- 3 1 2)&#34;&#34;&#34;
+    (a2, (a1, (a0, stack))) = stack
+    return (a1, (a0, (a2, stack)))
+
+
+def rrest(stack):
+    &#34;&#34;&#34;([0 1 .2.] -- 2)&#34;&#34;&#34;
+    ((a0, (a1, a2)), stack) = stack
+    return (a2, stack)
+
+
+def swap(stack):
+    &#34;&#34;&#34;(1 2 -- 2 1)&#34;&#34;&#34;
+    (a1, (a0, stack)) = stack
+    return (a0, (a1, stack))
+
+
+def swons(stack):
+    &#34;&#34;&#34;(0 1 -- [1 .0.])&#34;&#34;&#34;
+    (a1, (a0, stack)) = stack
+    return ((a1, a0), stack)
+
+
+def uncons(stack):
+    &#34;&#34;&#34;([1 .2.] -- 1 2)&#34;&#34;&#34;
+    ((a0, a1), stack) = stack
+    return (a1, (a0, stack))
+
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h2 id="Types-and-Subtypes-of-Arguments">Types and Subtypes of Arguments<a class="anchor-link" href="#Types-and-Subtypes-of-Arguments">&#182;</a></h2><p>So far we have dealt with types of functions, those dealing with simple stack manipulation.  Let's extend our machinery to deal with types of arguments.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="&quot;Number&quot;-Type">"Number" Type<a class="anchor-link" href="#&quot;Number&quot;-Type">&#182;</a></h3><p>Consider the definition of <code>sqr</code>:</p>
+
+<pre><code>sqr == dup mul
+
+
+</code></pre>
+<p>The <code>dup</code> function accepts one <em>anything</em> and returns two of that:</p>
+
+<pre><code>dup (1 -- 1 1)
+
+</code></pre>
+<p>And <code>mul</code> accepts two "numbers" (we're ignoring ints vs. floats vs. complex, etc., for now) and returns just one:</p>
+
+<pre><code>mul (n n -- n)
+
+</code></pre>
+<p>So we're composing:</p>
+
+<pre><code>(1 -- 1 1)∘(n n -- n)
+
+</code></pre>
+<p>The rules say we unify 1 with <code>n</code>:</p>
+
+<pre><code>   (1 -- 1 1)∘(n n -- n)
+---------------------------  w/  {1: n}
+   (1 -- 1  )∘(n   -- n)
+
+</code></pre>
+<p>This involves detecting that "Any type" arguments can accept "numbers".  If we were composing these functions the other way round this is still the case:</p>
+
+<pre><code>   (n n -- n)∘(1 -- 1 1)
+---------------------------  w/  {1: n}
+   (n n --  )∘(  -- n n) 
+
+</code></pre>
+<p>The important thing here is that the mapping is going the same way in both cases, from the "any" integer to the number</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="Distinguishing-Numbers">Distinguishing Numbers<a class="anchor-link" href="#Distinguishing-Numbers">&#182;</a></h3><p>We should also mind that the number that <code>mul</code> produces is not (necessarily) the same as either of its inputs, which are not (necessarily) the same as each other:</p>
+
+<pre><code>mul (n2 n1 -- n3)
+
+
+   (1  -- 1  1)∘(n2 n1 -- n3)
+--------------------------------  w/  {1: n2}
+   (n2 -- n2  )∘(n2    -- n3)
+
+
+   (n2 n1 -- n3)∘(1 -- 1  1 )
+--------------------------------  w/  {1: n3}
+   (n2 n1 --   )∘(  -- n3 n3) </code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="Distinguishing-Types">Distinguishing Types<a class="anchor-link" href="#Distinguishing-Types">&#182;</a></h3><p>So we need separate domains of "any" numbers and "number" numbers, and we need to be able to ask the order of these domains.  Now the notes on the right side of rule three make more sense, eh?</p>
+
+<pre><code>   (a -- b t[i])∘(c u[j] -- d)   t &lt;= u (t is subtype of u)
+-------------------------------
+   (a -- b     )∘(c      -- d)   t[i] == t[k] == u[j]
+                                         ^
+
+   (a -- b t[i])∘(c u[j] -- d)   u &lt;= t (u is subtype of t)
+-------------------------------
+   (a -- b     )∘(c      -- d)   t[i] == u[k] == u[j]
+
+</code></pre>
+<p>The indices <code>i</code>, <code>k</code>, and <code>j</code> are the number part of our labels and <code>t</code> and <code>u</code> are the domains.</p>
+<p>By creative use of Python's "double underscore" methods we can define a Python class hierarchy of Joy types and use the <code>issubclass()</code> method to establish domain ordering, as well as other handy behaviour that will make it fairly easy to reuse most of the code above.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[37]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">class</span> <span class="nc">AnyJoyType</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
+
+    <span class="n">prefix</span> <span class="o">=</span> <span class="s1">&#39;a&#39;</span>
+
+    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">number</span><span class="p">):</span>
+        <span class="bp">self</span><span class="o">.</span><span class="n">number</span> <span class="o">=</span> <span class="n">number</span>
+
+    <span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">prefix</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">number</span><span class="p">)</span>
+
+    <span class="k">def</span> <span class="fm">__eq__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
+        <span class="k">return</span> <span class="p">(</span>
+            <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="p">)</span>
+            <span class="ow">and</span> <span class="n">other</span><span class="o">.</span><span class="n">prefix</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">prefix</span>
+            <span class="ow">and</span> <span class="n">other</span><span class="o">.</span><span class="n">number</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">number</span>
+        <span class="p">)</span>
+
+    <span class="k">def</span> <span class="fm">__ge__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
+        <span class="k">return</span> <span class="nb">issubclass</span><span class="p">(</span><span class="n">other</span><span class="o">.</span><span class="vm">__class__</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="p">)</span>
+
+    <span class="k">def</span> <span class="fm">__add__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
+        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">number</span> <span class="o">+</span> <span class="n">other</span><span class="p">)</span>
+    <span class="fm">__radd__</span> <span class="o">=</span> <span class="fm">__add__</span>
+    
+    <span class="k">def</span> <span class="fm">__hash__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+        <span class="k">return</span> <span class="nb">hash</span><span class="p">(</span><span class="nb">repr</span><span class="p">(</span><span class="bp">self</span><span class="p">))</span>
+
+
+<span class="k">class</span> <span class="nc">NumberJoyType</span><span class="p">(</span><span class="n">AnyJoyType</span><span class="p">):</span> <span class="n">prefix</span> <span class="o">=</span> <span class="s1">&#39;n&#39;</span>
+<span class="k">class</span> <span class="nc">FloatJoyType</span><span class="p">(</span><span class="n">NumberJoyType</span><span class="p">):</span> <span class="n">prefix</span> <span class="o">=</span> <span class="s1">&#39;f&#39;</span>
+<span class="k">class</span> <span class="nc">IntJoyType</span><span class="p">(</span><span class="n">FloatJoyType</span><span class="p">):</span> <span class="n">prefix</span> <span class="o">=</span> <span class="s1">&#39;i&#39;</span>
+
+
+<span class="k">class</span> <span class="nc">StackJoyType</span><span class="p">(</span><span class="n">AnyJoyType</span><span class="p">):</span>
+    <span class="n">prefix</span> <span class="o">=</span> <span class="s1">&#39;s&#39;</span>
+
+
+<span class="n">_R</span> <span class="o">=</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span>
+<span class="n">A</span> <span class="o">=</span> <span class="nb">map</span><span class="p">(</span><span class="n">AnyJoyType</span><span class="p">,</span> <span class="n">_R</span><span class="p">)</span>
+<span class="n">N</span> <span class="o">=</span> <span class="nb">map</span><span class="p">(</span><span class="n">NumberJoyType</span><span class="p">,</span> <span class="n">_R</span><span class="p">)</span>
+<span class="n">S</span> <span class="o">=</span> <span class="nb">map</span><span class="p">(</span><span class="n">StackJoyType</span><span class="p">,</span> <span class="n">_R</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>Mess with it a little:</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[38]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">permutations</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>"Any" types can be specialized to numbers and stacks, but not vice versa:</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[39]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">for</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="ow">in</span> <span class="n">permutations</span><span class="p">((</span><span class="n">A</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">N</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">S</span><span class="p">[</span><span class="mi">0</span><span class="p">]),</span> <span class="mi">2</span><span class="p">):</span>
+    <span class="k">print</span> <span class="n">a</span><span class="p">,</span> <span class="s1">&#39;&gt;=&#39;</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="s1">&#39;-&gt;&#39;</span><span class="p">,</span> <span class="n">a</span> <span class="o">&gt;=</span> <span class="n">b</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>a0 &gt;= n0 -&gt; True
+a0 &gt;= s0 -&gt; True
+n0 &gt;= a0 -&gt; False
+n0 &gt;= s0 -&gt; False
+s0 &gt;= a0 -&gt; False
+s0 &gt;= n0 -&gt; False
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>Our crude <a href="https://en.wikipedia.org/wiki/Numerical_tower">Numerical Tower</a> of <em>numbers</em> &gt; <em>floats</em> &gt; <em>integers</em> works as well (but we're not going to use it yet):</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[40]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">for</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="ow">in</span> <span class="n">permutations</span><span class="p">((</span><span class="n">A</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">N</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">FloatJoyType</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span> <span class="n">IntJoyType</span><span class="p">(</span><span class="mi">0</span><span class="p">)),</span> <span class="mi">2</span><span class="p">):</span>
+    <span class="k">print</span> <span class="n">a</span><span class="p">,</span> <span class="s1">&#39;&gt;=&#39;</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="s1">&#39;-&gt;&#39;</span><span class="p">,</span> <span class="n">a</span> <span class="o">&gt;=</span> <span class="n">b</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>a0 &gt;= n0 -&gt; True
+a0 &gt;= f0 -&gt; True
+a0 &gt;= i0 -&gt; True
+n0 &gt;= a0 -&gt; False
+n0 &gt;= f0 -&gt; True
+n0 &gt;= i0 -&gt; True
+f0 &gt;= a0 -&gt; False
+f0 &gt;= n0 -&gt; False
+f0 &gt;= i0 -&gt; True
+i0 &gt;= a0 -&gt; False
+i0 &gt;= n0 -&gt; False
+i0 &gt;= f0 -&gt; False
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="Typing-sqr">Typing <code>sqr</code><a class="anchor-link" href="#Typing-sqr">&#182;</a></h3>
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[41]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">dup</span> <span class="o">=</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">],),</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
+
+<span class="n">mul</span> <span class="o">=</span> <span class="p">(</span><span class="n">N</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">N</span><span class="p">[</span><span class="mi">2</span><span class="p">]),</span> <span class="p">(</span><span class="n">N</span><span class="p">[</span><span class="mi">3</span><span class="p">],)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[42]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">dup</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt output_prompt">Out[42]:</div>
+
+
+
+
+<div class="output_text output_subarea output_execute_result">
+<pre>((a1,), (a1, a1))</pre>
+</div>
+
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[43]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">mul</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt output_prompt">Out[43]:</div>
+
+
+
+
+<div class="output_text output_subarea output_execute_result">
+<pre>((n1, n2), (n3,))</pre>
+</div>
+
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="Modifying-the-Inferencer">Modifying the Inferencer<a class="anchor-link" href="#Modifying-the-Inferencer">&#182;</a></h3><p>Re-labeling still works fine:</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[44]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">foo</span> <span class="o">=</span> <span class="n">relabel</span><span class="p">(</span><span class="n">dup</span><span class="p">,</span> <span class="n">mul</span><span class="p">)</span>
+
+<span class="n">foo</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt output_prompt">Out[44]:</div>
+
+
+
+
+<div class="output_text output_subarea output_execute_result">
+<pre>(((a1,), (a1, a1)), ((n1001, n1002), (n1003,)))</pre>
+</div>
+
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h4 id="delabel()-version-2"><code>delabel()</code> version 2<a class="anchor-link" href="#delabel()-version-2">&#182;</a></h4><p>The <code>delabel()</code> function needs an overhaul.  It now has to keep track of how many labels of each domain it has "seen".</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[45]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">Counter</span>
+
+
+<span class="k">def</span> <span class="nf">delabel</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">seen</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">c</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
+    <span class="k">if</span> <span class="n">seen</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
+        <span class="k">assert</span> <span class="n">c</span> <span class="ow">is</span> <span class="bp">None</span>
+        <span class="n">seen</span><span class="p">,</span> <span class="n">c</span> <span class="o">=</span> <span class="p">{},</span> <span class="n">Counter</span><span class="p">()</span>
+
+    <span class="k">try</span><span class="p">:</span>
+        <span class="k">return</span> <span class="n">seen</span><span class="p">[</span><span class="n">f</span><span class="p">]</span>
+    <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
+        <span class="k">pass</span>
+
+    <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">):</span>
+        <span class="n">seen</span><span class="p">[</span><span class="n">f</span><span class="p">]</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="vm">__class__</span><span class="p">(</span><span class="n">c</span><span class="p">[</span><span class="n">f</span><span class="o">.</span><span class="n">prefix</span><span class="p">])</span>
+        <span class="n">c</span><span class="p">[</span><span class="n">f</span><span class="o">.</span><span class="n">prefix</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
+        <span class="k">return</span> <span class="n">seen</span><span class="p">[</span><span class="n">f</span><span class="p">]</span>
+
+    <span class="k">return</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">delabel</span><span class="p">(</span><span class="n">inner</span><span class="p">,</span> <span class="n">seen</span><span class="p">,</span> <span class="n">c</span><span class="p">)</span> <span class="k">for</span> <span class="n">inner</span> <span class="ow">in</span> <span class="n">f</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[46]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">delabel</span><span class="p">(</span><span class="n">foo</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt output_prompt">Out[46]:</div>
+
+
+
+
+<div class="output_text output_subarea output_execute_result">
+<pre>(((a0,), (a0, a0)), ((n0, n1), (n2,)))</pre>
+</div>
+
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h4 id="unify()-version-3"><code>unify()</code> version 3<a class="anchor-link" href="#unify()-version-3">&#182;</a></h4>
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[47]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">unify</span><span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">s</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
+    <span class="k">if</span> <span class="n">s</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
+        <span class="n">s</span> <span class="o">=</span> <span class="p">{}</span>
+    <span class="k">else</span><span class="p">:</span>
+        <span class="n">u</span> <span class="o">=</span> <span class="n">update</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">u</span><span class="p">)</span>
+        <span class="n">v</span> <span class="o">=</span> <span class="n">update</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span>
+
+    <span class="k">if</span> <span class="n">u</span> <span class="o">==</span> <span class="n">v</span><span class="p">:</span>
+        <span class="k">return</span> <span class="n">s</span>
+
+    <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="n">AnyJoyType</span><span class="p">)</span> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">AnyJoyType</span><span class="p">):</span>
+        <span class="k">if</span> <span class="n">u</span> <span class="o">&gt;=</span> <span class="n">v</span><span class="p">:</span>
+            <span class="n">s</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="n">v</span>
+            <span class="k">return</span> <span class="n">s</span>
+        <span class="k">if</span> <span class="n">v</span> <span class="o">&gt;=</span> <span class="n">u</span><span class="p">:</span>
+            <span class="n">s</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">u</span>
+            <span class="k">return</span> <span class="n">s</span>
+        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s1">&#39;Cannot unify </span><span class="si">%r</span><span class="s1"> and </span><span class="si">%r</span><span class="s1">.&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">))</span>
+
+    <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">)</span> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">):</span>
+        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">u</span><span class="p">)</span> <span class="o">!=</span> <span class="nb">len</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">2</span><span class="p">:</span>
+            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="nb">repr</span><span class="p">((</span><span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">)))</span>
+        <span class="k">for</span> <span class="n">uu</span><span class="p">,</span> <span class="n">vv</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">):</span>
+            <span class="n">s</span> <span class="o">=</span> <span class="n">unify</span><span class="p">(</span><span class="n">uu</span><span class="p">,</span> <span class="n">vv</span><span class="p">,</span> <span class="n">s</span><span class="p">)</span>
+            <span class="k">if</span> <span class="n">s</span> <span class="o">==</span> <span class="bp">False</span><span class="p">:</span> <span class="c1"># (instead of a substitution dict.)</span>
+                <span class="k">break</span>
+        <span class="k">return</span> <span class="n">s</span>
+    <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">):</span>
+        <span class="k">if</span> <span class="ow">not</span> <span class="n">stacky</span><span class="p">(</span><span class="n">u</span><span class="p">):</span>
+            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s1">&#39;Cannot unify </span><span class="si">%r</span><span class="s1"> and </span><span class="si">%r</span><span class="s1">.&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">))</span>
+        <span class="n">s</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="n">v</span>
+        <span class="k">return</span> <span class="n">s</span>
+
+    <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">):</span>
+        <span class="k">if</span> <span class="ow">not</span> <span class="n">stacky</span><span class="p">(</span><span class="n">v</span><span class="p">):</span>
+            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s1">&#39;Cannot unify </span><span class="si">%r</span><span class="s1"> and </span><span class="si">%r</span><span class="s1">.&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">u</span><span class="p">))</span>
+        <span class="n">s</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">u</span>
+        <span class="k">return</span> <span class="n">s</span>
+
+    <span class="k">return</span> <span class="bp">False</span>
+
+
+<span class="k">def</span> <span class="nf">stacky</span><span class="p">(</span><span class="n">thing</span><span class="p">):</span>
+    <span class="k">return</span> <span class="n">thing</span><span class="o">.</span><span class="vm">__class__</span> <span class="ow">in</span> <span class="p">{</span><span class="n">AnyJoyType</span><span class="p">,</span> <span class="n">StackJoyType</span><span class="p">}</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>Rewrite the stack effect comments:</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[48]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">defs</span><span class="p">():</span>
+
+    <span class="n">roll_down</span> <span class="o">=</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">3</span><span class="p">]),</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
+
+    <span class="n">roll_up</span> <span class="o">=</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">3</span><span class="p">]),</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>
+
+    <span class="n">pop</span> <span class="o">=</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">],),</span> <span class="p">()</span>
+
+    <span class="n">popop</span> <span class="o">=</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">],),</span> <span class="p">()</span>
+
+    <span class="n">popd</span> <span class="o">=</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">],),</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">],)</span>
+
+    <span class="n">popdd</span> <span class="o">=</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">],),</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">],)</span>
+
+    <span class="n">swap</span> <span class="o">=</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">2</span><span class="p">]),</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
+
+    <span class="n">rest</span> <span class="o">=</span> <span class="p">((</span><span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">S</span><span class="p">[</span><span class="mi">1</span><span class="p">]),),</span> <span class="p">(</span><span class="n">S</span><span class="p">[</span><span class="mi">1</span><span class="p">],)</span>
+
+    <span class="n">rrest</span> <span class="o">=</span> <span class="n">C</span><span class="p">(</span><span class="n">rest</span><span class="p">,</span> <span class="n">rest</span><span class="p">)</span>
+
+    <span class="n">cons</span> <span class="o">=</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">S</span><span class="p">[</span><span class="mi">1</span><span class="p">]),</span> <span class="p">((</span><span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">S</span><span class="p">[</span><span class="mi">1</span><span class="p">]),)</span>
+
+    <span class="n">ccons</span> <span class="o">=</span> <span class="n">C</span><span class="p">(</span><span class="n">cons</span><span class="p">,</span> <span class="n">cons</span><span class="p">)</span>
+
+    <span class="n">uncons</span> <span class="o">=</span> <span class="p">((</span><span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">S</span><span class="p">[</span><span class="mi">1</span><span class="p">]),),</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">S</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
+
+    <span class="n">swons</span> <span class="o">=</span> <span class="n">C</span><span class="p">(</span><span class="n">swap</span><span class="p">,</span> <span class="n">cons</span><span class="p">)</span>
+
+    <span class="n">dup</span> <span class="o">=</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">],),</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
+
+    <span class="n">dupd</span> <span class="o">=</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]),</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
+
+    <span class="n">mul</span> <span class="o">=</span> <span class="p">(</span><span class="n">N</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">N</span><span class="p">[</span><span class="mi">2</span><span class="p">]),</span> <span class="p">(</span><span class="n">N</span><span class="p">[</span><span class="mi">3</span><span class="p">],)</span>
+    
+    <span class="n">sqrt</span> <span class="o">=</span> <span class="n">C</span><span class="p">(</span><span class="n">dup</span><span class="p">,</span> <span class="n">mul</span><span class="p">)</span>
+
+    <span class="n">first</span> <span class="o">=</span> <span class="p">((</span><span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">S</span><span class="p">[</span><span class="mi">1</span><span class="p">]),),</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">],)</span>
+
+    <span class="n">second</span> <span class="o">=</span> <span class="n">C</span><span class="p">(</span><span class="n">rest</span><span class="p">,</span> <span class="n">first</span><span class="p">)</span>
+
+    <span class="n">third</span> <span class="o">=</span> <span class="n">C</span><span class="p">(</span><span class="n">rest</span><span class="p">,</span> <span class="n">second</span><span class="p">)</span>
+
+    <span class="n">tuck</span> <span class="o">=</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]),</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
+
+    <span class="n">over</span> <span class="o">=</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]),</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>
+    
+    <span class="n">succ</span> <span class="o">=</span> <span class="n">pred</span> <span class="o">=</span> <span class="p">(</span><span class="n">N</span><span class="p">[</span><span class="mi">1</span><span class="p">],),</span> <span class="p">(</span><span class="n">N</span><span class="p">[</span><span class="mi">2</span><span class="p">],)</span>
+    
+    <span class="n">divmod_</span> <span class="o">=</span> <span class="n">pm</span> <span class="o">=</span> <span class="p">(</span><span class="n">N</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">N</span><span class="p">[</span><span class="mi">1</span><span class="p">]),</span> <span class="p">(</span><span class="n">N</span><span class="p">[</span><span class="mi">4</span><span class="p">],</span> <span class="n">N</span><span class="p">[</span><span class="mi">3</span><span class="p">])</span>
+
+    <span class="k">return</span> <span class="nb">locals</span><span class="p">()</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[49]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">DEFS</span> <span class="o">=</span> <span class="n">defs</span><span class="p">()</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[50]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">for</span> <span class="n">name</span><span class="p">,</span> <span class="n">stack_effect_comment</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">DEFS</span><span class="o">.</span><span class="n">items</span><span class="p">()):</span>
+    <span class="k">print</span> <span class="n">name</span><span class="p">,</span> <span class="s1">&#39;=&#39;</span><span class="p">,</span> <span class="n">doc_from_stack_effect</span><span class="p">(</span><span class="o">*</span><span class="n">stack_effect_comment</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>ccons = (a0 a1 [.0.] -- [a0 a1 .0.])
+cons = (a1 [.1.] -- [a1 .1.])
+divmod_ = (n2 n1 -- n4 n3)
+dup = (a1 -- a1 a1)
+dupd = (a2 a1 -- a2 a2 a1)
+first = ([a1 .1.] -- a1)
+mul = (n1 n2 -- n3)
+over = (a2 a1 -- a2 a1 a2)
+pm = (n2 n1 -- n4 n3)
+pop = (a1 --)
+popd = (a2 a1 -- a1)
+popdd = (a3 a2 a1 -- a2 a1)
+popop = (a2 a1 --)
+pred = (n1 -- n2)
+rest = ([a1 .1.] -- [.1.])
+roll_down = (a1 a2 a3 -- a2 a3 a1)
+roll_up = (a1 a2 a3 -- a3 a1 a2)
+rrest = ([a0 a1 .0.] -- [.0.])
+second = ([a0 a1 .0.] -- a1)
+sqrt = (n0 -- n1)
+succ = (n1 -- n2)
+swap = (a1 a2 -- a2 a1)
+swons = ([.0.] a0 -- [a0 .0.])
+third = ([a0 a1 a2 .0.] -- a2)
+tuck = (a2 a1 -- a1 a2 a1)
+uncons = ([a1 .1.] -- a1 [.1.])
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[51]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="nb">globals</span><span class="p">()</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">DEFS</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h4 id="Compose-dup-and-mul">Compose <code>dup</code> and <code>mul</code><a class="anchor-link" href="#Compose-dup-and-mul">&#182;</a></h4>
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[52]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">C</span><span class="p">(</span><span class="n">dup</span><span class="p">,</span> <span class="n">mul</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt output_prompt">Out[52]:</div>
+
+
+
+
+<div class="output_text output_subarea output_execute_result">
+<pre>((n0,), (n1,))</pre>
+</div>
+
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>Revisit the <code>F</code> function, works fine.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[53]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">F</span> <span class="o">=</span> <span class="nb">reduce</span><span class="p">(</span><span class="n">C</span><span class="p">,</span> <span class="p">(</span><span class="n">pop</span><span class="p">,</span> <span class="n">swap</span><span class="p">,</span> <span class="n">roll_down</span><span class="p">,</span> <span class="n">rest</span><span class="p">,</span> <span class="n">rest</span><span class="p">,</span> <span class="n">cons</span><span class="p">,</span> <span class="n">cons</span><span class="p">))</span>
+<span class="n">F</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt output_prompt">Out[53]:</div>
+
+
+
+
+<div class="output_text output_subarea output_execute_result">
+<pre>(((a0, (a1, s0)), a2, a3, a4), ((a3, (a2, s0)),))</pre>
+</div>
+
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[54]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">print</span> <span class="n">doc_from_stack_effect</span><span class="p">(</span><span class="o">*</span><span class="n">F</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>([a0 a1 .0.] a2 a3 a4 -- [a3 a2 .0.])
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>Some otherwise inefficient functions are no longer to be feared.  We can also get the effect of combinators in some limited cases.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[55]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">neato</span><span class="p">(</span><span class="o">*</span><span class="n">funcs</span><span class="p">):</span>
+    <span class="k">print</span> <span class="n">doc_from_stack_effect</span><span class="p">(</span><span class="o">*</span><span class="nb">reduce</span><span class="p">(</span><span class="n">C</span><span class="p">,</span> <span class="n">funcs</span><span class="p">))</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[56]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="c1"># e.g. [swap] dip</span>
+<span class="n">neato</span><span class="p">(</span><span class="n">roll_up</span><span class="p">,</span> <span class="n">swap</span><span class="p">,</span> <span class="n">roll_down</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>(a0 a1 a2 -- a1 a0 a2)
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[57]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="c1"># e.g. [popop] dip</span>
+<span class="n">neato</span><span class="p">(</span><span class="n">popdd</span><span class="p">,</span> <span class="n">roll_down</span><span class="p">,</span> <span class="n">pop</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>(a0 a1 a2 a3 -- a2 a3)
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[58]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="c1"># Reverse the order of the top three items.</span>
+<span class="n">neato</span><span class="p">(</span><span class="n">roll_up</span><span class="p">,</span> <span class="n">swap</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>(a0 a1 a2 -- a2 a1 a0)
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h4 id="compile_()-version-2"><code>compile_()</code> version 2<a class="anchor-link" href="#compile_()-version-2">&#182;</a></h4><p>Because the type labels represent themselves as valid Python identifiers the <code>compile_()</code> function doesn't need to generate them anymore:</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[59]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">compile_</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">f</span><span class="p">,</span> <span class="n">doc</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
+    <span class="n">inputs</span><span class="p">,</span> <span class="n">outputs</span> <span class="o">=</span> <span class="n">f</span>
+    <span class="k">if</span> <span class="n">doc</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
+        <span class="n">doc</span> <span class="o">=</span> <span class="n">doc_from_stack_effect</span><span class="p">(</span><span class="n">inputs</span><span class="p">,</span> <span class="n">outputs</span><span class="p">)</span>
+    <span class="n">i</span> <span class="o">=</span> <span class="n">o</span> <span class="o">=</span> <span class="n">Symbol</span><span class="p">(</span><span class="s1">&#39;stack&#39;</span><span class="p">)</span>
+    <span class="k">for</span> <span class="n">term</span> <span class="ow">in</span> <span class="n">inputs</span><span class="p">:</span>
+        <span class="n">i</span> <span class="o">=</span> <span class="n">term</span><span class="p">,</span> <span class="n">i</span>
+    <span class="k">for</span> <span class="n">term</span> <span class="ow">in</span> <span class="n">outputs</span><span class="p">:</span>
+        <span class="n">o</span> <span class="o">=</span> <span class="n">term</span><span class="p">,</span> <span class="n">o</span>
+    <span class="k">return</span> <span class="s1">&#39;&#39;&#39;def </span><span class="si">%s</span><span class="s1">(stack):</span>
+<span class="s1">    &quot;&quot;&quot;</span><span class="si">%s</span><span class="s1">&quot;&quot;&quot;</span>
+<span class="s1">    </span><span class="si">%s</span><span class="s1"> = stack</span>
+<span class="s1">    return </span><span class="si">%s</span><span class="s1">&#39;&#39;&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">doc</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">o</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[60]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">print</span> <span class="n">compile_</span><span class="p">(</span><span class="s1">&#39;F&#39;</span><span class="p">,</span> <span class="n">F</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>def F(stack):
+    &#34;&#34;&#34;([a0 a1 .0.] a2 a3 a4 -- [a3 a2 .0.])&#34;&#34;&#34;
+    (a4, (a3, (a2, ((a0, (a1, s0)), stack)))) = stack
+    return ((a3, (a2, s0)), stack)
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>But it cannot magically create new functions that involve e.g. math and such.  Note that this is <em>not</em> a <code>sqr</code> function implementation:</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[61]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">print</span> <span class="n">compile_</span><span class="p">(</span><span class="s1">&#39;sqr&#39;</span><span class="p">,</span> <span class="n">C</span><span class="p">(</span><span class="n">dup</span><span class="p">,</span> <span class="n">mul</span><span class="p">))</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>def sqr(stack):
+    &#34;&#34;&#34;(n0 -- n1)&#34;&#34;&#34;
+    (n0, stack) = stack
+    return (n1, stack)
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h4 id="compilable()"><code>compilable()</code><a class="anchor-link" href="#compilable()">&#182;</a></h4><p>The functions that <em>can</em> be compiled are the ones that have only <code>AnyJoyType</code> and <code>StackJoyType</code> labels in their stack effect comments.  We can write a function to check that:</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[62]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">imap</span>
+
+
+<span class="k">def</span> <span class="nf">compilable</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
+    <span class="k">return</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">)</span> <span class="ow">and</span> <span class="nb">all</span><span class="p">(</span><span class="n">imap</span><span class="p">(</span><span class="n">compilable</span><span class="p">,</span> <span class="n">f</span><span class="p">))</span> <span class="ow">or</span> <span class="n">stacky</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[63]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">for</span> <span class="n">name</span><span class="p">,</span> <span class="n">stack_effect_comment</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">defs</span><span class="p">()</span><span class="o">.</span><span class="n">items</span><span class="p">()):</span>
+    <span class="k">if</span> <span class="n">compilable</span><span class="p">(</span><span class="n">stack_effect_comment</span><span class="p">):</span>
+        <span class="k">print</span> <span class="n">name</span><span class="p">,</span> <span class="s1">&#39;=&#39;</span><span class="p">,</span> <span class="n">doc_from_stack_effect</span><span class="p">(</span><span class="o">*</span><span class="n">stack_effect_comment</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>ccons = (a0 a1 [.0.] -- [a0 a1 .0.])
+cons = (a1 [.1.] -- [a1 .1.])
+dup = (a1 -- a1 a1)
+dupd = (a2 a1 -- a2 a2 a1)
+first = ([a1 .1.] -- a1)
+over = (a2 a1 -- a2 a1 a2)
+pop = (a1 --)
+popd = (a2 a1 -- a1)
+popdd = (a3 a2 a1 -- a2 a1)
+popop = (a2 a1 --)
+rest = ([a1 .1.] -- [.1.])
+roll_down = (a1 a2 a3 -- a2 a3 a1)
+roll_up = (a1 a2 a3 -- a3 a1 a2)
+rrest = ([a0 a1 .0.] -- [.0.])
+second = ([a0 a1 .0.] -- a1)
+swap = (a1 a2 -- a2 a1)
+swons = ([.0.] a0 -- [a0 .0.])
+third = ([a0 a1 a2 .0.] -- a2)
+tuck = (a2 a1 -- a1 a2 a1)
+uncons = ([a1 .1.] -- a1 [.1.])
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h2 id="Functions-that-use-the-Stack">Functions that use the Stack<a class="anchor-link" href="#Functions-that-use-the-Stack">&#182;</a></h2><p>Consider the <code>stack</code> function which grabs the whole stack, quotes it, and puts it on itself:</p>
+
+<pre><code>stack (...     -- ... [...]        )
+stack (... a   -- ... a [a ...]    )
+stack (... b a -- ... b a [a b ...])
+
+</code></pre>
+<p>We would like to represent this in Python somehow. 
+To do this we use a simple, elegant trick.</p>
+
+<pre><code>stack         S   -- (         S,           S)
+stack     (a, S)  -- (     (a, S),      (a, S))
+stack (a, (b, S)) -- ( (a, (b, S)), (a, (b, S)))
+
+</code></pre>
+<p>Instead of representing the stack effect comments as a single tuple (with N items in it) we use the same cons-list structure to hold the sequence and <code>unify()</code> the whole comments.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="stack&#8728;uncons"><code>stack&#8728;uncons</code><a class="anchor-link" href="#stack&#8728;uncons">&#182;</a></h3><p>Let's try composing <code>stack</code> and <code>uncons</code>.  We want this result:</p>
+
+<pre><code>stack∘uncons (... a -- ... a a [...])</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>The stack effects are:</p>
+
+<pre><code>stack = S -- (S, S)
+
+uncons = ((a, Z), S) -- (Z, (a, S))</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>Unifying:</p>
+
+<pre><code>  S    -- (S, S) ∘ ((a, Z), S) -- (Z, (a,   S   ))
+                                                    w/ { S: (a, Z) }
+(a, Z) --        ∘             -- (Z, (a, (a, Z)))
+
+</code></pre>
+<p>So:</p>
+
+<pre><code>stack∘uncons == (a, Z) -- (Z, (a, (a, Z)))
+
+</code></pre>
+<p>It works.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="stack&#8728;uncons&#8728;uncons"><code>stack&#8728;uncons&#8728;uncons</code><a class="anchor-link" href="#stack&#8728;uncons&#8728;uncons">&#182;</a></h3><p>Let's try <code>stack∘uncons∘uncons</code>:</p>
+
+<pre><code>(a, S     ) -- (S,      (a, (a, S     ))) ∘ ((b, Z),  S`             ) -- (Z, (b,   S`   ))
+
+                                                                                w/ { S: (b, Z) }
+
+(a, (b, Z)) -- ((b, Z), (a, (a, (b, Z)))) ∘ ((b, Z),  S`             ) -- (Z, (b,   S`   ))
+
+                                                                                w/ { S`: (a, (a, (b, Z))) }
+
+(a, (b, Z)) -- ((b, Z), (a, (a, (b, Z)))) ∘ ((b, Z), (a, (a, (b, Z)))) -- (Z, (b, (a, (a, (b, Z)))))
+
+(a, (b, Z)) -- (Z, (b, (a, (a, (b, Z)))))
+
+</code></pre>
+<p>It works.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h4 id="compose()-version-2"><code>compose()</code> version 2<a class="anchor-link" href="#compose()-version-2">&#182;</a></h4><p>This function has to be modified to use the new datastructures and it is no longer recursive, instead recursion happens as part of unification.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[64]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">compose</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">g</span><span class="p">):</span>
+
+    <span class="p">(</span><span class="n">f_in</span><span class="p">,</span> <span class="n">f_out</span><span class="p">),</span> <span class="p">(</span><span class="n">g_in</span><span class="p">,</span> <span class="n">g_out</span><span class="p">)</span> <span class="o">=</span> <span class="n">f</span><span class="p">,</span> <span class="n">g</span>
+
+    <span class="k">if</span> <span class="ow">not</span> <span class="n">g_in</span><span class="p">:</span>
+        <span class="n">fg_in</span><span class="p">,</span> <span class="n">fg_out</span> <span class="o">=</span> <span class="n">f_in</span><span class="p">,</span> <span class="n">stack_concat</span><span class="p">(</span><span class="n">g_out</span><span class="p">,</span> <span class="n">f_out</span><span class="p">)</span>
+
+    <span class="k">elif</span> <span class="ow">not</span> <span class="n">f_out</span><span class="p">:</span>
+        <span class="n">fg_in</span><span class="p">,</span> <span class="n">fg_out</span> <span class="o">=</span> <span class="n">stack_concat</span><span class="p">(</span><span class="n">f_in</span><span class="p">,</span> <span class="n">g_in</span><span class="p">),</span> <span class="n">g_out</span>
+
+    <span class="k">else</span><span class="p">:</span> <span class="c1"># Unify and update.</span>
+
+        <span class="n">s</span> <span class="o">=</span> <span class="n">unify</span><span class="p">(</span><span class="n">g_in</span><span class="p">,</span> <span class="n">f_out</span><span class="p">)</span>
+
+        <span class="k">if</span> <span class="n">s</span> <span class="o">==</span> <span class="bp">False</span><span class="p">:</span>  <span class="c1"># s can also be the empty dict, which is ok.</span>
+            <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="s1">&#39;Cannot unify </span><span class="si">%r</span><span class="s1"> and </span><span class="si">%r</span><span class="s1">.&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">fo</span><span class="p">,</span> <span class="n">gi</span><span class="p">))</span>
+
+        <span class="n">fg_in</span><span class="p">,</span> <span class="n">fg_out</span> <span class="o">=</span> <span class="n">update</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="p">(</span><span class="n">f_in</span><span class="p">,</span> <span class="n">g_out</span><span class="p">))</span>
+
+    <span class="k">return</span> <span class="n">fg_in</span><span class="p">,</span> <span class="n">fg_out</span>
+
+
+<span class="n">stack_concat</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">q</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span> <span class="p">(</span><span class="n">q</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">stack_concat</span><span class="p">(</span><span class="n">q</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">e</span><span class="p">))</span> <span class="k">if</span> <span class="n">q</span> <span class="k">else</span> <span class="n">e</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>I don't want to rewrite all the defs myself, so I'll write a little conversion function instead.  This is programmer's laziness.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[65]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">sequence_to_stack</span><span class="p">(</span><span class="n">seq</span><span class="p">,</span> <span class="n">stack</span><span class="o">=</span><span class="n">StackJoyType</span><span class="p">(</span><span class="mi">23</span><span class="p">)):</span>
+    <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">seq</span><span class="p">:</span> <span class="n">stack</span> <span class="o">=</span> <span class="n">item</span><span class="p">,</span> <span class="n">stack</span>
+    <span class="k">return</span> <span class="n">stack</span>
+
+<span class="n">NEW_DEFS</span> <span class="o">=</span> <span class="p">{</span>
+    <span class="n">name</span><span class="p">:</span> <span class="p">(</span><span class="n">sequence_to_stack</span><span class="p">(</span><span class="n">i</span><span class="p">),</span> <span class="n">sequence_to_stack</span><span class="p">(</span><span class="n">o</span><span class="p">))</span>
+    <span class="k">for</span> <span class="n">name</span><span class="p">,</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">o</span><span class="p">)</span> <span class="ow">in</span> <span class="n">DEFS</span><span class="o">.</span><span class="n">iteritems</span><span class="p">()</span>
+<span class="p">}</span>
+
+<span class="nb">globals</span><span class="p">()</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">NEW_DEFS</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[66]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">stack</span> <span class="o">=</span> <span class="n">S</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="p">(</span><span class="n">S</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">S</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[67]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">C</span><span class="p">(</span><span class="n">stack</span><span class="p">,</span> <span class="n">uncons</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt output_prompt">Out[67]:</div>
+
+
+
+
+<div class="output_text output_subarea output_execute_result">
+<pre>((a0, s0), (s0, (a0, (a0, s0))))</pre>
+</div>
+
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[68]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">C</span><span class="p">(</span><span class="n">C</span><span class="p">(</span><span class="n">stack</span><span class="p">,</span> <span class="n">uncons</span><span class="p">),</span> <span class="n">uncons</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt output_prompt">Out[68]:</div>
+
+
+
+
+<div class="output_text output_subarea output_execute_result">
+<pre>((a0, (a1, s0)), (s0, (a1, (a0, (a0, (a1, s0))))))</pre>
+</div>
+
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>The display function should be changed too.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h3 id="doc_from_stack_effect()-version-2"><code>doc_from_stack_effect()</code> version 2<a class="anchor-link" href="#doc_from_stack_effect()-version-2">&#182;</a></h3><p>Clunky junk, but it will suffice for now.</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[69]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">doc_from_stack_effect</span><span class="p">(</span><span class="n">inputs</span><span class="p">,</span> <span class="n">outputs</span><span class="p">):</span>
+    <span class="n">switch</span> <span class="o">=</span> <span class="p">[</span><span class="bp">False</span><span class="p">]</span>  <span class="c1"># Do we need to display the &#39;...&#39; for the rest of the main stack?</span>
+    <span class="n">i</span><span class="p">,</span> <span class="n">o</span> <span class="o">=</span> <span class="n">_f</span><span class="p">(</span><span class="n">inputs</span><span class="p">,</span> <span class="n">switch</span><span class="p">),</span> <span class="n">_f</span><span class="p">(</span><span class="n">outputs</span><span class="p">,</span> <span class="n">switch</span><span class="p">)</span>
+    <span class="k">if</span> <span class="n">switch</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span>
+        <span class="n">i</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39;...&#39;</span><span class="p">)</span>
+        <span class="n">o</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39;...&#39;</span><span class="p">)</span>
+    <span class="k">return</span> <span class="s1">&#39;(</span><span class="si">%s</span><span class="s1">--</span><span class="si">%s</span><span class="s1">)&#39;</span> <span class="o">%</span> <span class="p">(</span>
+        <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">reversed</span><span class="p">([</span><span class="s1">&#39;&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="n">i</span><span class="p">)),</span>
+        <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">reversed</span><span class="p">(</span><span class="n">o</span> <span class="o">+</span> <span class="p">[</span><span class="s1">&#39;&#39;</span><span class="p">])),</span>
+    <span class="p">)</span>
+
+
+<span class="k">def</span> <span class="nf">_f</span><span class="p">(</span><span class="n">term</span><span class="p">,</span> <span class="n">switch</span><span class="p">):</span>
+    <span class="n">a</span> <span class="o">=</span> <span class="p">[]</span>
+    <span class="k">while</span> <span class="n">term</span> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">term</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">):</span>
+        <span class="n">item</span><span class="p">,</span> <span class="n">term</span> <span class="o">=</span> <span class="n">term</span>
+        <span class="n">a</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
+    <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">term</span><span class="p">,</span> <span class="n">StackJoyType</span><span class="p">),</span> <span class="nb">repr</span><span class="p">(</span><span class="n">term</span><span class="p">)</span>
+    <span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="n">_to_str</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">term</span><span class="p">,</span> <span class="n">switch</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">a</span><span class="p">]</span>
+    <span class="k">return</span> <span class="n">a</span>
+
+
+<span class="k">def</span> <span class="nf">_to_str</span><span class="p">(</span><span class="n">term</span><span class="p">,</span> <span class="n">stack</span><span class="p">,</span> <span class="n">switch</span><span class="p">):</span>
+    <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">term</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">):</span>
+        <span class="k">if</span> <span class="n">term</span> <span class="o">==</span> <span class="n">stack</span><span class="p">:</span>
+            <span class="n">switch</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="bp">True</span>
+            <span class="k">return</span> <span class="s1">&#39;[...]&#39;</span>
+        <span class="k">return</span> <span class="p">(</span>
+            <span class="s1">&#39;[.</span><span class="si">%i</span><span class="s1">.]&#39;</span> <span class="o">%</span> <span class="n">term</span><span class="o">.</span><span class="n">number</span>
+            <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">term</span><span class="p">,</span> <span class="n">StackJoyType</span><span class="p">)</span>
+            <span class="k">else</span> <span class="nb">str</span><span class="p">(</span><span class="n">term</span><span class="p">)</span>
+        <span class="p">)</span>
+
+    <span class="n">a</span> <span class="o">=</span> <span class="p">[]</span>
+    <span class="k">while</span> <span class="n">term</span> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">term</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">):</span>
+        <span class="n">item</span><span class="p">,</span> <span class="n">term</span> <span class="o">=</span> <span class="n">term</span>
+        <span class="n">a</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">_to_str</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">stack</span><span class="p">,</span> <span class="n">switch</span><span class="p">))</span>
+    <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">term</span><span class="p">,</span> <span class="n">StackJoyType</span><span class="p">),</span> <span class="nb">repr</span><span class="p">(</span><span class="n">term</span><span class="p">)</span>
+    <span class="k">if</span> <span class="n">term</span> <span class="o">==</span> <span class="n">stack</span><span class="p">:</span>
+        <span class="n">switch</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="bp">True</span>
+        <span class="n">end</span> <span class="o">=</span> <span class="s1">&#39;...&#39;</span>
+    <span class="k">else</span><span class="p">:</span>
+        <span class="n">end</span> <span class="o">=</span> <span class="s1">&#39;.</span><span class="si">%i</span><span class="s1">.&#39;</span> <span class="o">%</span> <span class="n">term</span><span class="o">.</span><span class="n">number</span>
+    <span class="n">a</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">end</span><span class="p">)</span>
+    <span class="k">return</span> <span class="s1">&#39;[</span><span class="si">%s</span><span class="s1">]&#39;</span> <span class="o">%</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[70]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">for</span> <span class="n">name</span><span class="p">,</span> <span class="n">stack_effect_comment</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">NEW_DEFS</span><span class="o">.</span><span class="n">items</span><span class="p">()):</span>
+    <span class="k">print</span> <span class="n">name</span><span class="p">,</span> <span class="s1">&#39;=&#39;</span><span class="p">,</span> <span class="n">doc_from_stack_effect</span><span class="p">(</span><span class="o">*</span><span class="n">stack_effect_comment</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>ccons = (a0 a1 [.0.] -- [a0 a1 .0.])
+cons = (a1 [.1.] -- [a1 .1.])
+divmod_ = (n2 n1 -- n4 n3)
+dup = (a1 -- a1 a1)
+dupd = (a2 a1 -- a2 a2 a1)
+first = ([a1 .1.] -- a1)
+mul = (n1 n2 -- n3)
+over = (a2 a1 -- a2 a1 a2)
+pm = (n2 n1 -- n4 n3)
+pop = (a1 --)
+popd = (a2 a1 -- a1)
+popdd = (a3 a2 a1 -- a2 a1)
+popop = (a2 a1 --)
+pred = (n1 -- n2)
+rest = ([a1 .1.] -- [.1.])
+roll_down = (a1 a2 a3 -- a2 a3 a1)
+roll_up = (a1 a2 a3 -- a3 a1 a2)
+rrest = ([a0 a1 .0.] -- [.0.])
+second = ([a0 a1 .0.] -- a1)
+sqrt = (n0 -- n1)
+succ = (n1 -- n2)
+swap = (a1 a2 -- a2 a1)
+swons = ([.0.] a0 -- [a0 .0.])
+third = ([a0 a1 a2 .0.] -- a2)
+tuck = (a2 a1 -- a1 a2 a1)
+uncons = ([a1 .1.] -- a1 [.1.])
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[71]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">print</span> <span class="p">;</span> <span class="k">print</span> <span class="n">doc_from_stack_effect</span><span class="p">(</span><span class="o">*</span><span class="n">stack</span><span class="p">)</span>
+<span class="k">print</span> <span class="p">;</span> <span class="k">print</span> <span class="n">doc_from_stack_effect</span><span class="p">(</span><span class="o">*</span><span class="n">C</span><span class="p">(</span><span class="n">stack</span><span class="p">,</span> <span class="n">uncons</span><span class="p">))</span>
+<span class="k">print</span> <span class="p">;</span> <span class="k">print</span> <span class="n">doc_from_stack_effect</span><span class="p">(</span><span class="o">*</span><span class="n">C</span><span class="p">(</span><span class="n">C</span><span class="p">(</span><span class="n">stack</span><span class="p">,</span> <span class="n">uncons</span><span class="p">),</span> <span class="n">uncons</span><span class="p">))</span>
+<span class="k">print</span> <span class="p">;</span> <span class="k">print</span> <span class="n">doc_from_stack_effect</span><span class="p">(</span><span class="o">*</span><span class="n">C</span><span class="p">(</span><span class="n">C</span><span class="p">(</span><span class="n">stack</span><span class="p">,</span> <span class="n">uncons</span><span class="p">),</span> <span class="n">cons</span><span class="p">))</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>
+(... -- ... [...])
+
+(... a0 -- ... a0 a0 [...])
+
+(... a1 a0 -- ... a1 a0 a0 a1 [...])
+
+(... a0 -- ... a0 [a0 ...])
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[72]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">print</span> <span class="n">doc_from_stack_effect</span><span class="p">(</span><span class="o">*</span><span class="n">C</span><span class="p">(</span><span class="n">ccons</span><span class="p">,</span> <span class="n">stack</span><span class="p">))</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>(... a1 a0 [.0.] -- ... [a1 a0 .0.] [[a1 a0 .0.] ...])
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[73]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">Q</span> <span class="o">=</span> <span class="n">C</span><span class="p">(</span><span class="n">ccons</span><span class="p">,</span> <span class="n">stack</span><span class="p">)</span>
+
+<span class="n">Q</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt output_prompt">Out[73]:</div>
+
+
+
+
+<div class="output_text output_subarea output_execute_result">
+<pre>((s0, (a0, (a1, s1))), (((a1, (a0, s0)), s1), ((a1, (a0, s0)), s1)))</pre>
+</div>
+
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h4 id="compile_()-version-3"><code>compile_()</code> version 3<a class="anchor-link" href="#compile_()-version-3">&#182;</a></h4><p>This makes the <code>compile_()</code> function pretty simple as the stack effect comments are now already in the form needed for the Python code:</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[74]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">def</span> <span class="nf">compile_</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">f</span><span class="p">,</span> <span class="n">doc</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
+    <span class="n">i</span><span class="p">,</span> <span class="n">o</span> <span class="o">=</span> <span class="n">f</span>
+    <span class="k">if</span> <span class="n">doc</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
+        <span class="n">doc</span> <span class="o">=</span> <span class="n">doc_from_stack_effect</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">o</span><span class="p">)</span>
+    <span class="k">return</span> <span class="s1">&#39;&#39;&#39;def </span><span class="si">%s</span><span class="s1">(stack):</span>
+<span class="s1">    &quot;&quot;&quot;</span><span class="si">%s</span><span class="s1">&quot;&quot;&quot;</span>
+<span class="s1">    </span><span class="si">%s</span><span class="s1"> = stack</span>
+<span class="s1">    return </span><span class="si">%s</span><span class="s1">&#39;&#39;&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">doc</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">o</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[75]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">print</span> <span class="n">compile_</span><span class="p">(</span><span class="s1">&#39;Q&#39;</span><span class="p">,</span> <span class="n">Q</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>def Q(stack):
+    &#34;&#34;&#34;(... a1 a0 [.0.] -- ... [a1 a0 .0.] [[a1 a0 .0.] ...])&#34;&#34;&#34;
+    (s0, (a0, (a1, s1))) = stack
+    return (((a1, (a0, s0)), s1), ((a1, (a0, s0)), s1))
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[76]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">unstack</span> <span class="o">=</span> <span class="p">(</span><span class="n">S</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">S</span><span class="p">[</span><span class="mi">0</span><span class="p">]),</span> <span class="n">S</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
+<span class="n">enstacken</span> <span class="o">=</span> <span class="n">S</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="p">(</span><span class="n">S</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">S</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[77]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">print</span> <span class="n">doc_from_stack_effect</span><span class="p">(</span><span class="o">*</span><span class="n">unstack</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>([.1.] --)
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[78]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">print</span> <span class="n">doc_from_stack_effect</span><span class="p">(</span><span class="o">*</span><span class="n">enstacken</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>(-- [.0.])
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[79]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">print</span> <span class="n">doc_from_stack_effect</span><span class="p">(</span><span class="o">*</span><span class="n">C</span><span class="p">(</span><span class="n">cons</span><span class="p">,</span> <span class="n">unstack</span><span class="p">))</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>(a0 [.0.] -- a0)
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[80]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="k">print</span> <span class="n">doc_from_stack_effect</span><span class="p">(</span><span class="o">*</span><span class="n">C</span><span class="p">(</span><span class="n">cons</span><span class="p">,</span> <span class="n">enstacken</span><span class="p">))</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt"></div>
+
+
+<div class="output_subarea output_stream output_stdout output_text">
+<pre>(a0 [.0.] -- [[a0 .0.] .1.])
+</pre>
+</div>
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[81]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">C</span><span class="p">(</span><span class="n">cons</span><span class="p">,</span> <span class="n">unstack</span><span class="p">)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+<div class="output_wrapper">
+<div class="output">
+
+
+<div class="output_area">
+
+<div class="prompt output_prompt">Out[81]:</div>
+
+
+
+
+<div class="output_text output_subarea output_execute_result">
+<pre>((s0, (a0, s1)), (a0, s0))</pre>
+</div>
+
+</div>
+
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h2 id="Sets-of-Stack-Effects">Sets of Stack Effects<a class="anchor-link" href="#Sets-of-Stack-Effects">&#182;</a></h2><p>...</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h2 id="concat"><code>concat</code><a class="anchor-link" href="#concat">&#182;</a></h2><p>How to deal with <code>concat</code>?</p>
+
+<pre><code>concat ([.0.] [.1.] -- [.0. .1.])
+
+</code></pre>
+<p>We would like to represent this in Python somehow...</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[82]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">concat</span> <span class="o">=</span> <span class="p">(</span><span class="n">S</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">S</span><span class="p">[</span><span class="mi">1</span><span class="p">]),</span> <span class="p">((</span><span class="n">S</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">S</span><span class="p">[</span><span class="mi">1</span><span class="p">]),)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>But this is actually <code>cons</code> with the first argument restricted to be a stack:</p>
+
+<pre><code>([.0.] [.1.] -- [[.0.] .1.])
+
+</code></pre>
+<p>What we have implemented so far would actually only permit:</p>
+
+<pre><code>([.0.] [.1.] -- [.2.])</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing code_cell rendered">
+<div class="input">
+<div class="prompt input_prompt">In&nbsp;[83]:</div>
+<div class="inner_cell">
+    <div class="input_area">
+<div class=" highlight hl-ipython2"><pre><span></span><span class="n">concat</span> <span class="o">=</span> <span class="p">(</span><span class="n">S</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">S</span><span class="p">[</span><span class="mi">1</span><span class="p">]),</span> <span class="p">(</span><span class="n">S</span><span class="p">[</span><span class="mi">2</span><span class="p">],)</span>
+</pre></div>
+
+</div>
+</div>
+</div>
+
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>Which works but can lose information.  Consider <code>cons concat</code>, this is how much information we <em>could</em> retain:</p>
+
+<pre><code>(1 [.0.] [.1.] -- [1 .0. .1.])
+
+</code></pre>
+<p>As opposed to just:</p>
+
+<pre><code>(1 [.0.] [.1.] -- [.2.])</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<p>Which works but can lose information.  Consider <code>cons concat</code>, this is how much information we <em>could</em> retain:</p>
+
+<pre><code>(1 [.0.] [.1.] -- [1 .0. .1.]) uncons uncons
+
+(1 [.0.] [.1.] -- 1 [.0. .1.])        uncons
+                                                So far so good...
+(1 [2 .2.] [.1.] -- 1 2 [.2. .1.])
+
+
+
+
+(1 [.0.] [.1.] -- 1 [.0. .1.]) ([a1 .10.] -- a1 [.10.])
+                                                         w/ { [a1 .10.] : [  .0.   .1.] }
+                                                       -or-
+                                                         w/ { [  .0.   .1.] : [a1 .10.    ] }</code></pre>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h2 id="Typing-Combinators">Typing Combinators<a class="anchor-link" href="#Typing-Combinators">&#182;</a></h2><p>TBD</p>
+<p>This is an open subject.</p>
+<p>The obvious thing is that you now need two pairs of tuples to describe the combinators' effects,  a stack effect comment and an expression effect comment:</p>
+
+<pre><code>dip (a [F] --)--(-- F a)
+
+</code></pre>
+<p>One thing that might help is...</p>
+
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h2 id="Abstract-Interpretation">Abstract Interpretation<a class="anchor-link" href="#Abstract-Interpretation">&#182;</a></h2>
+</div>
+</div>
+</div>
+<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
+</div>
+<div class="inner_cell">
+<div class="text_cell_render border-box-sizing rendered_html">
+<h2 id="Something-else...">Something else...<a class="anchor-link" href="#Something-else...">&#182;</a></h2>
+<pre><code>[4 5 ...] 2 1 0 pop∘swap∘roll&lt;∘rest∘rest∘cons∘cons
+[4 5 ...] 2 1       swap∘roll&lt;∘rest∘rest∘cons∘cons
+[4 5 ...] 1 2            roll&lt;∘rest∘rest∘cons∘cons
+1 2 [4 5 ...]                  rest∘rest∘cons∘cons
+1 2   [5 ...]                       rest∘cons∘cons
+1 2     [...]                            cons∘cons
+1     [2 ...]                                 cons
+    [1 2 ...]
+
+</code></pre>
+<p>Eh?</p>
+
+</div>
+</div>
+</div>
+    </div>
+  </div>
+</body>
+
+
+
+</html>
diff --git a/docs/Types.ipynb b/docs/Types.ipynb
new file mode 100644 (file)
index 0000000..ed16c7f
--- /dev/null
@@ -0,0 +1,3949 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Type Inference"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Pöial's Rules\n",
+    "\n",
+    "[\"Typing Tools for Typeless Stack Languages\" by Jaanus Pöial\n",
+    "](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.212.6026)\n",
+    "\n",
+    "    @INPROCEEDINGS{Pöial06typingtools,\n",
+    "        author = {Jaanus Pöial},\n",
+    "        title = {Typing tools for typeless stack languages},\n",
+    "        booktitle = {In 23rd Euro-Forth Conference},\n",
+    "        year = {2006},\n",
+    "        pages = {40--46}\n",
+    "    }"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### First Rule\n",
+    "This rule deals with functions (and literals) that put items on the stack `(-- d)`:\n",
+    "\n",
+    "\n",
+    "       (a -- b)∘(-- d)\n",
+    "    ---------------------\n",
+    "         (a -- b d)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Second Rule\n",
+    "This rule deals with functions that consume items from the stack `(a --)`:\n",
+    "\n",
+    "       (a --)∘(c -- d)\n",
+    "    ---------------------\n",
+    "         (c a -- d)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Third Rule\n",
+    "The third rule is actually two rules.  These two rules deal with composing functions when the second one will consume one of items the first one produces.  The two types must be *unified* or a type conflict declared.\n",
+    "\n",
+    "       (a -- b t[i])∘(c u[j] -- d)   t <= u (t is subtype of u)\n",
+    "    -------------------------------\n",
+    "       (a -- b     )∘(c      -- d)   t[i] == t[k] == u[j]\n",
+    "                                             ^\n",
+    "\n",
+    "       (a -- b t[i])∘(c u[j] -- d)   u <= t (u is subtype of t)\n",
+    "    -------------------------------\n",
+    "       (a -- b     )∘(c      -- d)   t[i] == u[k] == u[j]"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Examples\n",
+    "Let's work through some examples by hand to develop an intuition for the algorithm."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "There's a function in one of the other notebooks.\n",
+    "\n",
+    "    F == pop swap roll< rest rest cons cons\n",
+    "\n",
+    "It's all \"stack chatter\" and list manipulation so we should be able to deduce its type."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Stack Effect Comments\n",
+    "Joy function types will be represented by Forth-style stack effect comments.  I'm going to use numbers instead of names to keep track of the stack arguments.  (A little bit like [De Bruijn index](https://en.wikipedia.org/wiki/De_Bruijn_index), at least it reminds me of them):\n",
+    "\n",
+    "    pop (1 --)\n",
+    "\n",
+    "    swap (1 2 -- 2 1)\n",
+    "\n",
+    "    roll< (1 2 3 -- 2 3 1)\n",
+    "\n",
+    "These commands alter the stack but don't \"look at\" the values so these numbers represent an \"Any type\"."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `pop swap`\n",
+    "\n",
+    "    (1 --) (1 2 -- 2 1)\n",
+    "    \n",
+    "Here we encounter a complication. The argument numbers need to be made unique among both sides.   For this let's change `pop` to use 0:\n",
+    "\n",
+    "    (0 --) (1 2 -- 2 1)\n",
+    "\n",
+    "Following the second rule:\n",
+    "    \n",
+    "    (1 2 0 -- 2 1)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `pop∘swap roll<`\n",
+    "\n",
+    "    (1 2 0 -- 2 1) (1 2 3 -- 2 3 1)\n",
+    "\n",
+    "Let's re-label them:\n",
+    "\n",
+    "    (1a 2a 0a -- 2a 1a) (1b 2b 3b -- 2b 3b 1b)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now we follow the rules.\n",
+    "\n",
+    "We must unify `1a` and `3b`, and `2a` and `2b`, replacing the terms in the forms:\n",
+    "\n",
+    "    (1a 2a 0a -- 2a 1a) (1b 2b 3b -- 2b 3b 1b)\n",
+    "                                                w/  {1a: 3b}\n",
+    "    (3b 2a 0a -- 2a   ) (1b 2b    -- 2b 3b 1b)\n",
+    "                                                w/  {2a: 2b}\n",
+    "    (3b 2b 0a --      ) (1b       -- 2b 3b 1b)\n",
+    "\n",
+    "Here we must apply the second rule:\n",
+    "\n",
+    "       (3b 2b 0a --) (1b -- 2b 3b 1b)\n",
+    "    -----------------------------------\n",
+    "         (1b 3b 2b 0a -- 2b 3b 1b)\n",
+    "\n",
+    "Now we de-label the type, uh, labels:\n",
+    "\n",
+    "    (1b 3b 2b 0a -- 2b 3b 1b)\n",
+    "\n",
+    "    w/ {\n",
+    "        1b: 1,\n",
+    "        3b: 2,\n",
+    "        2b: 3,\n",
+    "        0a: 0,\n",
+    "        }\n",
+    "\n",
+    "    (1 2 3 0 -- 3 2 1)\n",
+    "\n",
+    "And now we have the stack effect comment for `pop∘swap∘roll<`."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Compiling `pop∘swap∘roll<`\n",
+    "The simplest way to \"compile\" this function would be something like:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def poswrd(s, e, d):\n",
+    "    return roll_down(*swap(*pop(s, e, d)))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "However, internally this function would still be allocating tuples (stack cells) and doing other unnecesssary work.\n",
+    "\n",
+    "Looking ahead for a moment, from the stack effect comment:\n",
+    "\n",
+    "    (1 2 3 0 -- 3 2 1)\n",
+    "\n",
+    "We should be able to directly write out a Python function like:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def poswrd(stack):\n",
+    "    (_, (a, (b, (c, stack)))) = stack\n",
+    "    return (c, (b, (a, stack)))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "This eliminates the internal work of the first version.  Because this function only rearranges the stack and doesn't do any actual processing on the stack items themselves all the information needed to implement it is in the stack effect comment."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Functions on Lists\n",
+    "These are slightly tricky.\n",
+    "\n",
+    "    rest ( [1 ...] -- [...] )\n",
+    "\n",
+    "    cons ( 1 [...] -- [1 ...] )"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `pop∘swap∘roll< rest`\n",
+    "\n",
+    "    (1 2 3 0 -- 3 2 1) ([1 ...] -- [...])\n",
+    "\n",
+    "Re-label (instead of adding left and right tags I'm just taking the next available index number for the right-side stack effect comment):\n",
+    "\n",
+    "    (1 2 3 0 -- 3 2 1) ([4 ...] -- [...])\n",
+    "\n",
+    "Unify and update:\n",
+    "\n",
+    "    (1       2 3 0 -- 3 2 1) ([4 ...] -- [...])\n",
+    "                                                 w/ {1: [4 ...]}\n",
+    "    ([4 ...] 2 3 0 -- 3 2  ) (        -- [...])\n",
+    "\n",
+    "Apply the first rule:\n",
+    "\n",
+    "       ([4 ...] 2 3 0 -- 3 2) (-- [...])\n",
+    "    ---------------------------------------\n",
+    "         ([4 ...] 2 3 0 -- 3 2 [...])\n",
+    "\n",
+    "And there we are."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `pop∘swap∘roll<∘rest rest`\n",
+    "\n",
+    "Let's do it again.\n",
+    "\n",
+    "    ([4 ...] 2 3 0 -- 3 2 [...]) ([1 ...] -- [...])\n",
+    "\n",
+    "Re-label (the tails of the lists on each side each get their own label):\n",
+    "\n",
+    "    ([4 .0.] 2 3 0 -- 3 2 [.0.]) ([5 .1.] -- [.1.])\n",
+    "\n",
+    "Unify and update (note the opening square brackets have been omited in the substitution dict, this is deliberate and I'll explain below):\n",
+    "\n",
+    "    ([4 .0.]   2 3 0 -- 3 2 [.0.]  ) ([5 .1.] -- [.1.])\n",
+    "                                                        w/ { .0.] : 5 .1.] }\n",
+    "    ([4 5 .1.] 2 3 0 -- 3 2 [5 .1.]) ([5 .1.] -- [.1.])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "How do we find `.0.]` in `[4 .0.]` and replace it with `5 .1.]` getting the result `[4 5 .1.]`?  This might seem hard, but because the underlying structure of the Joy list is a cons-list in Python it's actually pretty easy.  I'll explain below."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Next we unify and find our two terms are the same already: `[5 .1.]`:\n",
+    "\n",
+    "    ([4 5 .1.] 2 3 0 -- 3 2 [5 .1.]) ([5 .1.] -- [.1.])\n",
+    "\n",
+    "Giving us:\n",
+    "\n",
+    "    ([4 5 .1.] 2 3 0 -- 3 2) (-- [.1.])\n",
+    "\n",
+    "From here we apply the first rule and get:\n",
+    "\n",
+    "    ([4 5 .1.] 2 3 0 -- 3 2 [.1.])\n",
+    "\n",
+    "Cleaning up the labels:\n",
+    "\n",
+    "    ([4 5 ...] 2 3 1 -- 3 2 [...])\n",
+    "\n",
+    "This is the stack effect of `pop∘swap∘roll<∘rest∘rest`."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `pop∘swap∘roll<∘rest∘rest cons`\n",
+    "\n",
+    "    ([4 5 ...] 2 3 1 -- 3 2 [...]) (1 [...] -- [1 ...])\n",
+    "\n",
+    "Re-label:\n",
+    "\n",
+    "    ([4 5 .1.] 2 3 1 -- 3 2 [.1.]) (6 [.2.] -- [6 .2.])\n",
+    "\n",
+    "Unify:\n",
+    "\n",
+    "    ([4 5 .1.] 2 3 1 -- 3 2 [.1.]) (6 [.2.] -- [6 .2.])\n",
+    "                                                         w/ { .1.] : .2.] }\n",
+    "    ([4 5 .2.] 2 3 1 -- 3 2      ) (6       -- [6 .2.])\n",
+    "                                                         w/ {2: 6}\n",
+    "    ([4 5 .2.] 6 3 1 -- 3        ) (        -- [6 .2.])\n",
+    "\n",
+    "First rule:\n",
+    "\n",
+    "    ([4 5 .2.] 6 3 1 -- 3 [6 .2.])\n",
+    "\n",
+    "Re-label:\n",
+    "\n",
+    "    ([4 5 ...] 2 3 1 -- 3 [2 ...])\n",
+    "\n",
+    "Done."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `pop∘swap∘roll<∘rest∘rest∘cons cons`\n",
+    "One more time.\n",
+    "\n",
+    "    ([4 5 ...] 2 3 1 -- 3 [2 ...]) (1 [...] -- [1 ...])\n",
+    "\n",
+    "Re-label:\n",
+    "\n",
+    "    ([4 5 .1.] 2 3 1 -- 3 [2 .1.]) (6 [.2.] -- [6 .2.])\n",
+    "\n",
+    "Unify:\n",
+    "\n",
+    "    ([4 5 .1.] 2 3 1 -- 3 [2 .1.]) (6 [.2.] -- [6 .2.]  )\n",
+    "                                                           w/ { .2.] : 2 .1.] }\n",
+    "    ([4 5 .1.] 2 3 1 -- 3        ) (6       -- [6 2 .1.])\n",
+    "                                                           w/ {3: 6}\n",
+    "    ([4 5 .1.] 2 6 1 --          ) (        -- [6 2 .1.])\n",
+    "\n",
+    "First or second rule:\n",
+    "\n",
+    "    ([4 5 .1.] 2 6 1 -- [6 2 .1.])\n",
+    "\n",
+    "Clean up the labels:\n",
+    "\n",
+    "    ([4 5 ...] 2 3 1 -- [3 2 ...])\n",
+    "\n",
+    "And there you have it, the stack effect for `pop∘swap∘roll<∘rest∘rest∘cons∘cons`.\n",
+    "\n",
+    "    ([4 5 ...] 2 3 1 -- [3 2 ...])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "From this stack effect comment it should be possible to construct the following Python code:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def F(stack):\n",
+    "    (_, (d, (c, ((a, (b, S0)), stack)))) = stack\n",
+    "    return (d, (c, S0)), stack"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Implementation"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Representing Stack Effect Comments in Python\n",
+    "\n",
+    "I'm going to use pairs of tuples of type descriptors, which will be integers or tuples of type descriptors:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "roll_dn = (1, 2, 3), (2, 3, 1)\n",
+    "\n",
+    "pop = (1,), ()\n",
+    "\n",
+    "swap = (1, 2), (2, 1)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `compose()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def compose(f, g):\n",
+    "\n",
+    "    (f_in, f_out), (g_in, g_out) = f, g\n",
+    "\n",
+    "    # First rule.\n",
+    "    #\n",
+    "    #       (a -- b) (-- d)\n",
+    "    #    ---------------------\n",
+    "    #         (a -- b d)\n",
+    "\n",
+    "    if not g_in:\n",
+    "\n",
+    "        fg_in, fg_out = f_in, f_out + g_out\n",
+    "\n",
+    "    # Second rule.\n",
+    "    #\n",
+    "    #       (a --) (c -- d)\n",
+    "    #    ---------------------\n",
+    "    #         (c a -- d)\n",
+    "\n",
+    "    elif not f_out:\n",
+    "\n",
+    "        fg_in, fg_out = g_in + f_in, g_out\n",
+    "\n",
+    "    else: # Unify, update, recur.\n",
+    "\n",
+    "        fo, gi = f_out[-1], g_in[-1]\n",
+    "\n",
+    "        s = unify(gi, fo)\n",
+    "\n",
+    "        if s == False:  # s can also be the empty dict, which is ok.\n",
+    "            raise TypeError('Cannot unify %r and %r.' % (fo, gi))\n",
+    "\n",
+    "        f_g = (f_in, f_out[:-1]), (g_in[:-1], g_out)\n",
+    "\n",
+    "        if s: f_g = update(s, f_g)\n",
+    "\n",
+    "        fg_in, fg_out = compose(*f_g)\n",
+    "\n",
+    "    return fg_in, fg_out"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `unify()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def unify(u, v, s=None):\n",
+    "    if s is None:\n",
+    "        s = {}\n",
+    "\n",
+    "    if u == v:\n",
+    "        return s\n",
+    "\n",
+    "    if isinstance(u, int):\n",
+    "        s[u] = v\n",
+    "        return s\n",
+    "\n",
+    "    if isinstance(v, int):\n",
+    "        s[v] = u\n",
+    "        return s\n",
+    "\n",
+    "    return False"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `update()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def update(s, term):\n",
+    "    if not isinstance(term, tuple):\n",
+    "        return s.get(term, term)\n",
+    "    return tuple(update(s, inner) for inner in term)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `relabel()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(((1,), ()), ((1001, 1002), (1002, 1001)))"
+      ]
+     },
+     "execution_count": 8,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "def relabel(left, right):\n",
+    "    return left, _1000(right)\n",
+    "\n",
+    "def _1000(right):\n",
+    "    if not isinstance(right, tuple):\n",
+    "        return 1000 + right\n",
+    "    return tuple(_1000(n) for n in right)\n",
+    "\n",
+    "relabel(pop, swap)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `delabel()`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(((0,), ()), ((1, 2), (2, 1)))"
+      ]
+     },
+     "execution_count": 9,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "def delabel(f):\n",
+    "    s = {u: i for i, u in enumerate(sorted(_unique(f)))}\n",
+    "    return update(s, f)\n",
+    "\n",
+    "def _unique(f, seen=None):\n",
+    "    if seen is None:\n",
+    "        seen = set()\n",
+    "    if not isinstance(f, tuple):\n",
+    "        seen.add(f)\n",
+    "    else:\n",
+    "        for inner in f:\n",
+    "            _unique(inner, seen)\n",
+    "    return seen\n",
+    "\n",
+    "delabel(relabel(pop, swap))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `C()`\n",
+    "\n",
+    "At last we put it all together in a function `C()` that accepts two stack effect comments and returns their composition (or raises and exception if they can't be composed due to type conflicts.)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def C(f, g):\n",
+    "    f, g = relabel(f, g)\n",
+    "    fg = compose(f, g)\n",
+    "    return delabel(fg)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Let's try it out."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "((1, 2, 0), (2, 1))"
+      ]
+     },
+     "execution_count": 11,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "C(pop, swap)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "((3, 1, 2, 0), (2, 1, 3))"
+      ]
+     },
+     "execution_count": 12,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "C(C(pop, swap), roll_dn)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "((2, 0, 1), (1, 0, 2))"
+      ]
+     },
+     "execution_count": 13,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "C(swap, roll_dn)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "((3, 1, 2, 0), (2, 1, 3))"
+      ]
+     },
+     "execution_count": 14,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "C(pop, C(swap, roll_dn))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "((3, 1, 2, 0), (2, 1, 3))"
+      ]
+     },
+     "execution_count": 15,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "poswrd = reduce(C, (pop, swap, roll_dn))\n",
+    "poswrd"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### List Functions\n",
+    "Here's that trick to represent functions like `rest` and `cons` that manipulate lists.  We use a cons-list of tuples and give the tails their own numbers.  Then everything above already works. "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "rest = ((1, 2),), (2,)\n",
+    "\n",
+    "cons = (1, 2), ((1, 2),)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(((3, 4), 1, 2, 0), (2, 1, 4))"
+      ]
+     },
+     "execution_count": 17,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "C(poswrd, rest)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Compare this to the stack effect comment we wrote above:\n",
+    "\n",
+    "    ((  (3, 4), 1, 2, 0 ), ( 2, 1,   4  ))\n",
+    "    (   [4 ...] 2  3  0  --  3  2  [...])\n",
+    "\n",
+    "The translation table, if you will, would be:\n",
+    "\n",
+    "    {\n",
+    "    3: 4,\n",
+    "    4: ...],\n",
+    "    1: 2,\n",
+    "    2: 3,\n",
+    "    0: 0,\n",
+    "    }"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(((3, (4, 5)), 1, 2, 0), ((2, (1, 5)),))"
+      ]
+     },
+     "execution_count": 18,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "F = reduce(C, (pop, swap, roll_dn, rest, rest, cons, cons))\n",
+    "\n",
+    "F"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Compare with the stack effect comment and you can see it works fine:\n",
+    "\n",
+    "    ([4 5 ...] 2 3 1 -- [3 2 ...])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Dealing with `cons` and `uncons`\n",
+    "However, if we try to compose e.g. `cons` and `uncons` it won't work:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 19,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "uncons = ((1, 2),), (1, 2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 20,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Cannot unify (1, 2) and (1001, 1002).\n"
+     ]
+    }
+   ],
+   "source": [
+    "try:\n",
+    "    C(cons, uncons)\n",
+    "except Exception, e:\n",
+    "    print e"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### `unify()` version 2\n",
+    "The problem is that the `unify()` function as written doesn't handle the case when both terms are tuples.  We just have to add a clause to deal with this recursively:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 21,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def unify(u, v, s=None):\n",
+    "    if s is None:\n",
+    "        s = {}\n",
+    "    else:\n",
+    "        u = update(s, u)\n",
+    "        v = update(s, v)\n",
+    "\n",
+    "    if u == v:\n",
+    "        return s\n",
+    "\n",
+    "    if isinstance(u, int):\n",
+    "        s[u] = v\n",
+    "        return s\n",
+    "\n",
+    "    if isinstance(v, int):\n",
+    "        s[v] = u\n",
+    "        return s\n",
+    "\n",
+    "    if isinstance(u, tuple) and isinstance(v, tuple):\n",
+    "        if len(u) != len(v) != 2:\n",
+    "            raise ValueError(repr((u, v)))\n",
+    "        for uu, vv in zip(u, v):\n",
+    "            s = unify(uu, vv, s)\n",
+    "            if s == False: # (instead of a substitution dict.)\n",
+    "                break\n",
+    "        return s\n",
+    " \n",
+    "    return False"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 22,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "((0, 1), (0, 1))"
+      ]
+     },
+     "execution_count": 22,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "C(cons, uncons)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Compiling\n",
+    "Now consider the Python function we would like to derive:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 23,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def F_python(stack):\n",
+    "    (_, (d, (c, ((a, (b, S0)), stack)))) = stack\n",
+    "    return (d, (c, S0)), stack"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "And compare it to the input stack effect comment tuple we just computed:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 24,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "((3, (4, 5)), 1, 2, 0)"
+      ]
+     },
+     "execution_count": 24,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "F[0]"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The stack-de-structuring tuple has nearly the same form as our input stack effect comment tuple, just in the reverse order:\n",
+    "\n",
+    "    (_, (d, (c, ((a, (b, S0)), stack))))\n",
+    "\n",
+    "Remove the punctuation:\n",
+    "\n",
+    "     _   d   c   (a, (b, S0))\n",
+    "\n",
+    "Reverse the order and compare:\n",
+    "\n",
+    "     (a, (b, S0))   c   d   _\n",
+    "    ((3, (4, 5 )),  1,  2,  0)\n",
+    "\n",
+    "Eh?"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "And the return tuple "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 25,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "((2, (1, 5)),)"
+      ]
+     },
+     "execution_count": 25,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "F[1]"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "is similar to the output stack effect comment tuple:\n",
+    "\n",
+    "    ((d, (c, S0)), stack)\n",
+    "    ((2, (1, 5 )),      )\n",
+    "\n",
+    "This should make it pretty easy to write a Python function that accepts the stack effect comment tuples and returns a new Python function (either as a string of code or a function object ready to use) that performs the semantics of that Joy function (described by the stack effect.)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Python Identifiers\n",
+    "We want to substitute Python identifiers for the integers.  I'm going to repurpose `joy.parser.Symbol` class for this:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 26,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from collections import defaultdict\n",
+    "from joy.parser import Symbol\n",
+    "\n",
+    "\n",
+    "def _names_for():\n",
+    "    I = iter(xrange(1000))\n",
+    "    return lambda: Symbol('a%i' % next(I))\n",
+    "\n",
+    "\n",
+    "def identifiers(term, s=None):\n",
+    "    if s is None:\n",
+    "        s = defaultdict(_names_for())\n",
+    "    if isinstance(term, int):\n",
+    "        return s[term]\n",
+    "    return tuple(identifiers(inner, s) for inner in term)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `doc_from_stack_effect()`\n",
+    "As a convenience I've implemented a function to convert the Python stack effect comment tuples to reasonable text format.  There are some details in how this code works that related to stuff later in the notebook, so you should skip it for now and read it later if you're interested."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 27,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def doc_from_stack_effect(inputs, outputs):\n",
+    "    return '(%s--%s)' % (\n",
+    "        ' '.join(map(_to_str, inputs + ('',))),\n",
+    "        ' '.join(map(_to_str, ('',) + outputs))\n",
+    "    )\n",
+    "\n",
+    "\n",
+    "def _to_str(term):\n",
+    "    if not isinstance(term, tuple):\n",
+    "        try:\n",
+    "            t = term.prefix == 's'\n",
+    "        except AttributeError:\n",
+    "            return str(term)\n",
+    "        return '[.%i.]' % term.number if t else str(term)\n",
+    "\n",
+    "    a = []\n",
+    "    while term and isinstance(term, tuple):\n",
+    "        item, term = term\n",
+    "        a.append(_to_str(item))\n",
+    "\n",
+    "    try:\n",
+    "        n = term.number\n",
+    "    except AttributeError:\n",
+    "        n = term\n",
+    "    else:\n",
+    "        if term.prefix != 's':\n",
+    "            raise ValueError('Stack label: %s' % (term,))\n",
+    "\n",
+    "    a.append('.%s.' % (n,))\n",
+    "    return '[%s]' % ' '.join(a)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `compile_()`\n",
+    "Now we can write a compiler function to emit Python source code.  (The underscore suffix distiguishes it from the built-in `compile()` function.)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 28,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def compile_(name, f, doc=None):\n",
+    "    if doc is None:\n",
+    "        doc = doc_from_stack_effect(*f)\n",
+    "    inputs, outputs = identifiers(f)\n",
+    "    i = o = Symbol('stack')\n",
+    "    for term in inputs:\n",
+    "        i = term, i\n",
+    "    for term in outputs:\n",
+    "        o = term, o\n",
+    "    return '''def %s(stack):\n",
+    "    \"\"\"%s\"\"\"\n",
+    "    %s = stack\n",
+    "    return %s''' % (name, doc, i, o)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Here it is in action:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 29,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "def F(stack):\n",
+      "    \"\"\"([3 4 .5.] 1 2 0 -- [2 1 .5.])\"\"\"\n",
+      "    (a5, (a4, (a3, ((a0, (a1, a2)), stack)))) = stack\n",
+      "    return ((a4, (a3, a2)), stack)\n"
+     ]
+    }
+   ],
+   "source": [
+    "source = compile_('F', F)\n",
+    "\n",
+    "print source"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Compare:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 30,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def F_python(stack):\n",
+    "    (_, (d, (c, ((a, (b, S0)), stack)))) = stack\n",
+    "    return ((d, (c, S0)), stack)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Next steps:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 31,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<function F>"
+      ]
+     },
+     "execution_count": 31,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "L = {}\n",
+    "\n",
+    "eval(compile(source, '__main__', 'single'), {}, L)\n",
+    "\n",
+    "L['F']"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Let's try it out:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 32,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from notebook_preamble import D, J, V\n",
+    "from joy.library import SimpleFunctionWrapper"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 33,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "D['F'] = SimpleFunctionWrapper(L['F'])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 34,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[3 2 ...]\n"
+     ]
+    }
+   ],
+   "source": [
+    "J('[4 5 ...] 2 3 1 F')"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "With this, we have a partial Joy compiler that works on the subset of Joy functions that manipulate stacks (both what I call \"stack chatter\" and the ones that manipulate stacks on the stack.)\n",
+    "\n",
+    "I'm probably going to modify the definition wrapper code to detect definitions that can be compiled by this partial compiler and do it automatically.  It might be a reasonable idea to detect sequences of compilable functions in definitions that have uncompilable functions in them and just compile those.  However, if your library is well-factored this might be less helpful."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Compiling Library Functions\n",
+    "We can use `compile_()` to generate many primitives in the library from their stack effect comments:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 35,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def defs():\n",
+    "\n",
+    "    roll_down = (1, 2, 3), (2, 3, 1)\n",
+    "\n",
+    "    roll_up = (1, 2, 3), (3, 1, 2)\n",
+    "\n",
+    "    pop = (1,), ()\n",
+    "\n",
+    "    swap = (1, 2), (2, 1)\n",
+    "\n",
+    "    rest = ((1, 2),), (2,)\n",
+    "    \n",
+    "    rrest = C(rest, rest)\n",
+    "\n",
+    "    cons = (1, 2), ((1, 2),)\n",
+    "\n",
+    "    uncons = ((1, 2),), (1, 2)\n",
+    "    \n",
+    "    swons = C(swap, cons)\n",
+    "\n",
+    "    return locals()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 36,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "\n",
+      "def cons(stack):\n",
+      "    \"\"\"(1 2 -- [1 .2.])\"\"\"\n",
+      "    (a1, (a0, stack)) = stack\n",
+      "    return ((a0, a1), stack)\n",
+      "\n",
+      "\n",
+      "def pop(stack):\n",
+      "    \"\"\"(1 --)\"\"\"\n",
+      "    (a0, stack) = stack\n",
+      "    return stack\n",
+      "\n",
+      "\n",
+      "def rest(stack):\n",
+      "    \"\"\"([1 .2.] -- 2)\"\"\"\n",
+      "    ((a0, a1), stack) = stack\n",
+      "    return (a1, stack)\n",
+      "\n",
+      "\n",
+      "def roll_down(stack):\n",
+      "    \"\"\"(1 2 3 -- 2 3 1)\"\"\"\n",
+      "    (a2, (a1, (a0, stack))) = stack\n",
+      "    return (a0, (a2, (a1, stack)))\n",
+      "\n",
+      "\n",
+      "def roll_up(stack):\n",
+      "    \"\"\"(1 2 3 -- 3 1 2)\"\"\"\n",
+      "    (a2, (a1, (a0, stack))) = stack\n",
+      "    return (a1, (a0, (a2, stack)))\n",
+      "\n",
+      "\n",
+      "def rrest(stack):\n",
+      "    \"\"\"([0 1 .2.] -- 2)\"\"\"\n",
+      "    ((a0, (a1, a2)), stack) = stack\n",
+      "    return (a2, stack)\n",
+      "\n",
+      "\n",
+      "def swap(stack):\n",
+      "    \"\"\"(1 2 -- 2 1)\"\"\"\n",
+      "    (a1, (a0, stack)) = stack\n",
+      "    return (a0, (a1, stack))\n",
+      "\n",
+      "\n",
+      "def swons(stack):\n",
+      "    \"\"\"(0 1 -- [1 .0.])\"\"\"\n",
+      "    (a1, (a0, stack)) = stack\n",
+      "    return ((a1, a0), stack)\n",
+      "\n",
+      "\n",
+      "def uncons(stack):\n",
+      "    \"\"\"([1 .2.] -- 1 2)\"\"\"\n",
+      "    ((a0, a1), stack) = stack\n",
+      "    return (a1, (a0, stack))\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "for name, stack_effect_comment in sorted(defs().items()):\n",
+    "    print\n",
+    "    print compile_(name, stack_effect_comment)\n",
+    "    print"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Types and Subtypes of Arguments\n",
+    "So far we have dealt with types of functions, those dealing with simple stack manipulation.  Let's extend our machinery to deal with types of arguments."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### \"Number\" Type\n",
+    "\n",
+    "Consider the definition of `sqr`:\n",
+    "\n",
+    "    sqr == dup mul\n",
+    "\n",
+    "\n",
+    "The `dup` function accepts one *anything* and returns two of that:\n",
+    "\n",
+    "    dup (1 -- 1 1)\n",
+    "\n",
+    "And `mul` accepts two \"numbers\" (we're ignoring ints vs. floats vs. complex, etc., for now) and returns just one:\n",
+    "\n",
+    "    mul (n n -- n)\n",
+    "\n",
+    "So we're composing:\n",
+    "\n",
+    "    (1 -- 1 1)∘(n n -- n)\n",
+    "\n",
+    "The rules say we unify 1 with `n`:\n",
+    "\n",
+    "       (1 -- 1 1)∘(n n -- n)\n",
+    "    ---------------------------  w/  {1: n}\n",
+    "       (1 -- 1  )∘(n   -- n)\n",
+    "\n",
+    "This involves detecting that \"Any type\" arguments can accept \"numbers\".  If we were composing these functions the other way round this is still the case:\n",
+    "\n",
+    "       (n n -- n)∘(1 -- 1 1)\n",
+    "    ---------------------------  w/  {1: n}\n",
+    "       (n n --  )∘(  -- n n) \n",
+    "\n",
+    "The important thing here is that the mapping is going the same way in both cases, from the \"any\" integer to the number"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Distinguishing Numbers\n",
+    "We should also mind that the number that `mul` produces is not (necessarily) the same as either of its inputs, which are not (necessarily) the same as each other:\n",
+    "\n",
+    "    mul (n2 n1 -- n3)\n",
+    "\n",
+    "\n",
+    "       (1  -- 1  1)∘(n2 n1 -- n3)\n",
+    "    --------------------------------  w/  {1: n2}\n",
+    "       (n2 -- n2  )∘(n2    -- n3)\n",
+    "\n",
+    "\n",
+    "       (n2 n1 -- n3)∘(1 -- 1  1 )\n",
+    "    --------------------------------  w/  {1: n3}\n",
+    "       (n2 n1 --   )∘(  -- n3 n3) \n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Distinguishing Types\n",
+    "So we need separate domains of \"any\" numbers and \"number\" numbers, and we need to be able to ask the order of these domains.  Now the notes on the right side of rule three make more sense, eh?\n",
+    "\n",
+    "       (a -- b t[i])∘(c u[j] -- d)   t <= u (t is subtype of u)\n",
+    "    -------------------------------\n",
+    "       (a -- b     )∘(c      -- d)   t[i] == t[k] == u[j]\n",
+    "                                             ^\n",
+    "\n",
+    "       (a -- b t[i])∘(c u[j] -- d)   u <= t (u is subtype of t)\n",
+    "    -------------------------------\n",
+    "       (a -- b     )∘(c      -- d)   t[i] == u[k] == u[j]\n",
+    "\n",
+    "The indices `i`, `k`, and `j` are the number part of our labels and `t` and `u` are the domains.\n",
+    "\n",
+    "By creative use of Python's \"double underscore\" methods we can define a Python class hierarchy of Joy types and use the `issubclass()` method to establish domain ordering, as well as other handy behaviour that will make it fairly easy to reuse most of the code above."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 37,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "class AnyJoyType(object):\n",
+    "\n",
+    "    prefix = 'a'\n",
+    "\n",
+    "    def __init__(self, number):\n",
+    "        self.number = number\n",
+    "\n",
+    "    def __repr__(self):\n",
+    "        return self.prefix + str(self.number)\n",
+    "\n",
+    "    def __eq__(self, other):\n",
+    "        return (\n",
+    "            isinstance(other, self.__class__)\n",
+    "            and other.prefix == self.prefix\n",
+    "            and other.number == self.number\n",
+    "        )\n",
+    "\n",
+    "    def __ge__(self, other):\n",
+    "        return issubclass(other.__class__, self.__class__)\n",
+    "\n",
+    "    def __add__(self, other):\n",
+    "        return self.__class__(self.number + other)\n",
+    "    __radd__ = __add__\n",
+    "    \n",
+    "    def __hash__(self):\n",
+    "        return hash(repr(self))\n",
+    "\n",
+    "\n",
+    "class NumberJoyType(AnyJoyType): prefix = 'n'\n",
+    "class FloatJoyType(NumberJoyType): prefix = 'f'\n",
+    "class IntJoyType(FloatJoyType): prefix = 'i'\n",
+    "\n",
+    "\n",
+    "class StackJoyType(AnyJoyType):\n",
+    "    prefix = 's'\n",
+    "\n",
+    "\n",
+    "_R = range(10)\n",
+    "A = map(AnyJoyType, _R)\n",
+    "N = map(NumberJoyType, _R)\n",
+    "S = map(StackJoyType, _R)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Mess with it a little:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 38,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from itertools import permutations"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "\"Any\" types can be specialized to numbers and stacks, but not vice versa:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 39,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "a0 >= n0 -> True\n",
+      "a0 >= s0 -> True\n",
+      "n0 >= a0 -> False\n",
+      "n0 >= s0 -> False\n",
+      "s0 >= a0 -> False\n",
+      "s0 >= n0 -> False\n"
+     ]
+    }
+   ],
+   "source": [
+    "for a, b in permutations((A[0], N[0], S[0]), 2):\n",
+    "    print a, '>=', b, '->', a >= b"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Our crude [Numerical Tower](https://en.wikipedia.org/wiki/Numerical_tower) of *numbers* > *floats* > *integers* works as well (but we're not going to use it yet):"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 40,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "a0 >= n0 -> True\n",
+      "a0 >= f0 -> True\n",
+      "a0 >= i0 -> True\n",
+      "n0 >= a0 -> False\n",
+      "n0 >= f0 -> True\n",
+      "n0 >= i0 -> True\n",
+      "f0 >= a0 -> False\n",
+      "f0 >= n0 -> False\n",
+      "f0 >= i0 -> True\n",
+      "i0 >= a0 -> False\n",
+      "i0 >= n0 -> False\n",
+      "i0 >= f0 -> False\n"
+     ]
+    }
+   ],
+   "source": [
+    "for a, b in permutations((A[0], N[0], FloatJoyType(0), IntJoyType(0)), 2):\n",
+    "    print a, '>=', b, '->', a >= b"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Typing `sqr`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 41,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "dup = (A[1],), (A[1], A[1])\n",
+    "\n",
+    "mul = (N[1], N[2]), (N[3],)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 42,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "((a1,), (a1, a1))"
+      ]
+     },
+     "execution_count": 42,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "dup"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 43,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "((n1, n2), (n3,))"
+      ]
+     },
+     "execution_count": 43,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "mul"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Modifying the Inferencer\n",
+    "Re-labeling still works fine:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 44,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(((a1,), (a1, a1)), ((n1001, n1002), (n1003,)))"
+      ]
+     },
+     "execution_count": 44,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "foo = relabel(dup, mul)\n",
+    "\n",
+    "foo"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### `delabel()` version 2\n",
+    "The `delabel()` function needs an overhaul.  It now has to keep track of how many labels of each domain it has \"seen\"."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 45,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from collections import Counter\n",
+    "\n",
+    "\n",
+    "def delabel(f, seen=None, c=None):\n",
+    "    if seen is None:\n",
+    "        assert c is None\n",
+    "        seen, c = {}, Counter()\n",
+    "\n",
+    "    try:\n",
+    "        return seen[f]\n",
+    "    except KeyError:\n",
+    "        pass\n",
+    "\n",
+    "    if not isinstance(f, tuple):\n",
+    "        seen[f] = f.__class__(c[f.prefix])\n",
+    "        c[f.prefix] += 1\n",
+    "        return seen[f]\n",
+    "\n",
+    "    return tuple(delabel(inner, seen, c) for inner in f)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 46,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(((a0,), (a0, a0)), ((n0, n1), (n2,)))"
+      ]
+     },
+     "execution_count": 46,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "delabel(foo)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### `unify()` version 3"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 47,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def unify(u, v, s=None):\n",
+    "    if s is None:\n",
+    "        s = {}\n",
+    "    else:\n",
+    "        u = update(s, u)\n",
+    "        v = update(s, v)\n",
+    "\n",
+    "    if u == v:\n",
+    "        return s\n",
+    "\n",
+    "    if isinstance(u, AnyJoyType) and isinstance(v, AnyJoyType):\n",
+    "        if u >= v:\n",
+    "            s[u] = v\n",
+    "            return s\n",
+    "        if v >= u:\n",
+    "            s[v] = u\n",
+    "            return s\n",
+    "        raise TypeError('Cannot unify %r and %r.' % (u, v))\n",
+    "\n",
+    "    if isinstance(u, tuple) and isinstance(v, tuple):\n",
+    "        if len(u) != len(v) != 2:\n",
+    "            raise TypeError(repr((u, v)))\n",
+    "        for uu, vv in zip(u, v):\n",
+    "            s = unify(uu, vv, s)\n",
+    "            if s == False: # (instead of a substitution dict.)\n",
+    "                break\n",
+    "        return s\n",
+    " \n",
+    "    if isinstance(v, tuple):\n",
+    "        if not stacky(u):\n",
+    "            raise TypeError('Cannot unify %r and %r.' % (u, v))\n",
+    "        s[u] = v\n",
+    "        return s\n",
+    "\n",
+    "    if isinstance(u, tuple):\n",
+    "        if not stacky(v):\n",
+    "            raise TypeError('Cannot unify %r and %r.' % (v, u))\n",
+    "        s[v] = u\n",
+    "        return s\n",
+    "\n",
+    "    return False\n",
+    "\n",
+    "\n",
+    "def stacky(thing):\n",
+    "    return thing.__class__ in {AnyJoyType, StackJoyType}"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Rewrite the stack effect comments:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 48,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def defs():\n",
+    "\n",
+    "    roll_down = (A[1], A[2], A[3]), (A[2], A[3], A[1])\n",
+    "\n",
+    "    roll_up = (A[1], A[2], A[3]), (A[3], A[1], A[2])\n",
+    "\n",
+    "    pop = (A[1],), ()\n",
+    "\n",
+    "    popop = (A[2], A[1],), ()\n",
+    "\n",
+    "    popd = (A[2], A[1],), (A[1],)\n",
+    "\n",
+    "    popdd = (A[3], A[2], A[1],), (A[2], A[1],)\n",
+    "\n",
+    "    swap = (A[1], A[2]), (A[2], A[1])\n",
+    "\n",
+    "    rest = ((A[1], S[1]),), (S[1],)\n",
+    "\n",
+    "    rrest = C(rest, rest)\n",
+    "\n",
+    "    cons = (A[1], S[1]), ((A[1], S[1]),)\n",
+    "\n",
+    "    ccons = C(cons, cons)\n",
+    "\n",
+    "    uncons = ((A[1], S[1]),), (A[1], S[1])\n",
+    "\n",
+    "    swons = C(swap, cons)\n",
+    "\n",
+    "    dup = (A[1],), (A[1], A[1])\n",
+    "\n",
+    "    dupd = (A[2], A[1]), (A[2], A[2], A[1])\n",
+    "\n",
+    "    mul = (N[1], N[2]), (N[3],)\n",
+    "    \n",
+    "    sqrt = C(dup, mul)\n",
+    "\n",
+    "    first = ((A[1], S[1]),), (A[1],)\n",
+    "\n",
+    "    second = C(rest, first)\n",
+    "\n",
+    "    third = C(rest, second)\n",
+    "\n",
+    "    tuck = (A[2], A[1]), (A[1], A[2], A[1])\n",
+    "\n",
+    "    over = (A[2], A[1]), (A[2], A[1], A[2])\n",
+    "    \n",
+    "    succ = pred = (N[1],), (N[2],)\n",
+    "    \n",
+    "    divmod_ = pm = (N[2], N[1]), (N[4], N[3])\n",
+    "\n",
+    "    return locals()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 49,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "DEFS = defs()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 50,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "ccons = (a0 a1 [.0.] -- [a0 a1 .0.])\n",
+      "cons = (a1 [.1.] -- [a1 .1.])\n",
+      "divmod_ = (n2 n1 -- n4 n3)\n",
+      "dup = (a1 -- a1 a1)\n",
+      "dupd = (a2 a1 -- a2 a2 a1)\n",
+      "first = ([a1 .1.] -- a1)\n",
+      "mul = (n1 n2 -- n3)\n",
+      "over = (a2 a1 -- a2 a1 a2)\n",
+      "pm = (n2 n1 -- n4 n3)\n",
+      "pop = (a1 --)\n",
+      "popd = (a2 a1 -- a1)\n",
+      "popdd = (a3 a2 a1 -- a2 a1)\n",
+      "popop = (a2 a1 --)\n",
+      "pred = (n1 -- n2)\n",
+      "rest = ([a1 .1.] -- [.1.])\n",
+      "roll_down = (a1 a2 a3 -- a2 a3 a1)\n",
+      "roll_up = (a1 a2 a3 -- a3 a1 a2)\n",
+      "rrest = ([a0 a1 .0.] -- [.0.])\n",
+      "second = ([a0 a1 .0.] -- a1)\n",
+      "sqrt = (n0 -- n1)\n",
+      "succ = (n1 -- n2)\n",
+      "swap = (a1 a2 -- a2 a1)\n",
+      "swons = ([.0.] a0 -- [a0 .0.])\n",
+      "third = ([a0 a1 a2 .0.] -- a2)\n",
+      "tuck = (a2 a1 -- a1 a2 a1)\n",
+      "uncons = ([a1 .1.] -- a1 [.1.])\n"
+     ]
+    }
+   ],
+   "source": [
+    "for name, stack_effect_comment in sorted(DEFS.items()):\n",
+    "    print name, '=', doc_from_stack_effect(*stack_effect_comment)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 51,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "globals().update(DEFS)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Compose `dup` and `mul`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 52,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "((n0,), (n1,))"
+      ]
+     },
+     "execution_count": 52,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "C(dup, mul)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Revisit the `F` function, works fine."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 53,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(((a0, (a1, s0)), a2, a3, a4), ((a3, (a2, s0)),))"
+      ]
+     },
+     "execution_count": 53,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "F = reduce(C, (pop, swap, roll_down, rest, rest, cons, cons))\n",
+    "F"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 54,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "([a0 a1 .0.] a2 a3 a4 -- [a3 a2 .0.])\n"
+     ]
+    }
+   ],
+   "source": [
+    "print doc_from_stack_effect(*F)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Some otherwise inefficient functions are no longer to be feared.  We can also get the effect of combinators in some limited cases."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 55,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def neato(*funcs):\n",
+    "    print doc_from_stack_effect(*reduce(C, funcs))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 56,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(a0 a1 a2 -- a1 a0 a2)\n"
+     ]
+    }
+   ],
+   "source": [
+    "# e.g. [swap] dip\n",
+    "neato(roll_up, swap, roll_down)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 57,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(a0 a1 a2 a3 -- a2 a3)\n"
+     ]
+    }
+   ],
+   "source": [
+    "# e.g. [popop] dip\n",
+    "neato(popdd, roll_down, pop)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 58,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(a0 a1 a2 -- a2 a1 a0)\n"
+     ]
+    }
+   ],
+   "source": [
+    "# Reverse the order of the top three items.\n",
+    "neato(roll_up, swap)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### `compile_()` version 2\n",
+    "Because the type labels represent themselves as valid Python identifiers the `compile_()` function doesn't need to generate them anymore:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 59,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def compile_(name, f, doc=None):\n",
+    "    inputs, outputs = f\n",
+    "    if doc is None:\n",
+    "        doc = doc_from_stack_effect(inputs, outputs)\n",
+    "    i = o = Symbol('stack')\n",
+    "    for term in inputs:\n",
+    "        i = term, i\n",
+    "    for term in outputs:\n",
+    "        o = term, o\n",
+    "    return '''def %s(stack):\n",
+    "    \"\"\"%s\"\"\"\n",
+    "    %s = stack\n",
+    "    return %s''' % (name, doc, i, o)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 60,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "def F(stack):\n",
+      "    \"\"\"([a0 a1 .0.] a2 a3 a4 -- [a3 a2 .0.])\"\"\"\n",
+      "    (a4, (a3, (a2, ((a0, (a1, s0)), stack)))) = stack\n",
+      "    return ((a3, (a2, s0)), stack)\n"
+     ]
+    }
+   ],
+   "source": [
+    "print compile_('F', F)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "But it cannot magically create new functions that involve e.g. math and such.  Note that this is *not* a `sqr` function implementation:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 61,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "def sqr(stack):\n",
+      "    \"\"\"(n0 -- n1)\"\"\"\n",
+      "    (n0, stack) = stack\n",
+      "    return (n1, stack)\n"
+     ]
+    }
+   ],
+   "source": [
+    "print compile_('sqr', C(dup, mul))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### `compilable()`\n",
+    "The functions that *can* be compiled are the ones that have only `AnyJoyType` and `StackJoyType` labels in their stack effect comments.  We can write a function to check that:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 62,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from itertools import imap\n",
+    "\n",
+    "\n",
+    "def compilable(f):\n",
+    "    return isinstance(f, tuple) and all(imap(compilable, f)) or stacky(f)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 63,
+   "metadata": {
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "ccons = (a0 a1 [.0.] -- [a0 a1 .0.])\n",
+      "cons = (a1 [.1.] -- [a1 .1.])\n",
+      "dup = (a1 -- a1 a1)\n",
+      "dupd = (a2 a1 -- a2 a2 a1)\n",
+      "first = ([a1 .1.] -- a1)\n",
+      "over = (a2 a1 -- a2 a1 a2)\n",
+      "pop = (a1 --)\n",
+      "popd = (a2 a1 -- a1)\n",
+      "popdd = (a3 a2 a1 -- a2 a1)\n",
+      "popop = (a2 a1 --)\n",
+      "rest = ([a1 .1.] -- [.1.])\n",
+      "roll_down = (a1 a2 a3 -- a2 a3 a1)\n",
+      "roll_up = (a1 a2 a3 -- a3 a1 a2)\n",
+      "rrest = ([a0 a1 .0.] -- [.0.])\n",
+      "second = ([a0 a1 .0.] -- a1)\n",
+      "swap = (a1 a2 -- a2 a1)\n",
+      "swons = ([.0.] a0 -- [a0 .0.])\n",
+      "third = ([a0 a1 a2 .0.] -- a2)\n",
+      "tuck = (a2 a1 -- a1 a2 a1)\n",
+      "uncons = ([a1 .1.] -- a1 [.1.])\n"
+     ]
+    }
+   ],
+   "source": [
+    "for name, stack_effect_comment in sorted(defs().items()):\n",
+    "    if compilable(stack_effect_comment):\n",
+    "        print name, '=', doc_from_stack_effect(*stack_effect_comment)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Functions that use the Stack\n",
+    "\n",
+    "Consider the `stack` function which grabs the whole stack, quotes it, and puts it on itself:\n",
+    "\n",
+    "    stack (...     -- ... [...]        )\n",
+    "    stack (... a   -- ... a [a ...]    )\n",
+    "    stack (... b a -- ... b a [a b ...])\n",
+    "\n",
+    "We would like to represent this in Python somehow. \n",
+    "To do this we use a simple, elegant trick.\n",
+    "\n",
+    "    stack         S   -- (         S,           S)\n",
+    "    stack     (a, S)  -- (     (a, S),      (a, S))\n",
+    "    stack (a, (b, S)) -- ( (a, (b, S)), (a, (b, S)))\n",
+    "\n",
+    "Instead of representing the stack effect comments as a single tuple (with N items in it) we use the same cons-list structure to hold the sequence and `unify()` the whole comments."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `stack∘uncons`\n",
+    "Let's try composing `stack` and `uncons`.  We want this result:\n",
+    "\n",
+    "    stack∘uncons (... a -- ... a a [...])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The stack effects are:\n",
+    "\n",
+    "    stack = S -- (S, S)\n",
+    "\n",
+    "    uncons = ((a, Z), S) -- (Z, (a, S))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Unifying:\n",
+    "\n",
+    "      S    -- (S, S) ∘ ((a, Z), S) -- (Z, (a,   S   ))\n",
+    "                                                        w/ { S: (a, Z) }\n",
+    "    (a, Z) --        ∘             -- (Z, (a, (a, Z)))\n",
+    "\n",
+    "So:\n",
+    "\n",
+    "    stack∘uncons == (a, Z) -- (Z, (a, (a, Z)))\n",
+    "\n",
+    "It works."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `stack∘uncons∘uncons`\n",
+    "Let's try `stack∘uncons∘uncons`:\n",
+    "\n",
+    "    (a, S     ) -- (S,      (a, (a, S     ))) ∘ ((b, Z),  S`             ) -- (Z, (b,   S`   ))\n",
+    "    \n",
+    "                                                                                    w/ { S: (b, Z) }\n",
+    "                                                                                    \n",
+    "    (a, (b, Z)) -- ((b, Z), (a, (a, (b, Z)))) ∘ ((b, Z),  S`             ) -- (Z, (b,   S`   ))\n",
+    "    \n",
+    "                                                                                    w/ { S`: (a, (a, (b, Z))) }\n",
+    "                                                                                    \n",
+    "    (a, (b, Z)) -- ((b, Z), (a, (a, (b, Z)))) ∘ ((b, Z), (a, (a, (b, Z)))) -- (Z, (b, (a, (a, (b, Z)))))\n",
+    "\n",
+    "    (a, (b, Z)) -- (Z, (b, (a, (a, (b, Z)))))\n",
+    "\n",
+    "It works."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### `compose()` version 2\n",
+    "This function has to be modified to use the new datastructures and it is no longer recursive, instead recursion happens as part of unification."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 64,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def compose(f, g):\n",
+    "\n",
+    "    (f_in, f_out), (g_in, g_out) = f, g\n",
+    "\n",
+    "    if not g_in:\n",
+    "        fg_in, fg_out = f_in, stack_concat(g_out, f_out)\n",
+    "\n",
+    "    elif not f_out:\n",
+    "        fg_in, fg_out = stack_concat(f_in, g_in), g_out\n",
+    "\n",
+    "    else: # Unify and update.\n",
+    "\n",
+    "        s = unify(g_in, f_out)\n",
+    "\n",
+    "        if s == False:  # s can also be the empty dict, which is ok.\n",
+    "            raise TypeError('Cannot unify %r and %r.' % (fo, gi))\n",
+    "\n",
+    "        fg_in, fg_out = update(s, (f_in, g_out))\n",
+    "\n",
+    "    return fg_in, fg_out\n",
+    "\n",
+    "\n",
+    "stack_concat = lambda q, e: (q[0], stack_concat(q[1], e)) if q else e"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "I don't want to rewrite all the defs myself, so I'll write a little conversion function instead.  This is programmer's laziness."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 65,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def sequence_to_stack(seq, stack=StackJoyType(23)):\n",
+    "    for item in seq: stack = item, stack\n",
+    "    return stack\n",
+    "\n",
+    "NEW_DEFS = {\n",
+    "    name: (sequence_to_stack(i), sequence_to_stack(o))\n",
+    "    for name, (i, o) in DEFS.iteritems()\n",
+    "}\n",
+    "\n",
+    "globals().update(NEW_DEFS)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 66,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "stack = S[0], (S[0], S[0])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 67,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "((a0, s0), (s0, (a0, (a0, s0))))"
+      ]
+     },
+     "execution_count": 67,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "C(stack, uncons)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 68,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "((a0, (a1, s0)), (s0, (a1, (a0, (a0, (a1, s0))))))"
+      ]
+     },
+     "execution_count": 68,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "C(C(stack, uncons), uncons)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The display function should be changed too."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### `doc_from_stack_effect()` version 2\n",
+    "Clunky junk, but it will suffice for now."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 69,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def doc_from_stack_effect(inputs, outputs):\n",
+    "    switch = [False]  # Do we need to display the '...' for the rest of the main stack?\n",
+    "    i, o = _f(inputs, switch), _f(outputs, switch)\n",
+    "    if switch[0]:\n",
+    "        i.append('...')\n",
+    "        o.append('...')\n",
+    "    return '(%s--%s)' % (\n",
+    "        ' '.join(reversed([''] + i)),\n",
+    "        ' '.join(reversed(o + [''])),\n",
+    "    )\n",
+    "\n",
+    "\n",
+    "def _f(term, switch):\n",
+    "    a = []\n",
+    "    while term and isinstance(term, tuple):\n",
+    "        item, term = term\n",
+    "        a.append(item)\n",
+    "    assert isinstance(term, StackJoyType), repr(term)\n",
+    "    a = [_to_str(i, term, switch) for i in a]\n",
+    "    return a\n",
+    "\n",
+    "\n",
+    "def _to_str(term, stack, switch):\n",
+    "    if not isinstance(term, tuple):\n",
+    "        if term == stack:\n",
+    "            switch[0] = True\n",
+    "            return '[...]'\n",
+    "        return (\n",
+    "            '[.%i.]' % term.number\n",
+    "            if isinstance(term, StackJoyType)\n",
+    "            else str(term)\n",
+    "        )\n",
+    "\n",
+    "    a = []\n",
+    "    while term and isinstance(term, tuple):\n",
+    "        item, term = term\n",
+    "        a.append(_to_str(item, stack, switch))\n",
+    "    assert isinstance(term, StackJoyType), repr(term)\n",
+    "    if term == stack:\n",
+    "        switch[0] = True\n",
+    "        end = '...'\n",
+    "    else:\n",
+    "        end = '.%i.' % term.number\n",
+    "    a.append(end)\n",
+    "    return '[%s]' % ' '.join(a)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 70,
+   "metadata": {
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "ccons = (a0 a1 [.0.] -- [a0 a1 .0.])\n",
+      "cons = (a1 [.1.] -- [a1 .1.])\n",
+      "divmod_ = (n2 n1 -- n4 n3)\n",
+      "dup = (a1 -- a1 a1)\n",
+      "dupd = (a2 a1 -- a2 a2 a1)\n",
+      "first = ([a1 .1.] -- a1)\n",
+      "mul = (n1 n2 -- n3)\n",
+      "over = (a2 a1 -- a2 a1 a2)\n",
+      "pm = (n2 n1 -- n4 n3)\n",
+      "pop = (a1 --)\n",
+      "popd = (a2 a1 -- a1)\n",
+      "popdd = (a3 a2 a1 -- a2 a1)\n",
+      "popop = (a2 a1 --)\n",
+      "pred = (n1 -- n2)\n",
+      "rest = ([a1 .1.] -- [.1.])\n",
+      "roll_down = (a1 a2 a3 -- a2 a3 a1)\n",
+      "roll_up = (a1 a2 a3 -- a3 a1 a2)\n",
+      "rrest = ([a0 a1 .0.] -- [.0.])\n",
+      "second = ([a0 a1 .0.] -- a1)\n",
+      "sqrt = (n0 -- n1)\n",
+      "succ = (n1 -- n2)\n",
+      "swap = (a1 a2 -- a2 a1)\n",
+      "swons = ([.0.] a0 -- [a0 .0.])\n",
+      "third = ([a0 a1 a2 .0.] -- a2)\n",
+      "tuck = (a2 a1 -- a1 a2 a1)\n",
+      "uncons = ([a1 .1.] -- a1 [.1.])\n"
+     ]
+    }
+   ],
+   "source": [
+    "for name, stack_effect_comment in sorted(NEW_DEFS.items()):\n",
+    "    print name, '=', doc_from_stack_effect(*stack_effect_comment)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 71,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "\n",
+      "(... -- ... [...])\n",
+      "\n",
+      "(... a0 -- ... a0 a0 [...])\n",
+      "\n",
+      "(... a1 a0 -- ... a1 a0 a0 a1 [...])\n",
+      "\n",
+      "(... a0 -- ... a0 [a0 ...])\n"
+     ]
+    }
+   ],
+   "source": [
+    "print ; print doc_from_stack_effect(*stack)\n",
+    "print ; print doc_from_stack_effect(*C(stack, uncons))\n",
+    "print ; print doc_from_stack_effect(*C(C(stack, uncons), uncons))\n",
+    "print ; print doc_from_stack_effect(*C(C(stack, uncons), cons))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 72,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(... a1 a0 [.0.] -- ... [a1 a0 .0.] [[a1 a0 .0.] ...])\n"
+     ]
+    }
+   ],
+   "source": [
+    "print doc_from_stack_effect(*C(ccons, stack))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 73,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "((s0, (a0, (a1, s1))), (((a1, (a0, s0)), s1), ((a1, (a0, s0)), s1)))"
+      ]
+     },
+     "execution_count": 73,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "Q = C(ccons, stack)\n",
+    "\n",
+    "Q"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### `compile_()` version 3\n",
+    "This makes the `compile_()` function pretty simple as the stack effect comments are now already in the form needed for the Python code:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 74,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def compile_(name, f, doc=None):\n",
+    "    i, o = f\n",
+    "    if doc is None:\n",
+    "        doc = doc_from_stack_effect(i, o)\n",
+    "    return '''def %s(stack):\n",
+    "    \"\"\"%s\"\"\"\n",
+    "    %s = stack\n",
+    "    return %s''' % (name, doc, i, o)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 75,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "def Q(stack):\n",
+      "    \"\"\"(... a1 a0 [.0.] -- ... [a1 a0 .0.] [[a1 a0 .0.] ...])\"\"\"\n",
+      "    (s0, (a0, (a1, s1))) = stack\n",
+      "    return (((a1, (a0, s0)), s1), ((a1, (a0, s0)), s1))\n"
+     ]
+    }
+   ],
+   "source": [
+    "print compile_('Q', Q)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 76,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "unstack = (S[1], S[0]), S[1]\n",
+    "enstacken = S[0], (S[0], S[1])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 77,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "([.1.] --)\n"
+     ]
+    }
+   ],
+   "source": [
+    "print doc_from_stack_effect(*unstack)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 78,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(-- [.0.])\n"
+     ]
+    }
+   ],
+   "source": [
+    "print doc_from_stack_effect(*enstacken)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 79,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(a0 [.0.] -- a0)\n"
+     ]
+    }
+   ],
+   "source": [
+    "print doc_from_stack_effect(*C(cons, unstack))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 80,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(a0 [.0.] -- [[a0 .0.] .1.])\n"
+     ]
+    }
+   ],
+   "source": [
+    "print doc_from_stack_effect(*C(cons, enstacken))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 81,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "((s0, (a0, s1)), (a0, s0))"
+      ]
+     },
+     "execution_count": 81,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "C(cons, unstack)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Multiple Stack Effects\n",
+    "..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 82,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "class IntJoyType(NumberJoyType): prefix = 'i'\n",
+    "\n",
+    "\n",
+    "F = map(FloatJoyType, _R)\n",
+    "I = map(IntJoyType, _R)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 83,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "muls = [\n",
+    "     ((I[2], (I[1], S[0])), (I[3], S[0])),\n",
+    "     ((F[2], (I[1], S[0])), (F[3], S[0])),\n",
+    "     ((I[2], (F[1], S[0])), (F[3], S[0])),\n",
+    "     ((F[2], (F[1], S[0])), (F[3], S[0])),\n",
+    "]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 84,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(i1 i2 -- i3)\n",
+      "(i1 f2 -- f3)\n",
+      "(f1 i2 -- f3)\n",
+      "(f1 f2 -- f3)\n"
+     ]
+    }
+   ],
+   "source": [
+    "for f in muls:\n",
+    "    print doc_from_stack_effect(*f)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 85,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(a1 -- a1 a1) (i1 i2 -- i3) (i0 -- i1)\n",
+      "(a1 -- a1 a1) (f1 f2 -- f3) (f0 -- f1)\n"
+     ]
+    }
+   ],
+   "source": [
+    "for f in muls:\n",
+    "    try:\n",
+    "        e = C(dup, f)\n",
+    "    except TypeError:\n",
+    "        continue\n",
+    "    print doc_from_stack_effect(*dup), doc_from_stack_effect(*f), doc_from_stack_effect(*e)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 86,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from itertools import product\n",
+    "\n",
+    "\n",
+    "def meta_compose(F, G):\n",
+    "    for f, g in product(F, G):\n",
+    "        try:\n",
+    "            yield C(f, g)\n",
+    "        except TypeError:\n",
+    "            pass\n",
+    "\n",
+    "\n",
+    "def MC(F, G):\n",
+    "    return sorted(set(meta_compose(F, G)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 87,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(f0 -- f1)\n",
+      "(i0 -- i1)\n"
+     ]
+    }
+   ],
+   "source": [
+    "for f in MC([dup], muls):\n",
+    "    print doc_from_stack_effect(*f)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 88,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(n0 -- n1)\n"
+     ]
+    }
+   ],
+   "source": [
+    "for f in MC([dup], [mul]):\n",
+    "    print doc_from_stack_effect(*f)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## `concat`\n",
+    "\n",
+    "How to deal with `concat`?\n",
+    "\n",
+    "    concat ([.0.] [.1.] -- [.0. .1.])\n",
+    "    \n",
+    "We would like to represent this in Python somehow..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 89,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "concat = (S[0], S[1]), ((S[0], S[1]),)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "But this is actually `cons` with the first argument restricted to be a stack:\n",
+    "\n",
+    "    ([.0.] [.1.] -- [[.0.] .1.])\n",
+    "\n",
+    "What we have implemented so far would actually only permit:\n",
+    "\n",
+    "    ([.0.] [.1.] -- [.2.])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 90,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "concat = (S[0], S[1]), (S[2],)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "    \n",
+    "Which works but can lose information.  Consider `cons concat`, this is how much information we *could* retain:\n",
+    "\n",
+    "    (1 [.0.] [.1.] -- [1 .0. .1.])\n",
+    "\n",
+    "As opposed to just:\n",
+    "\n",
+    "    (1 [.0.] [.1.] -- [.2.])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Brzo...'s Derivitives of Regular Expressions\n",
+    "\n",
+    "We can invent a new type of type variable, a \"sequence type\" (I think this is what they mean in the literature by that term...) or \"Kleene Star\" type.  I'm going to represent it as a type letter and the asterix, so a sequence of zero or more `AnyJoyType` variables would be:\n",
+    "\n",
+    "    A*"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The `A*` works by splitting the universe into two alternate histories:\n",
+    "\n",
+    "    A* -> 0 | A A*\n",
+    "\n",
+    "The Kleene star variable disappears in one universe, and in the other it turns into an `AnyJoyType` variable followed by itself again.  We have to return all universes (represented by their substitution dicts, the \"unifiers\") that don't lead to type conflicts."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Consider unifying two stacks (the lowercase letters are any type variables of the kinds we have defined so far):\n",
+    "\n",
+    "    [a A* b .0.] U [c d .1.]\n",
+    "                              w/ {c: a}\n",
+    "    [  A* b .0.] U [  d .1.]"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now we have to split universes to unify `A*`.  In the first universe it disappears:\n",
+    "\n",
+    "    [b .0.] U [d .1.]\n",
+    "                       w/ {d: b, .1.: .0.} \n",
+    "         [] U []"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "While in the second it spawns an `A`, which we will label `e`:\n",
+    "\n",
+    "    [e A* b .0.] U [d .1.]\n",
+    "                            w/ {d: e}\n",
+    "    [  A* b .0.] U [  .1.]\n",
+    "                            w/ {.1.: A* b .0.}\n",
+    "    [  A* b .0.] U [  .1.]"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Giving us two unifiers:\n",
+    "\n",
+    "    {c: a,  d: b,  .1.:      .0.}\n",
+    "    {c: a,  d: e,  .1.: A* b .0.}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 91,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "class KleeneStar(object):\n",
+    "\n",
+    "    kind = AnyJoyType\n",
+    "\n",
+    "    def __init__(self, number):\n",
+    "        self.number = number\n",
+    "        self.count = 0\n",
+    "        self.prefix = repr(self)\n",
+    "\n",
+    "    def __repr__(self):\n",
+    "        return '%s%i*' % (self.kind.prefix, self.number)\n",
+    "\n",
+    "    def another(self):\n",
+    "        self.count += 1\n",
+    "        return self.kind(10000 * self.number + self.count)\n",
+    "\n",
+    "    def __eq__(self, other):\n",
+    "        return (\n",
+    "            isinstance(other, self.__class__)\n",
+    "            and other.number == self.number\n",
+    "        )\n",
+    "\n",
+    "    def __ge__(self, other):\n",
+    "        return self.kind >= other.kind\n",
+    "\n",
+    "    def __add__(self, other):\n",
+    "        return self.__class__(self.number + other)\n",
+    "    __radd__ = __add__\n",
+    "    \n",
+    "    def __hash__(self):\n",
+    "        return hash(repr(self))\n",
+    "\n",
+    "class AnyStarJoyType(KleeneStar): kind = AnyJoyType\n",
+    "class NumberStarJoyType(KleeneStar): kind = NumberJoyType\n",
+    "#class FloatStarJoyType(KleeneStar): kind = FloatJoyType\n",
+    "#class IntStarJoyType(KleeneStar): kind = IntJoyType\n",
+    "class StackStarJoyType(KleeneStar): kind = StackJoyType\n",
+    "\n",
+    "\n",
+    "As = map(AnyStarJoyType, _R)\n",
+    "Ns = map(NumberStarJoyType, _R)\n",
+    "Ss = map(StackStarJoyType, _R)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### `unify()` version 4\n",
+    "Can now return multiple results..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 92,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def unify(u, v, s=None):\n",
+    "    if s is None:\n",
+    "        s = {}\n",
+    "    elif s:\n",
+    "        u = update(s, u)\n",
+    "        v = update(s, v)\n",
+    "\n",
+    "    if u == v:\n",
+    "        return s,\n",
+    "\n",
+    "    if isinstance(u, AnyJoyType) and isinstance(v, AnyJoyType):\n",
+    "        if u >= v:\n",
+    "            s[u] = v\n",
+    "            return s,\n",
+    "        if v >= u:\n",
+    "            s[v] = u\n",
+    "            return s,\n",
+    "        raise TypeError('Cannot unify %r and %r.' % (u, v))\n",
+    "\n",
+    "    if isinstance(u, tuple) and isinstance(v, tuple):\n",
+    "        if len(u) != len(v) != 2:\n",
+    "            raise TypeError(repr((u, v)))\n",
+    "            \n",
+    "        a, b = v\n",
+    "        if isinstance(a, KleeneStar):\n",
+    "            # Two universes, in one the Kleene star disappears and unification\n",
+    "            # continues without it...\n",
+    "            s0 = unify(u, b)\n",
+    "            \n",
+    "            # In the other it spawns a new variable.\n",
+    "            s1 = unify(u, (a.another(), v))\n",
+    "            \n",
+    "            t = s0 + s1\n",
+    "            for sn in t:\n",
+    "                sn.update(s)\n",
+    "            return t\n",
+    "\n",
+    "        a, b = u\n",
+    "        if isinstance(a, KleeneStar):\n",
+    "            s0 = unify(v, b)\n",
+    "            s1 = unify(v, (a.another(), u))\n",
+    "            t = s0 + s1\n",
+    "            for sn in t:\n",
+    "                sn.update(s)\n",
+    "            return t\n",
+    "\n",
+    "        ses = unify(u[0], v[0])\n",
+    "        results = ()\n",
+    "        for sn in ses:\n",
+    "            results += unify(u[1], v[1], sn)\n",
+    "        return results\n",
+    " \n",
+    "    if isinstance(v, tuple):\n",
+    "        if not stacky(u):\n",
+    "            raise TypeError('Cannot unify %r and %r.' % (u, v))\n",
+    "        s[u] = v\n",
+    "        return s,\n",
+    "\n",
+    "    if isinstance(u, tuple):\n",
+    "        if not stacky(v):\n",
+    "            raise TypeError('Cannot unify %r and %r.' % (v, u))\n",
+    "        s[v] = u\n",
+    "        return s,\n",
+    "\n",
+    "    return ()\n",
+    "\n",
+    "\n",
+    "def stacky(thing):\n",
+    "    return thing.__class__ in {AnyJoyType, StackJoyType}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 93,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(a1*, s1)"
+      ]
+     },
+     "execution_count": 93,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "a = (As[1], S[1])\n",
+    "a"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 94,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(a1, s2)"
+      ]
+     },
+     "execution_count": 94,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "b = (A[1], S[2])\n",
+    "b"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 95,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{s1: (a1, s2)} -> (a1*, (a1, s2)) (a1, s2)\n",
+      "{a1: a10001, s2: (a1*, s1)} -> (a1*, s1) (a10001, (a1*, s1))\n"
+     ]
+    }
+   ],
+   "source": [
+    "for result in unify(b, a):\n",
+    "    print result, '->', update(result, a), update(result, b)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 96,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{s1: (a1, s2)} -> (a1*, (a1, s2)) (a1, s2)\n",
+      "{a1: a10002, s2: (a1*, s1)} -> (a1*, s1) (a10002, (a1*, s1))\n"
+     ]
+    }
+   ],
+   "source": [
+    "for result in unify(a, b):\n",
+    "    print result, '->', update(result, a), update(result, b)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "\n",
+    "    (a1*, s1)       [a1*]       (a1, s2)        [a1]\n",
+    "\n",
+    "    (a1*, (a1, s2)) [a1* a1]    (a1, s2)        [a1]\n",
+    "\n",
+    "    (a1*, s1)       [a1*]       (a2, (a1*, s1)) [a2 a1*]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 97,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "([n1* .1.] -- n0)\n"
+     ]
+    }
+   ],
+   "source": [
+    "sum_ = ((Ns[1], S[1]), S[0]), (N[0], S[0])\n",
+    "\n",
+    "print doc_from_stack_effect(*sum_)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 98,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(-- [n1 n2 n3 .1.])\n"
+     ]
+    }
+   ],
+   "source": [
+    "f = (N[1], (N[2], (N[3], S[1]))), S[0]\n",
+    "\n",
+    "print doc_from_stack_effect(S[0], f)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 99,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{s1: (n1, (n2, (n3, s1)))} -> (n0, s0)\n",
+      "{n1: n10001, s1: (n2, (n3, s1))} -> (n0, s0)\n",
+      "{n1: n10001, s1: (n3, s1), n2: n10002} -> (n0, s0)\n",
+      "{n1: n10001, s1: (n1*, s1), n3: n10003, n2: n10002} -> (n0, s0)\n"
+     ]
+    }
+   ],
+   "source": [
+    "for result in unify(sum_[0], f):\n",
+    "    print result, '->', update(result, sum_[1])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### `compose()` version 3\n",
+    "This function has to be modified to use the new datastructures and it is no longer recursive, instead recursion happens as part of unification."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 100,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def compose(f, g):\n",
+    "\n",
+    "    (f_in, f_out), (g_in, g_out) = f, g\n",
+    "\n",
+    "    if not g_in:\n",
+    "        yield f_in, stack_concat(g_out, f_out)\n",
+    "\n",
+    "    elif not f_out:\n",
+    "        yield stack_concat(f_in, g_in), g_out\n",
+    "\n",
+    "    else: # Unify and update.\n",
+    "\n",
+    "        s = unify(g_in, f_out)\n",
+    "\n",
+    "        if not s:\n",
+    "            raise TypeError('Cannot unify %r and %r.' % (fo, gi))\n",
+    "\n",
+    "        for result in s:\n",
+    "            yield update(result, (f_in, g_out))\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 101,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def meta_compose(F, G):\n",
+    "    for f, g in product(F, G):\n",
+    "        try:\n",
+    "            for result in C(f, g):\n",
+    "                yield result\n",
+    "        except TypeError:\n",
+    "            pass\n",
+    "\n",
+    "\n",
+    "def C(f, g):\n",
+    "    f, g = relabel(f, g)\n",
+    "    for fg in compose(f, g):\n",
+    "        yield delabel(fg)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 102,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(a0 -- f0)\n",
+      "(a0 -- i0)\n"
+     ]
+    }
+   ],
+   "source": [
+    "for f in MC([dup], muls):\n",
+    "    print doc_from_stack_effect(*f)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 103,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "([n0* .0.] -- [n0* .0.] n0)\n"
+     ]
+    }
+   ],
+   "source": [
+    "\n",
+    "\n",
+    "for f in MC([dup], [sum_]):\n",
+    "    print doc_from_stack_effect(*f)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 104,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(a0 [.0.] -- n0)\n",
+      "(n0 [n0* .0.] -- n1)\n"
+     ]
+    }
+   ],
+   "source": [
+    "\n",
+    "\n",
+    "for f in MC([cons], [sum_]):\n",
+    "    print doc_from_stack_effect(*f)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 105,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(a1 [.1.] -- [a1 .1.]) ([n1 n1* .1.] -- n0) (n0 [n0* .0.] -- n1)\n"
+     ]
+    }
+   ],
+   "source": [
+    "sum_ = (((N[1], (Ns[1], S[1])), S[0]), (N[0], S[0]))\n",
+    "print doc_from_stack_effect(*cons),\n",
+    "print doc_from_stack_effect(*sum_),\n",
+    "\n",
+    "for f in MC([cons], [sum_]):\n",
+    "    print doc_from_stack_effect(*f)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 106,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(a4, (a1*, (a3, s1)))"
+      ]
+     },
+     "execution_count": 106,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "a = (A[4], (As[1], (A[3], S[1])))\n",
+    "a"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 107,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(a1, (a2, s2))"
+      ]
+     },
+     "execution_count": 107,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "b = (A[1], (A[2], S[2]))\n",
+    "b"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 108,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{a1: a4, s2: s1, a2: a3}\n",
+      "{a1: a4, s2: (a1*, (a3, s1)), a2: a10003}\n"
+     ]
+    }
+   ],
+   "source": [
+    "for result in unify(b, a):\n",
+    "    print result"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 109,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{s2: s1, a2: a3, a4: a1}\n",
+      "{s2: (a1*, (a3, s1)), a2: a10004, a4: a1}\n"
+     ]
+    }
+   ],
+   "source": [
+    "for result in unify(a, b):\n",
+    "    print result"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### represent `concat`\n",
+    "\n",
+    "    ([.0.] [.1.] -- [A*(.0.) .1.])\n",
+    "\n",
+    "Meaning that `A*` on the right-hand side should all the crap from `.0.`.\n",
+    "\n",
+    "    ([      .0.] [.1.] -- [      A* .1.])\n",
+    "    ([a     .0.] [.1.] -- [a     A* .1.])\n",
+    "    ([a b   .0.] [.1.] -- [a b   A* .1.])\n",
+    "    ([a b c .0.] [.1.] -- [a b c A* .1.])\n",
+    "\n",
+    "    "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "or...\n",
+    "\n",
+    "    ([       .0.] [.1.] -- [       .1.])\n",
+    "    ([a      .0.] [.1.] -- [a      .1.])\n",
+    "    ([a b    .0.] [.1.] -- [a b    .1.])\n",
+    "    ([a b  c .0.] [.1.] -- [a b  c .1.])\n",
+    "    ([a A* c .0.] [.1.] -- [a A* c .1.])\n",
+    "\n",
+    "    "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "    (a, (b, S0)) . S1 = (a, (b, (A*, S1)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 110,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "class Astar(object):\n",
+    "    def __repr__(self):\n",
+    "        return 'A*'\n",
+    "\n",
+    "\n",
+    "def concat(s0, s1):\n",
+    "    a = []\n",
+    "    while isinstance(s0, tuple):\n",
+    "        term, s0 = s0\n",
+    "        a.append(term)\n",
+    "    assert isinstance(s0, StackJoyType), repr(s0)\n",
+    "    s1 = Astar(), s1\n",
+    "    for term in reversed(a):\n",
+    "        s1 = term, s1\n",
+    "    return s1"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 111,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "a, b = (A[1], S[0]), (A[2], S[1])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 112,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(a1, (A*, (a2, s1)))"
+      ]
+     },
+     "execution_count": 112,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "concat(a, b)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Joy in the Logical Paradigm\n",
+    "For this to work the type label classes have to be modified to let `T >= t` succeed, where e.g. `T` is `IntJoyType` and `t` is `int`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 113,
+   "metadata": {},
+   "outputs": [
+    {
+     "ename": "ValueError",
+     "evalue": "need more than 1 value to unpack",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
+      "\u001b[0;32m<ipython-input-113-4b4cb6ff86e5>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0mF\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mreduce\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mC\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mpop\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mswap\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mroll_down\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrest\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrest\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcons\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcons\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0;32mprint\u001b[0m \u001b[0mdoc_from_stack_effect\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0mF\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+      "\u001b[0;32m<ipython-input-101-ddee30dbb1a6>\u001b[0m in \u001b[0;36mC\u001b[0;34m(f, g)\u001b[0m\n\u001b[1;32m     10\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mC\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     11\u001b[0m     \u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mrelabel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m     \u001b[0;32mfor\u001b[0m \u001b[0mfg\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mcompose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     13\u001b[0m         \u001b[0;32myield\u001b[0m \u001b[0mdelabel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m<ipython-input-100-4237a6bb159d>\u001b[0m in \u001b[0;36mcompose\u001b[0;34m(f, g)\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mcompose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m     \u001b[0;34m(\u001b[0m\u001b[0mf_in\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mf_out\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mg_in\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg_out\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mg_in\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m<ipython-input-101-ddee30dbb1a6>\u001b[0m in \u001b[0;36mC\u001b[0;34m(f, g)\u001b[0m\n\u001b[1;32m     10\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mC\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     11\u001b[0m     \u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mrelabel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m     \u001b[0;32mfor\u001b[0m \u001b[0mfg\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mcompose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     13\u001b[0m         \u001b[0;32myield\u001b[0m \u001b[0mdelabel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m<ipython-input-100-4237a6bb159d>\u001b[0m in \u001b[0;36mcompose\u001b[0;34m(f, g)\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mcompose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m     \u001b[0;34m(\u001b[0m\u001b[0mf_in\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mf_out\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mg_in\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg_out\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mg_in\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m<ipython-input-101-ddee30dbb1a6>\u001b[0m in \u001b[0;36mC\u001b[0;34m(f, g)\u001b[0m\n\u001b[1;32m     10\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mC\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     11\u001b[0m     \u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mrelabel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m     \u001b[0;32mfor\u001b[0m \u001b[0mfg\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mcompose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     13\u001b[0m         \u001b[0;32myield\u001b[0m \u001b[0mdelabel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m<ipython-input-100-4237a6bb159d>\u001b[0m in \u001b[0;36mcompose\u001b[0;34m(f, g)\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mcompose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m     \u001b[0;34m(\u001b[0m\u001b[0mf_in\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mf_out\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mg_in\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg_out\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mg_in\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m<ipython-input-101-ddee30dbb1a6>\u001b[0m in \u001b[0;36mC\u001b[0;34m(f, g)\u001b[0m\n\u001b[1;32m     10\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mC\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     11\u001b[0m     \u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mrelabel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m     \u001b[0;32mfor\u001b[0m \u001b[0mfg\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mcompose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     13\u001b[0m         \u001b[0;32myield\u001b[0m \u001b[0mdelabel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m<ipython-input-100-4237a6bb159d>\u001b[0m in \u001b[0;36mcompose\u001b[0;34m(f, g)\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mcompose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m     \u001b[0;34m(\u001b[0m\u001b[0mf_in\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mf_out\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mg_in\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg_out\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mg_in\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m<ipython-input-101-ddee30dbb1a6>\u001b[0m in \u001b[0;36mC\u001b[0;34m(f, g)\u001b[0m\n\u001b[1;32m     10\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mC\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     11\u001b[0m     \u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mrelabel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m     \u001b[0;32mfor\u001b[0m \u001b[0mfg\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mcompose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     13\u001b[0m         \u001b[0;32myield\u001b[0m \u001b[0mdelabel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m<ipython-input-100-4237a6bb159d>\u001b[0m in \u001b[0;36mcompose\u001b[0;34m(f, g)\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mcompose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m     \u001b[0;34m(\u001b[0m\u001b[0mf_in\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mf_out\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mg_in\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg_out\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mg_in\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;31mValueError\u001b[0m: need more than 1 value to unpack"
+     ]
+    }
+   ],
+   "source": [
+    "F = reduce(C, (pop, swap, roll_down, rest, rest, cons, cons))\n",
+    "\n",
+    "print doc_from_stack_effect(*F)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from joy.parser import text_to_expression"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "s = text_to_expression('[3 4 ...] 2 1')\n",
+    "s"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "L = unify(F[1], s)\n",
+    "L"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "F[1]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "F[1][0]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "s[0]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Typing Combinators\n",
+    "\n",
+    "TBD\n",
+    "\n",
+    "This is an open subject.\n",
+    "\n",
+    "The obvious thing is that you now need two pairs of tuples to describe the combinators' effects,  a stack effect comment and an expression effect comment:\n",
+    "\n",
+    "    dip (a [F] --)--(-- F a)\n",
+    "\n",
+    "One thing that might help is..."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Abstract Interpretation"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Something else...\n",
+    "    [4 5 ...] 2 1 0 pop∘swap∘roll<∘rest∘rest∘cons∘cons\n",
+    "    [4 5 ...] 2 1       swap∘roll<∘rest∘rest∘cons∘cons\n",
+    "    [4 5 ...] 1 2            roll<∘rest∘rest∘cons∘cons\n",
+    "    1 2 [4 5 ...]                  rest∘rest∘cons∘cons\n",
+    "    1 2   [5 ...]                       rest∘cons∘cons\n",
+    "    1 2     [...]                            cons∘cons\n",
+    "    1     [2 ...]                                 cons\n",
+    "        [1 2 ...]\n",
+    "\n",
+    "Eh?"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 2",
+   "language": "python",
+   "name": "python2"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 2
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython2",
+   "version": "2.7.12"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/docs/Types.md b/docs/Types.md
new file mode 100644 (file)
index 0000000..d1e2a6b
--- /dev/null
@@ -0,0 +1,1884 @@
+
+# Type Inference
+
+## Pöial's Rules
+
+["Typing Tools for Typeless Stack Languages" by Jaanus Pöial
+](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.212.6026)
+
+    @INPROCEEDINGS{Pöial06typingtools,
+        author = {Jaanus Pöial},
+        title = {Typing tools for typeless stack languages},
+        booktitle = {In 23rd Euro-Forth Conference},
+        year = {2006},
+        pages = {40--46}
+    }
+
+### First Rule
+This rule deals with functions (and literals) that put items on the stack `(-- d)`:
+
+
+       (a -- b)∘(-- d)
+    ---------------------
+         (a -- b d)
+
+### Second Rule
+This rule deals with functions that consume items from the stack `(a --)`:
+
+       (a --)∘(c -- d)
+    ---------------------
+         (c a -- d)
+
+### Third Rule
+The third rule is actually two rules.  These two rules deal with composing functions when the second one will consume one of items the first one produces.  The two types must be *unified* or a type conflict declared.
+
+       (a -- b t[i])∘(c u[j] -- d)   t <= u (t is subtype of u)
+    -------------------------------
+       (a -- b     )∘(c      -- d)   t[i] == t[k] == u[j]
+                                             ^
+
+       (a -- b t[i])∘(c u[j] -- d)   u <= t (u is subtype of t)
+    -------------------------------
+       (a -- b     )∘(c      -- d)   t[i] == u[k] == u[j]
+
+## Examples
+Let's work through some examples by hand to develop an intuition for the algorithm.
+
+There's a function in one of the other notebooks.
+
+    F == pop swap roll< rest rest cons cons
+
+It's all "stack chatter" and list manipulation so we should be able to deduce its type.
+
+### Stack Effect Comments
+Joy function types will be represented by Forth-style stack effect comments.  I'm going to use numbers instead of names to keep track of the stack arguments.  (A little bit like [De Bruijn index](https://en.wikipedia.org/wiki/De_Bruijn_index), at least it reminds me of them):
+
+    pop (1 --)
+
+    swap (1 2 -- 2 1)
+
+    roll< (1 2 3 -- 2 3 1)
+
+These commands alter the stack but don't "look at" the values so these numbers represent an "Any type".
+
+### `pop swap`
+
+    (1 --) (1 2 -- 2 1)
+    
+Here we encounter a complication. The argument numbers need to be made unique among both sides.   For this let's change `pop` to use 0:
+
+    (0 --) (1 2 -- 2 1)
+
+Following the second rule:
+    
+    (1 2 0 -- 2 1)
+
+### `pop∘swap roll<`
+
+    (1 2 0 -- 2 1) (1 2 3 -- 2 3 1)
+
+Let's re-label them:
+
+    (1a 2a 0a -- 2a 1a) (1b 2b 3b -- 2b 3b 1b)
+
+Now we follow the rules.
+
+We must unify `1a` and `3b`, and `2a` and `2b`, replacing the terms in the forms:
+
+    (1a 2a 0a -- 2a 1a) (1b 2b 3b -- 2b 3b 1b)
+                                                w/  {1a: 3b}
+    (3b 2a 0a -- 2a   ) (1b 2b    -- 2b 3b 1b)
+                                                w/  {2a: 2b}
+    (3b 2b 0a --      ) (1b       -- 2b 3b 1b)
+
+Here we must apply the second rule:
+
+       (3b 2b 0a --) (1b -- 2b 3b 1b)
+    -----------------------------------
+         (1b 3b 2b 0a -- 2b 3b 1b)
+
+Now we de-label the type, uh, labels:
+
+    (1b 3b 2b 0a -- 2b 3b 1b)
+
+    w/ {
+        1b: 1,
+        3b: 2,
+        2b: 3,
+        0a: 0,
+        }
+
+    (1 2 3 0 -- 3 2 1)
+
+And now we have the stack effect comment for `pop∘swap∘roll<`.
+
+### Compiling `pop∘swap∘roll<`
+The simplest way to "compile" this function would be something like:
+
+
+```python
+def poswrd(s, e, d):
+    return roll_down(*swap(*pop(s, e, d)))
+```
+
+However, internally this function would still be allocating tuples (stack cells) and doing other unnecesssary work.
+
+Looking ahead for a moment, from the stack effect comment:
+
+    (1 2 3 0 -- 3 2 1)
+
+We should be able to directly write out a Python function like:
+
+
+```python
+def poswrd(stack):
+    (_, (a, (b, (c, stack)))) = stack
+    return (c, (b, (a, stack)))
+```
+
+This eliminates the internal work of the first version.  Because this function only rearranges the stack and doesn't do any actual processing on the stack items themselves all the information needed to implement it is in the stack effect comment.
+
+### Functions on Lists
+These are slightly tricky.
+
+    rest ( [1 ...] -- [...] )
+
+    cons ( 1 [...] -- [1 ...] )
+
+### `pop∘swap∘roll< rest`
+
+    (1 2 3 0 -- 3 2 1) ([1 ...] -- [...])
+
+Re-label (instead of adding left and right tags I'm just taking the next available index number for the right-side stack effect comment):
+
+    (1 2 3 0 -- 3 2 1) ([4 ...] -- [...])
+
+Unify and update:
+
+    (1       2 3 0 -- 3 2 1) ([4 ...] -- [...])
+                                                 w/ {1: [4 ...]}
+    ([4 ...] 2 3 0 -- 3 2  ) (        -- [...])
+
+Apply the first rule:
+
+       ([4 ...] 2 3 0 -- 3 2) (-- [...])
+    ---------------------------------------
+         ([4 ...] 2 3 0 -- 3 2 [...])
+
+And there we are.
+
+### `pop∘swap∘roll<∘rest rest`
+
+Let's do it again.
+
+    ([4 ...] 2 3 0 -- 3 2 [...]) ([1 ...] -- [...])
+
+Re-label (the tails of the lists on each side each get their own label):
+
+    ([4 .0.] 2 3 0 -- 3 2 [.0.]) ([5 .1.] -- [.1.])
+
+Unify and update (note the opening square brackets have been omited in the substitution dict, this is deliberate and I'll explain below):
+
+    ([4 .0.]   2 3 0 -- 3 2 [.0.]  ) ([5 .1.] -- [.1.])
+                                                        w/ { .0.] : 5 .1.] }
+    ([4 5 .1.] 2 3 0 -- 3 2 [5 .1.]) ([5 .1.] -- [.1.])
+
+How do we find `.0.]` in `[4 .0.]` and replace it with `5 .1.]` getting the result `[4 5 .1.]`?  This might seem hard, but because the underlying structure of the Joy list is a cons-list in Python it's actually pretty easy.  I'll explain below.
+
+Next we unify and find our two terms are the same already: `[5 .1.]`:
+
+    ([4 5 .1.] 2 3 0 -- 3 2 [5 .1.]) ([5 .1.] -- [.1.])
+
+Giving us:
+
+    ([4 5 .1.] 2 3 0 -- 3 2) (-- [.1.])
+
+From here we apply the first rule and get:
+
+    ([4 5 .1.] 2 3 0 -- 3 2 [.1.])
+
+Cleaning up the labels:
+
+    ([4 5 ...] 2 3 1 -- 3 2 [...])
+
+This is the stack effect of `pop∘swap∘roll<∘rest∘rest`.
+
+### `pop∘swap∘roll<∘rest∘rest cons`
+
+    ([4 5 ...] 2 3 1 -- 3 2 [...]) (1 [...] -- [1 ...])
+
+Re-label:
+
+    ([4 5 .1.] 2 3 1 -- 3 2 [.1.]) (6 [.2.] -- [6 .2.])
+
+Unify:
+
+    ([4 5 .1.] 2 3 1 -- 3 2 [.1.]) (6 [.2.] -- [6 .2.])
+                                                         w/ { .1.] : .2.] }
+    ([4 5 .2.] 2 3 1 -- 3 2      ) (6       -- [6 .2.])
+                                                         w/ {2: 6}
+    ([4 5 .2.] 6 3 1 -- 3        ) (        -- [6 .2.])
+
+First rule:
+
+    ([4 5 .2.] 6 3 1 -- 3 [6 .2.])
+
+Re-label:
+
+    ([4 5 ...] 2 3 1 -- 3 [2 ...])
+
+Done.
+
+### `pop∘swap∘roll<∘rest∘rest∘cons cons`
+One more time.
+
+    ([4 5 ...] 2 3 1 -- 3 [2 ...]) (1 [...] -- [1 ...])
+
+Re-label:
+
+    ([4 5 .1.] 2 3 1 -- 3 [2 .1.]) (6 [.2.] -- [6 .2.])
+
+Unify:
+
+    ([4 5 .1.] 2 3 1 -- 3 [2 .1.]) (6 [.2.] -- [6 .2.]  )
+                                                           w/ { .2.] : 2 .1.] }
+    ([4 5 .1.] 2 3 1 -- 3        ) (6       -- [6 2 .1.])
+                                                           w/ {3: 6}
+    ([4 5 .1.] 2 6 1 --          ) (        -- [6 2 .1.])
+
+First or second rule:
+
+    ([4 5 .1.] 2 6 1 -- [6 2 .1.])
+
+Clean up the labels:
+
+    ([4 5 ...] 2 3 1 -- [3 2 ...])
+
+And there you have it, the stack effect for `pop∘swap∘roll<∘rest∘rest∘cons∘cons`.
+
+    ([4 5 ...] 2 3 1 -- [3 2 ...])
+
+From this stack effect comment it should be possible to construct the following Python code:
+
+
+```python
+def F(stack):
+    (_, (d, (c, ((a, (b, S0)), stack)))) = stack
+    return (d, (c, S0)), stack
+```
+
+## Implementation
+
+### Representing Stack Effect Comments in Python
+
+I'm going to use pairs of tuples of type descriptors, which will be integers or tuples of type descriptors:
+
+
+```python
+roll_dn = (1, 2, 3), (2, 3, 1)
+
+pop = (1,), ()
+
+swap = (1, 2), (2, 1)
+```
+
+### `compose()`
+
+
+```python
+def compose(f, g):
+
+    (f_in, f_out), (g_in, g_out) = f, g
+
+    # First rule.
+    #
+    #       (a -- b) (-- d)
+    #    ---------------------
+    #         (a -- b d)
+
+    if not g_in:
+
+        fg_in, fg_out = f_in, f_out + g_out
+
+    # Second rule.
+    #
+    #       (a --) (c -- d)
+    #    ---------------------
+    #         (c a -- d)
+
+    elif not f_out:
+
+        fg_in, fg_out = g_in + f_in, g_out
+
+    else: # Unify, update, recur.
+
+        fo, gi = f_out[-1], g_in[-1]
+
+        s = unify(gi, fo)
+
+        if s == False:  # s can also be the empty dict, which is ok.
+            raise TypeError('Cannot unify %r and %r.' % (fo, gi))
+
+        f_g = (f_in, f_out[:-1]), (g_in[:-1], g_out)
+
+        if s: f_g = update(s, f_g)
+
+        fg_in, fg_out = compose(*f_g)
+
+    return fg_in, fg_out
+```
+
+### `unify()`
+
+
+```python
+def unify(u, v, s=None):
+    if s is None:
+        s = {}
+
+    if u == v:
+        return s
+
+    if isinstance(u, int):
+        s[u] = v
+        return s
+
+    if isinstance(v, int):
+        s[v] = u
+        return s
+
+    return False
+```
+
+### `update()`
+
+
+```python
+def update(s, term):
+    if not isinstance(term, tuple):
+        return s.get(term, term)
+    return tuple(update(s, inner) for inner in term)
+```
+
+### `relabel()`
+
+
+```python
+def relabel(left, right):
+    return left, _1000(right)
+
+def _1000(right):
+    if not isinstance(right, tuple):
+        return 1000 + right
+    return tuple(_1000(n) for n in right)
+
+relabel(pop, swap)
+```
+
+
+
+
+    (((1,), ()), ((1001, 1002), (1002, 1001)))
+
+
+
+### `delabel()`
+
+
+```python
+def delabel(f):
+    s = {u: i for i, u in enumerate(sorted(_unique(f)))}
+    return update(s, f)
+
+def _unique(f, seen=None):
+    if seen is None:
+        seen = set()
+    if not isinstance(f, tuple):
+        seen.add(f)
+    else:
+        for inner in f:
+            _unique(inner, seen)
+    return seen
+
+delabel(relabel(pop, swap))
+```
+
+
+
+
+    (((0,), ()), ((1, 2), (2, 1)))
+
+
+
+### `C()`
+
+At last we put it all together in a function `C()` that accepts two stack effect comments and returns their composition (or raises and exception if they can't be composed due to type conflicts.)
+
+
+```python
+def C(f, g):
+    f, g = relabel(f, g)
+    fg = compose(f, g)
+    return delabel(fg)
+```
+
+Let's try it out.
+
+
+```python
+C(pop, swap)
+```
+
+
+
+
+    ((1, 2, 0), (2, 1))
+
+
+
+
+```python
+C(C(pop, swap), roll_dn)
+```
+
+
+
+
+    ((3, 1, 2, 0), (2, 1, 3))
+
+
+
+
+```python
+C(swap, roll_dn)
+```
+
+
+
+
+    ((2, 0, 1), (1, 0, 2))
+
+
+
+
+```python
+C(pop, C(swap, roll_dn))
+```
+
+
+
+
+    ((3, 1, 2, 0), (2, 1, 3))
+
+
+
+
+```python
+poswrd = reduce(C, (pop, swap, roll_dn))
+poswrd
+```
+
+
+
+
+    ((3, 1, 2, 0), (2, 1, 3))
+
+
+
+### List Functions
+Here's that trick to represent functions like `rest` and `cons` that manipulate lists.  We use a cons-list of tuples and give the tails their own numbers.  Then everything above already works. 
+
+
+```python
+rest = ((1, 2),), (2,)
+
+cons = (1, 2), ((1, 2),)
+```
+
+
+```python
+C(poswrd, rest)
+```
+
+
+
+
+    (((3, 4), 1, 2, 0), (2, 1, 4))
+
+
+
+Compare this to the stack effect comment we wrote above:
+
+    ((  (3, 4), 1, 2, 0 ), ( 2, 1,   4  ))
+    (   [4 ...] 2  3  0  --  3  2  [...])
+
+The translation table, if you will, would be:
+
+    {
+    3: 4,
+    4: ...],
+    1: 2,
+    2: 3,
+    0: 0,
+    }
+
+
+```python
+F = reduce(C, (pop, swap, roll_dn, rest, rest, cons, cons))
+
+F
+```
+
+
+
+
+    (((3, (4, 5)), 1, 2, 0), ((2, (1, 5)),))
+
+
+
+Compare with the stack effect comment and you can see it works fine:
+
+    ([4 5 ...] 2 3 1 -- [3 2 ...])
+
+### Dealing with `cons` and `uncons`
+However, if we try to compose e.g. `cons` and `uncons` it won't work:
+
+
+```python
+uncons = ((1, 2),), (1, 2)
+```
+
+
+```python
+try:
+    C(cons, uncons)
+except Exception, e:
+    print e
+```
+
+    Cannot unify (1, 2) and (1001, 1002).
+
+
+#### `unify()` version 2
+The problem is that the `unify()` function as written doesn't handle the case when both terms are tuples.  We just have to add a clause to deal with this recursively:
+
+
+```python
+def unify(u, v, s=None):
+    if s is None:
+        s = {}
+    else:
+        u = update(s, u)
+        v = update(s, v)
+
+    if u == v:
+        return s
+
+    if isinstance(u, int):
+        s[u] = v
+        return s
+
+    if isinstance(v, int):
+        s[v] = u
+        return s
+
+    if isinstance(u, tuple) and isinstance(v, tuple):
+        if len(u) != len(v) != 2:
+            raise ValueError(repr((u, v)))
+        for uu, vv in zip(u, v):
+            s = unify(uu, vv, s)
+            if s == False: # (instead of a substitution dict.)
+                break
+        return s
+    return False
+```
+
+
+```python
+C(cons, uncons)
+```
+
+
+
+
+    ((0, 1), (0, 1))
+
+
+
+## Compiling
+Now consider the Python function we would like to derive:
+
+
+```python
+def F_python(stack):
+    (_, (d, (c, ((a, (b, S0)), stack)))) = stack
+    return (d, (c, S0)), stack
+```
+
+And compare it to the input stack effect comment tuple we just computed:
+
+
+```python
+F[0]
+```
+
+
+
+
+    ((3, (4, 5)), 1, 2, 0)
+
+
+
+The stack-de-structuring tuple has nearly the same form as our input stack effect comment tuple, just in the reverse order:
+
+    (_, (d, (c, ((a, (b, S0)), stack))))
+
+Remove the punctuation:
+
+     _   d   c   (a, (b, S0))
+
+Reverse the order and compare:
+
+     (a, (b, S0))   c   d   _
+    ((3, (4, 5 )),  1,  2,  0)
+
+Eh?
+
+And the return tuple 
+
+
+```python
+F[1]
+```
+
+
+
+
+    ((2, (1, 5)),)
+
+
+
+is similar to the output stack effect comment tuple:
+
+    ((d, (c, S0)), stack)
+    ((2, (1, 5 )),      )
+
+This should make it pretty easy to write a Python function that accepts the stack effect comment tuples and returns a new Python function (either as a string of code or a function object ready to use) that performs the semantics of that Joy function (described by the stack effect.)
+
+### Python Identifiers
+We want to substitute Python identifiers for the integers.  I'm going to repurpose `joy.parser.Symbol` class for this:
+
+
+```python
+from collections import defaultdict
+from joy.parser import Symbol
+
+
+def _names_for():
+    I = iter(xrange(1000))
+    return lambda: Symbol('a%i' % next(I))
+
+
+def identifiers(term, s=None):
+    if s is None:
+        s = defaultdict(_names_for())
+    if isinstance(term, int):
+        return s[term]
+    return tuple(identifiers(inner, s) for inner in term)
+```
+
+### `doc_from_stack_effect()`
+As a convenience I've implemented a function to convert the Python stack effect comment tuples to reasonable text format.  There are some details in how this code works that related to stuff later in the notebook, so you should skip it for now and read it later if you're interested.
+
+
+```python
+def doc_from_stack_effect(inputs, outputs):
+    return '(%s--%s)' % (
+        ' '.join(map(_to_str, inputs + ('',))),
+        ' '.join(map(_to_str, ('',) + outputs))
+    )
+
+
+def _to_str(term):
+    if not isinstance(term, tuple):
+        try:
+            t = term.prefix == 's'
+        except AttributeError:
+            return str(term)
+        return '[.%i.]' % term.number if t else str(term)
+
+    a = []
+    while term and isinstance(term, tuple):
+        item, term = term
+        a.append(_to_str(item))
+
+    try:
+        n = term.number
+    except AttributeError:
+        n = term
+    else:
+        if term.prefix != 's':
+            raise ValueError('Stack label: %s' % (term,))
+
+    a.append('.%s.' % (n,))
+    return '[%s]' % ' '.join(a)
+```
+
+### `compile_()`
+Now we can write a compiler function to emit Python source code.  (The underscore suffix distiguishes it from the built-in `compile()` function.)
+
+
+```python
+def compile_(name, f, doc=None):
+    if doc is None:
+        doc = doc_from_stack_effect(*f)
+    inputs, outputs = identifiers(f)
+    i = o = Symbol('stack')
+    for term in inputs:
+        i = term, i
+    for term in outputs:
+        o = term, o
+    return '''def %s(stack):
+    """%s"""
+    %s = stack
+    return %s''' % (name, doc, i, o)
+```
+
+Here it is in action:
+
+
+```python
+source = compile_('F', F)
+
+print source
+```
+
+    def F(stack):
+        """([3 4 .5.] 1 2 0 -- [2 1 .5.])"""
+        (a5, (a4, (a3, ((a0, (a1, a2)), stack)))) = stack
+        return ((a4, (a3, a2)), stack)
+
+
+Compare:
+
+
+```python
+def F_python(stack):
+    (_, (d, (c, ((a, (b, S0)), stack)))) = stack
+    return ((d, (c, S0)), stack)
+```
+
+Next steps:
+
+
+```python
+L = {}
+
+eval(compile(source, '__main__', 'single'), {}, L)
+
+L['F']
+```
+
+
+
+
+    <function F>
+
+
+
+Let's try it out:
+
+
+```python
+from notebook_preamble import D, J, V
+from joy.library import SimpleFunctionWrapper
+```
+
+
+```python
+D['F'] = SimpleFunctionWrapper(L['F'])
+```
+
+
+```python
+J('[4 5 ...] 2 3 1 F')
+```
+
+    [3 2 ...]
+
+
+With this, we have a partial Joy compiler that works on the subset of Joy functions that manipulate stacks (both what I call "stack chatter" and the ones that manipulate stacks on the stack.)
+
+I'm probably going to modify the definition wrapper code to detect definitions that can be compiled by this partial compiler and do it automatically.  It might be a reasonable idea to detect sequences of compilable functions in definitions that have uncompilable functions in them and just compile those.  However, if your library is well-factored this might be less helpful.
+
+### Compiling Library Functions
+We can use `compile_()` to generate many primitives in the library from their stack effect comments:
+
+
+```python
+def defs():
+
+    roll_down = (1, 2, 3), (2, 3, 1)
+
+    roll_up = (1, 2, 3), (3, 1, 2)
+
+    pop = (1,), ()
+
+    swap = (1, 2), (2, 1)
+
+    rest = ((1, 2),), (2,)
+    
+    rrest = C(rest, rest)
+
+    cons = (1, 2), ((1, 2),)
+
+    uncons = ((1, 2),), (1, 2)
+    
+    swons = C(swap, cons)
+
+    return locals()
+```
+
+
+```python
+for name, stack_effect_comment in sorted(defs().items()):
+    print
+    print compile_(name, stack_effect_comment)
+    print
+```
+
+    
+    def cons(stack):
+        """(1 2 -- [1 .2.])"""
+        (a1, (a0, stack)) = stack
+        return ((a0, a1), stack)
+    
+    
+    def pop(stack):
+        """(1 --)"""
+        (a0, stack) = stack
+        return stack
+    
+    
+    def rest(stack):
+        """([1 .2.] -- 2)"""
+        ((a0, a1), stack) = stack
+        return (a1, stack)
+    
+    
+    def roll_down(stack):
+        """(1 2 3 -- 2 3 1)"""
+        (a2, (a1, (a0, stack))) = stack
+        return (a0, (a2, (a1, stack)))
+    
+    
+    def roll_up(stack):
+        """(1 2 3 -- 3 1 2)"""
+        (a2, (a1, (a0, stack))) = stack
+        return (a1, (a0, (a2, stack)))
+    
+    
+    def rrest(stack):
+        """([0 1 .2.] -- 2)"""
+        ((a0, (a1, a2)), stack) = stack
+        return (a2, stack)
+    
+    
+    def swap(stack):
+        """(1 2 -- 2 1)"""
+        (a1, (a0, stack)) = stack
+        return (a0, (a1, stack))
+    
+    
+    def swons(stack):
+        """(0 1 -- [1 .0.])"""
+        (a1, (a0, stack)) = stack
+        return ((a1, a0), stack)
+    
+    
+    def uncons(stack):
+        """([1 .2.] -- 1 2)"""
+        ((a0, a1), stack) = stack
+        return (a1, (a0, stack))
+    
+
+
+## Types and Subtypes of Arguments
+So far we have dealt with types of functions, those dealing with simple stack manipulation.  Let's extend our machinery to deal with types of arguments.
+
+### "Number" Type
+
+Consider the definition of `sqr`:
+
+    sqr == dup mul
+
+
+The `dup` function accepts one *anything* and returns two of that:
+
+    dup (1 -- 1 1)
+
+And `mul` accepts two "numbers" (we're ignoring ints vs. floats vs. complex, etc., for now) and returns just one:
+
+    mul (n n -- n)
+
+So we're composing:
+
+    (1 -- 1 1)∘(n n -- n)
+
+The rules say we unify 1 with `n`:
+
+       (1 -- 1 1)∘(n n -- n)
+    ---------------------------  w/  {1: n}
+       (1 -- 1  )∘(n   -- n)
+
+This involves detecting that "Any type" arguments can accept "numbers".  If we were composing these functions the other way round this is still the case:
+
+       (n n -- n)∘(1 -- 1 1)
+    ---------------------------  w/  {1: n}
+       (n n --  )∘(  -- n n) 
+
+The important thing here is that the mapping is going the same way in both cases, from the "any" integer to the number
+
+### Distinguishing Numbers
+We should also mind that the number that `mul` produces is not (necessarily) the same as either of its inputs, which are not (necessarily) the same as each other:
+
+    mul (n2 n1 -- n3)
+
+
+       (1  -- 1  1)∘(n2 n1 -- n3)
+    --------------------------------  w/  {1: n2}
+       (n2 -- n2  )∘(n2    -- n3)
+
+
+       (n2 n1 -- n3)∘(1 -- 1  1 )
+    --------------------------------  w/  {1: n3}
+       (n2 n1 --   )∘(  -- n3 n3) 
+
+
+
+### Distinguishing Types
+So we need separate domains of "any" numbers and "number" numbers, and we need to be able to ask the order of these domains.  Now the notes on the right side of rule three make more sense, eh?
+
+       (a -- b t[i])∘(c u[j] -- d)   t <= u (t is subtype of u)
+    -------------------------------
+       (a -- b     )∘(c      -- d)   t[i] == t[k] == u[j]
+                                             ^
+
+       (a -- b t[i])∘(c u[j] -- d)   u <= t (u is subtype of t)
+    -------------------------------
+       (a -- b     )∘(c      -- d)   t[i] == u[k] == u[j]
+
+The indices `i`, `k`, and `j` are the number part of our labels and `t` and `u` are the domains.
+
+By creative use of Python's "double underscore" methods we can define a Python class hierarchy of Joy types and use the `issubclass()` method to establish domain ordering, as well as other handy behaviour that will make it fairly easy to reuse most of the code above.
+
+
+```python
+class AnyJoyType(object):
+
+    prefix = 'a'
+
+    def __init__(self, number):
+        self.number = number
+
+    def __repr__(self):
+        return self.prefix + str(self.number)
+
+    def __eq__(self, other):
+        return (
+            isinstance(other, self.__class__)
+            and other.prefix == self.prefix
+            and other.number == self.number
+        )
+
+    def __ge__(self, other):
+        return issubclass(other.__class__, self.__class__)
+
+    def __add__(self, other):
+        return self.__class__(self.number + other)
+    __radd__ = __add__
+    
+    def __hash__(self):
+        return hash(repr(self))
+
+
+class NumberJoyType(AnyJoyType): prefix = 'n'
+class FloatJoyType(NumberJoyType): prefix = 'f'
+class IntJoyType(FloatJoyType): prefix = 'i'
+
+
+class StackJoyType(AnyJoyType):
+    prefix = 's'
+
+
+_R = range(10)
+A = map(AnyJoyType, _R)
+N = map(NumberJoyType, _R)
+S = map(StackJoyType, _R)
+```
+
+Mess with it a little:
+
+
+```python
+from itertools import permutations
+```
+
+"Any" types can be specialized to numbers and stacks, but not vice versa:
+
+
+```python
+for a, b in permutations((A[0], N[0], S[0]), 2):
+    print a, '>=', b, '->', a >= b
+```
+
+    a0 >= n0 -> True
+    a0 >= s0 -> True
+    n0 >= a0 -> False
+    n0 >= s0 -> False
+    s0 >= a0 -> False
+    s0 >= n0 -> False
+
+
+Our crude [Numerical Tower](https://en.wikipedia.org/wiki/Numerical_tower) of *numbers* > *floats* > *integers* works as well (but we're not going to use it yet):
+
+
+```python
+for a, b in permutations((A[0], N[0], FloatJoyType(0), IntJoyType(0)), 2):
+    print a, '>=', b, '->', a >= b
+```
+
+    a0 >= n0 -> True
+    a0 >= f0 -> True
+    a0 >= i0 -> True
+    n0 >= a0 -> False
+    n0 >= f0 -> True
+    n0 >= i0 -> True
+    f0 >= a0 -> False
+    f0 >= n0 -> False
+    f0 >= i0 -> True
+    i0 >= a0 -> False
+    i0 >= n0 -> False
+    i0 >= f0 -> False
+
+
+### Typing `sqr`
+
+
+```python
+dup = (A[1],), (A[1], A[1])
+
+mul = (N[1], N[2]), (N[3],)
+```
+
+
+```python
+dup
+```
+
+
+
+
+    ((a1,), (a1, a1))
+
+
+
+
+```python
+mul
+```
+
+
+
+
+    ((n1, n2), (n3,))
+
+
+
+### Modifying the Inferencer
+Re-labeling still works fine:
+
+
+```python
+foo = relabel(dup, mul)
+
+foo
+```
+
+
+
+
+    (((a1,), (a1, a1)), ((n1001, n1002), (n1003,)))
+
+
+
+#### `delabel()` version 2
+The `delabel()` function needs an overhaul.  It now has to keep track of how many labels of each domain it has "seen".
+
+
+```python
+from collections import Counter
+
+
+def delabel(f, seen=None, c=None):
+    if seen is None:
+        assert c is None
+        seen, c = {}, Counter()
+
+    try:
+        return seen[f]
+    except KeyError:
+        pass
+
+    if not isinstance(f, tuple):
+        seen[f] = f.__class__(c[f.prefix])
+        c[f.prefix] += 1
+        return seen[f]
+
+    return tuple(delabel(inner, seen, c) for inner in f)
+```
+
+
+```python
+delabel(foo)
+```
+
+
+
+
+    (((a0,), (a0, a0)), ((n0, n1), (n2,)))
+
+
+
+#### `unify()` version 3
+
+
+```python
+def unify(u, v, s=None):
+    if s is None:
+        s = {}
+    else:
+        u = update(s, u)
+        v = update(s, v)
+
+    if u == v:
+        return s
+
+    if isinstance(u, AnyJoyType) and isinstance(v, AnyJoyType):
+        if u >= v:
+            s[u] = v
+            return s
+        if v >= u:
+            s[v] = u
+            return s
+        raise ValueError('Cannot unify %r and %r.' % (u, v))
+
+    if isinstance(u, tuple) and isinstance(v, tuple):
+        if len(u) != len(v) != 2:
+            raise ValueError(repr((u, v)))
+        for uu, vv in zip(u, v):
+            s = unify(uu, vv, s)
+            if s == False: # (instead of a substitution dict.)
+                break
+        return s
+    if isinstance(v, tuple):
+        if not stacky(u):
+            raise ValueError('Cannot unify %r and %r.' % (u, v))
+        s[u] = v
+        return s
+
+    if isinstance(u, tuple):
+        if not stacky(v):
+            raise ValueError('Cannot unify %r and %r.' % (v, u))
+        s[v] = u
+        return s
+
+    return False
+
+
+def stacky(thing):
+    return thing.__class__ in {AnyJoyType, StackJoyType}
+```
+
+Rewrite the stack effect comments:
+
+
+```python
+def defs():
+
+    roll_down = (A[1], A[2], A[3]), (A[2], A[3], A[1])
+
+    roll_up = (A[1], A[2], A[3]), (A[3], A[1], A[2])
+
+    pop = (A[1],), ()
+
+    popop = (A[2], A[1],), ()
+
+    popd = (A[2], A[1],), (A[1],)
+
+    popdd = (A[3], A[2], A[1],), (A[2], A[1],)
+
+    swap = (A[1], A[2]), (A[2], A[1])
+
+    rest = ((A[1], S[1]),), (S[1],)
+
+    rrest = C(rest, rest)
+
+    cons = (A[1], S[1]), ((A[1], S[1]),)
+
+    ccons = C(cons, cons)
+
+    uncons = ((A[1], S[1]),), (A[1], S[1])
+
+    swons = C(swap, cons)
+
+    dup = (A[1],), (A[1], A[1])
+
+    dupd = (A[2], A[1]), (A[2], A[2], A[1])
+
+    mul = (N[1], N[2]), (N[3],)
+    
+    sqrt = C(dup, mul)
+
+    first = ((A[1], S[1]),), (A[1],)
+
+    second = C(rest, first)
+
+    third = C(rest, second)
+
+    tuck = (A[2], A[1]), (A[1], A[2], A[1])
+
+    over = (A[2], A[1]), (A[2], A[1], A[2])
+    
+    succ = pred = (N[1],), (N[2],)
+    
+    divmod_ = pm = (N[2], N[1]), (N[4], N[3])
+
+    return locals()
+```
+
+
+```python
+DEFS = defs()
+```
+
+
+```python
+for name, stack_effect_comment in sorted(DEFS.items()):
+    print name, '=', doc_from_stack_effect(*stack_effect_comment)
+```
+
+    ccons = (a0 a1 [.0.] -- [a0 a1 .0.])
+    cons = (a1 [.1.] -- [a1 .1.])
+    divmod_ = (n2 n1 -- n4 n3)
+    dup = (a1 -- a1 a1)
+    dupd = (a2 a1 -- a2 a2 a1)
+    first = ([a1 .1.] -- a1)
+    mul = (n1 n2 -- n3)
+    over = (a2 a1 -- a2 a1 a2)
+    pm = (n2 n1 -- n4 n3)
+    pop = (a1 --)
+    popd = (a2 a1 -- a1)
+    popdd = (a3 a2 a1 -- a2 a1)
+    popop = (a2 a1 --)
+    pred = (n1 -- n2)
+    rest = ([a1 .1.] -- [.1.])
+    roll_down = (a1 a2 a3 -- a2 a3 a1)
+    roll_up = (a1 a2 a3 -- a3 a1 a2)
+    rrest = ([a0 a1 .0.] -- [.0.])
+    second = ([a0 a1 .0.] -- a1)
+    sqrt = (n0 -- n1)
+    succ = (n1 -- n2)
+    swap = (a1 a2 -- a2 a1)
+    swons = ([.0.] a0 -- [a0 .0.])
+    third = ([a0 a1 a2 .0.] -- a2)
+    tuck = (a2 a1 -- a1 a2 a1)
+    uncons = ([a1 .1.] -- a1 [.1.])
+
+
+
+```python
+globals().update(DEFS)
+```
+
+#### Compose `dup` and `mul`
+
+
+```python
+C(dup, mul)
+```
+
+
+
+
+    ((n0,), (n1,))
+
+
+
+Revisit the `F` function, works fine.
+
+
+```python
+F = reduce(C, (pop, swap, roll_down, rest, rest, cons, cons))
+F
+```
+
+
+
+
+    (((a0, (a1, s0)), a2, a3, a4), ((a3, (a2, s0)),))
+
+
+
+
+```python
+print doc_from_stack_effect(*F)
+```
+
+    ([a0 a1 .0.] a2 a3 a4 -- [a3 a2 .0.])
+
+
+Some otherwise inefficient functions are no longer to be feared.  We can also get the effect of combinators in some limited cases.
+
+
+```python
+def neato(*funcs):
+    print doc_from_stack_effect(*reduce(C, funcs))
+```
+
+
+```python
+# e.g. [swap] dip
+neato(roll_up, swap, roll_down)
+```
+
+    (a0 a1 a2 -- a1 a0 a2)
+
+
+
+```python
+# e.g. [popop] dip
+neato(popdd, roll_down, pop)
+```
+
+    (a0 a1 a2 a3 -- a2 a3)
+
+
+
+```python
+# Reverse the order of the top three items.
+neato(roll_up, swap)
+```
+
+    (a0 a1 a2 -- a2 a1 a0)
+
+
+#### `compile_()` version 2
+Because the type labels represent themselves as valid Python identifiers the `compile_()` function doesn't need to generate them anymore:
+
+
+```python
+def compile_(name, f, doc=None):
+    inputs, outputs = f
+    if doc is None:
+        doc = doc_from_stack_effect(inputs, outputs)
+    i = o = Symbol('stack')
+    for term in inputs:
+        i = term, i
+    for term in outputs:
+        o = term, o
+    return '''def %s(stack):
+    """%s"""
+    %s = stack
+    return %s''' % (name, doc, i, o)
+```
+
+
+```python
+print compile_('F', F)
+```
+
+    def F(stack):
+        """([a0 a1 .0.] a2 a3 a4 -- [a3 a2 .0.])"""
+        (a4, (a3, (a2, ((a0, (a1, s0)), stack)))) = stack
+        return ((a3, (a2, s0)), stack)
+
+
+But it cannot magically create new functions that involve e.g. math and such.  Note that this is *not* a `sqr` function implementation:
+
+
+```python
+print compile_('sqr', C(dup, mul))
+```
+
+    def sqr(stack):
+        """(n0 -- n1)"""
+        (n0, stack) = stack
+        return (n1, stack)
+
+
+#### `compilable()`
+The functions that *can* be compiled are the ones that have only `AnyJoyType` and `StackJoyType` labels in their stack effect comments.  We can write a function to check that:
+
+
+```python
+from itertools import imap
+
+
+def compilable(f):
+    return isinstance(f, tuple) and all(imap(compilable, f)) or stacky(f)
+```
+
+
+```python
+for name, stack_effect_comment in sorted(defs().items()):
+    if compilable(stack_effect_comment):
+        print name, '=', doc_from_stack_effect(*stack_effect_comment)
+```
+
+    ccons = (a0 a1 [.0.] -- [a0 a1 .0.])
+    cons = (a1 [.1.] -- [a1 .1.])
+    dup = (a1 -- a1 a1)
+    dupd = (a2 a1 -- a2 a2 a1)
+    first = ([a1 .1.] -- a1)
+    over = (a2 a1 -- a2 a1 a2)
+    pop = (a1 --)
+    popd = (a2 a1 -- a1)
+    popdd = (a3 a2 a1 -- a2 a1)
+    popop = (a2 a1 --)
+    rest = ([a1 .1.] -- [.1.])
+    roll_down = (a1 a2 a3 -- a2 a3 a1)
+    roll_up = (a1 a2 a3 -- a3 a1 a2)
+    rrest = ([a0 a1 .0.] -- [.0.])
+    second = ([a0 a1 .0.] -- a1)
+    swap = (a1 a2 -- a2 a1)
+    swons = ([.0.] a0 -- [a0 .0.])
+    third = ([a0 a1 a2 .0.] -- a2)
+    tuck = (a2 a1 -- a1 a2 a1)
+    uncons = ([a1 .1.] -- a1 [.1.])
+
+
+## Functions that use the Stack
+
+Consider the `stack` function which grabs the whole stack, quotes it, and puts it on itself:
+
+    stack (...     -- ... [...]        )
+    stack (... a   -- ... a [a ...]    )
+    stack (... b a -- ... b a [a b ...])
+
+We would like to represent this in Python somehow. 
+To do this we use a simple, elegant trick.
+
+    stack         S   -- (         S,           S)
+    stack     (a, S)  -- (     (a, S),      (a, S))
+    stack (a, (b, S)) -- ( (a, (b, S)), (a, (b, S)))
+
+Instead of representing the stack effect comments as a single tuple (with N items in it) we use the same cons-list structure to hold the sequence and `unify()` the whole comments.
+
+### `stack∘uncons`
+Let's try composing `stack` and `uncons`.  We want this result:
+
+    stack∘uncons (... a -- ... a a [...])
+
+The stack effects are:
+
+    stack = S -- (S, S)
+
+    uncons = ((a, Z), S) -- (Z, (a, S))
+
+Unifying:
+
+      S    -- (S, S) ∘ ((a, Z), S) -- (Z, (a,   S   ))
+                                                        w/ { S: (a, Z) }
+    (a, Z) --        ∘             -- (Z, (a, (a, Z)))
+
+So:
+
+    stack∘uncons == (a, Z) -- (Z, (a, (a, Z)))
+
+It works.
+
+### `stack∘uncons∘uncons`
+Let's try `stack∘uncons∘uncons`:
+
+    (a, S     ) -- (S,      (a, (a, S     ))) ∘ ((b, Z),  S`             ) -- (Z, (b,   S`   ))
+    
+                                                                                    w/ { S: (b, Z) }
+                                                                                    
+    (a, (b, Z)) -- ((b, Z), (a, (a, (b, Z)))) ∘ ((b, Z),  S`             ) -- (Z, (b,   S`   ))
+    
+                                                                                    w/ { S`: (a, (a, (b, Z))) }
+                                                                                    
+    (a, (b, Z)) -- ((b, Z), (a, (a, (b, Z)))) ∘ ((b, Z), (a, (a, (b, Z)))) -- (Z, (b, (a, (a, (b, Z)))))
+
+    (a, (b, Z)) -- (Z, (b, (a, (a, (b, Z)))))
+
+It works.
+
+#### `compose()` version 2
+This function has to be modified to use the new datastructures and it is no longer recursive, instead recursion happens as part of unification.
+
+
+```python
+def compose(f, g):
+
+    (f_in, f_out), (g_in, g_out) = f, g
+
+    if not g_in:
+        fg_in, fg_out = f_in, stack_concat(g_out, f_out)
+
+    elif not f_out:
+        fg_in, fg_out = stack_concat(f_in, g_in), g_out
+
+    else: # Unify and update.
+
+        s = unify(g_in, f_out)
+
+        if s == False:  # s can also be the empty dict, which is ok.
+            raise TypeError('Cannot unify %r and %r.' % (fo, gi))
+
+        fg_in, fg_out = update(s, (f_in, g_out))
+
+    return fg_in, fg_out
+
+
+stack_concat = lambda q, e: (q[0], stack_concat(q[1], e)) if q else e
+```
+
+I don't want to rewrite all the defs myself, so I'll write a little conversion function instead.  This is programmer's laziness.
+
+
+```python
+def sequence_to_stack(seq, stack=StackJoyType(23)):
+    for item in seq: stack = item, stack
+    return stack
+
+NEW_DEFS = {
+    name: (sequence_to_stack(i), sequence_to_stack(o))
+    for name, (i, o) in DEFS.iteritems()
+}
+
+globals().update(NEW_DEFS)
+```
+
+
+```python
+stack = S[0], (S[0], S[0])
+```
+
+
+```python
+C(stack, uncons)
+```
+
+
+
+
+    ((a0, s0), (s0, (a0, (a0, s0))))
+
+
+
+
+```python
+C(C(stack, uncons), uncons)
+```
+
+
+
+
+    ((a0, (a1, s0)), (s0, (a1, (a0, (a0, (a1, s0))))))
+
+
+
+The display function should be changed too.
+
+### `doc_from_stack_effect()` version 2
+Clunky junk, but it will suffice for now.
+
+
+```python
+def doc_from_stack_effect(inputs, outputs):
+    switch = [False]  # Do we need to display the '...' for the rest of the main stack?
+    i, o = _f(inputs, switch), _f(outputs, switch)
+    if switch[0]:
+        i.append('...')
+        o.append('...')
+    return '(%s--%s)' % (
+        ' '.join(reversed([''] + i)),
+        ' '.join(reversed(o + [''])),
+    )
+
+
+def _f(term, switch):
+    a = []
+    while term and isinstance(term, tuple):
+        item, term = term
+        a.append(item)
+    assert isinstance(term, StackJoyType), repr(term)
+    a = [_to_str(i, term, switch) for i in a]
+    return a
+
+
+def _to_str(term, stack, switch):
+    if not isinstance(term, tuple):
+        if term == stack:
+            switch[0] = True
+            return '[...]'
+        return (
+            '[.%i.]' % term.number
+            if isinstance(term, StackJoyType)
+            else str(term)
+        )
+
+    a = []
+    while term and isinstance(term, tuple):
+        item, term = term
+        a.append(_to_str(item, stack, switch))
+    assert isinstance(term, StackJoyType), repr(term)
+    if term == stack:
+        switch[0] = True
+        end = '...'
+    else:
+        end = '.%i.' % term.number
+    a.append(end)
+    return '[%s]' % ' '.join(a)
+```
+
+
+```python
+for name, stack_effect_comment in sorted(NEW_DEFS.items()):
+    print name, '=', doc_from_stack_effect(*stack_effect_comment)
+```
+
+    ccons = (a0 a1 [.0.] -- [a0 a1 .0.])
+    cons = (a1 [.1.] -- [a1 .1.])
+    divmod_ = (n2 n1 -- n4 n3)
+    dup = (a1 -- a1 a1)
+    dupd = (a2 a1 -- a2 a2 a1)
+    first = ([a1 .1.] -- a1)
+    mul = (n1 n2 -- n3)
+    over = (a2 a1 -- a2 a1 a2)
+    pm = (n2 n1 -- n4 n3)
+    pop = (a1 --)
+    popd = (a2 a1 -- a1)
+    popdd = (a3 a2 a1 -- a2 a1)
+    popop = (a2 a1 --)
+    pred = (n1 -- n2)
+    rest = ([a1 .1.] -- [.1.])
+    roll_down = (a1 a2 a3 -- a2 a3 a1)
+    roll_up = (a1 a2 a3 -- a3 a1 a2)
+    rrest = ([a0 a1 .0.] -- [.0.])
+    second = ([a0 a1 .0.] -- a1)
+    sqrt = (n0 -- n1)
+    succ = (n1 -- n2)
+    swap = (a1 a2 -- a2 a1)
+    swons = ([.0.] a0 -- [a0 .0.])
+    third = ([a0 a1 a2 .0.] -- a2)
+    tuck = (a2 a1 -- a1 a2 a1)
+    uncons = ([a1 .1.] -- a1 [.1.])
+
+
+
+```python
+print ; print doc_from_stack_effect(*stack)
+print ; print doc_from_stack_effect(*C(stack, uncons))
+print ; print doc_from_stack_effect(*C(C(stack, uncons), uncons))
+print ; print doc_from_stack_effect(*C(C(stack, uncons), cons))
+```
+
+    
+    (... -- ... [...])
+    
+    (... a0 -- ... a0 a0 [...])
+    
+    (... a1 a0 -- ... a1 a0 a0 a1 [...])
+    
+    (... a0 -- ... a0 [a0 ...])
+
+
+
+```python
+print doc_from_stack_effect(*C(ccons, stack))
+```
+
+    (... a1 a0 [.0.] -- ... [a1 a0 .0.] [[a1 a0 .0.] ...])
+
+
+
+```python
+Q = C(ccons, stack)
+
+Q
+```
+
+
+
+
+    ((s0, (a0, (a1, s1))), (((a1, (a0, s0)), s1), ((a1, (a0, s0)), s1)))
+
+
+
+#### `compile_()` version 3
+This makes the `compile_()` function pretty simple as the stack effect comments are now already in the form needed for the Python code:
+
+
+```python
+def compile_(name, f, doc=None):
+    i, o = f
+    if doc is None:
+        doc = doc_from_stack_effect(i, o)
+    return '''def %s(stack):
+    """%s"""
+    %s = stack
+    return %s''' % (name, doc, i, o)
+```
+
+
+```python
+print compile_('Q', Q)
+```
+
+    def Q(stack):
+        """(... a1 a0 [.0.] -- ... [a1 a0 .0.] [[a1 a0 .0.] ...])"""
+        (s0, (a0, (a1, s1))) = stack
+        return (((a1, (a0, s0)), s1), ((a1, (a0, s0)), s1))
+
+
+
+```python
+unstack = (S[1], S[0]), S[1]
+enstacken = S[0], (S[0], S[1])
+```
+
+
+```python
+print doc_from_stack_effect(*unstack)
+```
+
+    ([.1.] --)
+
+
+
+```python
+print doc_from_stack_effect(*enstacken)
+```
+
+    (-- [.0.])
+
+
+
+```python
+print doc_from_stack_effect(*C(cons, unstack))
+```
+
+    (a0 [.0.] -- a0)
+
+
+
+```python
+print doc_from_stack_effect(*C(cons, enstacken))
+```
+
+    (a0 [.0.] -- [[a0 .0.] .1.])
+
+
+
+```python
+C(cons, unstack)
+```
+
+
+
+
+    ((s0, (a0, s1)), (a0, s0))
+
+
+
+## Sets of Stack Effects
+...
+
+## `concat`
+
+How to deal with `concat`?
+
+    concat ([.0.] [.1.] -- [.0. .1.])
+    
+We would like to represent this in Python somehow...
+
+
+```python
+concat = (S[0], S[1]), ((S[0], S[1]),)
+```
+
+But this is actually `cons` with the first argument restricted to be a stack:
+
+    ([.0.] [.1.] -- [[.0.] .1.])
+
+What we have implemented so far would actually only permit:
+
+    ([.0.] [.1.] -- [.2.])
+
+
+```python
+concat = (S[0], S[1]), (S[2],)
+```
+
+    
+Which works but can lose information.  Consider `cons concat`, this is how much information we *could* retain:
+
+    (1 [.0.] [.1.] -- [1 .0. .1.])
+
+As opposed to just:
+
+    (1 [.0.] [.1.] -- [.2.])
+
+    
+Which works but can lose information.  Consider `cons concat`, this is how much information we *could* retain:
+
+    (1 [.0.] [.1.] -- [1 .0. .1.]) uncons uncons
+
+    (1 [.0.] [.1.] -- 1 [.0. .1.])        uncons
+                                                    So far so good...
+    (1 [2 .2.] [.1.] -- 1 2 [.2. .1.])
+
+
+
+
+    (1 [.0.] [.1.] -- 1 [.0. .1.]) ([a1 .10.] -- a1 [.10.])
+                                                             w/ { [a1 .10.] : [  .0.   .1.] }
+                                                           -or-
+                                                             w/ { [  .0.   .1.] : [a1 .10.    ] }
+
+
+
+
+
+
+
+## Typing Combinators
+
+TBD
+
+This is an open subject.
+
+The obvious thing is that you now need two pairs of tuples to describe the combinators' effects,  a stack effect comment and an expression effect comment:
+
+    dip (a [F] --)--(-- F a)
+
+One thing that might help is...
+
+## Abstract Interpretation
+
+## Something else...
+    [4 5 ...] 2 1 0 pop∘swap∘roll<∘rest∘rest∘cons∘cons
+    [4 5 ...] 2 1       swap∘roll<∘rest∘rest∘cons∘cons
+    [4 5 ...] 1 2            roll<∘rest∘rest∘cons∘cons
+    1 2 [4 5 ...]                  rest∘rest∘cons∘cons
+    1 2   [5 ...]                       rest∘cons∘cons
+    1 2     [...]                            cons∘cons
+    1     [2 ...]                                 cons
+        [1 2 ...]
+
+Eh?
diff --git a/docs/Types.rst b/docs/Types.rst
new file mode 100644 (file)
index 0000000..971fdfc
--- /dev/null
@@ -0,0 +1,2206 @@
+
+Type Inference
+==============
+
+Pöial's Rules
+-------------
+
+`"Typing Tools for Typeless Stack Languages" by Jaanus
+Pöial <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.212.6026>`__
+
+::
+
+    @INPROCEEDINGS{Pöial06typingtools,
+        author = {Jaanus Pöial},
+        title = {Typing tools for typeless stack languages},
+        booktitle = {In 23rd Euro-Forth Conference},
+        year = {2006},
+        pages = {40--46}
+    }
+
+First Rule
+~~~~~~~~~~
+
+This rule deals with functions (and literals) that put items on the
+stack ``(-- d)``:
+
+::
+
+       (a -- b)∘(-- d)
+    ---------------------
+         (a -- b d)
+
+Second Rule
+~~~~~~~~~~~
+
+This rule deals with functions that consume items from the stack
+``(a --)``:
+
+::
+
+       (a --)∘(c -- d)
+    ---------------------
+         (c a -- d)
+
+Third Rule
+~~~~~~~~~~
+
+The third rule is actually two rules. These two rules deal with
+composing functions when the second one will consume one of items the
+first one produces. The two types must be *unified* or a type conflict
+declared.
+
+::
+
+       (a -- b t[i])∘(c u[j] -- d)   t <= u (t is subtype of u)
+    -------------------------------
+       (a -- b     )∘(c      -- d)   t[i] == t[k] == u[j]
+                                             ^
+
+       (a -- b t[i])∘(c u[j] -- d)   u <= t (u is subtype of t)
+    -------------------------------
+       (a -- b     )∘(c      -- d)   t[i] == u[k] == u[j]
+
+Examples
+--------
+
+Let's work through some examples by hand to develop an intuition for the
+algorithm.
+
+There's a function in one of the other notebooks.
+
+::
+
+    F == pop swap roll< rest rest cons cons
+
+It's all "stack chatter" and list manipulation so we should be able to
+deduce its type.
+
+Stack Effect Comments
+~~~~~~~~~~~~~~~~~~~~~
+
+Joy function types will be represented by Forth-style stack effect
+comments. I'm going to use numbers instead of names to keep track of the
+stack arguments. (A little bit like `De Bruijn
+index <https://en.wikipedia.org/wiki/De_Bruijn_index>`__, at least it
+reminds me of them):
+
+::
+
+    pop (1 --)
+
+    swap (1 2 -- 2 1)
+
+    roll< (1 2 3 -- 2 3 1)
+
+These commands alter the stack but don't "look at" the values so these
+numbers represent an "Any type".
+
+``pop swap``
+~~~~~~~~~~~~
+
+::
+
+    (1 --) (1 2 -- 2 1)
+
+Here we encounter a complication. The argument numbers need to be made
+unique among both sides. For this let's change ``pop`` to use 0:
+
+::
+
+    (0 --) (1 2 -- 2 1)
+
+Following the second rule:
+
+::
+
+    (1 2 0 -- 2 1)
+
+``pop∘swap roll<``
+~~~~~~~~~~~~~~~~~~
+
+::
+
+    (1 2 0 -- 2 1) (1 2 3 -- 2 3 1)
+
+Let's re-label them:
+
+::
+
+    (1a 2a 0a -- 2a 1a) (1b 2b 3b -- 2b 3b 1b)
+
+Now we follow the rules.
+
+We must unify ``1a`` and ``3b``, and ``2a`` and ``2b``, replacing the
+terms in the forms:
+
+::
+
+    (1a 2a 0a -- 2a 1a) (1b 2b 3b -- 2b 3b 1b)
+                                                w/  {1a: 3b}
+    (3b 2a 0a -- 2a   ) (1b 2b    -- 2b 3b 1b)
+                                                w/  {2a: 2b}
+    (3b 2b 0a --      ) (1b       -- 2b 3b 1b)
+
+Here we must apply the second rule:
+
+::
+
+       (3b 2b 0a --) (1b -- 2b 3b 1b)
+    -----------------------------------
+         (1b 3b 2b 0a -- 2b 3b 1b)
+
+Now we de-label the type, uh, labels:
+
+::
+
+    (1b 3b 2b 0a -- 2b 3b 1b)
+
+    w/ {
+        1b: 1,
+        3b: 2,
+        2b: 3,
+        0a: 0,
+        }
+
+    (1 2 3 0 -- 3 2 1)
+
+And now we have the stack effect comment for ``pop∘swap∘roll<``.
+
+Compiling ``pop∘swap∘roll<``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The simplest way to "compile" this function would be something like:
+
+.. code:: ipython2
+
+    def poswrd(s, e, d):
+        return roll_down(*swap(*pop(s, e, d)))
+
+However, internally this function would still be allocating tuples
+(stack cells) and doing other unnecesssary work.
+
+Looking ahead for a moment, from the stack effect comment:
+
+::
+
+    (1 2 3 0 -- 3 2 1)
+
+We should be able to directly write out a Python function like:
+
+.. code:: ipython2
+
+    def poswrd(stack):
+        (_, (a, (b, (c, stack)))) = stack
+        return (c, (b, (a, stack)))
+
+This eliminates the internal work of the first version. Because this
+function only rearranges the stack and doesn't do any actual processing
+on the stack items themselves all the information needed to implement it
+is in the stack effect comment.
+
+Functions on Lists
+~~~~~~~~~~~~~~~~~~
+
+These are slightly tricky.
+
+::
+
+    rest ( [1 ...] -- [...] )
+
+    cons ( 1 [...] -- [1 ...] )
+
+``pop∘swap∘roll< rest``
+~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    (1 2 3 0 -- 3 2 1) ([1 ...] -- [...])
+
+Re-label (instead of adding left and right tags I'm just taking the next
+available index number for the right-side stack effect comment):
+
+::
+
+    (1 2 3 0 -- 3 2 1) ([4 ...] -- [...])
+
+Unify and update:
+
+::
+
+    (1       2 3 0 -- 3 2 1) ([4 ...] -- [...])
+                                                 w/ {1: [4 ...]}
+    ([4 ...] 2 3 0 -- 3 2  ) (        -- [...])
+
+Apply the first rule:
+
+::
+
+       ([4 ...] 2 3 0 -- 3 2) (-- [...])
+    ---------------------------------------
+         ([4 ...] 2 3 0 -- 3 2 [...])
+
+And there we are.
+
+``pop∘swap∘roll<∘rest rest``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Let's do it again.
+
+::
+
+    ([4 ...] 2 3 0 -- 3 2 [...]) ([1 ...] -- [...])
+
+Re-label (the tails of the lists on each side each get their own label):
+
+::
+
+    ([4 .0.] 2 3 0 -- 3 2 [.0.]) ([5 .1.] -- [.1.])
+
+Unify and update (note the opening square brackets have been omited in
+the substitution dict, this is deliberate and I'll explain below):
+
+::
+
+    ([4 .0.]   2 3 0 -- 3 2 [.0.]  ) ([5 .1.] -- [.1.])
+                                                        w/ { .0.] : 5 .1.] }
+    ([4 5 .1.] 2 3 0 -- 3 2 [5 .1.]) ([5 .1.] -- [.1.])
+
+How do we find ``.0.]`` in ``[4 .0.]`` and replace it with ``5 .1.]``
+getting the result ``[4 5 .1.]``? This might seem hard, but because the
+underlying structure of the Joy list is a cons-list in Python it's
+actually pretty easy. I'll explain below.
+
+Next we unify and find our two terms are the same already: ``[5 .1.]``:
+
+::
+
+    ([4 5 .1.] 2 3 0 -- 3 2 [5 .1.]) ([5 .1.] -- [.1.])
+
+Giving us:
+
+::
+
+    ([4 5 .1.] 2 3 0 -- 3 2) (-- [.1.])
+
+From here we apply the first rule and get:
+
+::
+
+    ([4 5 .1.] 2 3 0 -- 3 2 [.1.])
+
+Cleaning up the labels:
+
+::
+
+    ([4 5 ...] 2 3 1 -- 3 2 [...])
+
+This is the stack effect of ``pop∘swap∘roll<∘rest∘rest``.
+
+``pop∘swap∘roll<∘rest∘rest cons``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    ([4 5 ...] 2 3 1 -- 3 2 [...]) (1 [...] -- [1 ...])
+
+Re-label:
+
+::
+
+    ([4 5 .1.] 2 3 1 -- 3 2 [.1.]) (6 [.2.] -- [6 .2.])
+
+Unify:
+
+::
+
+    ([4 5 .1.] 2 3 1 -- 3 2 [.1.]) (6 [.2.] -- [6 .2.])
+                                                         w/ { .1.] : .2.] }
+    ([4 5 .2.] 2 3 1 -- 3 2      ) (6       -- [6 .2.])
+                                                         w/ {2: 6}
+    ([4 5 .2.] 6 3 1 -- 3        ) (        -- [6 .2.])
+
+First rule:
+
+::
+
+    ([4 5 .2.] 6 3 1 -- 3 [6 .2.])
+
+Re-label:
+
+::
+
+    ([4 5 ...] 2 3 1 -- 3 [2 ...])
+
+Done.
+
+``pop∘swap∘roll<∘rest∘rest∘cons cons``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+One more time.
+
+::
+
+    ([4 5 ...] 2 3 1 -- 3 [2 ...]) (1 [...] -- [1 ...])
+
+Re-label:
+
+::
+
+    ([4 5 .1.] 2 3 1 -- 3 [2 .1.]) (6 [.2.] -- [6 .2.])
+
+Unify:
+
+::
+
+    ([4 5 .1.] 2 3 1 -- 3 [2 .1.]) (6 [.2.] -- [6 .2.]  )
+                                                           w/ { .2.] : 2 .1.] }
+    ([4 5 .1.] 2 3 1 -- 3        ) (6       -- [6 2 .1.])
+                                                           w/ {3: 6}
+    ([4 5 .1.] 2 6 1 --          ) (        -- [6 2 .1.])
+
+First or second rule:
+
+::
+
+    ([4 5 .1.] 2 6 1 -- [6 2 .1.])
+
+Clean up the labels:
+
+::
+
+    ([4 5 ...] 2 3 1 -- [3 2 ...])
+
+And there you have it, the stack effect for
+``pop∘swap∘roll<∘rest∘rest∘cons∘cons``.
+
+::
+
+    ([4 5 ...] 2 3 1 -- [3 2 ...])
+
+From this stack effect comment it should be possible to construct the
+following Python code:
+
+.. code:: ipython2
+
+    def F(stack):
+        (_, (d, (c, ((a, (b, S0)), stack)))) = stack
+        return (d, (c, S0)), stack
+
+Implementation
+--------------
+
+Representing Stack Effect Comments in Python
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+I'm going to use pairs of tuples of type descriptors, which will be
+integers or tuples of type descriptors:
+
+.. code:: ipython2
+
+    roll_dn = (1, 2, 3), (2, 3, 1)
+    
+    pop = (1,), ()
+    
+    swap = (1, 2), (2, 1)
+
+``compose()``
+~~~~~~~~~~~~~
+
+.. code:: ipython2
+
+    def compose(f, g):
+    
+        (f_in, f_out), (g_in, g_out) = f, g
+    
+        # First rule.
+        #
+        #       (a -- b) (-- d)
+        #    ---------------------
+        #         (a -- b d)
+    
+        if not g_in:
+    
+            fg_in, fg_out = f_in, f_out + g_out
+    
+        # Second rule.
+        #
+        #       (a --) (c -- d)
+        #    ---------------------
+        #         (c a -- d)
+    
+        elif not f_out:
+    
+            fg_in, fg_out = g_in + f_in, g_out
+    
+        else: # Unify, update, recur.
+    
+            fo, gi = f_out[-1], g_in[-1]
+    
+            s = unify(gi, fo)
+    
+            if s == False:  # s can also be the empty dict, which is ok.
+                raise TypeError('Cannot unify %r and %r.' % (fo, gi))
+    
+            f_g = (f_in, f_out[:-1]), (g_in[:-1], g_out)
+    
+            if s: f_g = update(s, f_g)
+    
+            fg_in, fg_out = compose(*f_g)
+    
+        return fg_in, fg_out
+
+``unify()``
+~~~~~~~~~~~
+
+.. code:: ipython2
+
+    def unify(u, v, s=None):
+        if s is None:
+            s = {}
+    
+        if u == v:
+            return s
+    
+        if isinstance(u, int):
+            s[u] = v
+            return s
+    
+        if isinstance(v, int):
+            s[v] = u
+            return s
+    
+        return False
+
+``update()``
+~~~~~~~~~~~~
+
+.. code:: ipython2
+
+    def update(s, term):
+        if not isinstance(term, tuple):
+            return s.get(term, term)
+        return tuple(update(s, inner) for inner in term)
+
+``relabel()``
+~~~~~~~~~~~~~
+
+.. code:: ipython2
+
+    def relabel(left, right):
+        return left, _1000(right)
+    
+    def _1000(right):
+        if not isinstance(right, tuple):
+            return 1000 + right
+        return tuple(_1000(n) for n in right)
+    
+    relabel(pop, swap)
+
+
+
+
+.. parsed-literal::
+
+    (((1,), ()), ((1001, 1002), (1002, 1001)))
+
+
+
+``delabel()``
+~~~~~~~~~~~~~
+
+.. code:: ipython2
+
+    def delabel(f):
+        s = {u: i for i, u in enumerate(sorted(_unique(f)))}
+        return update(s, f)
+    
+    def _unique(f, seen=None):
+        if seen is None:
+            seen = set()
+        if not isinstance(f, tuple):
+            seen.add(f)
+        else:
+            for inner in f:
+                _unique(inner, seen)
+        return seen
+    
+    delabel(relabel(pop, swap))
+
+
+
+
+.. parsed-literal::
+
+    (((0,), ()), ((1, 2), (2, 1)))
+
+
+
+``C()``
+~~~~~~~
+
+At last we put it all together in a function ``C()`` that accepts two
+stack effect comments and returns their composition (or raises and
+exception if they can't be composed due to type conflicts.)
+
+.. code:: ipython2
+
+    def C(f, g):
+        f, g = relabel(f, g)
+        fg = compose(f, g)
+        return delabel(fg)
+
+Let's try it out.
+
+.. code:: ipython2
+
+    C(pop, swap)
+
+
+
+
+.. parsed-literal::
+
+    ((1, 2, 0), (2, 1))
+
+
+
+.. code:: ipython2
+
+    C(C(pop, swap), roll_dn)
+
+
+
+
+.. parsed-literal::
+
+    ((3, 1, 2, 0), (2, 1, 3))
+
+
+
+.. code:: ipython2
+
+    C(swap, roll_dn)
+
+
+
+
+.. parsed-literal::
+
+    ((2, 0, 1), (1, 0, 2))
+
+
+
+.. code:: ipython2
+
+    C(pop, C(swap, roll_dn))
+
+
+
+
+.. parsed-literal::
+
+    ((3, 1, 2, 0), (2, 1, 3))
+
+
+
+.. code:: ipython2
+
+    poswrd = reduce(C, (pop, swap, roll_dn))
+    poswrd
+
+
+
+
+.. parsed-literal::
+
+    ((3, 1, 2, 0), (2, 1, 3))
+
+
+
+List Functions
+~~~~~~~~~~~~~~
+
+Here's that trick to represent functions like ``rest`` and ``cons`` that
+manipulate lists. We use a cons-list of tuples and give the tails their
+own numbers. Then everything above already works.
+
+.. code:: ipython2
+
+    rest = ((1, 2),), (2,)
+    
+    cons = (1, 2), ((1, 2),)
+
+.. code:: ipython2
+
+    C(poswrd, rest)
+
+
+
+
+.. parsed-literal::
+
+    (((3, 4), 1, 2, 0), (2, 1, 4))
+
+
+
+Compare this to the stack effect comment we wrote above:
+
+::
+
+    ((  (3, 4), 1, 2, 0 ), ( 2, 1,   4  ))
+    (   [4 ...] 2  3  0  --  3  2  [...])
+
+The translation table, if you will, would be:
+
+::
+
+    {
+    3: 4,
+    4: ...],
+    1: 2,
+    2: 3,
+    0: 0,
+    }
+
+.. code:: ipython2
+
+    F = reduce(C, (pop, swap, roll_dn, rest, rest, cons, cons))
+    
+    F
+
+
+
+
+.. parsed-literal::
+
+    (((3, (4, 5)), 1, 2, 0), ((2, (1, 5)),))
+
+
+
+Compare with the stack effect comment and you can see it works fine:
+
+::
+
+    ([4 5 ...] 2 3 1 -- [3 2 ...])
+
+Dealing with ``cons`` and ``uncons``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+However, if we try to compose e.g. ``cons`` and ``uncons`` it won't
+work:
+
+.. code:: ipython2
+
+    uncons = ((1, 2),), (1, 2)
+
+.. code:: ipython2
+
+    try:
+        C(cons, uncons)
+    except Exception, e:
+        print e
+
+
+.. parsed-literal::
+
+    Cannot unify (1, 2) and (1001, 1002).
+
+
+``unify()`` version 2
+^^^^^^^^^^^^^^^^^^^^^
+
+The problem is that the ``unify()`` function as written doesn't handle
+the case when both terms are tuples. We just have to add a clause to
+deal with this recursively:
+
+.. code:: ipython2
+
+    def unify(u, v, s=None):
+        if s is None:
+            s = {}
+        else:
+            u = update(s, u)
+            v = update(s, v)
+    
+        if u == v:
+            return s
+    
+        if isinstance(u, int):
+            s[u] = v
+            return s
+    
+        if isinstance(v, int):
+            s[v] = u
+            return s
+    
+        if isinstance(u, tuple) and isinstance(v, tuple):
+            if len(u) != len(v) != 2:
+                raise ValueError(repr((u, v)))
+            for uu, vv in zip(u, v):
+                s = unify(uu, vv, s)
+                if s == False: # (instead of a substitution dict.)
+                    break
+            return s
+     
+        return False
+
+.. code:: ipython2
+
+    C(cons, uncons)
+
+
+
+
+.. parsed-literal::
+
+    ((0, 1), (0, 1))
+
+
+
+Compiling
+---------
+
+Now consider the Python function we would like to derive:
+
+.. code:: ipython2
+
+    def F_python(stack):
+        (_, (d, (c, ((a, (b, S0)), stack)))) = stack
+        return (d, (c, S0)), stack
+
+And compare it to the input stack effect comment tuple we just computed:
+
+.. code:: ipython2
+
+    F[0]
+
+
+
+
+.. parsed-literal::
+
+    ((3, (4, 5)), 1, 2, 0)
+
+
+
+The stack-de-structuring tuple has nearly the same form as our input
+stack effect comment tuple, just in the reverse order:
+
+::
+
+    (_, (d, (c, ((a, (b, S0)), stack))))
+
+Remove the punctuation:
+
+::
+
+     _   d   c   (a, (b, S0))
+
+Reverse the order and compare:
+
+::
+
+     (a, (b, S0))   c   d   _
+    ((3, (4, 5 )),  1,  2,  0)
+
+Eh?
+
+And the return tuple
+
+.. code:: ipython2
+
+    F[1]
+
+
+
+
+.. parsed-literal::
+
+    ((2, (1, 5)),)
+
+
+
+is similar to the output stack effect comment tuple:
+
+::
+
+    ((d, (c, S0)), stack)
+    ((2, (1, 5 )),      )
+
+This should make it pretty easy to write a Python function that accepts
+the stack effect comment tuples and returns a new Python function
+(either as a string of code or a function object ready to use) that
+performs the semantics of that Joy function (described by the stack
+effect.)
+
+Python Identifiers
+~~~~~~~~~~~~~~~~~~
+
+We want to substitute Python identifiers for the integers. I'm going to
+repurpose ``joy.parser.Symbol`` class for this:
+
+.. code:: ipython2
+
+    from collections import defaultdict
+    from joy.parser import Symbol
+    
+    
+    def _names_for():
+        I = iter(xrange(1000))
+        return lambda: Symbol('a%i' % next(I))
+    
+    
+    def identifiers(term, s=None):
+        if s is None:
+            s = defaultdict(_names_for())
+        if isinstance(term, int):
+            return s[term]
+        return tuple(identifiers(inner, s) for inner in term)
+
+``doc_from_stack_effect()``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+As a convenience I've implemented a function to convert the Python stack
+effect comment tuples to reasonable text format. There are some details
+in how this code works that related to stuff later in the notebook, so
+you should skip it for now and read it later if you're interested.
+
+.. code:: ipython2
+
+    def doc_from_stack_effect(inputs, outputs):
+        return '(%s--%s)' % (
+            ' '.join(map(_to_str, inputs + ('',))),
+            ' '.join(map(_to_str, ('',) + outputs))
+        )
+    
+    
+    def _to_str(term):
+        if not isinstance(term, tuple):
+            try:
+                t = term.prefix == 's'
+            except AttributeError:
+                return str(term)
+            return '[.%i.]' % term.number if t else str(term)
+    
+        a = []
+        while term and isinstance(term, tuple):
+            item, term = term
+            a.append(_to_str(item))
+    
+        try:
+            n = term.number
+        except AttributeError:
+            n = term
+        else:
+            if term.prefix != 's':
+                raise ValueError('Stack label: %s' % (term,))
+    
+        a.append('.%s.' % (n,))
+        return '[%s]' % ' '.join(a)
+
+``compile_()``
+~~~~~~~~~~~~~~
+
+Now we can write a compiler function to emit Python source code. (The
+underscore suffix distiguishes it from the built-in ``compile()``
+function.)
+
+.. code:: ipython2
+
+    def compile_(name, f, doc=None):
+        if doc is None:
+            doc = doc_from_stack_effect(*f)
+        inputs, outputs = identifiers(f)
+        i = o = Symbol('stack')
+        for term in inputs:
+            i = term, i
+        for term in outputs:
+            o = term, o
+        return '''def %s(stack):
+        """%s"""
+        %s = stack
+        return %s''' % (name, doc, i, o)
+
+Here it is in action:
+
+.. code:: ipython2
+
+    source = compile_('F', F)
+    
+    print source
+
+
+.. parsed-literal::
+
+    def F(stack):
+        """([3 4 .5.] 1 2 0 -- [2 1 .5.])"""
+        (a5, (a4, (a3, ((a0, (a1, a2)), stack)))) = stack
+        return ((a4, (a3, a2)), stack)
+
+
+Compare:
+
+.. code:: ipython2
+
+    def F_python(stack):
+        (_, (d, (c, ((a, (b, S0)), stack)))) = stack
+        return ((d, (c, S0)), stack)
+
+Next steps:
+
+.. code:: ipython2
+
+    L = {}
+    
+    eval(compile(source, '__main__', 'single'), {}, L)
+    
+    L['F']
+
+
+
+
+.. parsed-literal::
+
+    <function F>
+
+
+
+Let's try it out:
+
+.. code:: ipython2
+
+    from notebook_preamble import D, J, V
+    from joy.library import SimpleFunctionWrapper
+
+.. code:: ipython2
+
+    D['F'] = SimpleFunctionWrapper(L['F'])
+
+.. code:: ipython2
+
+    J('[4 5 ...] 2 3 1 F')
+
+
+.. parsed-literal::
+
+    [3 2 ...]
+
+
+With this, we have a partial Joy compiler that works on the subset of
+Joy functions that manipulate stacks (both what I call "stack chatter"
+and the ones that manipulate stacks on the stack.)
+
+I'm probably going to modify the definition wrapper code to detect
+definitions that can be compiled by this partial compiler and do it
+automatically. It might be a reasonable idea to detect sequences of
+compilable functions in definitions that have uncompilable functions in
+them and just compile those. However, if your library is well-factored
+this might be less helpful.
+
+Compiling Library Functions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+We can use ``compile_()`` to generate many primitives in the library
+from their stack effect comments:
+
+.. code:: ipython2
+
+    def defs():
+    
+        roll_down = (1, 2, 3), (2, 3, 1)
+    
+        roll_up = (1, 2, 3), (3, 1, 2)
+    
+        pop = (1,), ()
+    
+        swap = (1, 2), (2, 1)
+    
+        rest = ((1, 2),), (2,)
+        
+        rrest = C(rest, rest)
+    
+        cons = (1, 2), ((1, 2),)
+    
+        uncons = ((1, 2),), (1, 2)
+        
+        swons = C(swap, cons)
+    
+        return locals()
+
+.. code:: ipython2
+
+    for name, stack_effect_comment in sorted(defs().items()):
+        print
+        print compile_(name, stack_effect_comment)
+        print
+
+
+.. parsed-literal::
+
+    
+    def cons(stack):
+        """(1 2 -- [1 .2.])"""
+        (a1, (a0, stack)) = stack
+        return ((a0, a1), stack)
+    
+    
+    def pop(stack):
+        """(1 --)"""
+        (a0, stack) = stack
+        return stack
+    
+    
+    def rest(stack):
+        """([1 .2.] -- 2)"""
+        ((a0, a1), stack) = stack
+        return (a1, stack)
+    
+    
+    def roll_down(stack):
+        """(1 2 3 -- 2 3 1)"""
+        (a2, (a1, (a0, stack))) = stack
+        return (a0, (a2, (a1, stack)))
+    
+    
+    def roll_up(stack):
+        """(1 2 3 -- 3 1 2)"""
+        (a2, (a1, (a0, stack))) = stack
+        return (a1, (a0, (a2, stack)))
+    
+    
+    def rrest(stack):
+        """([0 1 .2.] -- 2)"""
+        ((a0, (a1, a2)), stack) = stack
+        return (a2, stack)
+    
+    
+    def swap(stack):
+        """(1 2 -- 2 1)"""
+        (a1, (a0, stack)) = stack
+        return (a0, (a1, stack))
+    
+    
+    def swons(stack):
+        """(0 1 -- [1 .0.])"""
+        (a1, (a0, stack)) = stack
+        return ((a1, a0), stack)
+    
+    
+    def uncons(stack):
+        """([1 .2.] -- 1 2)"""
+        ((a0, a1), stack) = stack
+        return (a1, (a0, stack))
+    
+
+
+Types and Subtypes of Arguments
+-------------------------------
+
+So far we have dealt with types of functions, those dealing with simple
+stack manipulation. Let's extend our machinery to deal with types of
+arguments.
+
+"Number" Type
+~~~~~~~~~~~~~
+
+Consider the definition of ``sqr``:
+
+::
+
+    sqr == dup mul
+
+The ``dup`` function accepts one *anything* and returns two of that:
+
+::
+
+    dup (1 -- 1 1)
+
+And ``mul`` accepts two "numbers" (we're ignoring ints vs. floats vs.
+complex, etc., for now) and returns just one:
+
+::
+
+    mul (n n -- n)
+
+So we're composing:
+
+::
+
+    (1 -- 1 1)∘(n n -- n)
+
+The rules say we unify 1 with ``n``:
+
+::
+
+       (1 -- 1 1)∘(n n -- n)
+    ---------------------------  w/  {1: n}
+       (1 -- 1  )∘(n   -- n)
+
+This involves detecting that "Any type" arguments can accept "numbers".
+If we were composing these functions the other way round this is still
+the case:
+
+::
+
+       (n n -- n)∘(1 -- 1 1)
+    ---------------------------  w/  {1: n}
+       (n n --  )∘(  -- n n) 
+
+The important thing here is that the mapping is going the same way in
+both cases, from the "any" integer to the number
+
+Distinguishing Numbers
+~~~~~~~~~~~~~~~~~~~~~~
+
+We should also mind that the number that ``mul`` produces is not
+(necessarily) the same as either of its inputs, which are not
+(necessarily) the same as each other:
+
+::
+
+    mul (n2 n1 -- n3)
+
+
+       (1  -- 1  1)∘(n2 n1 -- n3)
+    --------------------------------  w/  {1: n2}
+       (n2 -- n2  )∘(n2    -- n3)
+
+
+       (n2 n1 -- n3)∘(1 -- 1  1 )
+    --------------------------------  w/  {1: n3}
+       (n2 n1 --   )∘(  -- n3 n3) 
+
+Distinguishing Types
+~~~~~~~~~~~~~~~~~~~~
+
+So we need separate domains of "any" numbers and "number" numbers, and
+we need to be able to ask the order of these domains. Now the notes on
+the right side of rule three make more sense, eh?
+
+::
+
+       (a -- b t[i])∘(c u[j] -- d)   t <= u (t is subtype of u)
+    -------------------------------
+       (a -- b     )∘(c      -- d)   t[i] == t[k] == u[j]
+                                             ^
+
+       (a -- b t[i])∘(c u[j] -- d)   u <= t (u is subtype of t)
+    -------------------------------
+       (a -- b     )∘(c      -- d)   t[i] == u[k] == u[j]
+
+The indices ``i``, ``k``, and ``j`` are the number part of our labels
+and ``t`` and ``u`` are the domains.
+
+By creative use of Python's "double underscore" methods we can define a
+Python class hierarchy of Joy types and use the ``issubclass()`` method
+to establish domain ordering, as well as other handy behaviour that will
+make it fairly easy to reuse most of the code above.
+
+.. code:: ipython2
+
+    class AnyJoyType(object):
+    
+        prefix = 'a'
+    
+        def __init__(self, number):
+            self.number = number
+    
+        def __repr__(self):
+            return self.prefix + str(self.number)
+    
+        def __eq__(self, other):
+            return (
+                isinstance(other, self.__class__)
+                and other.prefix == self.prefix
+                and other.number == self.number
+            )
+    
+        def __ge__(self, other):
+            return issubclass(other.__class__, self.__class__)
+    
+        def __add__(self, other):
+            return self.__class__(self.number + other)
+        __radd__ = __add__
+        
+        def __hash__(self):
+            return hash(repr(self))
+    
+    
+    class NumberJoyType(AnyJoyType): prefix = 'n'
+    class FloatJoyType(NumberJoyType): prefix = 'f'
+    class IntJoyType(FloatJoyType): prefix = 'i'
+    
+    
+    class StackJoyType(AnyJoyType):
+        prefix = 's'
+    
+    
+    _R = range(10)
+    A = map(AnyJoyType, _R)
+    N = map(NumberJoyType, _R)
+    S = map(StackJoyType, _R)
+
+Mess with it a little:
+
+.. code:: ipython2
+
+    from itertools import permutations
+
+"Any" types can be specialized to numbers and stacks, but not vice
+versa:
+
+.. code:: ipython2
+
+    for a, b in permutations((A[0], N[0], S[0]), 2):
+        print a, '>=', b, '->', a >= b
+
+
+.. parsed-literal::
+
+    a0 >= n0 -> True
+    a0 >= s0 -> True
+    n0 >= a0 -> False
+    n0 >= s0 -> False
+    s0 >= a0 -> False
+    s0 >= n0 -> False
+
+
+Our crude `Numerical
+Tower <https://en.wikipedia.org/wiki/Numerical_tower>`__ of *numbers* >
+*floats* > *integers* works as well (but we're not going to use it yet):
+
+.. code:: ipython2
+
+    for a, b in permutations((A[0], N[0], FloatJoyType(0), IntJoyType(0)), 2):
+        print a, '>=', b, '->', a >= b
+
+
+.. parsed-literal::
+
+    a0 >= n0 -> True
+    a0 >= f0 -> True
+    a0 >= i0 -> True
+    n0 >= a0 -> False
+    n0 >= f0 -> True
+    n0 >= i0 -> True
+    f0 >= a0 -> False
+    f0 >= n0 -> False
+    f0 >= i0 -> True
+    i0 >= a0 -> False
+    i0 >= n0 -> False
+    i0 >= f0 -> False
+
+
+Typing ``sqr``
+~~~~~~~~~~~~~~
+
+.. code:: ipython2
+
+    dup = (A[1],), (A[1], A[1])
+    
+    mul = (N[1], N[2]), (N[3],)
+
+.. code:: ipython2
+
+    dup
+
+
+
+
+.. parsed-literal::
+
+    ((a1,), (a1, a1))
+
+
+
+.. code:: ipython2
+
+    mul
+
+
+
+
+.. parsed-literal::
+
+    ((n1, n2), (n3,))
+
+
+
+Modifying the Inferencer
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Re-labeling still works fine:
+
+.. code:: ipython2
+
+    foo = relabel(dup, mul)
+    
+    foo
+
+
+
+
+.. parsed-literal::
+
+    (((a1,), (a1, a1)), ((n1001, n1002), (n1003,)))
+
+
+
+``delabel()`` version 2
+^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``delabel()`` function needs an overhaul. It now has to keep track
+of how many labels of each domain it has "seen".
+
+.. code:: ipython2
+
+    from collections import Counter
+    
+    
+    def delabel(f, seen=None, c=None):
+        if seen is None:
+            assert c is None
+            seen, c = {}, Counter()
+    
+        try:
+            return seen[f]
+        except KeyError:
+            pass
+    
+        if not isinstance(f, tuple):
+            seen[f] = f.__class__(c[f.prefix])
+            c[f.prefix] += 1
+            return seen[f]
+    
+        return tuple(delabel(inner, seen, c) for inner in f)
+
+.. code:: ipython2
+
+    delabel(foo)
+
+
+
+
+.. parsed-literal::
+
+    (((a0,), (a0, a0)), ((n0, n1), (n2,)))
+
+
+
+``unify()`` version 3
+^^^^^^^^^^^^^^^^^^^^^
+
+.. code:: ipython2
+
+    def unify(u, v, s=None):
+        if s is None:
+            s = {}
+        else:
+            u = update(s, u)
+            v = update(s, v)
+    
+        if u == v:
+            return s
+    
+        if isinstance(u, AnyJoyType) and isinstance(v, AnyJoyType):
+            if u >= v:
+                s[u] = v
+                return s
+            if v >= u:
+                s[v] = u
+                return s
+            raise ValueError('Cannot unify %r and %r.' % (u, v))
+    
+        if isinstance(u, tuple) and isinstance(v, tuple):
+            if len(u) != len(v) != 2:
+                raise ValueError(repr((u, v)))
+            for uu, vv in zip(u, v):
+                s = unify(uu, vv, s)
+                if s == False: # (instead of a substitution dict.)
+                    break
+            return s
+     
+        if isinstance(v, tuple):
+            if not stacky(u):
+                raise ValueError('Cannot unify %r and %r.' % (u, v))
+            s[u] = v
+            return s
+    
+        if isinstance(u, tuple):
+            if not stacky(v):
+                raise ValueError('Cannot unify %r and %r.' % (v, u))
+            s[v] = u
+            return s
+    
+        return False
+    
+    
+    def stacky(thing):
+        return thing.__class__ in {AnyJoyType, StackJoyType}
+
+Rewrite the stack effect comments:
+
+.. code:: ipython2
+
+    def defs():
+    
+        roll_down = (A[1], A[2], A[3]), (A[2], A[3], A[1])
+    
+        roll_up = (A[1], A[2], A[3]), (A[3], A[1], A[2])
+    
+        pop = (A[1],), ()
+    
+        popop = (A[2], A[1],), ()
+    
+        popd = (A[2], A[1],), (A[1],)
+    
+        popdd = (A[3], A[2], A[1],), (A[2], A[1],)
+    
+        swap = (A[1], A[2]), (A[2], A[1])
+    
+        rest = ((A[1], S[1]),), (S[1],)
+    
+        rrest = C(rest, rest)
+    
+        cons = (A[1], S[1]), ((A[1], S[1]),)
+    
+        ccons = C(cons, cons)
+    
+        uncons = ((A[1], S[1]),), (A[1], S[1])
+    
+        swons = C(swap, cons)
+    
+        dup = (A[1],), (A[1], A[1])
+    
+        dupd = (A[2], A[1]), (A[2], A[2], A[1])
+    
+        mul = (N[1], N[2]), (N[3],)
+        
+        sqrt = C(dup, mul)
+    
+        first = ((A[1], S[1]),), (A[1],)
+    
+        second = C(rest, first)
+    
+        third = C(rest, second)
+    
+        tuck = (A[2], A[1]), (A[1], A[2], A[1])
+    
+        over = (A[2], A[1]), (A[2], A[1], A[2])
+        
+        succ = pred = (N[1],), (N[2],)
+        
+        divmod_ = pm = (N[2], N[1]), (N[4], N[3])
+    
+        return locals()
+
+.. code:: ipython2
+
+    DEFS = defs()
+
+.. code:: ipython2
+
+    for name, stack_effect_comment in sorted(DEFS.items()):
+        print name, '=', doc_from_stack_effect(*stack_effect_comment)
+
+
+.. parsed-literal::
+
+    ccons = (a0 a1 [.0.] -- [a0 a1 .0.])
+    cons = (a1 [.1.] -- [a1 .1.])
+    divmod_ = (n2 n1 -- n4 n3)
+    dup = (a1 -- a1 a1)
+    dupd = (a2 a1 -- a2 a2 a1)
+    first = ([a1 .1.] -- a1)
+    mul = (n1 n2 -- n3)
+    over = (a2 a1 -- a2 a1 a2)
+    pm = (n2 n1 -- n4 n3)
+    pop = (a1 --)
+    popd = (a2 a1 -- a1)
+    popdd = (a3 a2 a1 -- a2 a1)
+    popop = (a2 a1 --)
+    pred = (n1 -- n2)
+    rest = ([a1 .1.] -- [.1.])
+    roll_down = (a1 a2 a3 -- a2 a3 a1)
+    roll_up = (a1 a2 a3 -- a3 a1 a2)
+    rrest = ([a0 a1 .0.] -- [.0.])
+    second = ([a0 a1 .0.] -- a1)
+    sqrt = (n0 -- n1)
+    succ = (n1 -- n2)
+    swap = (a1 a2 -- a2 a1)
+    swons = ([.0.] a0 -- [a0 .0.])
+    third = ([a0 a1 a2 .0.] -- a2)
+    tuck = (a2 a1 -- a1 a2 a1)
+    uncons = ([a1 .1.] -- a1 [.1.])
+
+
+.. code:: ipython2
+
+    globals().update(DEFS)
+
+Compose ``dup`` and ``mul``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code:: ipython2
+
+    C(dup, mul)
+
+
+
+
+.. parsed-literal::
+
+    ((n0,), (n1,))
+
+
+
+Revisit the ``F`` function, works fine.
+
+.. code:: ipython2
+
+    F = reduce(C, (pop, swap, roll_down, rest, rest, cons, cons))
+    F
+
+
+
+
+.. parsed-literal::
+
+    (((a0, (a1, s0)), a2, a3, a4), ((a3, (a2, s0)),))
+
+
+
+.. code:: ipython2
+
+    print doc_from_stack_effect(*F)
+
+
+.. parsed-literal::
+
+    ([a0 a1 .0.] a2 a3 a4 -- [a3 a2 .0.])
+
+
+Some otherwise inefficient functions are no longer to be feared. We can
+also get the effect of combinators in some limited cases.
+
+.. code:: ipython2
+
+    def neato(*funcs):
+        print doc_from_stack_effect(*reduce(C, funcs))
+
+.. code:: ipython2
+
+    # e.g. [swap] dip
+    neato(roll_up, swap, roll_down)
+
+
+.. parsed-literal::
+
+    (a0 a1 a2 -- a1 a0 a2)
+
+
+.. code:: ipython2
+
+    # e.g. [popop] dip
+    neato(popdd, roll_down, pop)
+
+
+.. parsed-literal::
+
+    (a0 a1 a2 a3 -- a2 a3)
+
+
+.. code:: ipython2
+
+    # Reverse the order of the top three items.
+    neato(roll_up, swap)
+
+
+.. parsed-literal::
+
+    (a0 a1 a2 -- a2 a1 a0)
+
+
+``compile_()`` version 2
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Because the type labels represent themselves as valid Python identifiers
+the ``compile_()`` function doesn't need to generate them anymore:
+
+.. code:: ipython2
+
+    def compile_(name, f, doc=None):
+        inputs, outputs = f
+        if doc is None:
+            doc = doc_from_stack_effect(inputs, outputs)
+        i = o = Symbol('stack')
+        for term in inputs:
+            i = term, i
+        for term in outputs:
+            o = term, o
+        return '''def %s(stack):
+        """%s"""
+        %s = stack
+        return %s''' % (name, doc, i, o)
+
+.. code:: ipython2
+
+    print compile_('F', F)
+
+
+.. parsed-literal::
+
+    def F(stack):
+        """([a0 a1 .0.] a2 a3 a4 -- [a3 a2 .0.])"""
+        (a4, (a3, (a2, ((a0, (a1, s0)), stack)))) = stack
+        return ((a3, (a2, s0)), stack)
+
+
+But it cannot magically create new functions that involve e.g. math and
+such. Note that this is *not* a ``sqr`` function implementation:
+
+.. code:: ipython2
+
+    print compile_('sqr', C(dup, mul))
+
+
+.. parsed-literal::
+
+    def sqr(stack):
+        """(n0 -- n1)"""
+        (n0, stack) = stack
+        return (n1, stack)
+
+
+``compilable()``
+^^^^^^^^^^^^^^^^
+
+The functions that *can* be compiled are the ones that have only
+``AnyJoyType`` and ``StackJoyType`` labels in their stack effect
+comments. We can write a function to check that:
+
+.. code:: ipython2
+
+    from itertools import imap
+    
+    
+    def compilable(f):
+        return isinstance(f, tuple) and all(imap(compilable, f)) or stacky(f)
+
+.. code:: ipython2
+
+    for name, stack_effect_comment in sorted(defs().items()):
+        if compilable(stack_effect_comment):
+            print name, '=', doc_from_stack_effect(*stack_effect_comment)
+
+
+.. parsed-literal::
+
+    ccons = (a0 a1 [.0.] -- [a0 a1 .0.])
+    cons = (a1 [.1.] -- [a1 .1.])
+    dup = (a1 -- a1 a1)
+    dupd = (a2 a1 -- a2 a2 a1)
+    first = ([a1 .1.] -- a1)
+    over = (a2 a1 -- a2 a1 a2)
+    pop = (a1 --)
+    popd = (a2 a1 -- a1)
+    popdd = (a3 a2 a1 -- a2 a1)
+    popop = (a2 a1 --)
+    rest = ([a1 .1.] -- [.1.])
+    roll_down = (a1 a2 a3 -- a2 a3 a1)
+    roll_up = (a1 a2 a3 -- a3 a1 a2)
+    rrest = ([a0 a1 .0.] -- [.0.])
+    second = ([a0 a1 .0.] -- a1)
+    swap = (a1 a2 -- a2 a1)
+    swons = ([.0.] a0 -- [a0 .0.])
+    third = ([a0 a1 a2 .0.] -- a2)
+    tuck = (a2 a1 -- a1 a2 a1)
+    uncons = ([a1 .1.] -- a1 [.1.])
+
+
+Functions that use the Stack
+----------------------------
+
+Consider the ``stack`` function which grabs the whole stack, quotes it,
+and puts it on itself:
+
+::
+
+    stack (...     -- ... [...]        )
+    stack (... a   -- ... a [a ...]    )
+    stack (... b a -- ... b a [a b ...])
+
+We would like to represent this in Python somehow. To do this we use a
+simple, elegant trick.
+
+::
+
+    stack         S   -- (         S,           S)
+    stack     (a, S)  -- (     (a, S),      (a, S))
+    stack (a, (b, S)) -- ( (a, (b, S)), (a, (b, S)))
+
+Instead of representing the stack effect comments as a single tuple
+(with N items in it) we use the same cons-list structure to hold the
+sequence and ``unify()`` the whole comments.
+
+``stack∘uncons``
+~~~~~~~~~~~~~~~~
+
+Let's try composing ``stack`` and ``uncons``. We want this result:
+
+::
+
+    stack∘uncons (... a -- ... a a [...])
+
+The stack effects are:
+
+::
+
+    stack = S -- (S, S)
+
+    uncons = ((a, Z), S) -- (Z, (a, S))
+
+Unifying:
+
+::
+
+      S    -- (S, S) ∘ ((a, Z), S) -- (Z, (a,   S   ))
+                                                        w/ { S: (a, Z) }
+    (a, Z) --        ∘             -- (Z, (a, (a, Z)))
+
+So:
+
+::
+
+    stack∘uncons == (a, Z) -- (Z, (a, (a, Z)))
+
+It works.
+
+``stack∘uncons∘uncons``
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Let's try ``stack∘uncons∘uncons``:
+
+::
+
+    (a, S     ) -- (S,      (a, (a, S     ))) ∘ ((b, Z),  S`             ) -- (Z, (b,   S`   ))
+
+                                                                                    w/ { S: (b, Z) }
+                                                                                    
+    (a, (b, Z)) -- ((b, Z), (a, (a, (b, Z)))) ∘ ((b, Z),  S`             ) -- (Z, (b,   S`   ))
+
+                                                                                    w/ { S`: (a, (a, (b, Z))) }
+                                                                                    
+    (a, (b, Z)) -- ((b, Z), (a, (a, (b, Z)))) ∘ ((b, Z), (a, (a, (b, Z)))) -- (Z, (b, (a, (a, (b, Z)))))
+
+    (a, (b, Z)) -- (Z, (b, (a, (a, (b, Z)))))
+
+It works.
+
+``compose()`` version 2
+^^^^^^^^^^^^^^^^^^^^^^^
+
+This function has to be modified to use the new datastructures and it is
+no longer recursive, instead recursion happens as part of unification.
+
+.. code:: ipython2
+
+    def compose(f, g):
+    
+        (f_in, f_out), (g_in, g_out) = f, g
+    
+        if not g_in:
+            fg_in, fg_out = f_in, stack_concat(g_out, f_out)
+    
+        elif not f_out:
+            fg_in, fg_out = stack_concat(f_in, g_in), g_out
+    
+        else: # Unify and update.
+    
+            s = unify(g_in, f_out)
+    
+            if s == False:  # s can also be the empty dict, which is ok.
+                raise TypeError('Cannot unify %r and %r.' % (fo, gi))
+    
+            fg_in, fg_out = update(s, (f_in, g_out))
+    
+        return fg_in, fg_out
+    
+    
+    stack_concat = lambda q, e: (q[0], stack_concat(q[1], e)) if q else e
+
+I don't want to rewrite all the defs myself, so I'll write a little
+conversion function instead. This is programmer's laziness.
+
+.. code:: ipython2
+
+    def sequence_to_stack(seq, stack=StackJoyType(23)):
+        for item in seq: stack = item, stack
+        return stack
+    
+    NEW_DEFS = {
+        name: (sequence_to_stack(i), sequence_to_stack(o))
+        for name, (i, o) in DEFS.iteritems()
+    }
+    
+    globals().update(NEW_DEFS)
+
+.. code:: ipython2
+
+    stack = S[0], (S[0], S[0])
+
+.. code:: ipython2
+
+    C(stack, uncons)
+
+
+
+
+.. parsed-literal::
+
+    ((a0, s0), (s0, (a0, (a0, s0))))
+
+
+
+.. code:: ipython2
+
+    C(C(stack, uncons), uncons)
+
+
+
+
+.. parsed-literal::
+
+    ((a0, (a1, s0)), (s0, (a1, (a0, (a0, (a1, s0))))))
+
+
+
+The display function should be changed too.
+
+``doc_from_stack_effect()`` version 2
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Clunky junk, but it will suffice for now.
+
+.. code:: ipython2
+
+    def doc_from_stack_effect(inputs, outputs):
+        switch = [False]  # Do we need to display the '...' for the rest of the main stack?
+        i, o = _f(inputs, switch), _f(outputs, switch)
+        if switch[0]:
+            i.append('...')
+            o.append('...')
+        return '(%s--%s)' % (
+            ' '.join(reversed([''] + i)),
+            ' '.join(reversed(o + [''])),
+        )
+    
+    
+    def _f(term, switch):
+        a = []
+        while term and isinstance(term, tuple):
+            item, term = term
+            a.append(item)
+        assert isinstance(term, StackJoyType), repr(term)
+        a = [_to_str(i, term, switch) for i in a]
+        return a
+    
+    
+    def _to_str(term, stack, switch):
+        if not isinstance(term, tuple):
+            if term == stack:
+                switch[0] = True
+                return '[...]'
+            return (
+                '[.%i.]' % term.number
+                if isinstance(term, StackJoyType)
+                else str(term)
+            )
+    
+        a = []
+        while term and isinstance(term, tuple):
+            item, term = term
+            a.append(_to_str(item, stack, switch))
+        assert isinstance(term, StackJoyType), repr(term)
+        if term == stack:
+            switch[0] = True
+            end = '...'
+        else:
+            end = '.%i.' % term.number
+        a.append(end)
+        return '[%s]' % ' '.join(a)
+
+.. code:: ipython2
+
+    for name, stack_effect_comment in sorted(NEW_DEFS.items()):
+        print name, '=', doc_from_stack_effect(*stack_effect_comment)
+
+
+.. parsed-literal::
+
+    ccons = (a0 a1 [.0.] -- [a0 a1 .0.])
+    cons = (a1 [.1.] -- [a1 .1.])
+    divmod_ = (n2 n1 -- n4 n3)
+    dup = (a1 -- a1 a1)
+    dupd = (a2 a1 -- a2 a2 a1)
+    first = ([a1 .1.] -- a1)
+    mul = (n1 n2 -- n3)
+    over = (a2 a1 -- a2 a1 a2)
+    pm = (n2 n1 -- n4 n3)
+    pop = (a1 --)
+    popd = (a2 a1 -- a1)
+    popdd = (a3 a2 a1 -- a2 a1)
+    popop = (a2 a1 --)
+    pred = (n1 -- n2)
+    rest = ([a1 .1.] -- [.1.])
+    roll_down = (a1 a2 a3 -- a2 a3 a1)
+    roll_up = (a1 a2 a3 -- a3 a1 a2)
+    rrest = ([a0 a1 .0.] -- [.0.])
+    second = ([a0 a1 .0.] -- a1)
+    sqrt = (n0 -- n1)
+    succ = (n1 -- n2)
+    swap = (a1 a2 -- a2 a1)
+    swons = ([.0.] a0 -- [a0 .0.])
+    third = ([a0 a1 a2 .0.] -- a2)
+    tuck = (a2 a1 -- a1 a2 a1)
+    uncons = ([a1 .1.] -- a1 [.1.])
+
+
+.. code:: ipython2
+
+    print ; print doc_from_stack_effect(*stack)
+    print ; print doc_from_stack_effect(*C(stack, uncons))
+    print ; print doc_from_stack_effect(*C(C(stack, uncons), uncons))
+    print ; print doc_from_stack_effect(*C(C(stack, uncons), cons))
+
+
+.. parsed-literal::
+
+    
+    (... -- ... [...])
+    
+    (... a0 -- ... a0 a0 [...])
+    
+    (... a1 a0 -- ... a1 a0 a0 a1 [...])
+    
+    (... a0 -- ... a0 [a0 ...])
+
+
+.. code:: ipython2
+
+    print doc_from_stack_effect(*C(ccons, stack))
+
+
+.. parsed-literal::
+
+    (... a1 a0 [.0.] -- ... [a1 a0 .0.] [[a1 a0 .0.] ...])
+
+
+.. code:: ipython2
+
+    Q = C(ccons, stack)
+    
+    Q
+
+
+
+
+.. parsed-literal::
+
+    ((s0, (a0, (a1, s1))), (((a1, (a0, s0)), s1), ((a1, (a0, s0)), s1)))
+
+
+
+``compile_()`` version 3
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+This makes the ``compile_()`` function pretty simple as the stack effect
+comments are now already in the form needed for the Python code:
+
+.. code:: ipython2
+
+    def compile_(name, f, doc=None):
+        i, o = f
+        if doc is None:
+            doc = doc_from_stack_effect(i, o)
+        return '''def %s(stack):
+        """%s"""
+        %s = stack
+        return %s''' % (name, doc, i, o)
+
+.. code:: ipython2
+
+    print compile_('Q', Q)
+
+
+.. parsed-literal::
+
+    def Q(stack):
+        """(... a1 a0 [.0.] -- ... [a1 a0 .0.] [[a1 a0 .0.] ...])"""
+        (s0, (a0, (a1, s1))) = stack
+        return (((a1, (a0, s0)), s1), ((a1, (a0, s0)), s1))
+
+
+.. code:: ipython2
+
+    unstack = (S[1], S[0]), S[1]
+    enstacken = S[0], (S[0], S[1])
+
+.. code:: ipython2
+
+    print doc_from_stack_effect(*unstack)
+
+
+.. parsed-literal::
+
+    ([.1.] --)
+
+
+.. code:: ipython2
+
+    print doc_from_stack_effect(*enstacken)
+
+
+.. parsed-literal::
+
+    (-- [.0.])
+
+
+.. code:: ipython2
+
+    print doc_from_stack_effect(*C(cons, unstack))
+
+
+.. parsed-literal::
+
+    (a0 [.0.] -- a0)
+
+
+.. code:: ipython2
+
+    print doc_from_stack_effect(*C(cons, enstacken))
+
+
+.. parsed-literal::
+
+    (a0 [.0.] -- [[a0 .0.] .1.])
+
+
+.. code:: ipython2
+
+    C(cons, unstack)
+
+
+
+
+.. parsed-literal::
+
+    ((s0, (a0, s1)), (a0, s0))
+
+
+
+Sets of Stack Effects
+---------------------
+
+...
+
+``concat``
+----------
+
+How to deal with ``concat``?
+
+::
+
+    concat ([.0.] [.1.] -- [.0. .1.])
+
+We would like to represent this in Python somehow...
+
+.. code:: ipython2
+
+    concat = (S[0], S[1]), ((S[0], S[1]),)
+
+But this is actually ``cons`` with the first argument restricted to be a
+stack:
+
+::
+
+    ([.0.] [.1.] -- [[.0.] .1.])
+
+What we have implemented so far would actually only permit:
+
+::
+
+    ([.0.] [.1.] -- [.2.])
+
+.. code:: ipython2
+
+    concat = (S[0], S[1]), (S[2],)
+
+Which works but can lose information. Consider ``cons concat``, this is
+how much information we *could* retain:
+
+::
+
+    (1 [.0.] [.1.] -- [1 .0. .1.])
+
+As opposed to just:
+
+::
+
+    (1 [.0.] [.1.] -- [.2.])
+
+Which works but can lose information. Consider ``cons concat``, this is
+how much information we *could* retain:
+
+::
+
+    (1 [.0.] [.1.] -- [1 .0. .1.]) uncons uncons
+
+    (1 [.0.] [.1.] -- 1 [.0. .1.])        uncons
+                                                    So far so good...
+    (1 [2 .2.] [.1.] -- 1 2 [.2. .1.])
+
+
+
+
+    (1 [.0.] [.1.] -- 1 [.0. .1.]) ([a1 .10.] -- a1 [.10.])
+                                                             w/ { [a1 .10.] : [  .0.   .1.] }
+                                                           -or-
+                                                             w/ { [  .0.   .1.] : [a1 .10.    ] }
+
+Typing Combinators
+------------------
+
+TBD
+
+This is an open subject.
+
+The obvious thing is that you now need two pairs of tuples to describe
+the combinators' effects, a stack effect comment and an expression
+effect comment:
+
+::
+
+    dip (a [F] --)--(-- F a)
+
+One thing that might help is...
+
+Abstract Interpretation
+-----------------------
+
+Something else...
+-----------------
+
+::
+
+    [4 5 ...] 2 1 0 pop∘swap∘roll<∘rest∘rest∘cons∘cons
+    [4 5 ...] 2 1       swap∘roll<∘rest∘rest∘cons∘cons
+    [4 5 ...] 1 2            roll<∘rest∘rest∘cons∘cons
+    1 2 [4 5 ...]                  rest∘rest∘cons∘cons
+    1 2   [5 ...]                       rest∘cons∘cons
+    1 2     [...]                            cons∘cons
+    1     [2 ...]                                 cons
+        [1 2 ...]
+
+Eh?
diff --git a/docs/notebook_preamble.pyc b/docs/notebook_preamble.pyc
new file mode 100644 (file)
index 0000000..32b6331
Binary files /dev/null and b/docs/notebook_preamble.pyc differ
index 55a87a3..3f18dc6 100644 (file)
@@ -61,7 +61,7 @@
 <span class="kn">import</span> <span class="nn">operator</span><span class="o">,</span> <span class="nn">math</span>
 
 <span class="kn">from</span> <span class="nn">.parser</span> <span class="k">import</span> <span class="n">text_to_expression</span><span class="p">,</span> <span class="n">Symbol</span>
-<span class="kn">from</span> <span class="nn">.utils.stack</span> <span class="k">import</span> <span class="n">list_to_stack</span><span class="p">,</span> <span class="n">iter_stack</span><span class="p">,</span> <span class="n">pick</span><span class="p">,</span> <span class="n">pushback</span>
+<span class="kn">from</span> <span class="nn">.utils.stack</span> <span class="k">import</span> <span class="n">list_to_stack</span><span class="p">,</span> <span class="n">iter_stack</span><span class="p">,</span> <span class="n">pick</span><span class="p">,</span> <span class="n">concat</span>
 <span class="kn">from</span> <span class="nn">.utils.brutal_hackery</span> <span class="k">import</span> <span class="n">rename_code_object</span>
 
 
 <span class="s1">? == dup truthy</span>
 <span class="s1">dinfrirst == dip infra first</span>
 <span class="s1">nullary == [stack] dinfrirst</span>
-<span class="s1">unary == [stack [pop] dip] dinfrirst</span>
-<span class="s1">binary == [stack [popop] dip] dinfrirst</span>
-<span class="s1">ternary == [stack [popop pop] dip] dinfrirst</span>
+<span class="s1">unary == nullary popd</span>
+<span class="s1">binary == nullary [popop] dip</span>
+<span class="s1">ternary == unary [popop] dip</span>
 <span class="s1">pam == [i] map</span>
 <span class="s1">run == [] swap infra</span>
 <span class="s1">sqr == dup mul</span>
   <span class="k">return</span> <span class="n">res</span><span class="p">,</span> <span class="n">stack</span></div>
 
 
-<div class="viewcode-block" id="concat"><a class="viewcode-back" href="../../library.html#joy.library.concat">[docs]</a><span class="nd">@inscribe</span>
+<div class="viewcode-block" id="concat_"><a class="viewcode-back" href="../../library.html#joy.library.concat_">[docs]</a><span class="nd">@inscribe</span>
 <span class="nd">@SimpleFunctionWrapper</span>
-<span class="k">def</span> <span class="nf">concat</span><span class="p">(</span><span class="n">S</span><span class="p">):</span>
+<span class="k">def</span> <span class="nf">concat_</span><span class="p">(</span><span class="n">S</span><span class="p">):</span>
   <span class="sd">&#39;&#39;&#39;Concatinate the two lists on the top of the stack.</span>
 <span class="sd">  ::</span>
 
 
 <span class="sd">&#39;&#39;&#39;</span>
   <span class="p">(</span><span class="n">tos</span><span class="p">,</span> <span class="p">(</span><span class="n">second</span><span class="p">,</span> <span class="n">stack</span><span class="p">))</span> <span class="o">=</span> <span class="n">S</span>
-  <span class="k">for</span> <span class="n">term</span> <span class="ow">in</span> <span class="nb">reversed</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="n">iter_stack</span><span class="p">(</span><span class="n">second</span><span class="p">))):</span>
-    <span class="n">tos</span> <span class="o">=</span> <span class="n">term</span><span class="p">,</span> <span class="n">tos</span>
-  <span class="k">return</span> <span class="n">tos</span><span class="p">,</span> <span class="n">stack</span></div>
+  <span class="k">return</span> <span class="n">concat</span><span class="p">(</span><span class="n">second</span><span class="p">,</span> <span class="n">tos</span><span class="p">),</span> <span class="n">stack</span></div>
 
 
 <div class="viewcode-block" id="shunt"><a class="viewcode-back" href="../../library.html#joy.library.shunt">[docs]</a><span class="nd">@inscribe</span>
 
 <span class="sd">  &#39;&#39;&#39;</span>
   <span class="n">quote</span><span class="p">,</span> <span class="n">stack</span> <span class="o">=</span> <span class="n">stack</span>
-  <span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">pushback</span><span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="n">expression</span><span class="p">),</span> <span class="n">dictionary</span></div>
+  <span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">concat</span><span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="n">expression</span><span class="p">),</span> <span class="n">dictionary</span></div>
 
 
 <div class="viewcode-block" id="x"><a class="viewcode-back" href="../../library.html#joy.library.x">[docs]</a><span class="nd">@inscribe</span>
 
 <span class="sd">  &#39;&#39;&#39;</span>
   <span class="n">quote</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">stack</span>
-  <span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">pushback</span><span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="n">expression</span><span class="p">),</span> <span class="n">dictionary</span></div>
+  <span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">concat</span><span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="n">expression</span><span class="p">),</span> <span class="n">dictionary</span></div>
 
 
 <div class="viewcode-block" id="b"><a class="viewcode-back" href="../../library.html#joy.library.b">[docs]</a><span class="nd">@inscribe</span>
 
 <span class="sd">  &#39;&#39;&#39;</span>
   <span class="n">q</span><span class="p">,</span> <span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="p">(</span><span class="n">stack</span><span class="p">))</span> <span class="o">=</span> <span class="n">stack</span>
-  <span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">pushback</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">pushback</span><span class="p">(</span><span class="n">q</span><span class="p">,</span> <span class="n">expression</span><span class="p">)),</span> <span class="n">dictionary</span></div>
+  <span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">concat</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">concat</span><span class="p">(</span><span class="n">q</span><span class="p">,</span> <span class="n">expression</span><span class="p">)),</span> <span class="n">dictionary</span></div>
 
 
 <div class="viewcode-block" id="dupdip"><a class="viewcode-back" href="../../library.html#joy.library.dupdip">[docs]</a><span class="nd">@inscribe</span>
 <span class="sd">  &#39;&#39;&#39;</span>
   <span class="n">F</span><span class="p">,</span> <span class="n">stack</span> <span class="o">=</span> <span class="n">stack</span>
   <span class="n">a</span> <span class="o">=</span> <span class="n">stack</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
-  <span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">pushback</span><span class="p">(</span><span class="n">F</span><span class="p">,</span> <span class="p">(</span><span class="n">a</span><span class="p">,</span>  <span class="n">expression</span><span class="p">)),</span> <span class="n">dictionary</span></div>
+  <span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">concat</span><span class="p">(</span><span class="n">F</span><span class="p">,</span> <span class="p">(</span><span class="n">a</span><span class="p">,</span>  <span class="n">expression</span><span class="p">)),</span> <span class="n">dictionary</span></div>
 
 
 <div class="viewcode-block" id="infra"><a class="viewcode-back" href="../../library.html#joy.library.infra">[docs]</a><span class="nd">@inscribe</span>
 
 <span class="sd">  &#39;&#39;&#39;</span>
   <span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="p">(</span><span class="n">aggregate</span><span class="p">,</span> <span class="n">stack</span><span class="p">))</span> <span class="o">=</span> <span class="n">stack</span>
-  <span class="k">return</span> <span class="n">aggregate</span><span class="p">,</span> <span class="n">pushback</span><span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="p">(</span><span class="n">stack</span><span class="p">,</span> <span class="p">(</span><span class="n">S_swaack</span><span class="p">,</span> <span class="n">expression</span><span class="p">))),</span> <span class="n">dictionary</span></div>
+  <span class="k">return</span> <span class="n">aggregate</span><span class="p">,</span> <span class="n">concat</span><span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="p">(</span><span class="n">stack</span><span class="p">,</span> <span class="p">(</span><span class="n">S_swaack</span><span class="p">,</span> <span class="n">expression</span><span class="p">))),</span> <span class="n">dictionary</span></div>
 
 
 <div class="viewcode-block" id="genrec"><a class="viewcode-back" href="../../library.html#joy.library.genrec">[docs]</a><span class="nd">@inscribe</span>
   <span class="p">(</span><span class="n">rec2</span><span class="p">,</span> <span class="p">(</span><span class="n">rec1</span><span class="p">,</span> <span class="n">stack</span><span class="p">))</span> <span class="o">=</span> <span class="n">stack</span>
   <span class="p">(</span><span class="n">then</span><span class="p">,</span> <span class="p">(</span><span class="n">if_</span><span class="p">,</span> <span class="n">_</span><span class="p">))</span> <span class="o">=</span> <span class="n">stack</span>
   <span class="n">F</span> <span class="o">=</span> <span class="p">(</span><span class="n">if_</span><span class="p">,</span> <span class="p">(</span><span class="n">then</span><span class="p">,</span> <span class="p">(</span><span class="n">rec1</span><span class="p">,</span> <span class="p">(</span><span class="n">rec2</span><span class="p">,</span> <span class="p">(</span><span class="n">S_genrec</span><span class="p">,</span> <span class="p">())))))</span>
-  <span class="n">else_</span> <span class="o">=</span> <span class="n">pushback</span><span class="p">(</span><span class="n">rec1</span><span class="p">,</span> <span class="p">(</span><span class="n">F</span><span class="p">,</span> <span class="n">rec2</span><span class="p">))</span>
+  <span class="n">else_</span> <span class="o">=</span> <span class="n">concat</span><span class="p">(</span><span class="n">rec1</span><span class="p">,</span> <span class="p">(</span><span class="n">F</span><span class="p">,</span> <span class="n">rec2</span><span class="p">))</span>
   <span class="k">return</span> <span class="p">(</span><span class="n">else_</span><span class="p">,</span> <span class="n">stack</span><span class="p">),</span> <span class="p">(</span><span class="n">S_ifte</span><span class="p">,</span> <span class="n">expression</span><span class="p">),</span> <span class="n">dictionary</span></div>
 
 
 
 <span class="sd">  &#39;&#39;&#39;</span>
   <span class="p">(</span><span class="n">then</span><span class="p">,</span> <span class="p">(</span><span class="n">else_</span><span class="p">,</span> <span class="p">(</span><span class="n">flag</span><span class="p">,</span> <span class="n">stack</span><span class="p">)))</span> <span class="o">=</span> <span class="n">stack</span>
-  <span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">pushback</span><span class="p">(</span><span class="n">then</span> <span class="k">if</span> <span class="n">flag</span> <span class="k">else</span> <span class="n">else_</span><span class="p">,</span> <span class="n">expression</span><span class="p">),</span> <span class="n">dictionary</span></div>
+  <span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">concat</span><span class="p">(</span><span class="n">then</span> <span class="k">if</span> <span class="n">flag</span> <span class="k">else</span> <span class="n">else_</span><span class="p">,</span> <span class="n">expression</span><span class="p">),</span> <span class="n">dictionary</span></div>
 
 
 <div class="viewcode-block" id="ifte"><a class="viewcode-back" href="../../library.html#joy.library.ifte">[docs]</a><span class="nd">@inscribe</span>
 <span class="sd">  &#39;&#39;&#39;</span>
   <span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">stack</span><span class="p">))</span> <span class="o">=</span> <span class="n">stack</span>
   <span class="n">expression</span> <span class="o">=</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">expression</span><span class="p">)</span>
-  <span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">pushback</span><span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="n">expression</span><span class="p">),</span> <span class="n">dictionary</span></div>
+  <span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">concat</span><span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="n">expression</span><span class="p">),</span> <span class="n">dictionary</span></div>
 
 
 <div class="viewcode-block" id="dipd"><a class="viewcode-back" href="../../library.html#joy.library.dipd">[docs]</a><span class="nd">@inscribe</span>
 <span class="sd">  &#39;&#39;&#39;</span>
   <span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">stack</span><span class="p">)))</span> <span class="o">=</span> <span class="n">S</span>
   <span class="n">expression</span> <span class="o">=</span> <span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">expression</span><span class="p">))</span>
-  <span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">pushback</span><span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="n">expression</span><span class="p">),</span> <span class="n">dictionary</span></div>
+  <span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">concat</span><span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="n">expression</span><span class="p">),</span> <span class="n">dictionary</span></div>
 
 
 <div class="viewcode-block" id="dipdd"><a class="viewcode-back" href="../../library.html#joy.library.dipdd">[docs]</a><span class="nd">@inscribe</span>
 <span class="sd">  &#39;&#39;&#39;</span>
   <span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="p">(</span><span class="n">z</span><span class="p">,</span> <span class="n">stack</span><span class="p">))))</span> <span class="o">=</span> <span class="n">S</span>
   <span class="n">expression</span> <span class="o">=</span> <span class="p">(</span><span class="n">z</span><span class="p">,</span> <span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">expression</span><span class="p">)))</span>
-  <span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">pushback</span><span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="n">expression</span><span class="p">),</span> <span class="n">dictionary</span></div>
+  <span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">concat</span><span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="n">expression</span><span class="p">),</span> <span class="n">dictionary</span></div>
 
 
 <div class="viewcode-block" id="app1"><a class="viewcode-back" href="../../library.html#joy.library.app1">[docs]</a><span class="nd">@inscribe</span>
   <span class="n">n</span> <span class="o">-=</span> <span class="mi">1</span>
   <span class="k">if</span> <span class="n">n</span><span class="p">:</span>
     <span class="n">expression</span> <span class="o">=</span> <span class="n">n</span><span class="p">,</span> <span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="p">(</span><span class="n">S_times</span><span class="p">,</span> <span class="n">expression</span><span class="p">))</span>
-  <span class="n">expression</span> <span class="o">=</span> <span class="n">pushback</span><span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="n">expression</span><span class="p">)</span>
+  <span class="n">expression</span> <span class="o">=</span> <span class="n">concat</span><span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="n">expression</span><span class="p">)</span>
   <span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">expression</span><span class="p">,</span> <span class="n">dictionary</span></div>
 
 
 <span class="sd">  &#39;&#39;&#39;</span>
   <span class="n">quote</span><span class="p">,</span> <span class="p">(</span><span class="n">flag</span><span class="p">,</span> <span class="n">stack</span><span class="p">)</span> <span class="o">=</span> <span class="n">stack</span>
   <span class="k">if</span> <span class="n">flag</span><span class="p">:</span>
-    <span class="n">expression</span> <span class="o">=</span> <span class="n">pushback</span><span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="p">(</span><span class="n">S_loop</span><span class="p">,</span> <span class="n">expression</span><span class="p">)))</span>
+    <span class="n">expression</span> <span class="o">=</span> <span class="n">concat</span><span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="p">(</span><span class="n">S_loop</span><span class="p">,</span> <span class="n">expression</span><span class="p">)))</span>
   <span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">expression</span><span class="p">,</span> <span class="n">dictionary</span></div>
 
 
 <span class="sd">                        L</span>
 <span class="sd">  &#39;&#39;&#39;</span>
   <span class="n">L</span><span class="p">,</span> <span class="p">(</span><span class="n">E</span><span class="p">,</span> <span class="p">(</span><span class="n">G</span><span class="p">,</span> <span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">stack</span><span class="p">))))</span> <span class="o">=</span> <span class="n">stack</span>
-  <span class="n">expression</span> <span class="o">=</span> <span class="n">pushback</span><span class="p">(</span><span class="n">G</span> <span class="k">if</span> <span class="n">a</span> <span class="o">&gt;</span> <span class="n">b</span> <span class="k">else</span> <span class="n">L</span> <span class="k">if</span> <span class="n">a</span> <span class="o">&lt;</span> <span class="n">b</span> <span class="k">else</span> <span class="n">E</span><span class="p">,</span> <span class="n">expression</span><span class="p">)</span>
+  <span class="n">expression</span> <span class="o">=</span> <span class="n">concat</span><span class="p">(</span><span class="n">G</span> <span class="k">if</span> <span class="n">a</span> <span class="o">&gt;</span> <span class="n">b</span> <span class="k">else</span> <span class="n">L</span> <span class="k">if</span> <span class="n">a</span> <span class="o">&lt;</span> <span class="n">b</span> <span class="k">else</span> <span class="n">E</span><span class="p">,</span> <span class="n">expression</span><span class="p">)</span>
   <span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">expression</span><span class="p">,</span> <span class="n">dictionary</span></div>
 
 
index 7b6c19b..557dd55 100644 (file)
   <span class="p">)</span>
 
 
-<div class="viewcode-block" id="pushback"><a class="viewcode-back" href="../../../stack.html#joy.utils.stack.pushback">[docs]</a><span class="k">def</span> <span class="nf">pushback</span><span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="n">expression</span><span class="p">):</span>
+<div class="viewcode-block" id="concat"><a class="viewcode-back" href="../../../stack.html#joy.utils.stack.concat">[docs]</a><span class="k">def</span> <span class="nf">concat</span><span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="n">expression</span><span class="p">):</span>
   <span class="sd">&#39;&#39;&#39;Concatinate quote onto expression.</span>
 
 <span class="sd">  In joy [1 2] [3 4] would become [1 2 3 4].</span>
   <span class="c1"># This is the fastest implementation, but will trigger</span>
   <span class="c1"># RuntimeError: maximum recursion depth exceeded</span>
   <span class="c1"># on quotes longer than sys.getrecursionlimit().</span>
-  <span class="k">return</span> <span class="p">(</span><span class="n">quote</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">pushback</span><span class="p">(</span><span class="n">quote</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">expression</span><span class="p">))</span> <span class="k">if</span> <span class="n">quote</span> <span class="k">else</span> <span class="n">expression</span></div>
+
+<span class="c1">##  return (quote[0], concat(quote[1], expression)) if quote else expression</span>
 
   <span class="c1"># Original implementation.</span>
 
   <span class="c1"># In-lining is slightly faster (and won&#39;t break the</span>
   <span class="c1"># recursion limit on long quotes.)</span>
 
-<span class="c1">##  temp = []</span>
-<span class="c1">##  while quote:</span>
-<span class="c1">##    item, quote = quote</span>
-<span class="c1">##    temp.append(item)</span>
-<span class="c1">##  for item in reversed(temp):</span>
-<span class="c1">##    expression = item, expression</span>
-<span class="c1">##  return expression</span>
+  <span class="n">temp</span> <span class="o">=</span> <span class="p">[]</span>
+  <span class="k">while</span> <span class="n">quote</span><span class="p">:</span>
+    <span class="n">item</span><span class="p">,</span> <span class="n">quote</span> <span class="o">=</span> <span class="n">quote</span>
+    <span class="n">temp</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
+  <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="nb">reversed</span><span class="p">(</span><span class="n">temp</span><span class="p">):</span>
+    <span class="n">expression</span> <span class="o">=</span> <span class="n">item</span><span class="p">,</span> <span class="n">expression</span>
+  <span class="k">return</span> <span class="n">expression</span></div>
 
 
 
index e0c5224..8a0dc82 100644 (file)
 </li>
   </ul></td>
   <td style="width: 33%; vertical-align: top;"><ul>
-      <li><a href="library.html#joy.library.concat">concat() (in module joy.library)</a>
+      <li><a href="stack.html#joy.utils.stack.concat">concat() (in module joy.utils.stack)</a>
+</li>
+      <li><a href="library.html#joy.library.concat_">concat_() (in module joy.library)</a>
 </li>
       <li><a href="library.html#joy.library.cond">cond() (in module joy.library)</a>
 </li>
 </li>
       <li><a href="library.html#joy.library.pred">pred() (in module joy.library)</a>
 </li>
-      <li><a href="stack.html#joy.utils.stack.pushback">pushback() (in module joy.utils.stack)</a>
-</li>
   </ul></td>
 </tr></table>
 
index be7dcc6..97158a5 100644 (file)
@@ -132,13 +132,15 @@ interesting aspects.  It’s quite a treasure trove.</p>
 </li>
 <li class="toctree-l1"><a class="reference internal" href="notebooks/index.html">Essays about Programming in Joy</a><ul>
 <li class="toctree-l2"><a class="reference internal" href="notebooks/Developing.html">Developing a Program in Joy</a></li>
+<li class="toctree-l2"><a class="reference internal" href="notebooks/Quadratic.html">Quadratic formula</a></li>
 <li class="toctree-l2"><a class="reference internal" href="notebooks/Replacing.html">Replacing Functions in the Dictionary</a></li>
+<li class="toctree-l2"><a class="reference internal" href="notebooks/Recursion_Combinators.html">Recursive Combinators</a></li>
 <li class="toctree-l2"><a class="reference internal" href="notebooks/Ordered_Binary_Trees.html">Treating Trees I: Ordered Binary Trees</a></li>
 <li class="toctree-l2"><a class="reference internal" href="notebooks/Treestep.html">Treating Trees II: <code class="docutils literal notranslate"><span class="pre">treestep</span></code></a></li>
 <li class="toctree-l2"><a class="reference internal" href="notebooks/Generator_Programs.html">Using <code class="docutils literal notranslate"><span class="pre">x</span></code> to Generate Values</a></li>
 <li class="toctree-l2"><a class="reference internal" href="notebooks/Newton-Raphson.html">Newton’s method</a></li>
-<li class="toctree-l2"><a class="reference internal" href="notebooks/Quadratic.html">Quadratic formula</a></li>
 <li class="toctree-l2"><a class="reference internal" href="notebooks/Zipper.html">Traversing Datastructures with Zippers</a></li>
+<li class="toctree-l2"><a class="reference internal" href="notebooks/Types.html">Type Inference</a></li>
 <li class="toctree-l2"><a class="reference internal" href="notebooks/NoUpdates.html">No Updates</a></li>
 <li class="toctree-l2"><a class="reference internal" href="notebooks/Categorical.html">Categorical Programming</a></li>
 </ul>
index 588a05c..c4afc13 100644 (file)
@@ -214,8 +214,8 @@ one of the three depending on the results of comparing the two values:</p>
 </dd></dl>
 
 <dl class="function">
-<dt id="joy.library.concat">
-<code class="descclassname">joy.library.</code><code class="descname">concat</code><span class="sig-paren">(</span><em>stack</em>, <em>expression</em>, <em>dictionary</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/joy/library.html#concat"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#joy.library.concat" title="Permalink to this definition">¶</a></dt>
+<dt id="joy.library.concat_">
+<code class="descclassname">joy.library.</code><code class="descname">concat_</code><span class="sig-paren">(</span><em>stack</em>, <em>expression</em>, <em>dictionary</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/joy/library.html#concat_"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#joy.library.concat_" title="Permalink to this definition">¶</a></dt>
 <dd><p>Concatinate the two lists on the top of the stack.</p>
 <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>   <span class="p">[</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span><span class="p">]</span> <span class="p">[</span><span class="n">d</span> <span class="n">e</span> <span class="n">f</span><span class="p">]</span> <span class="n">concat</span>
 <span class="o">----------------------------</span>
index 85e2050..441c57c 100644 (file)
@@ -16,7 +16,7 @@
     <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
     <link rel="index" title="Index" href="../genindex.html" />
     <link rel="search" title="Search" href="../search.html" />
-    <link rel="next" title="Quadratic formula" href="Quadratic.html" />
+    <link rel="next" title="Traversing Datastructures with Zippers" href="Zipper.html" />
     <link rel="prev" title="Using x to Generate Values" href="Generator_Programs.html" />
    
   <link rel="stylesheet" href="../_static/custom.css" type="text/css" />
@@ -257,7 +257,7 @@ generated already and epsilon ε is handy on the stack…</p>
   <li><a href="../index.html">Documentation overview</a><ul>
   <li><a href="index.html">Essays about Programming in Joy</a><ul>
       <li>Previous: <a href="Generator_Programs.html" title="previous chapter">Using <code class="docutils literal notranslate"><span class="pre">x</span></code> to Generate Values</a></li>
-      <li>Next: <a href="Quadratic.html" title="next chapter">Quadratic formula</a></li>
+      <li>Next: <a href="Zipper.html" title="next chapter">Traversing Datastructures with Zippers</a></li>
   </ul></li>
   </ul></li>
 </ul>
index 2e7e8cc..5d03e7f 100644 (file)
@@ -16,8 +16,8 @@
     <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
     <link rel="index" title="Index" href="../genindex.html" />
     <link rel="search" title="Search" href="../search.html" />
-    <link rel="next" title="Traversing Datastructures with Zippers" href="Zipper.html" />
-    <link rel="prev" title="Newton’s method" href="Newton-Raphson.html" />
+    <link rel="next" title="Replacing Functions in the Dictionary" href="Replacing.html" />
+    <link rel="prev" title="Developing a Program in Joy" href="Developing.html" />
    
   <link rel="stylesheet" href="../_static/custom.css" type="text/css" />
   
         <div class="bodywrapper">
           <div class="body" role="main">
             
-  <div class="section" id="quadratic-formula">
-<h1><a class="reference external" href="https://en.wikipedia.org/wiki/Quadratic_formula">Quadratic formula</a><a class="headerlink" href="#quadratic-formula" title="Permalink to this headline">¶</a></h1>
-<div class="code ipython2 highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">notebook_preamble</span> <span class="k">import</span> <span class="n">J</span><span class="p">,</span> <span class="n">V</span><span class="p">,</span> <span class="n">define</span>
+  <div class="code ipython2 highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">notebook_preamble</span> <span class="k">import</span> <span class="n">J</span><span class="p">,</span> <span class="n">V</span><span class="p">,</span> <span class="n">define</span>
 </pre></div>
 </div>
+<div class="section" id="quadratic-formula">
+<h1><a class="reference external" href="https://en.wikipedia.org/wiki/Quadratic_formula">Quadratic formula</a><a class="headerlink" href="#quadratic-formula" title="Permalink to this headline">¶</a></h1>
 <p>Cf.
 <a class="reference external" href="http://www.kevinalbrecht.com/code/joy-mirror/jp-quadratic.html">jp-quadratic.html</a></p>
-<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">-</span><span class="n">b</span>  <span class="o">+/-</span> <span class="n">sqrt</span><span class="p">(</span><span class="n">b</span><span class="o">^</span><span class="mi">2</span> <span class="o">-</span> <span class="mi">4</span> <span class="o">*</span> <span class="n">a</span> <span class="o">*</span> <span class="n">c</span><span class="p">)</span>
-<span class="o">-----------------------------</span>
-           <span class="mi">2</span> <span class="o">*</span> <span class="n">a</span>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>   -b ± sqrt(b^2 - 4 * a * c)
+--------------------------------
+            2 * a
 </pre></div>
 </div>
 <p><span class="math notranslate nohighlight">\(\frac{-b \pm \sqrt{b^2 - 4ac}}{2a}\)</span></p>
 <div class="section" id="write-a-straightforward-program-with-variable-names">
 <h2>Write a straightforward program with variable names.<a class="headerlink" href="#write-a-straightforward-program-with-variable-names" title="Permalink to this headline">¶</a></h2>
-<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">b</span> <span class="n">neg</span> <span class="n">b</span> <span class="n">sqr</span> <span class="mi">4</span> <span class="n">a</span> <span class="n">c</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="p">]</span> <span class="n">cleave</span> <span class="n">a</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+<p>This math translates to Joy code in a straightforward manner. We are
+going to use named variables to keep track of the arguments, then write
+a definition without them.</p>
+<div class="section" id="b">
+<h3><code class="docutils literal notranslate"><span class="pre">-b</span></code><a class="headerlink" href="#b" title="Permalink to this headline">¶</a></h3>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">b</span> <span class="n">neg</span>
 </pre></div>
 </div>
-<p>We use <code class="docutils literal notranslate"><span class="pre">cleave</span></code> to compute the sum and difference and then <code class="docutils literal notranslate"><span class="pre">app2</span></code> to
-finish computing both roots using a quoted program <code class="docutils literal notranslate"><span class="pre">[2a</span> <span class="pre">truediv]</span></code>
-built with <code class="docutils literal notranslate"><span class="pre">cons</span></code>.</p>
-<div class="section" id="check-it">
-<h3>Check it.<a class="headerlink" href="#check-it" title="Permalink to this headline">¶</a></h3>
-<p>Evaluating by hand:</p>
-<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">b</span> <span class="n">neg</span> <span class="n">b</span> <span class="n">sqr</span> <span class="mi">4</span> <span class="n">a</span> <span class="n">c</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="p">]</span> <span class="n">cleave</span> <span class="n">a</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-<span class="o">-</span><span class="n">b</span>     <span class="n">b</span> <span class="n">sqr</span> <span class="mi">4</span> <span class="n">a</span> <span class="n">c</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="p">]</span> <span class="n">cleave</span> <span class="n">a</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-<span class="o">-</span><span class="n">b</span>     <span class="n">b</span><span class="o">^</span><span class="mi">2</span>   <span class="mi">4</span> <span class="n">a</span> <span class="n">c</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="p">]</span> <span class="n">cleave</span> <span class="n">a</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-<span class="o">-</span><span class="n">b</span>     <span class="n">b</span><span class="o">^</span><span class="mi">2</span> <span class="mi">4</span><span class="n">ac</span>         <span class="o">-</span> <span class="n">sqrt</span> <span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="p">]</span> <span class="n">cleave</span> <span class="n">a</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-<span class="o">-</span><span class="n">b</span>     <span class="n">b</span><span class="o">^</span><span class="mi">2</span><span class="o">-</span><span class="mi">4</span><span class="n">ac</span>           <span class="n">sqrt</span> <span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="p">]</span> <span class="n">cleave</span> <span class="n">a</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-<span class="o">-</span><span class="n">b</span> <span class="n">sqrt</span><span class="p">(</span><span class="n">b</span><span class="o">^</span><span class="mi">2</span><span class="o">-</span><span class="mi">4</span><span class="n">ac</span><span class="p">)</span>              <span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="p">]</span> <span class="n">cleave</span> <span class="n">a</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-
-<span class="o">-</span><span class="n">b</span> <span class="o">-</span><span class="n">b</span><span class="o">+</span><span class="n">sqrt</span><span class="p">(</span><span class="n">b</span><span class="o">^</span><span class="mi">2</span><span class="o">-</span><span class="mi">4</span><span class="n">ac</span><span class="p">)</span>    <span class="o">-</span><span class="n">b</span><span class="o">-</span><span class="n">sqrt</span><span class="p">(</span><span class="n">b</span><span class="o">^</span><span class="mi">2</span><span class="o">-</span><span class="mi">4</span><span class="n">ac</span><span class="p">)</span>    <span class="n">a</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-<span class="o">-</span><span class="n">b</span> <span class="o">-</span><span class="n">b</span><span class="o">+</span><span class="n">sqrt</span><span class="p">(</span><span class="n">b</span><span class="o">^</span><span class="mi">2</span><span class="o">-</span><span class="mi">4</span><span class="n">ac</span><span class="p">)</span>    <span class="o">-</span><span class="n">b</span><span class="o">-</span><span class="n">sqrt</span><span class="p">(</span><span class="n">b</span><span class="o">^</span><span class="mi">2</span><span class="o">-</span><span class="mi">4</span><span class="n">ac</span><span class="p">)</span>    <span class="mi">2</span><span class="n">a</span>    <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-<span class="o">-</span><span class="n">b</span> <span class="o">-</span><span class="n">b</span><span class="o">+</span><span class="n">sqrt</span><span class="p">(</span><span class="n">b</span><span class="o">^</span><span class="mi">2</span><span class="o">-</span><span class="mi">4</span><span class="n">ac</span><span class="p">)</span>    <span class="o">-</span><span class="n">b</span><span class="o">-</span><span class="n">sqrt</span><span class="p">(</span><span class="n">b</span><span class="o">^</span><span class="mi">2</span><span class="o">-</span><span class="mi">4</span><span class="n">ac</span><span class="p">)</span>    <span class="p">[</span><span class="mi">2</span><span class="n">a</span> <span class="n">truediv</span><span class="p">]</span>         <span class="n">app2</span>
-<span class="o">-</span><span class="n">b</span> <span class="o">-</span><span class="n">b</span><span class="o">+</span><span class="n">sqrt</span><span class="p">(</span><span class="n">b</span><span class="o">^</span><span class="mi">2</span><span class="o">-</span><span class="mi">4</span><span class="n">ac</span><span class="p">)</span><span class="o">/</span><span class="mi">2</span><span class="n">a</span> <span class="o">-</span><span class="n">b</span><span class="o">-</span><span class="n">sqrt</span><span class="p">(</span><span class="n">b</span><span class="o">^</span><span class="mi">2</span><span class="o">-</span><span class="mi">4</span><span class="n">ac</span><span class="p">)</span><span class="o">/</span><span class="mi">2</span><span class="n">a</span>
+</div>
+<div class="section" id="sqrt-b-2-4-a-c">
+<h3><code class="docutils literal notranslate"><span class="pre">sqrt(b^2</span> <span class="pre">-</span> <span class="pre">4</span> <span class="pre">*</span> <span class="pre">a</span> <span class="pre">*</span> <span class="pre">c)</span></code><a class="headerlink" href="#sqrt-b-2-4-a-c" title="Permalink to this headline">¶</a></h3>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">b</span> <span class="n">sqr</span> <span class="mi">4</span> <span class="n">a</span> <span class="n">c</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span>
 </pre></div>
 </div>
-<p>(Eventually we’ll be able to use e.g. Sympy versions of the Joy commands
-to do this sort of thing symbolically. This is part of what is meant by
-a “categorical” language.)</p>
 </div>
-<div class="section" id="cleanup">
-<h3>Cleanup<a class="headerlink" href="#cleanup" title="Permalink to this headline">¶</a></h3>
-<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">-</span><span class="n">b</span> <span class="o">-</span><span class="n">b</span><span class="o">+</span><span class="n">sqrt</span><span class="p">(</span><span class="n">b</span><span class="o">^</span><span class="mi">2</span><span class="o">-</span><span class="mi">4</span><span class="n">ac</span><span class="p">)</span><span class="o">/</span><span class="mi">2</span><span class="n">a</span> <span class="o">-</span><span class="n">b</span><span class="o">-</span><span class="n">sqrt</span><span class="p">(</span><span class="n">b</span><span class="o">^</span><span class="mi">2</span><span class="o">-</span><span class="mi">4</span><span class="n">ac</span><span class="p">)</span><span class="o">/</span><span class="mi">2</span><span class="n">a</span>                          <span class="n">roll</span><span class="o">&lt;</span> <span class="n">pop</span>
-   <span class="o">-</span><span class="n">b</span><span class="o">+</span><span class="n">sqrt</span><span class="p">(</span><span class="n">b</span><span class="o">^</span><span class="mi">2</span><span class="o">-</span><span class="mi">4</span><span class="n">ac</span><span class="p">)</span><span class="o">/</span><span class="mi">2</span><span class="n">a</span> <span class="o">-</span><span class="n">b</span><span class="o">-</span><span class="n">sqrt</span><span class="p">(</span><span class="n">b</span><span class="o">^</span><span class="mi">2</span><span class="o">-</span><span class="mi">4</span><span class="n">ac</span><span class="p">)</span><span class="o">/</span><span class="mi">2</span><span class="n">a</span> <span class="o">-</span><span class="n">b</span>                             <span class="n">pop</span>
-   <span class="o">-</span><span class="n">b</span><span class="o">+</span><span class="n">sqrt</span><span class="p">(</span><span class="n">b</span><span class="o">^</span><span class="mi">2</span><span class="o">-</span><span class="mi">4</span><span class="n">ac</span><span class="p">)</span><span class="o">/</span><span class="mi">2</span><span class="n">a</span> <span class="o">-</span><span class="n">b</span><span class="o">-</span><span class="n">sqrt</span><span class="p">(</span><span class="n">b</span><span class="o">^</span><span class="mi">2</span><span class="o">-</span><span class="mi">4</span><span class="n">ac</span><span class="p">)</span><span class="o">/</span><span class="mi">2</span><span class="n">a</span>
+<div class="section" id="a">
+<h3><code class="docutils literal notranslate"><span class="pre">/2a</span></code><a class="headerlink" href="#a" title="Permalink to this headline">¶</a></h3>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">a</span> <span class="mi">2</span> <span class="o">*</span> <span class="o">/</span>
 </pre></div>
 </div>
 </div>
-</div>
-<div class="section" id="derive-a-definition">
-<h2>Derive a definition.<a class="headerlink" href="#derive-a-definition" title="Permalink to this headline">¶</a></h2>
-<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">b</span> <span class="n">neg</span> <span class="n">b</span>           <span class="n">sqr</span> <span class="mi">4</span> <span class="n">a</span> <span class="n">c</span>        <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="p">]</span> <span class="n">cleave</span> <span class="n">a</span>       <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span> <span class="n">roll</span><span class="o">&lt;</span> <span class="n">pop</span>
-<span class="n">b</span>    <span class="p">[</span><span class="n">neg</span><span class="p">]</span> <span class="n">dupdip</span> <span class="n">sqr</span> <span class="mi">4</span> <span class="n">a</span> <span class="n">c</span>        <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="p">]</span> <span class="n">cleave</span> <span class="n">a</span>       <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span> <span class="n">roll</span><span class="o">&lt;</span> <span class="n">pop</span>
-<span class="n">b</span> <span class="n">a</span> <span class="n">c</span>    <span class="p">[[</span><span class="n">neg</span><span class="p">]</span> <span class="n">dupdip</span> <span class="n">sqr</span> <span class="mi">4</span><span class="p">]</span> <span class="n">dipd</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="p">]</span> <span class="n">cleave</span> <span class="n">a</span>       <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span> <span class="n">roll</span><span class="o">&lt;</span> <span class="n">pop</span>
-<span class="n">b</span> <span class="n">a</span> <span class="n">c</span> <span class="n">a</span>    <span class="p">[[[</span><span class="n">neg</span><span class="p">]</span> <span class="n">dupdip</span> <span class="n">sqr</span> <span class="mi">4</span><span class="p">]</span> <span class="n">dipd</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="p">]</span> <span class="n">cleave</span><span class="p">]</span> <span class="n">dip</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span> <span class="n">roll</span><span class="o">&lt;</span> <span class="n">pop</span>
-<span class="n">b</span> <span class="n">a</span> <span class="n">c</span> <span class="n">over</span> <span class="p">[[[</span><span class="n">neg</span><span class="p">]</span> <span class="n">dupdip</span> <span class="n">sqr</span> <span class="mi">4</span><span class="p">]</span> <span class="n">dipd</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="p">]</span> <span class="n">cleave</span><span class="p">]</span> <span class="n">dip</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span> <span class="n">roll</span><span class="o">&lt;</span> <span class="n">pop</span>
+<div class="section" id="id1">
+<h3><code class="docutils literal notranslate"><span class="pre">±</span></code><a class="headerlink" href="#id1" title="Permalink to this headline">¶</a></h3>
+<p>There is a function <code class="docutils literal notranslate"><span class="pre">pm</span></code> that accepts two values on the stack and
+replaces them with their sum and difference.</p>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pm</span> <span class="o">==</span> <span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="p">]</span> <span class="n">cleave</span> <span class="n">popdd</span>
 </pre></div>
 </div>
-<div class="code ipython2 highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">&#39;quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave] dip 2 * [truediv] cons app2 roll&lt; pop&#39;</span><span class="p">)</span>
-</pre></div>
 </div>
-<div class="code ipython2 highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">&#39;3 1 1 quadratic&#39;</span><span class="p">)</span>
+<div class="section" id="putting-them-together">
+<h3>Putting Them Together<a class="headerlink" href="#putting-them-together" title="Permalink to this headline">¶</a></h3>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">b</span> <span class="n">neg</span> <span class="n">b</span> <span class="n">sqr</span> <span class="mi">4</span> <span class="n">a</span> <span class="n">c</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="n">a</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
 </pre></div>
 </div>
-<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">-</span><span class="mf">0.3819660112501051</span> <span class="o">-</span><span class="mf">2.618033988749895</span>
-</pre></div>
+<p>We use <code class="docutils literal notranslate"><span class="pre">app2</span></code> to compute both roots by using a quoted program
+<code class="docutils literal notranslate"><span class="pre">[2a</span> <span class="pre">/]</span></code> built with <code class="docutils literal notranslate"><span class="pre">cons</span></code>.</p>
 </div>
 </div>
-<div class="section" id="simplify">
-<h2>Simplify<a class="headerlink" href="#simplify" title="Permalink to this headline">¶</a></h2>
-<p>We can define a <code class="docutils literal notranslate"><span class="pre">pm</span></code> plus-or-minus function:</p>
-<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pm</span> <span class="o">==</span> <span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="p">]</span> <span class="n">cleave</span> <span class="n">popdd</span>
+<div class="section" id="derive-a-definition">
+<h2>Derive a definition.<a class="headerlink" href="#derive-a-definition" title="Permalink to this headline">¶</a></h2>
+<p>Working backwards we use <code class="docutils literal notranslate"><span class="pre">dip</span></code> and <code class="docutils literal notranslate"><span class="pre">dipd</span></code> to extract the code from
+the variables:</p>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">b</span>             <span class="n">neg</span>  <span class="n">b</span>      <span class="n">sqr</span> <span class="mi">4</span> <span class="n">a</span> <span class="n">c</span>   <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="n">a</span>    <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+<span class="n">b</span>            <span class="p">[</span><span class="n">neg</span><span class="p">]</span> <span class="n">dupdip</span> <span class="n">sqr</span> <span class="mi">4</span> <span class="n">a</span> <span class="n">c</span>   <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="n">a</span>    <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+<span class="n">b</span> <span class="n">a</span> <span class="n">c</span>       <span class="p">[[</span><span class="n">neg</span><span class="p">]</span> <span class="n">dupdip</span> <span class="n">sqr</span> <span class="mi">4</span><span class="p">]</span> <span class="n">dipd</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="n">a</span>    <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+<span class="n">b</span> <span class="n">a</span> <span class="n">c</span> <span class="n">a</span>    <span class="p">[[[</span><span class="n">neg</span><span class="p">]</span> <span class="n">dupdip</span> <span class="n">sqr</span> <span class="mi">4</span><span class="p">]</span> <span class="n">dipd</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span><span class="p">]</span> <span class="n">dip</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+<span class="n">b</span> <span class="n">a</span> <span class="n">c</span> <span class="n">over</span> <span class="p">[[[</span><span class="n">neg</span><span class="p">]</span> <span class="n">dupdip</span> <span class="n">sqr</span> <span class="mi">4</span><span class="p">]</span> <span class="n">dipd</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span><span class="p">]</span> <span class="n">dip</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
 </pre></div>
 </div>
-<p>Then <code class="docutils literal notranslate"><span class="pre">quadratic</span></code> becomes:</p>
-<div class="code ipython2 highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">&#39;quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [truediv] cons app2&#39;</span><span class="p">)</span>
+<p>The three arguments are to the left, so we can “chop off” everything to
+the right and say it’s the definition of the <code class="docutils literal notranslate"><span class="pre">quadratic</span></code> function:</p>
+<div class="code ipython2 highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">&#39;quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2&#39;</span><span class="p">)</span>
 </pre></div>
 </div>
+<p>Let’s try it out:</p>
 <div class="code ipython2 highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">&#39;3 1 1 quadratic&#39;</span><span class="p">)</span>
 </pre></div>
 </div>
 <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">-</span><span class="mf">0.3819660112501051</span> <span class="o">-</span><span class="mf">2.618033988749895</span>
 </pre></div>
 </div>
-<div class="section" id="define-a-native-pm-function">
-<h3>Define a “native” <code class="docutils literal notranslate"><span class="pre">pm</span></code> function.<a class="headerlink" href="#define-a-native-pm-function" title="Permalink to this headline">¶</a></h3>
-<p>The definition of <code class="docutils literal notranslate"><span class="pre">pm</span></code> above is pretty elegant, but the implementation
-takes a lot of steps relative to what it’s accomplishing. Since we are
-likely to use <code class="docutils literal notranslate"><span class="pre">pm</span></code> more than once in the future, let’s write a
-primitive in Python and add it to the dictionary. (This has been done
-already.)</p>
-<div class="code ipython2 highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">pm</span><span class="p">(</span><span class="n">stack</span><span class="p">):</span>
-    <span class="n">a</span><span class="p">,</span> <span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="n">stack</span><span class="p">)</span> <span class="o">=</span> <span class="n">stack</span>
-    <span class="n">p</span><span class="p">,</span> <span class="n">m</span><span class="p">,</span> <span class="o">=</span> <span class="n">b</span> <span class="o">+</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">-</span> <span class="n">a</span>
-    <span class="k">return</span> <span class="n">m</span><span class="p">,</span> <span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">stack</span><span class="p">)</span>
+<p>If you look at the Joy evaluation trace you can see that the first few
+lines are the <code class="docutils literal notranslate"><span class="pre">dip</span></code> and <code class="docutils literal notranslate"><span class="pre">dipd</span></code> combinators building the main program
+by incorporating the values on the stack. Then that program runs and you
+get the results. This is pretty typical of Joy code.</p>
+<div class="code ipython2 highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">V</span><span class="p">(</span><span class="s1">&#39;-5 1 4 quadratic&#39;</span><span class="p">)</span>
+</pre></div>
+</div>
+<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>                                                   <span class="o">.</span> <span class="o">-</span><span class="mi">5</span> <span class="mi">1</span> <span class="mi">4</span> <span class="n">quadratic</span>
+                                                <span class="o">-</span><span class="mi">5</span> <span class="o">.</span> <span class="mi">1</span> <span class="mi">4</span> <span class="n">quadratic</span>
+                                              <span class="o">-</span><span class="mi">5</span> <span class="mi">1</span> <span class="o">.</span> <span class="mi">4</span> <span class="n">quadratic</span>
+                                            <span class="o">-</span><span class="mi">5</span> <span class="mi">1</span> <span class="mi">4</span> <span class="o">.</span> <span class="n">quadratic</span>
+                                            <span class="o">-</span><span class="mi">5</span> <span class="mi">1</span> <span class="mi">4</span> <span class="o">.</span> <span class="n">over</span> <span class="p">[[[</span><span class="n">neg</span><span class="p">]</span> <span class="n">dupdip</span> <span class="n">sqr</span> <span class="mi">4</span><span class="p">]</span> <span class="n">dipd</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span><span class="p">]</span> <span class="n">dip</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+                                          <span class="o">-</span><span class="mi">5</span> <span class="mi">1</span> <span class="mi">4</span> <span class="mi">1</span> <span class="o">.</span> <span class="p">[[[</span><span class="n">neg</span><span class="p">]</span> <span class="n">dupdip</span> <span class="n">sqr</span> <span class="mi">4</span><span class="p">]</span> <span class="n">dipd</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span><span class="p">]</span> <span class="n">dip</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+<span class="o">-</span><span class="mi">5</span> <span class="mi">1</span> <span class="mi">4</span> <span class="mi">1</span> <span class="p">[[[</span><span class="n">neg</span><span class="p">]</span> <span class="n">dupdip</span> <span class="n">sqr</span> <span class="mi">4</span><span class="p">]</span> <span class="n">dipd</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span><span class="p">]</span> <span class="o">.</span> <span class="n">dip</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+                                            <span class="o">-</span><span class="mi">5</span> <span class="mi">1</span> <span class="mi">4</span> <span class="o">.</span> <span class="p">[[</span><span class="n">neg</span><span class="p">]</span> <span class="n">dupdip</span> <span class="n">sqr</span> <span class="mi">4</span><span class="p">]</span> <span class="n">dipd</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+                       <span class="o">-</span><span class="mi">5</span> <span class="mi">1</span> <span class="mi">4</span> <span class="p">[[</span><span class="n">neg</span><span class="p">]</span> <span class="n">dupdip</span> <span class="n">sqr</span> <span class="mi">4</span><span class="p">]</span> <span class="o">.</span> <span class="n">dipd</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+                                                <span class="o">-</span><span class="mi">5</span> <span class="o">.</span> <span class="p">[</span><span class="n">neg</span><span class="p">]</span> <span class="n">dupdip</span> <span class="n">sqr</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">4</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+                                          <span class="o">-</span><span class="mi">5</span> <span class="p">[</span><span class="n">neg</span><span class="p">]</span> <span class="o">.</span> <span class="n">dupdip</span> <span class="n">sqr</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">4</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+                                                <span class="o">-</span><span class="mi">5</span> <span class="o">.</span> <span class="n">neg</span> <span class="o">-</span><span class="mi">5</span> <span class="n">sqr</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">4</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+                                                 <span class="mi">5</span> <span class="o">.</span> <span class="o">-</span><span class="mi">5</span> <span class="n">sqr</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">4</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+                                              <span class="mi">5</span> <span class="o">-</span><span class="mi">5</span> <span class="o">.</span> <span class="n">sqr</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">4</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+                                              <span class="mi">5</span> <span class="o">-</span><span class="mi">5</span> <span class="o">.</span> <span class="n">dup</span> <span class="n">mul</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">4</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+                                           <span class="mi">5</span> <span class="o">-</span><span class="mi">5</span> <span class="o">-</span><span class="mi">5</span> <span class="o">.</span> <span class="n">mul</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">4</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+                                              <span class="mi">5</span> <span class="mi">25</span> <span class="o">.</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">4</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+                                            <span class="mi">5</span> <span class="mi">25</span> <span class="mi">4</span> <span class="o">.</span> <span class="mi">1</span> <span class="mi">4</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+                                          <span class="mi">5</span> <span class="mi">25</span> <span class="mi">4</span> <span class="mi">1</span> <span class="o">.</span> <span class="mi">4</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+                                        <span class="mi">5</span> <span class="mi">25</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">4</span> <span class="o">.</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+                                          <span class="mi">5</span> <span class="mi">25</span> <span class="mi">4</span> <span class="mi">4</span> <span class="o">.</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+                                           <span class="mi">5</span> <span class="mi">25</span> <span class="mi">16</span> <span class="o">.</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+                                               <span class="mi">5</span> <span class="mi">9</span> <span class="o">.</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+                                             <span class="mi">5</span> <span class="mf">3.0</span> <span class="o">.</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+                                           <span class="mf">8.0</span> <span class="mf">2.0</span> <span class="o">.</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+                                         <span class="mf">8.0</span> <span class="mf">2.0</span> <span class="mi">1</span> <span class="o">.</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+                                       <span class="mf">8.0</span> <span class="mf">2.0</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">.</span> <span class="o">*</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+                                         <span class="mf">8.0</span> <span class="mf">2.0</span> <span class="mi">2</span> <span class="o">.</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
+                                     <span class="mf">8.0</span> <span class="mf">2.0</span> <span class="mi">2</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="o">.</span> <span class="n">cons</span> <span class="n">app2</span>
+                                     <span class="mf">8.0</span> <span class="mf">2.0</span> <span class="p">[</span><span class="mi">2</span> <span class="o">/</span><span class="p">]</span> <span class="o">.</span> <span class="n">app2</span>
+                                       <span class="p">[</span><span class="mf">8.0</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span> <span class="o">/</span><span class="p">]</span> <span class="o">.</span> <span class="n">infra</span> <span class="n">first</span> <span class="p">[</span><span class="mf">2.0</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span> <span class="o">/</span><span class="p">]</span> <span class="n">infra</span> <span class="n">first</span>
+                                               <span class="mf">8.0</span> <span class="o">.</span> <span class="mi">2</span> <span class="o">/</span> <span class="p">[]</span> <span class="n">swaack</span> <span class="n">first</span> <span class="p">[</span><span class="mf">2.0</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span> <span class="o">/</span><span class="p">]</span> <span class="n">infra</span> <span class="n">first</span>
+                                             <span class="mf">8.0</span> <span class="mi">2</span> <span class="o">.</span> <span class="o">/</span> <span class="p">[]</span> <span class="n">swaack</span> <span class="n">first</span> <span class="p">[</span><span class="mf">2.0</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span> <span class="o">/</span><span class="p">]</span> <span class="n">infra</span> <span class="n">first</span>
+                                               <span class="mf">4.0</span> <span class="o">.</span> <span class="p">[]</span> <span class="n">swaack</span> <span class="n">first</span> <span class="p">[</span><span class="mf">2.0</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span> <span class="o">/</span><span class="p">]</span> <span class="n">infra</span> <span class="n">first</span>
+                                            <span class="mf">4.0</span> <span class="p">[]</span> <span class="o">.</span> <span class="n">swaack</span> <span class="n">first</span> <span class="p">[</span><span class="mf">2.0</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span> <span class="o">/</span><span class="p">]</span> <span class="n">infra</span> <span class="n">first</span>
+                                             <span class="p">[</span><span class="mf">4.0</span><span class="p">]</span> <span class="o">.</span> <span class="n">first</span> <span class="p">[</span><span class="mf">2.0</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span> <span class="o">/</span><span class="p">]</span> <span class="n">infra</span> <span class="n">first</span>
+                                               <span class="mf">4.0</span> <span class="o">.</span> <span class="p">[</span><span class="mf">2.0</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span> <span class="o">/</span><span class="p">]</span> <span class="n">infra</span> <span class="n">first</span>
+                                         <span class="mf">4.0</span> <span class="p">[</span><span class="mf">2.0</span><span class="p">]</span> <span class="o">.</span> <span class="p">[</span><span class="mi">2</span> <span class="o">/</span><span class="p">]</span> <span class="n">infra</span> <span class="n">first</span>
+                                   <span class="mf">4.0</span> <span class="p">[</span><span class="mf">2.0</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span> <span class="o">/</span><span class="p">]</span> <span class="o">.</span> <span class="n">infra</span> <span class="n">first</span>
+                                               <span class="mf">2.0</span> <span class="o">.</span> <span class="mi">2</span> <span class="o">/</span> <span class="p">[</span><span class="mf">4.0</span><span class="p">]</span> <span class="n">swaack</span> <span class="n">first</span>
+                                             <span class="mf">2.0</span> <span class="mi">2</span> <span class="o">.</span> <span class="o">/</span> <span class="p">[</span><span class="mf">4.0</span><span class="p">]</span> <span class="n">swaack</span> <span class="n">first</span>
+                                               <span class="mf">1.0</span> <span class="o">.</span> <span class="p">[</span><span class="mf">4.0</span><span class="p">]</span> <span class="n">swaack</span> <span class="n">first</span>
+                                         <span class="mf">1.0</span> <span class="p">[</span><span class="mf">4.0</span><span class="p">]</span> <span class="o">.</span> <span class="n">swaack</span> <span class="n">first</span>
+                                         <span class="mf">4.0</span> <span class="p">[</span><span class="mf">1.0</span><span class="p">]</span> <span class="o">.</span> <span class="n">first</span>
+                                           <span class="mf">4.0</span> <span class="mf">1.0</span> <span class="o">.</span>
 </pre></div>
 </div>
-<p>The resulting trace is short enough to fit on a page.</p>
-<div class="code ipython2 highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">V</span><span class="p">(</span><span class="s1">&#39;3 1 1 quadratic&#39;</span><span class="p">)</span>
-</pre></div>
-</div>
-<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>                                                    <span class="o">.</span> <span class="mi">3</span> <span class="mi">1</span> <span class="mi">1</span> <span class="n">quadratic</span>
-                                                  <span class="mi">3</span> <span class="o">.</span> <span class="mi">1</span> <span class="mi">1</span> <span class="n">quadratic</span>
-                                                <span class="mi">3</span> <span class="mi">1</span> <span class="o">.</span> <span class="mi">1</span> <span class="n">quadratic</span>
-                                              <span class="mi">3</span> <span class="mi">1</span> <span class="mi">1</span> <span class="o">.</span> <span class="n">quadratic</span>
-                                              <span class="mi">3</span> <span class="mi">1</span> <span class="mi">1</span> <span class="o">.</span> <span class="n">over</span> <span class="p">[[[</span><span class="n">neg</span><span class="p">]</span> <span class="n">dupdip</span> <span class="n">sqr</span> <span class="mi">4</span><span class="p">]</span> <span class="n">dipd</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span><span class="p">]</span> <span class="n">dip</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-                                            <span class="mi">3</span> <span class="mi">1</span> <span class="mi">1</span> <span class="mi">1</span> <span class="o">.</span> <span class="p">[[[</span><span class="n">neg</span><span class="p">]</span> <span class="n">dupdip</span> <span class="n">sqr</span> <span class="mi">4</span><span class="p">]</span> <span class="n">dipd</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span><span class="p">]</span> <span class="n">dip</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-  <span class="mi">3</span> <span class="mi">1</span> <span class="mi">1</span> <span class="mi">1</span> <span class="p">[[[</span><span class="n">neg</span><span class="p">]</span> <span class="n">dupdip</span> <span class="n">sqr</span> <span class="mi">4</span><span class="p">]</span> <span class="n">dipd</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span><span class="p">]</span> <span class="o">.</span> <span class="n">dip</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-                                              <span class="mi">3</span> <span class="mi">1</span> <span class="mi">1</span> <span class="o">.</span> <span class="p">[[</span><span class="n">neg</span><span class="p">]</span> <span class="n">dupdip</span> <span class="n">sqr</span> <span class="mi">4</span><span class="p">]</span> <span class="n">dipd</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-                         <span class="mi">3</span> <span class="mi">1</span> <span class="mi">1</span> <span class="p">[[</span><span class="n">neg</span><span class="p">]</span> <span class="n">dupdip</span> <span class="n">sqr</span> <span class="mi">4</span><span class="p">]</span> <span class="o">.</span> <span class="n">dipd</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-                                                  <span class="mi">3</span> <span class="o">.</span> <span class="p">[</span><span class="n">neg</span><span class="p">]</span> <span class="n">dupdip</span> <span class="n">sqr</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">1</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-                                            <span class="mi">3</span> <span class="p">[</span><span class="n">neg</span><span class="p">]</span> <span class="o">.</span> <span class="n">dupdip</span> <span class="n">sqr</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">1</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-                                                  <span class="mi">3</span> <span class="o">.</span> <span class="n">neg</span> <span class="mi">3</span> <span class="n">sqr</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">1</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-                                                 <span class="o">-</span><span class="mi">3</span> <span class="o">.</span> <span class="mi">3</span> <span class="n">sqr</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">1</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-                                               <span class="o">-</span><span class="mi">3</span> <span class="mi">3</span> <span class="o">.</span> <span class="n">sqr</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">1</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-                                               <span class="o">-</span><span class="mi">3</span> <span class="mi">3</span> <span class="o">.</span> <span class="n">dup</span> <span class="n">mul</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">1</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-                                             <span class="o">-</span><span class="mi">3</span> <span class="mi">3</span> <span class="mi">3</span> <span class="o">.</span> <span class="n">mul</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">1</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-                                               <span class="o">-</span><span class="mi">3</span> <span class="mi">9</span> <span class="o">.</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">1</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-                                             <span class="o">-</span><span class="mi">3</span> <span class="mi">9</span> <span class="mi">4</span> <span class="o">.</span> <span class="mi">1</span> <span class="mi">1</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-                                           <span class="o">-</span><span class="mi">3</span> <span class="mi">9</span> <span class="mi">4</span> <span class="mi">1</span> <span class="o">.</span> <span class="mi">1</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-                                         <span class="o">-</span><span class="mi">3</span> <span class="mi">9</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">1</span> <span class="o">.</span> <span class="o">*</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-                                           <span class="o">-</span><span class="mi">3</span> <span class="mi">9</span> <span class="mi">4</span> <span class="mi">1</span> <span class="o">.</span> <span class="o">*</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-                                             <span class="o">-</span><span class="mi">3</span> <span class="mi">9</span> <span class="mi">4</span> <span class="o">.</span> <span class="o">-</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-                                               <span class="o">-</span><span class="mi">3</span> <span class="mi">5</span> <span class="o">.</span> <span class="n">sqrt</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-                                <span class="o">-</span><span class="mi">3</span> <span class="mf">2.23606797749979</span> <span class="o">.</span> <span class="n">pm</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-              <span class="o">-</span><span class="mf">0.7639320225002102</span> <span class="o">-</span><span class="mf">5.23606797749979</span> <span class="o">.</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-            <span class="o">-</span><span class="mf">0.7639320225002102</span> <span class="o">-</span><span class="mf">5.23606797749979</span> <span class="mi">1</span> <span class="o">.</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-          <span class="o">-</span><span class="mf">0.7639320225002102</span> <span class="o">-</span><span class="mf">5.23606797749979</span> <span class="mi">1</span> <span class="mi">2</span> <span class="o">.</span> <span class="o">*</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-            <span class="o">-</span><span class="mf">0.7639320225002102</span> <span class="o">-</span><span class="mf">5.23606797749979</span> <span class="mi">2</span> <span class="o">.</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="n">cons</span> <span class="n">app2</span>
-  <span class="o">-</span><span class="mf">0.7639320225002102</span> <span class="o">-</span><span class="mf">5.23606797749979</span> <span class="mi">2</span> <span class="p">[</span><span class="n">truediv</span><span class="p">]</span> <span class="o">.</span> <span class="n">cons</span> <span class="n">app2</span>
-  <span class="o">-</span><span class="mf">0.7639320225002102</span> <span class="o">-</span><span class="mf">5.23606797749979</span> <span class="p">[</span><span class="mi">2</span> <span class="n">truediv</span><span class="p">]</span> <span class="o">.</span> <span class="n">app2</span>
-                  <span class="p">[</span><span class="o">-</span><span class="mf">0.7639320225002102</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span> <span class="n">truediv</span><span class="p">]</span> <span class="o">.</span> <span class="n">infra</span> <span class="n">first</span> <span class="p">[</span><span class="o">-</span><span class="mf">5.23606797749979</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span> <span class="n">truediv</span><span class="p">]</span> <span class="n">infra</span> <span class="n">first</span>
-                                <span class="o">-</span><span class="mf">0.7639320225002102</span> <span class="o">.</span> <span class="mi">2</span> <span class="n">truediv</span> <span class="p">[]</span> <span class="n">swaack</span> <span class="n">first</span> <span class="p">[</span><span class="o">-</span><span class="mf">5.23606797749979</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span> <span class="n">truediv</span><span class="p">]</span> <span class="n">infra</span> <span class="n">first</span>
-                              <span class="o">-</span><span class="mf">0.7639320225002102</span> <span class="mi">2</span> <span class="o">.</span> <span class="n">truediv</span> <span class="p">[]</span> <span class="n">swaack</span> <span class="n">first</span> <span class="p">[</span><span class="o">-</span><span class="mf">5.23606797749979</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span> <span class="n">truediv</span><span class="p">]</span> <span class="n">infra</span> <span class="n">first</span>
-                                <span class="o">-</span><span class="mf">0.3819660112501051</span> <span class="o">.</span> <span class="p">[]</span> <span class="n">swaack</span> <span class="n">first</span> <span class="p">[</span><span class="o">-</span><span class="mf">5.23606797749979</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span> <span class="n">truediv</span><span class="p">]</span> <span class="n">infra</span> <span class="n">first</span>
-                             <span class="o">-</span><span class="mf">0.3819660112501051</span> <span class="p">[]</span> <span class="o">.</span> <span class="n">swaack</span> <span class="n">first</span> <span class="p">[</span><span class="o">-</span><span class="mf">5.23606797749979</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span> <span class="n">truediv</span><span class="p">]</span> <span class="n">infra</span> <span class="n">first</span>
-                              <span class="p">[</span><span class="o">-</span><span class="mf">0.3819660112501051</span><span class="p">]</span> <span class="o">.</span> <span class="n">first</span> <span class="p">[</span><span class="o">-</span><span class="mf">5.23606797749979</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span> <span class="n">truediv</span><span class="p">]</span> <span class="n">infra</span> <span class="n">first</span>
-                                <span class="o">-</span><span class="mf">0.3819660112501051</span> <span class="o">.</span> <span class="p">[</span><span class="o">-</span><span class="mf">5.23606797749979</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span> <span class="n">truediv</span><span class="p">]</span> <span class="n">infra</span> <span class="n">first</span>
-            <span class="o">-</span><span class="mf">0.3819660112501051</span> <span class="p">[</span><span class="o">-</span><span class="mf">5.23606797749979</span><span class="p">]</span> <span class="o">.</span> <span class="p">[</span><span class="mi">2</span> <span class="n">truediv</span><span class="p">]</span> <span class="n">infra</span> <span class="n">first</span>
-<span class="o">-</span><span class="mf">0.3819660112501051</span> <span class="p">[</span><span class="o">-</span><span class="mf">5.23606797749979</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span> <span class="n">truediv</span><span class="p">]</span> <span class="o">.</span> <span class="n">infra</span> <span class="n">first</span>
-                                  <span class="o">-</span><span class="mf">5.23606797749979</span> <span class="o">.</span> <span class="mi">2</span> <span class="n">truediv</span> <span class="p">[</span><span class="o">-</span><span class="mf">0.3819660112501051</span><span class="p">]</span> <span class="n">swaack</span> <span class="n">first</span>
-                                <span class="o">-</span><span class="mf">5.23606797749979</span> <span class="mi">2</span> <span class="o">.</span> <span class="n">truediv</span> <span class="p">[</span><span class="o">-</span><span class="mf">0.3819660112501051</span><span class="p">]</span> <span class="n">swaack</span> <span class="n">first</span>
-                                 <span class="o">-</span><span class="mf">2.618033988749895</span> <span class="o">.</span> <span class="p">[</span><span class="o">-</span><span class="mf">0.3819660112501051</span><span class="p">]</span> <span class="n">swaack</span> <span class="n">first</span>
-           <span class="o">-</span><span class="mf">2.618033988749895</span> <span class="p">[</span><span class="o">-</span><span class="mf">0.3819660112501051</span><span class="p">]</span> <span class="o">.</span> <span class="n">swaack</span> <span class="n">first</span>
-           <span class="o">-</span><span class="mf">0.3819660112501051</span> <span class="p">[</span><span class="o">-</span><span class="mf">2.618033988749895</span><span class="p">]</span> <span class="o">.</span> <span class="n">first</span>
-             <span class="o">-</span><span class="mf">0.3819660112501051</span> <span class="o">-</span><span class="mf">2.618033988749895</span> <span class="o">.</span>
-</pre></div>
-</div>
-</div>
 </div>
 </div>
 
@@ -195,15 +175,14 @@ already.)</p>
   <ul>
 <li><a class="reference internal" href="#">Quadratic formula</a><ul>
 <li><a class="reference internal" href="#write-a-straightforward-program-with-variable-names">Write a straightforward program with variable names.</a><ul>
-<li><a class="reference internal" href="#check-it">Check it.</a></li>
-<li><a class="reference internal" href="#cleanup">Cleanup</a></li>
+<li><a class="reference internal" href="#b"><code class="docutils literal notranslate"><span class="pre">-b</span></code></a></li>
+<li><a class="reference internal" href="#sqrt-b-2-4-a-c"><code class="docutils literal notranslate"><span class="pre">sqrt(b^2</span> <span class="pre">-</span> <span class="pre">4</span> <span class="pre">*</span> <span class="pre">a</span> <span class="pre">*</span> <span class="pre">c)</span></code></a></li>
+<li><a class="reference internal" href="#a"><code class="docutils literal notranslate"><span class="pre">/2a</span></code></a></li>
+<li><a class="reference internal" href="#id1"><code class="docutils literal notranslate"><span class="pre">±</span></code></a></li>
+<li><a class="reference internal" href="#putting-them-together">Putting Them Together</a></li>
 </ul>
 </li>
 <li><a class="reference internal" href="#derive-a-definition">Derive a definition.</a></li>
-<li><a class="reference internal" href="#simplify">Simplify</a><ul>
-<li><a class="reference internal" href="#define-a-native-pm-function">Define a “native” <code class="docutils literal notranslate"><span class="pre">pm</span></code> function.</a></li>
-</ul>
-</li>
 </ul>
 </li>
 </ul>
@@ -212,8 +191,8 @@ already.)</p>
 <ul>
   <li><a href="../index.html">Documentation overview</a><ul>
   <li><a href="index.html">Essays about Programming in Joy</a><ul>
-      <li>Previous: <a href="Newton-Raphson.html" title="previous chapter">Newton’s method</a></li>
-      <li>Next: <a href="Zipper.html" title="next chapter">Traversing Datastructures with Zippers</a></li>
+      <li>Previous: <a href="Developing.html" title="previous chapter">Developing a Program in Joy</a></li>
+      <li>Next: <a href="Replacing.html" title="next chapter">Replacing Functions in the Dictionary</a></li>
   </ul></li>
   </ul></li>
 </ul>
index d424e17..22d2d17 100644 (file)
@@ -16,8 +16,8 @@
     <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
     <link rel="index" title="Index" href="../genindex.html" />
     <link rel="search" title="Search" href="../search.html" />
-    <link rel="next" title="No Updates" href="NoUpdates.html" />
-    <link rel="prev" title="Quadratic formula" href="Quadratic.html" />
+    <link rel="next" title="Type Inference" href="Types.html" />
+    <link rel="prev" title="Newton’s method" href="Newton-Raphson.html" />
    
   <link rel="stylesheet" href="../_static/custom.css" type="text/css" />
   
@@ -326,8 +326,8 @@ i d i d i d d Bingo!
 <ul>
   <li><a href="../index.html">Documentation overview</a><ul>
   <li><a href="index.html">Essays about Programming in Joy</a><ul>
-      <li>Previous: <a href="Quadratic.html" title="previous chapter">Quadratic formula</a></li>
-      <li>Next: <a href="NoUpdates.html" title="next chapter">No Updates</a></li>
+      <li>Previous: <a href="Newton-Raphson.html" title="previous chapter">Newton’s method</a></li>
+      <li>Next: <a href="Types.html" title="next chapter">Type Inference</a></li>
   </ul></li>
   </ul></li>
 </ul>
index f5213e5..4c74e30 100644 (file)
 <li class="toctree-l2"><a class="reference internal" href="Developing.html#the-simplest-program">The Simplest Program</a></li>
 </ul>
 </li>
+<li class="toctree-l1"><a class="reference internal" href="Quadratic.html">Quadratic formula</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="Quadratic.html#write-a-straightforward-program-with-variable-names">Write a straightforward program with variable names.</a></li>
+<li class="toctree-l2"><a class="reference internal" href="Quadratic.html#derive-a-definition">Derive a definition.</a></li>
+</ul>
+</li>
 <li class="toctree-l1"><a class="reference internal" href="Replacing.html">Replacing Functions in the Dictionary</a><ul>
 <li class="toctree-l2"><a class="reference internal" href="Replacing.html#a-long-trace">A long trace</a></li>
 <li class="toctree-l2"><a class="reference internal" href="Replacing.html#replacing-size-with-a-python-version">Replacing <code class="docutils literal notranslate"><span class="pre">size</span></code> with a Python version</a></li>
 <li class="toctree-l2"><a class="reference internal" href="Replacing.html#a-shorter-trace">A shorter trace</a></li>
 </ul>
 </li>
+<li class="toctree-l1"><a class="reference internal" href="Recursion_Combinators.html">Recursive Combinators</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="Recursion_Combinators.html#designing-recursive-functions">Designing Recursive Functions</a></li>
+<li class="toctree-l2"><a class="reference internal" href="Recursion_Combinators.html#primitive-recursive-functions">Primitive Recursive Functions</a></li>
+<li class="toctree-l2"><a class="reference internal" href="Recursion_Combinators.html#hylomorphism">Hylomorphism</a></li>
+<li class="toctree-l2"><a class="reference internal" href="Recursion_Combinators.html#hylomorphism-in-joy">Hylomorphism in Joy</a></li>
+<li class="toctree-l2"><a class="reference internal" href="Recursion_Combinators.html#derivation-of-hylomorphism-combinator">Derivation of <code class="docutils literal notranslate"><span class="pre">hylomorphism</span></code> combinator</a></li>
+<li class="toctree-l2"><a class="reference internal" href="Recursion_Combinators.html#four-specializations">Four Specializations</a></li>
+<li class="toctree-l2"><a class="reference internal" href="Recursion_Combinators.html#anamorphism">Anamorphism</a></li>
+<li class="toctree-l2"><a class="reference internal" href="Recursion_Combinators.html#catamorphism">Catamorphism</a></li>
+<li class="toctree-l2"><a class="reference internal" href="Recursion_Combinators.html#example-factorial-function">Example: Factorial Function</a></li>
+<li class="toctree-l2"><a class="reference internal" href="Recursion_Combinators.html#example-tails">Example: <code class="docutils literal notranslate"><span class="pre">tails</span></code></a></li>
+<li class="toctree-l2"><a class="reference internal" href="Recursion_Combinators.html#conclusion-patterns-of-recursion">Conclusion: Patterns of Recursion</a></li>
+<li class="toctree-l2"><a class="reference internal" href="Recursion_Combinators.html#appendix-fun-with-symbols">Appendix: Fun with Symbols</a></li>
+</ul>
+</li>
 <li class="toctree-l1"><a class="reference internal" href="Ordered_Binary_Trees.html">Treating Trees I: Ordered Binary Trees</a><ul>
 <li class="toctree-l2"><a class="reference internal" href="Ordered_Binary_Trees.html#adding-nodes-to-the-tree">Adding Nodes to the Tree</a></li>
 <li class="toctree-l2"><a class="reference internal" href="Ordered_Binary_Trees.html#interlude-cmp-combinator">Interlude: <code class="docutils literal notranslate"><span class="pre">cmp</span></code> combinator</a></li>
 <li class="toctree-l2"><a class="reference internal" href="Newton-Raphson.html#finding-consecutive-approximations-within-a-tolerance">Finding Consecutive Approximations within a Tolerance</a></li>
 </ul>
 </li>
-<li class="toctree-l1"><a class="reference internal" href="Quadratic.html">Quadratic formula</a><ul>
-<li class="toctree-l2"><a class="reference internal" href="Quadratic.html#write-a-straightforward-program-with-variable-names">Write a straightforward program with variable names.</a></li>
-<li class="toctree-l2"><a class="reference internal" href="Quadratic.html#derive-a-definition">Derive a definition.</a></li>
-<li class="toctree-l2"><a class="reference internal" href="Quadratic.html#simplify">Simplify</a></li>
-</ul>
-</li>
 <li class="toctree-l1"><a class="reference internal" href="Zipper.html">Traversing Datastructures with Zippers</a><ul>
 <li class="toctree-l2"><a class="reference internal" href="Zipper.html#trees">Trees</a></li>
 <li class="toctree-l2"><a class="reference internal" href="Zipper.html#zipper-in-joy">Zipper in Joy</a></li>
 <li class="toctree-l2"><a class="reference internal" href="Zipper.html#determining-the-right-path-for-an-item-in-a-tree">Determining the right “path” for an item in a tree.</a></li>
 </ul>
 </li>
+<li class="toctree-l1"><a class="reference internal" href="Types.html">Type Inference</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="Types.html#poial-s-rules">Pöial’s Rules</a></li>
+<li class="toctree-l2"><a class="reference internal" href="Types.html#examples">Examples</a></li>
+<li class="toctree-l2"><a class="reference internal" href="Types.html#implementation">Implementation</a></li>
+<li class="toctree-l2"><a class="reference internal" href="Types.html#compiling">Compiling</a></li>
+<li class="toctree-l2"><a class="reference internal" href="Types.html#types-and-subtypes-of-arguments">Types and Subtypes of Arguments</a></li>
+<li class="toctree-l2"><a class="reference internal" href="Types.html#functions-that-use-the-stack">Functions that use the Stack</a></li>
+<li class="toctree-l2"><a class="reference internal" href="Types.html#sets-of-stack-effects">Sets of Stack Effects</a></li>
+<li class="toctree-l2"><a class="reference internal" href="Types.html#concat"><code class="docutils literal notranslate"><span class="pre">concat</span></code></a></li>
+<li class="toctree-l2"><a class="reference internal" href="Types.html#typing-combinators">Typing Combinators</a></li>
+<li class="toctree-l2"><a class="reference internal" href="Types.html#abstract-interpretation">Abstract Interpretation</a></li>
+<li class="toctree-l2"><a class="reference internal" href="Types.html#something-else">Something else…</a></li>
+</ul>
+</li>
 <li class="toctree-l1"><a class="reference internal" href="NoUpdates.html">No Updates</a></li>
 <li class="toctree-l1"><a class="reference internal" href="Categorical.html">Categorical Programming</a></li>
 </ul>
index d60701a..fad1ba9 100644 (file)
Binary files a/docs/sphinx_docs/_build/html/objects.inv and b/docs/sphinx_docs/_build/html/objects.inv differ
index 2d59585..5ea0dfc 100644 (file)
@@ -1 +1 @@
-Search.setIndex({docnames:["index","joy","lib","library","notebooks/Categorical","notebooks/Developing","notebooks/Generator_Programs","notebooks/Intro","notebooks/Newton-Raphson","notebooks/NoUpdates","notebooks/Ordered_Binary_Trees","notebooks/Quadratic","notebooks/Replacing","notebooks/Treestep","notebooks/Zipper","notebooks/index","parser","pretty","stack"],envversion:52,filenames:["index.rst","joy.rst","lib.rst","library.rst","notebooks/Categorical.rst","notebooks/Developing.rst","notebooks/Generator_Programs.rst","notebooks/Intro.rst","notebooks/Newton-Raphson.rst","notebooks/NoUpdates.rst","notebooks/Ordered_Binary_Trees.rst","notebooks/Quadratic.rst","notebooks/Replacing.rst","notebooks/Treestep.rst","notebooks/Zipper.rst","notebooks/index.rst","parser.rst","pretty.rst","stack.rst"],objects:{"joy.joy":{joy:[1,1,1,""],repl:[1,1,1,""],run:[1,1,1,""]},"joy.library":{"void":[3,1,1,""],BinaryBuiltinWrapper:[3,1,1,""],DefinitionWrapper:[3,2,1,""],FunctionWrapper:[3,1,1,""],SimpleFunctionWrapper:[3,1,1,""],UnaryBuiltinWrapper:[3,1,1,""],add_aliases:[3,1,1,""],app1:[3,1,1,""],app2:[3,1,1,""],app3:[3,1,1,""],b:[3,1,1,""],branch:[3,1,1,""],choice:[3,1,1,""],clear:[3,1,1,""],cmp_:[3,1,1,""],concat:[3,1,1,""],cond:[3,1,1,""],cons:[3,1,1,""],dip:[3,1,1,""],dipd:[3,1,1,""],dipdd:[3,1,1,""],divmod_:[3,1,1,""],drop:[3,1,1,""],dup:[3,1,1,""],dupd:[3,1,1,""],dupdip:[3,1,1,""],first:[3,1,1,""],floor:[3,1,1,""],genrec:[3,1,1,""],getitem:[3,1,1,""],help_:[3,1,1,""],i:[3,1,1,""],id_:[3,1,1,""],ifte:[3,1,1,""],infra:[3,1,1,""],initialize:[3,1,1,""],inscribe:[3,1,1,""],loop:[3,1,1,""],map_:[3,1,1,""],max_:[3,1,1,""],min_:[3,1,1,""],over:[3,1,1,""],parse:[3,1,1,""],pm:[3,1,1,""],pop:[3,1,1,""],popd:[3,1,1,""],popdd:[3,1,1,""],popop:[3,1,1,""],pred:[3,1,1,""],remove:[3,1,1,""],rest:[3,1,1,""],reverse:[3,1,1,""],rolldown:[3,1,1,""],rollup:[3,1,1,""],select:[3,1,1,""],sharing:[3,1,1,""],shunt:[3,1,1,""],sort_:[3,1,1,""],sqrt:[3,1,1,""],stack_:[3,1,1,""],step:[3,1,1,""],succ:[3,1,1,""],sum_:[3,1,1,""],swaack:[3,1,1,""],swap:[3,1,1,""],take:[3,1,1,""],times:[3,1,1,""],tuck:[3,1,1,""],uncons:[3,1,1,""],unique:[3,1,1,""],unstack:[3,1,1,""],warranty:[3,1,1,""],words:[3,1,1,""],x:[3,1,1,""],zip_:[3,1,1,""]},"joy.library.DefinitionWrapper":{add_def:[3,3,1,""],add_definitions:[3,3,1,""],parse_definition:[3,3,1,""]},"joy.parser":{ParseError:[16,4,1,""],Symbol:[16,2,1,""],text_to_expression:[16,1,1,""]},"joy.utils":{pretty_print:[17,0,0,"-"],stack:[18,0,0,"-"]},"joy.utils.pretty_print":{TracePrinter:[17,2,1,""]},"joy.utils.pretty_print.TracePrinter":{go:[17,5,1,""],viewer:[17,5,1,""]},"joy.utils.stack":{expression_to_string:[18,1,1,""],iter_stack:[18,1,1,""],list_to_stack:[18,1,1,""],pick:[18,1,1,""],pushback:[18,1,1,""],stack_to_string:[18,1,1,""]},joy:{joy:[1,0,0,"-"],library:[3,0,0,"-"],parser:[16,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","function","Python function"],"2":["py","class","Python class"],"3":["py","classmethod","Python class method"],"4":["py","exception","Python exception"],"5":["py","method","Python method"]},objtypes:{"0":"py:module","1":"py:function","2":"py:class","3":"py:classmethod","4":"py:exception","5":"py:method"},terms:{"0b11100111011011":5,"4ac":11,"5bkei":10,"\u03b5":8,"abstract":[7,10],"boolean":[2,3,7,10],"break":7,"byte":5,"case":[2,3,13,18],"class":[3,7,16,17,18],"default":[3,6,10,18],"export":[3,16],"final":[2,10],"float":[3,7,14,16],"function":[0,1,4,5,6,9,14,15,16,17,18],"g\u00e9rard":14,"import":[2,5,6,8,10,11,12,13,14],"int":[6,7,14,16,18],"long":[10,15],"new":[2,3,6,7,9,12],"public":9,"return":[1,3,5,7,10,11,12,13,16,17,18],"short":11,"static":[2,9],"switch":2,"throw":10,"true":[2,3,5],"try":[6,8,13],"void":[0,3],"while":[3,7,10,16,18],Adding:[7,12,15],And:[5,6,8,10,14,18],But:[0,4,5,6,7,10,12],CPS:7,For:[2,3,10,12,15,18],Has:3,Its:3,One:[2,7,15],TOS:[2,3],That:[5,10],The:[0,1,2,3,4,6,8,9,11,14,15,16,18],Then:[2,3,10,11],There:[13,18],These:[15,18],Use:[3,8],Using:[0,8,10,15],With:[8,15],__str__:17,_tree_add_:10,_tree_add_e:10,_tree_add_p:10,_tree_add_r:10,_tree_add_t:10,_tree_delete_:10,_tree_delete_clear_stuff:10,_tree_delete_del:10,_tree_delete_r0:10,_tree_delete_r1:10,_tree_delete_rightmost:10,_tree_delete_w:10,_tree_get_:10,_tree_get_p:10,_tree_get_r:10,_tree_get_t:10,_tree_iter_order_curr:10,_tree_iter_order_left:10,_tree_iter_order_r:10,_tree_iter_order_right:10,_tree_t:10,_treestep_0:13,_treestep_1:13,_within_b:8,_within_p:8,_within_r:8,abbrevi:13,abl:11,about:[0,7,10,14,18],abov:[0,5,8,10,11],abs:8,absolut:7,accept:[1,2,3,5,6,7,10,12,13,14],accomplish:11,accordingli:10,accumul:5,action:[7,12,14],actual:[2,5,7,10],adapt:15,add:[3,5,6,7,11,12,17],add_alias:3,add_def:3,add_definit:[3,10,13],added:[4,10],adding:9,addit:[0,2,3,5,7,12,13],address:15,adjust:10,after:[5,6,7],afterward:7,again:[2,3,5,7,10],aggreg:[3,14],aka:[7,14],albrecht:0,algorithm:7,alia:3,alias:[3,7],align:[7,17],all:[3,5,6,7,10,12,13,17],allow:[9,10],almost:10,along:7,alphabet:3,alreadi:[8,11,12,14],also:[0,5,7,10,18],altern:4,although:[4,10],altogeth:6,alwai:[5,9],amort:10,analysi:[4,15],anamorph:7,ani:[4,5,7,9,10,14,16],annual:7,anonym:10,anoth:[10,18],anyth:[2,3,7],api:9,app1:3,app2:[3,7,11,12],app3:3,app:7,appear:[2,4,5,10],appendix:15,appli:[2,3,5,6,10],applic:6,approach:5,approxim:15,archiv:0,aren:14,arg:[2,3],argument:[2,3,7,8,17,18],arithmet:2,ariti:2,around:[5,18],arrang:13,arriv:[6,13],articl:[0,4,6],ask:[4,6],aspect:0,assign:18,associ:10,assum:8,asterisk:13,attack:7,attempt:[0,1],attribut:3,automat:4,auxiliari:13,avail:0,averag:[7,12],avoid:10,awai:10,awar:2,awkward:10,azur:15,back:10,backward:[9,10,13],bag:7,base:[0,2,3,9,13],basic:[1,2,3,7,10],becaus:[2,3,7,10,13,14,18],becom:[10,11,13,18],been:[8,9,10,11,14],befor:[6,7,10],begin:[10,13],behavior:[9,13],behaviour:[0,1],being:0,below:[2,3,5,6,10,14],bespok:7,best:0,better:[5,10],between:[0,5],beyond:6,biannual:7,binari:[0,6,7,15],binary_search_tre:10,binarybuiltinwrapp:3,bind:7,bingo:14,bit:[5,6,10],block:5,bodi:[2,7,10],body_text:3,borrow:7,both:[2,5,7,11,12,18],bottom:6,bracket:[7,16],branch:[3,5,6],breakpoint:7,bring:[5,7],btree:[10,13],buck:10,bug:[0,7],build:[6,7,14,18],built:11,bundl:[2,3],burgeon:7,calculu:4,call:[2,7,9,10,17,18],caller:10,can:[0,2,3,4,5,6,7,8,9,11,12,13,14,15,18],captur:7,card:7,care:[5,18],carefulli:14,carri:[6,10],cartesian:4,categor:[0,11,15],categori:4,ccc:4,ccon:10,certain:[7,18],certainli:10,chain:3,chang:[2,9,10,14],charact:14,chat:7,chatter:0,check:[6,8],child:13,choic:3,choos:9,cinf:10,circuit:4,cite_not:10,classmethod:3,claus:3,clear:[3,5,7],clear_stuff:10,cleav:[7,11,12],close:[0,1,4],clunki:5,cmp:[3,13,15],cmp_:3,code:[0,1,4,15],codireco:[6,8],collect:[4,6,7],combin:[0,3,5,6,7,8,13,14,15],come:[7,10],command:[7,10,11],common:[2,5],compar:[3,4],comparison:[0,10],compel:4,compil:[2,4,7,10,12,15],complet:4,complex:[3,14],compound:10,comput:[2,4,5,7,11],con:[3,5,6,7,8,10,11,13,14,18],conal:4,concat:[3,6,7,13],concaten:0,concatin:[0,3,18],concurr:2,cond:[3,10],condit:[3,7],conflict:10,consecut:15,consid:[5,6,10,13,14],consist:[2,6,7,13],constant:10,contain:[0,2,3,6,7],context:2,conting:10,continu:[0,14],control:7,conveni:4,convert:[12,13,16,18],cool:10,copi:[2,3,5,10,13,15],copyright:7,correspond:4,could:[2,4,5,7,9,10,14],count:3,counter:5,coupl:13,cours:[5,10],crack:10,crash:10,creat:[0,2,3,5,8,10],crude:[10,16],current:[2,3,7,13,14,17],custom:9,cycl:[5,6],cython:7,dai:7,data:[2,3],datastructur:[0,2,15,16,18],datatyp:18,ddididi:14,deal:[0,10],decid:10,decor:3,decrement:3,deduc:5,deeper:0,deepli:4,def:[3,7,11,12,18],defi:3,defin:[2,3,4,5,6,7,8,9,12,14,15],definit:[2,3,5,6,7,9,10,13,15],definitionwrapp:[3,10,13],deleg:7,delet:15,demonstr:4,depend:[3,10],deposit:13,der:10,deriv:[2,3,5,7,8,10,15],describ:[3,4,10,13,16],descript:[5,7],design:[2,3,10],desir:[7,13],destruct:10,detail:[7,10],detect:[6,10],determin:15,develop:[0,6,7,15],diagram:5,dialect:1,dict:[1,3],dictionari:[0,1,3,7,11,15],differ:[0,4,5,8,10,11,18],differenti:4,dig:[10,14],digit:5,dinfrirst:7,dip:[3,5,6,7,8,10,11,12,13,15],dipd:[3,6,7,10,11,14],dipdd:[3,10],direco:15,direct:7,directli:[5,13,18],disappear:2,discard:[3,6,8,10],disciplin:10,disenstacken:7,disk:7,displac:2,ditch:10,div:[3,7],dive:13,divis:10,divmod:3,divmod_:3,doc:[2,3,7],document:[15,16,18],doe:[0,1,4,6,7,12,15,17],doesn:[5,9,10,13,18],doing:[4,5,7,14],domain:4,don:[5,7,10],done:[2,5,7,9,11],door:7,dot:17,doubl:[5,7],down:[2,3,8,14],down_to_zero:7,dozen:7,draft:[4,9],dream:7,drive:[6,8],driven:5,driver:6,drop:[3,10],dudipd:7,dup:[3,5,6,7,8,10,11,14,18],dupd:3,dupdip:[3,5,10,11],duplic:[3,10],durat:2,dure:2,each:[2,3,4,5,7,12,13,17],easi:[0,10,13,14],easier:[3,10],easili:4,edit:15,effect:[2,3,7,14],effici:[6,12,14],either:[1,2,3,10],eleg:[7,10,11],element:[2,3],elliott:4,els:[2,3],embed:[4,10,14],empti:[3,7,13,18],encapsul:7,enclos:7,encod:6,end:[5,10,13,18],endless:6,enforc:[2,7],engend:7,enough:[7,11,17],enstacken:[6,7],enter:7,entir:18,entri:[3,14,17],epsilon:8,equal:[5,13,18],equat:[7,8],ergo:10,err:10,error:[7,16],essai:0,etc:[3,13,14,16],euler:15,eval:0,evalu:[1,2,3,7,8,10,11,12,13],eventu:11,everi:6,everyth:[3,10],evolv:9,exampl:[0,3,5,15,16,18],exce:6,except:[7,10,16],execut:[0,1,2,3,7,12,13,14,18],exercis:10,exist:[4,10],expand:10,expect:[2,3,13,18],experi:[7,13],explan:7,explor:7,express:[0,1,2,3,4,10,12,14,17,18],expression_to_str:18,extra:[5,6],extract:[10,15],extrem:7,extrememli:7,facet:0,facil:7,fact:16,factor:[2,5,7,10],fail:[2,3,10,16],fals:[2,3,5],far:[8,10],fascin:0,fear:10,few:[5,7,8],fewer:[3,7],fib:6,fib_gen:6,fibonacci:15,figur:[2,3,10],filter:10,fin:5,find:[2,3,5,6,13,15],finder:8,fine:[0,5,10],finish:11,first:[3,6,7,8,10,11,12,13,14,15],first_two:10,fit:[5,7,11],five:[5,7,15],fix:[2,3],flatten:[7,13],flexibl:15,floor:3,floordiv:5,flow:7,follow:[0,2,3,7,9,13,14],foo:[7,9,10],foo_ii:9,form:[2,3,4,5,6,13,18],forman:7,format:[15,17],formula:[0,5,15],forth:7,forum:0,found:7,four:[2,3,5,6,7,10],fourteen:5,fourth:[2,3,10],fractal:7,fraction0:7,fraction:[2,7],framework:7,free:[4,7,10],freeli:2,from:[0,1,2,3,5,6,7,8,10,11,12,13,14,15,18],front:[2,3],full:5,functionwrapp:3,funtion:10,further:[8,15],futur:11,garbag:7,gari:10,gcd:7,gener:[0,2,3,4,15,18],genrec:[3,7,10,13],geometr:5,get:[2,4,5,6,7,15],getitem:3,getrecursionlimit:18,getsourc:7,ghc:4,give:[4,5,10,13,18],given:[2,3,5,6,8,10,14,15],glue:7,going:[10,13,14],good:[5,10],grab:3,grammar:16,grand:7,great:[0,7,15],greater:18,group:0,gsra:8,guard:10,had:[5,14],haiku:7,half:[5,14],hand:[7,11,12,15],handi:8,handl:[10,18],happen:7,hard:14,hardwar:4,has:[0,2,6,7,8,9,10,11,14,18],haskel:4,have:[2,3,5,6,7,8,9,12,14,15,18],head:18,help:[7,10],help_:3,helper:3,herd:7,here:[5,6,10,13,14],hide:10,higher:[7,10],highli:7,histori:17,hmm:10,hoist:3,hold:5,hood:10,hope:[0,5,7,15],host:15,how:[0,4,8,10,14,15],howev:12,html:[2,3,6,11,15],http:10,huet:14,huge:10,hugh:[8,13],human:7,hypothet:2,id_:3,idea:[4,5,7],ident:3,if_not_empti:10,ift:[3,10,13],ignor:[3,10],imagin:14,imit:13,immut:[7,10],implement:[0,1,2,3,4,7,9,10,11,12],implicit:7,includ:[4,10,13],inclus:5,incom:18,incompat:9,increas:5,increment:[3,4,5,9],index:[0,7,18],indexerror:18,indic:13,inform:3,infra:[3,6,7,10,11,12,13,15],infrastructur:3,initi:[2,3,7,8,10],inlin:10,input:[1,8],inscrib:3,inspect:7,instal:0,instanti:[4,17],instead:[5,6,10,14,18],integ:[2,3,7,13],integr:3,intend:[0,7],interact:[7,15],interest:[0,5,10,15],interlud:15,intern:[0,17,18],interpret:[0,4,9,12,16,17],interrupt:7,interv:[4,5],introduc:9,introduct:0,invari:3,invers:3,ipf:7,isn:[10,14],item:[2,3,7,10,13,15,18],iter:[1,3,7,13,15,18],iter_stack:[12,18],its:[0,2,3,4,5,7,10,13,18],itself:[0,2,7,10],j05cmp:[2,3],job:15,john:[8,13],joi:[2,4,9,10,11,12],joypi:[7,14],jupyt:15,just:[0,2,3,6,7,9,10,13,14],keep:[10,14],kei:[13,15],kevin:0,key_n:10,keyerror:10,kind:[2,4,7,10,13],kleen:13,know:[5,10],known:4,l_kei:10,l_left:10,l_right:10,l_valu:10,lambda:4,languag:[4,7,9,10,11,12],larger:18,largest:3,last:[5,10],lastli:6,later:[7,13],law:2,lazili:8,lcm:5,lead:7,leaf:10,lean:7,learn:0,least:[2,5,18],least_fract:7,leav:5,left:[7,13,14,17,18],length:[3,5,18],less:[5,6,7,18],let:[6,8,10,11,13,14],level:[4,10],librari:[0,12],like:[2,3,5,7,11,13,15,16],line:[3,7,10,17],linear:18,link:0,linux:0,list:[0,3,5,7,8,10,13,14,17],list_to_stack:18,liter:[1,10,13,14,16],littl:[6,10,15],live:15,lkei:13,load:[5,7],locat:2,locu:17,log_2:10,logic:[0,5],longer:10,look:[6,7,8,10],lookup:7,loop:[0,1,3,5],lot:[7,10,11,14],love:5,low:4,lower:5,lowest:10,machin:0,machineri:10,macro:7,made:[0,7,14],mai:2,mail:0,main:[0,3,7,14],mainloop:9,maintain:14,major:9,make:[2,3,4,5,7,10,12,13,14,15],make_gener:8,manfr:[0,2,3,4],mani:[0,7],map:[1,3,5,7,9,13],map_:3,marker:7,mask:[5,6],match:[0,1],materi:0,math:[0,7,8,10],mathemat:7,matter:[5,8,10,13],max_:3,maximum:3,mayb:10,mean:[4,5,7,8,10,13,18],meant:[7,10,11,13],member:[2,3],mental:7,mention:2,mercuri:0,meta:[7,10,12],method:[0,3,7,15,17],midpoint:5,might:[4,6,10],mike:10,million:6,min_:3,minimum:3,minor:10,minu:[3,11],mirror:0,miscellan:0,mix:7,mod:3,model:[4,7],modern:0,modif:6,modifi:[7,10,14],modul:[0,1,3,7,16],modulu:7,month:7,more:[0,3,4,5,6,7,8,11,12,13,16,18],mostli:0,move:10,movement:2,much:[5,6,10],muck:10,mul:[7,11,14,17],multi:3,multipl:15,must:[2,3,5,9,13],name:[1,3,7,9,10,14,15,16,18],natur:[5,6,10],navig:14,neat:10,need:[2,3,5,6,8,9,10],neg:[3,11],nest:[3,7,10,14],network:7,never:9,new_kei:10,new_valu:10,newton:[0,15],next:[5,13],nice:[0,18],niether:2,node:[13,15],node_kei:10,node_valu:10,non:13,none:[1,3],nope:13,notat:[7,10],note:[2,5,8,10,18],notebook:[5,6,7,14,15],notebook_preambl:[2,5,6,8,10,11,12,13,14],noth:[2,10],notic:5,now:[5,6,7,12,13,15],nth:[3,18],nullari:[7,10],number:[1,2,3,5,6,8,18],object:16,observ:5,obviou:6,occur:10,odd:[5,6],off:[2,3,5,6,14],old:[2,12],old_k:10,old_kei:10,old_valu:10,onc:[3,9,10,11],one:[2,3,5,6,10,13,17,18],ones:6,onli:[2,3,5,10,14,18],onto:[1,2,3,7,18],open:7,oper:[3,7,10,18],optim:10,option:[1,7,10,18],order:[0,2,3,7,15,18],org:[0,10],origin:[0,1,2,3,10,14],other:[0,2,3,4,7,10,13,18],otherwis:[3,5,6,10,13],our:[5,6,7,8,13],out:[2,3,4,5,6,7,8,10,14],outcom:13,output:8,outsid:4,over:[3,4,5,6,7,8,10,11,13,15],own:10,pack:18,packag:[0,7],page:[0,10,11,18],pair:[2,3,5,6,10],palidrom:5,palindrom:5,pam:7,paper:[4,7,14],parallel:2,paramet:[1,2,3,12,16,17,18],parameter:15,parenthes:[10,18],pariti:6,pars:[0,3,7],parse_definit:3,parseerror:16,parser:0,part:[2,3,8,11,13],particular:14,pass:[0,10,17],path:15,pattern:[5,13],pe1:[5,6],pe2:6,pearl:14,pend:[3,7,14,17],peopl:15,per:[7,13],perhap:6,period:7,permit:18,persist:10,phase:2,pick:[5,6,18],pickl:7,pictur:10,pip:0,place:[3,5,7],plai:0,plu:[3,11],plug:[6,13],point:[4,7,10],pointless:2,pop:[3,5,6,7,10,11,12,13,18],popd:[3,7,8,10,12],popdd:[3,6,11],popop:[3,5,6,7,8,10,13],posit:[3,5,7],possibilit:10,possibl:[10,13,15],post:7,potenti:3,power:7,pragmat:5,preambl:8,precis:[0,1],pred:3,predic:[2,3,6],prefix:17,preserv:[4,13],pretti:[8,10,11,13,17,18],pretty_print:0,previou:7,prime:8,primit:[2,3,11],primrec:[3,6,7,8],print:[0,1,2,3,17,18],probabl:[6,7,10],problem:[7,15],proc_curr:10,proc_left:10,proc_right:10,proce:5,process:[7,13,17],produc:[5,10,13],product:[6,7],program:[0,2,3,6,7,8,10,14],project:15,prompt:7,proper:[2,3],properti:0,provid:[0,3,4,7],pun:[0,7],pure:0,puriti:7,purpos:7,push:[2,3,7,14,18],pushback:[7,18],put:[1,2,6,7,15,18],pypi:0,python:[0,2,3,10,11,14,15,16,18],quadrat:[0,15],queri:[10,13],query_kei:13,quit:[0,1,13],quot:[0,3,6,7,10,11,13,14,17],quotat:[2,3],quotient:3,r_kei:10,r_left:10,r_right:10,r_valu:10,rais:[10,16,18],rang:7,range_to_zero:7,raphson:8,rather:[5,7,13],ratio:7,reach:[5,6],read:[0,1,5,6,10,14],readabl:12,reader:10,real:10,realiz:[4,10],rearrang:[2,10],reason:[5,7],rebuild:[13,14],rec1:[2,3],rec2:[2,3],recogn:16,record:[7,17],recurs:[2,3,6,7,8,15,18],recus:7,redefin:15,redistribut:[3,7],reduc:2,redund:18,refactor:[7,9],refer:[0,2],regist:2,regular:16,reimplement:15,rel:11,releas:9,remain:[2,3,7,9],remaind:[3,8],remov:[3,10,18],render:15,repeat:5,repeatedli:5,repl:[0,1],replac:[0,2,3,6,13,14,15,18],repositori:0,repres:[2,7,10,16,17],represent:18,reprod:6,requir:18,resembl:7,respect:5,rest:[3,5,6,7,10,14,15,18],rest_two:10,restor:2,result:[1,2,3,5,10,11,13,14],resum:7,retir:2,retri:7,reus:10,revers:[3,5,6,14,18],rewrit:[3,7],rewritten:7,rid:10,right:[6,7,13,15,17,18],rightest:10,rightmost:5,rkei:13,roll:[3,8,10,11,13],rolldown:3,rollup:3,root:[3,8,11],run:[0,1,3,5,7,8,10,13,14],runtimeerror:18,sai:[6,10,13],same:[2,4,5,10,18],sandwich:[2,3],save:[2,5,7],scan:3,scanner:[7,16],scenario:14,scope:[6,10],search:[0,10],second:[3,7,10,13,18],see:[0,6,7,8,9,12,14,17],seem:[0,5,7,13],seen:14,select:3,semant:[2,3,7,9,10],semi:7,send:7,sens:[0,2,5,14],separ:7,sequenc:[0,1,2,3,5,7,10,12,14,15,16],seri:[5,6,10,14],set:[2,3,15],seven:[5,6],sever:[0,4,7],share:[3,7],shelf:2,shift:[5,6],shorter:15,shorthand:10,should:[2,3,5,10],shouldn:7,show:[4,14],shunt:[3,14],side:10,signifi:[7,10],similar:[10,13],simon:7,simpl:[7,18],simplefunctionwrapp:[3,12],simpler:13,simplest:15,simpli:4,simplifi:[5,10,14,15],sinc:[2,5,10,11],singl:[3,6,7,12,16],situ:10,situat:10,six:[5,6,7],sixti:[5,6],size:[7,15],skeptic:7,slight:8,slightli:10,smallest:3,smart:10,softwar:7,solei:2,solut:[5,6],solvabl:7,some:[2,3,6,7,10,13,15,18],somehow:10,someth:[2,9,10],sometim:10,somewher:[10,15],sort:[3,10,11],sort_:3,sourc:[0,1,3,15,16,17,18],space:[5,17],span:5,special:[6,10],specif:[0,4],specifi:10,speed:12,spell:13,sphinx:[15,18],spirit:[0,1,13],sqr:[7,8,11,14],sqrt:[3,8,11],squar:[3,8,16],stack:[0,1,3,5,6,8,10,11,12,13,14,16,17],stack_:3,stack_to_str:18,stage:13,stai:[0,1],stand:4,standard:[7,10],star:13,stare:10,start:[5,6,7,8,10,13],state:7,statement:3,step:[3,5,7,10,11,12,14,15],still:10,stop:10,storag:[5,10],store:5,str:[1,16,17,18],straightforward:[1,6,8,15],stream:5,stretch:10,string:[1,2,3,7,14,16,17,18],structur:[7,13,14,15,18],stuff:10,style:[0,4],sub:9,subclass:7,subject:14,substitut:10,subtract:5,succ:3,success:8,suffici:10,suggest:[4,10],suitabl:[3,4,5],sum:[3,6,7,11,12,13],sum_:3,summand:5,sumtre:13,suppli:[10,16],support:[7,17,18],suspect:2,swaack:[3,11,12,14],swap:[3,5,6,7,8,10,12,13,14],swon:[3,6,7,13,14],swoncat:[6,7,8,13],symbol:[2,3,11,14,16],symmetr:[5,10],sympi:11,syntact:7,syntax:[7,18],sys:18,system:[7,10],tail:[10,18],take:[3,5,7,8,10,11,18],talk:[7,10,18],target:14,tast:4,tbd:7,technic:2,techniqu:[4,14],technolog:2,temporari:14,ten:5,term:[1,2,7,8,15,16,18],termin:[2,3],ternari:7,test:[2,3],text:[0,1,3],text_to_express:[7,16],textual:7,than:[0,3,5,6,7,8,11,13,18],thei:[2,5,6,7,10,14,16,18],them:[2,3,5,6,10,14,15],theori:[2,3],therefor:6,thi:[0,1,2,3,4,5,6,7,8,11,13,14,15,16,17,18],thing:[2,6,10,11,14,16,18],think:[2,5,7,10,13],third:[3,6,7,10],thirti:5,those:[2,3,10,15],though:5,thought:7,thousand:5,thread:2,three:[2,3,5,7,10,13,15],through:[1,5,7,13,14,18],thun:[2,3,4,9],thunder:7,time:[3,5,7,8,10,14],to_set:10,todai:7,todo:[7,16],togeth:[6,7,15],token:16,toler:15,tool:7,top:[2,3,7,17,18],total:5,trace:[0,7,11,14,15,18],traceprint:17,track:14,tracker:0,transform:4,translat:4,travers:[0,15],treasur:0,treat:[0,2,3,15],treatment:6,tree:[0,7,15],treegrind:15,treestep:[0,15],tri:5,trick:5,trobe:0,trove:0,truediv:11,truthi:[3,7],tuck:[3,7],tupl:[3,7,18],turn:[2,3],twice:10,two:[2,3,5,7,8,10,13,14,15,18],type:[1,4,7,10,16,17,18],typic:[2,3],unari:7,unarybuiltinwrapp:3,unbalanc:[10,16],unchang:10,uncon:[3,6,7,10,13,14],under:[2,3,7,10],understand:[0,10],undistinguish:10,undocu:7,unfortun:18,uniqu:[3,10],unit:7,univers:[0,7],unnecessari:15,unpack:[2,3,10,18],unpair:5,unquot:[7,13],unstack:3,until:6,unus:5,unusu:10,updat:[0,15],usag:7,use:[0,2,3,4,5,6,7,8,9,10,11,12,13,14,18],used:[3,4,7,10,14,16,18],useful:0,user:13,uses:[2,5],using:[3,6,10,11,13,14],usual:[0,2],util:[0,12],valu:[0,2,3,5,7,8,12,13,15,18],value_n:10,valueerror:18,variabl:15,variant:10,variat:15,varieti:[4,7],variou:0,vener:18,verbos:4,veri:[0,1,4,7,10,18],versa:2,version:[0,1,2,6,9,11,13,14,15],via:7,vice:2,view:[10,15],viewer:[1,7,9,17],von:[0,2,3,4],wai:[0,2,3,4,5,7,12],want:[2,5,6,8,10],warranti:[3,7],wash:7,wast:7,web:18,websit:[0,5],welcom:7,well:[0,4,7,8,10,16],were:[7,14],what:[2,3,4,7,10,11,13,17],whatev:[2,3,13,18],when:[5,6,7,10,14,16,18],where:[2,3,7,10,15,18],which:[0,1,3,5,7,8,10,13,14,18],whole:[2,3,5,13],whose:6,why:[8,13],wiki:10,wikipedia:[0,10,14],wildli:7,wind:7,within:[7,10,12,15],without:[2,7,10],won:[10,18],word:[0,3,5,7,14],work:[0,3,5,6,7,8,10,13,14,18],worth:5,would:[2,5,6,7,8,10,14,18],wrap:[3,7],write:[4,8,10,13,14,15,18],written:[0,1,8,10,12,18],wrong:2,year:7,yet:[10,14],yield:[2,3,18],you:[0,2,3,5,6,7,9,10,12,13,14,17,18],your:[2,3,7],yourself:[7,10],zero:[3,10,13,16,18],zip:5,zip_:3,zipper:[0,15],zstr:14},titles:["Thun 0.2.0 Documentation","Joy Interpreter","Functions Grouped by, er, Function with Examples","Function Reference","Categorical Programming","Developing a Program in Joy","Using <code class=\"docutils literal notranslate\"><span class=\"pre\">x</span></code> to Generate Values","Thun: Joy in Python","Newton\u2019s method","No Updates","Treating Trees I: Ordered Binary Trees","Quadratic formula","Replacing Functions in the Dictionary","Treating Trees II: <code class=\"docutils literal notranslate\"><span class=\"pre\">treestep</span></code>","Traversing Datastructures with Zippers","Essays about Programming in Joy","Parsing Text into Joy Expressions","Tracing Joy Execution","Stack or Quote or Sequence or List\u2026"],titleterms:{"case":[8,10],"function":[2,3,7,8,10,11,12,13],"long":12,"new":10,"void":2,"while":2,Adding:10,One:[6,10],The:[5,7,10,13],There:7,Using:6,With:13,about:15,add:[2,10],adding:10,address:14,altern:13,analysi:5,anamorph:2,app1:2,app2:2,app3:2,appendix:10,approxim:8,averag:2,base:[8,10],binari:[2,10,13],both:10,branch:[2,10],can:10,categor:4,chatter:2,check:11,child:10,choic:2,cleanup:11,clear:2,cleav:2,cmp:10,code:[7,10],combin:[2,10],compar:10,comparison:2,compil:6,comput:8,con:2,concat:2,consecut:8,continu:7,current:10,datastructur:[7,10,14],defin:[10,11,13],definit:11,delet:10,deriv:[11,13],determin:14,develop:5,dialect:0,dictionari:12,dip:[2,14],dipd:2,dipdd:2,direco:6,disenstacken:2,div:2,document:0,doe:10,down_to_zero:2,drop:2,dup:2,dupd:2,dupdip:2,els:10,empti:10,enstacken:2,equal:10,essai:15,euler:[5,6],eval:7,even:6,exampl:[2,7,10,13],execut:17,express:[7,16],extract:13,fibonacci:6,filter:5,find:[8,10],first:[2,5],five:6,flatten:2,flexibl:13,floordiv:2,formula:11,found:10,further:5,gcd:2,gener:[5,6,8],genrec:2,get:[10,13],getitem:2,given:13,greater:10,group:2,have:[10,13],help:2,highest:10,host:0,how:[5,6],ift:2,indic:0,inform:0,infra:[2,14],integ:5,interest:6,interlud:10,intern:16,interpret:[1,7],item:14,iter:[5,10],joi:[0,1,3,5,7,14,15,16,17,18],just:5,kei:10,languag:0,least_fract:2,left:10,less:10,let:5,librari:[3,7],like:10,list:[2,18],literari:7,littl:5,logic:2,loop:[2,7],lower:10,lshift:2,make:[6,8],mani:5,map:2,math:2,method:8,min:2,miscellan:2,mod:2,modulu:2,more:10,most:10,mul:2,multipl:[5,6],must:10,name:11,nativ:11,neg:2,newton:8,next:8,node:10,non:10,now:10,nullari:2,one:7,onli:7,order:[10,13],osdn:0,our:10,over:2,pack:5,pam:2,parameter:[10,13],pars:[2,16],parser:[7,16],pass:7,path:14,per:10,pop:2,popd:2,popop:2,pow:2,power:6,pred:2,predic:[5,8,10,13],pretty_print:17,primrec:2,print:7,problem:[5,6],process:10,product:2,program:[4,5,11,13,15],project:[0,5,6],pure:7,put:[10,13],python:[7,12],quadrat:11,quick:0,quot:[2,18],rang:[2,5],range_to_zero:2,read:7,recur:[8,10],recurs:[10,13],redefin:[10,13],refactor:[5,10],refer:3,regular:7,reimplement:13,rem:2,remaind:2,remov:2,render:5,repl:7,replac:[10,12],reset:6,rest:2,revers:2,right:[10,14],rightmost:10,roll:2,rolldown:2,rollup:2,rshift:2,run:[2,6],second:2,select:2,sequenc:[6,18],set:[8,10],shorter:12,should:7,shunt:2,simplest:5,simplifi:11,size:[2,12],sourc:10,sqr:2,sqrt:2,stack:[2,7,18],start:0,step:[2,13],straightforward:11,structur:10,style:7,sub:[2,10],succ:2,sum:[2,5],swaack:2,swap:2,swon:2,swoncat:2,symbol:7,tabl:0,take:2,term:[5,6,13],ternari:2,text:16,than:10,thi:10,third:2,three:6,thun:[0,7],time:[2,6],togeth:[10,13],token:7,toler:8,trace:[12,17],traceprint:7,travers:[10,13,14],treat:[10,13],tree:[10,13,14],treegrind:13,treestep:13,truediv:2,truthi:2,tuck:2,two:6,unari:2,uncon:2,unit:2,unnecessari:5,unquot:2,unstack:2,updat:9,util:[17,18],valu:[6,10],variabl:11,variat:6,version:[5,10,12],view:7,within:8,word:2,write:11,xor:2,zero:6,zip:2,zipper:14}})
\ No newline at end of file
+Search.setIndex({docnames:["index","joy","lib","library","notebooks/Categorical","notebooks/Developing","notebooks/Generator_Programs","notebooks/Intro","notebooks/Newton-Raphson","notebooks/NoUpdates","notebooks/Ordered_Binary_Trees","notebooks/Quadratic","notebooks/Recursion_Combinators","notebooks/Replacing","notebooks/Treestep","notebooks/Types","notebooks/Zipper","notebooks/index","parser","pretty","stack"],envversion:52,filenames:["index.rst","joy.rst","lib.rst","library.rst","notebooks/Categorical.rst","notebooks/Developing.rst","notebooks/Generator_Programs.rst","notebooks/Intro.rst","notebooks/Newton-Raphson.rst","notebooks/NoUpdates.rst","notebooks/Ordered_Binary_Trees.rst","notebooks/Quadratic.rst","notebooks/Recursion_Combinators.rst","notebooks/Replacing.rst","notebooks/Treestep.rst","notebooks/Types.rst","notebooks/Zipper.rst","notebooks/index.rst","parser.rst","pretty.rst","stack.rst"],objects:{"joy.joy":{joy:[1,1,1,""],repl:[1,1,1,""],run:[1,1,1,""]},"joy.library":{"void":[3,1,1,""],BinaryBuiltinWrapper:[3,1,1,""],DefinitionWrapper:[3,2,1,""],FunctionWrapper:[3,1,1,""],SimpleFunctionWrapper:[3,1,1,""],UnaryBuiltinWrapper:[3,1,1,""],add_aliases:[3,1,1,""],app1:[3,1,1,""],app2:[3,1,1,""],app3:[3,1,1,""],b:[3,1,1,""],branch:[3,1,1,""],choice:[3,1,1,""],clear:[3,1,1,""],cmp_:[3,1,1,""],concat_:[3,1,1,""],cond:[3,1,1,""],cons:[3,1,1,""],dip:[3,1,1,""],dipd:[3,1,1,""],dipdd:[3,1,1,""],divmod_:[3,1,1,""],drop:[3,1,1,""],dup:[3,1,1,""],dupd:[3,1,1,""],dupdip:[3,1,1,""],first:[3,1,1,""],floor:[3,1,1,""],genrec:[3,1,1,""],getitem:[3,1,1,""],help_:[3,1,1,""],i:[3,1,1,""],id_:[3,1,1,""],ifte:[3,1,1,""],infra:[3,1,1,""],initialize:[3,1,1,""],inscribe:[3,1,1,""],loop:[3,1,1,""],map_:[3,1,1,""],max_:[3,1,1,""],min_:[3,1,1,""],over:[3,1,1,""],parse:[3,1,1,""],pm:[3,1,1,""],pop:[3,1,1,""],popd:[3,1,1,""],popdd:[3,1,1,""],popop:[3,1,1,""],pred:[3,1,1,""],remove:[3,1,1,""],rest:[3,1,1,""],reverse:[3,1,1,""],rolldown:[3,1,1,""],rollup:[3,1,1,""],select:[3,1,1,""],sharing:[3,1,1,""],shunt:[3,1,1,""],sort_:[3,1,1,""],sqrt:[3,1,1,""],stack_:[3,1,1,""],step:[3,1,1,""],succ:[3,1,1,""],sum_:[3,1,1,""],swaack:[3,1,1,""],swap:[3,1,1,""],take:[3,1,1,""],times:[3,1,1,""],tuck:[3,1,1,""],uncons:[3,1,1,""],unique:[3,1,1,""],unstack:[3,1,1,""],warranty:[3,1,1,""],words:[3,1,1,""],x:[3,1,1,""],zip_:[3,1,1,""]},"joy.library.DefinitionWrapper":{add_def:[3,3,1,""],add_definitions:[3,3,1,""],parse_definition:[3,3,1,""]},"joy.parser":{ParseError:[18,4,1,""],Symbol:[18,2,1,""],text_to_expression:[18,1,1,""]},"joy.utils":{pretty_print:[19,0,0,"-"],stack:[20,0,0,"-"]},"joy.utils.pretty_print":{TracePrinter:[19,2,1,""]},"joy.utils.pretty_print.TracePrinter":{go:[19,5,1,""],viewer:[19,5,1,""]},"joy.utils.stack":{concat:[20,1,1,""],expression_to_string:[20,1,1,""],iter_stack:[20,1,1,""],list_to_stack:[20,1,1,""],pick:[20,1,1,""],stack_to_string:[20,1,1,""]},joy:{joy:[1,0,0,"-"],library:[3,0,0,"-"],parser:[18,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","function","Python function"],"2":["py","class","Python class"],"3":["py","classmethod","Python class method"],"4":["py","exception","Python exception"],"5":["py","method","Python method"]},objtypes:{"0":"py:module","1":"py:function","2":"py:class","3":"py:classmethod","4":"py:exception","5":"py:method"},terms:{"0b11100111011011":5,"23rd":15,"4ac":[],"5bkei":10,"\u03b5":8,"abstract":[7,10,17],"boolean":[2,3,7,10],"break":[7,15],"byte":5,"case":[2,3,12,14,15,20],"class":[3,7,15,18,19,20],"default":[3,6,10,20],"export":[3,18],"final":[2,10,12],"float":[3,7,15,16,18],"function":[0,1,4,5,6,9,11,16,17,18,19,20],"g\u00e9rard":16,"import":[2,5,6,8,10,11,12,13,14,15,16],"int":[6,7,12,15,16,18,20],"long":[10,17],"new":[2,3,6,7,9,12,13,15],"p\u00f6ial":17,"p\u00f6ial06typingtool":15,"public":9,"return":[1,3,5,7,10,12,13,14,15,18,19,20],"short":[],"static":[2,9],"switch":[2,15],"throw":10,"true":[2,3,5,12,15],"try":[6,8,11,12,14,15],"void":[0,3],"while":[3,7,10,15,18,20],Adding:[7,13,17],And:[5,6,8,10,12,15,16,20],But:[0,4,5,6,7,10,13,15],CPS:7,For:[2,3,10,12,13,15,17,20],Has:3,Its:3,One:[2,7,15,17],TOS:[2,3],That:[5,10],The:[0,1,2,3,4,6,8,9,11,15,16,17,18,20],Then:[2,3,10,11,12,15],There:[11,12,14,15,20],These:[15,17,20],Use:[3,8,12],Using:[0,8,10,17],With:[8,12,15,17],_1000:15,__add__:15,__class__:15,__eq__:15,__ge__:15,__hash__:15,__init__:15,__main__:15,__radd__:15,__repr__:15,__str__:19,_names_for:15,_to_str:15,_tree_add_:10,_tree_add_e:10,_tree_add_p:10,_tree_add_r:10,_tree_add_t:10,_tree_delete_:10,_tree_delete_clear_stuff:10,_tree_delete_del:10,_tree_delete_r0:10,_tree_delete_r1:10,_tree_delete_rightmost:10,_tree_delete_w:10,_tree_get_:10,_tree_get_p:10,_tree_get_r:10,_tree_get_t:10,_tree_iter_order_curr:10,_tree_iter_order_left:10,_tree_iter_order_r:10,_tree_iter_order_right:10,_tree_t:10,_treestep_0:14,_treestep_1:14,_uniqu:15,_within_b:8,_within_p:8,_within_r:8,abbrevi:14,abl:15,about:[0,7,10,16,20],abov:[0,5,8,10,12,15],abs:8,absolut:7,accept:[1,2,3,5,6,7,10,11,13,14,15,16],accomplish:[],accordingli:10,accumul:5,action:[7,13,15,16],actual:[2,5,7,10,15],adapt:17,add:[3,5,6,7,13,15,19],add_alias:3,add_def:3,add_definit:[3,10,14],added:[4,10],adding:[9,15],addit:[0,2,3,5,7,12,13,14],address:17,adjust:10,after:[5,6,7,12],afterward:7,again:[2,3,5,7,10,12,15],aggreg:[3,16],ahead:15,aka:[7,16],albrecht:0,algorithm:[7,15],alia:3,alias:[3,7],align:[7,19],all:[3,5,6,7,10,12,13,14,15,19],alloc:15,allow:[9,10],almost:10,along:[7,12],alphabet:3,alreadi:[8,13,15,16],also:[0,5,7,10,15,20],alter:15,altern:4,although:[4,10],altogeth:6,alwai:[5,9,12],among:15,amort:10,analysi:[4,17],anamorph:[7,17],ani:[4,5,7,9,10,15,16,18],annual:7,anonym:10,anoth:[10,20],anyjoytyp:15,anymor:15,anyth:[2,3,7,15],api:9,app1:3,app2:[3,7,11,12,13],app3:3,app:7,appear:[2,4,5,10],append:15,appendix:17,appli:[2,3,5,6,10,12,15],applic:6,approach:5,approxim:17,archiv:0,aren:16,arg:[2,3],argument:[2,3,7,8,11,12,17,19,20],arithmet:2,ariti:2,around:[5,20],arrang:14,arriv:[6,14],articl:[0,4,6,12],ask:[4,6,15],aspect:0,assert:15,assign:20,associ:10,assum:8,asterisk:14,attack:7,attempt:[0,1],attribut:3,attributeerror:15,author:15,automat:[4,15],auxiliari:14,avail:[0,15],averag:[7,13],avoid:10,awai:10,awar:2,awkward:[10,12],azur:17,back:10,backward:[9,10,11,14],bag:7,banana:12,barb:12,base:[0,2,3,9,12,14],basic:[1,2,3,7,10],becaus:[2,3,7,10,14,15,16,20],becom:[10,14,20],been:[8,9,10,15,16],befor:[6,7,10],begin:[10,14],behavior:[9,14],behaviour:[0,1,15],being:0,below:[2,3,5,6,10,15,16],bespok:7,best:0,better:[5,10,12],between:[0,5],beyond:6,biannual:7,binari:[0,6,7,17],binary_search_tre:10,binarybuiltinwrapp:3,bind:7,bingo:16,bit:[5,6,10,15],block:5,bodi:[2,7,10],body_text:3,booktitl:15,bool:12,borrow:7,both:[2,5,7,11,12,13,15,20],bottom:6,bracket:[7,15,18],branch:[3,5,6,12],breakpoint:7,bring:[5,7],bruijn:15,btree:[10,14],buck:10,bug:[0,7],build:[6,7,11,12,16,20],built:[11,15],bundl:[2,3,12],burgeon:7,calculu:4,call:[2,7,9,10,12,15,19,20],caller:10,can:[0,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,20],cannot:15,captur:7,card:7,care:[5,20],carefulli:16,carri:[6,10],cartesian:4,catamorph:17,categor:[0,17],categori:4,ccc:4,ccon:[10,15],cell:[12,15],certain:[7,20],certainli:10,chain:3,chang:[2,9,10,15,16],charact:16,chat:7,chatter:[0,15],check:[6,8,15],child:14,choic:[3,12],choos:9,chop:11,cinf:10,circuit:4,cite_not:10,classmethod:3,claus:[3,15],clean:15,clear:[3,5,7],clear_stuff:10,cleav:[7,11,13],close:[0,1,4],clunki:[5,15],cmp:[3,14,17],cmp_:3,code:[0,1,4,11,12,15,17],codireco:[6,8],collaps:12,collect:[4,6,7,15],combin:[0,3,5,6,7,8,11,14,16,17],come:[7,10],command:[7,10,15],common:[2,5],compar:[3,4,15],comparison:[0,10],compel:4,compil:[2,4,7,10,13,17],compile_:[],complet:4,complex:[3,15,16],complic:15,compos:[],composit:15,compound:10,comput:[2,4,5,7,11,15],con:[3,5,6,7,8,10,11,12,14,16,20],conal:4,concat:[3,6,7,14,17,20],concat_:3,concaten:0,concatin:[0,3,20],conclus:17,concurr:2,cond:[3,10],condit:[3,7],confer:15,conflict:[10,15],consecut:17,consid:[5,6,10,12,14,15,16],consist:[2,6,7,14],constant:10,constitu:12,construct:15,consum:15,contain:[0,2,3,6,7,12],context:2,conting:10,continu:[0,12,16],control:7,conveni:[4,15],convers:15,convert:[12,13,14,15,18,20],cool:10,copi:[2,3,5,10,12,14,17],copyright:7,correspond:4,could:[2,4,5,7,9,10,15,16],count:3,counter:[5,15],coupl:14,cours:[5,10],crack:10,crash:10,creat:[0,2,3,5,8,10,15],creativ:15,crude:[10,15,18],current:[2,3,7,12,14,16,19],custom:9,cycl:[5,6],cython:7,dai:7,data:[2,3,12],datastructur:[0,2,12,15,17,18,20],datatyp:20,ddididi:16,de_bruijn_index:[],deal:[0,10],dealt:15,decid:10,declar:15,decor:3,decoupl:12,decrement:3,deduc:[5,15],deeper:0,deepli:4,def:[3,7,12,13,15,20],defaultdict:15,defi:3,defin:[2,3,4,5,6,7,8,9,11,12,13,15,16,17],definit:[2,3,5,6,7,9,10,12,14,15,17],definitionwrapp:[3,10,12,14],delabel:[],deleg:7,delet:17,deliber:15,demonstr:4,depend:[3,10,12],deposit:14,dequot:12,der:10,deriv:[2,3,5,7,8,10,15,17],describ:[3,4,10,12,14,15,18],descript:[5,7],descriptor:15,design:[2,3,10,17],desir:[7,14],destruct:10,detail:[7,10,15],detect:[6,10,12,15],determin:17,develop:[0,6,7,15,17],diagram:5,dialect:1,dict:[1,3,15],dictionari:[0,1,3,7,17],differ:[0,4,5,8,10,11,12,20],differenti:4,dig:[10,16],digit:5,dinfrirst:7,dip:[3,5,6,7,8,10,11,12,13,14,15,17],dipd:[3,6,7,10,11,12,16],dipdd:[3,10],direco:17,direct:7,directli:[5,14,15,20],disappear:2,discard:[3,6,8,10,12],disciplin:10,disenstacken:7,disk:7,displac:2,displai:15,distiguish:15,distinguish:[],ditch:10,div:[3,7],dive:14,divis:10,divmod:3,divmod_:[3,15],doc:[2,3,7,15],doc_from_stack_effect:[],document:[17,18,20],doe:[0,1,4,6,7,13,17,19],doesn:[5,9,10,14,15,20],doing:[4,5,7,15,16],domain:[4,15],don:[5,7,10,15],done:[2,5,7,9,15],door:7,dot:19,doubl:[5,7,15],down:[2,3,8,12,16],down_to_zero:7,dozen:7,draft:[4,9],dream:7,drive:[6,8],driven:5,driver:6,drop:[3,10],dudipd:7,due:15,dup:[3,5,6,7,8,10,11,12,16,20],dupd:[3,15],dupdip:[3,5,10,11,12],duplic:[3,10,12],durat:2,dure:[2,12],each:[2,3,4,5,7,12,13,14,15,19],easi:[0,10,14,15,16],easier:[3,10],easili:4,edit:17,effect:[2,3,7,16,17],effici:[6,13,16],either:[1,2,3,10,12,15],eleg:[7,10,15],element:[2,3],elif:15,elimin:15,elliott:4,els:[2,3,12,17],embed:[4,10,16],emit:15,empti:[3,7,14,15,20],encapsul:7,enclos:7,encod:6,encount:15,end:[5,10,12,14,15,20],endless:6,enforc:[2,7],engend:7,enough:[7,12,19],enstacken:[6,7,15],enter:7,entir:20,entri:[3,16,19],enumer:15,epsilon:8,equal:[5,14,20],equat:[7,8],ergo:10,err:10,error:[7,18],essai:0,establish:15,etc:[3,14,15,16,18],euler:17,euro:15,eval:[0,15],evalu:[1,2,3,7,8,10,11,12,13,14],eventu:[],everi:6,everyth:[3,10,11,15],evolv:9,examin:12,exampl:[0,3,5,17,18,20],exce:6,except:[7,10,15,18],execut:[0,1,2,3,7,12,13,14,16,20],exercis:10,exist:[4,10],expand:10,expect:[2,3,14,20],experi:[7,14],explain:15,explan:7,explor:7,express:[0,1,2,3,4,10,12,13,15,16,19,20],expression_to_str:20,extend:15,extra:[5,6],extract:[10,11,17],extrem:7,extrememli:7,f_g:15,f_in:15,f_out:15,f_python:15,facet:0,facil:7,fact:18,factor:[2,5,7,10,15],factori:17,fail:[2,3,10,18],fairli:15,fals:[2,3,5,12,15],far:[8,10,12,15],fascin:0,fear:[10,15],few:[5,7,8,11],fewer:[3,7],fg_in:15,fg_out:15,fib:6,fib_gen:6,fibonacci:17,figur:[2,3,10,12],filter:10,fin:5,find:[2,3,5,6,14,15,17],finder:8,fine:[0,5,10,15],finish:[],first:[3,6,7,8,10,11,12,13,14,16,17],first_two:10,fit:[5,7],five:[5,7,17],fix:[2,3,12],flatten:[7,14],flexibl:17,floatjoytyp:15,floor:3,floordiv:5,flow:7,follow:[0,2,3,7,9,12,14,15,16],foo:[7,9,10,15],foo_ii:9,form:[2,3,4,5,6,12,14,15,20],forman:7,format:[15,17,19],formula:[0,5,17],forth:[7,15],forum:0,found:7,four:[2,3,5,6,7,10,17],fourteen:5,fourth:[2,3,10,12],fractal:7,fraction0:7,fraction:[2,7],frame:12,framework:7,free:[4,7,10],freeli:2,from:[0,1,2,3,5,6,7,8,10,11,12,13,14,15,16,17,20],front:[2,3,12],full:5,fun:17,func:15,functionwrapp:3,funtion:10,further:[8,17],futur:[],g_in:15,g_out:15,garbag:7,gari:10,gcd:7,gener:[0,2,3,4,12,15,17,20],genrec:[3,7,10,12,14],geometr:5,get:[2,4,5,6,7,11,12,15,17],getitem:3,getrecursionlimit:20,getsourc:7,ghc:4,give:[4,5,10,12,14,15,20],given:[2,3,5,6,8,10,12,16,17],global:15,glue:7,going:[10,11,14,15,16],good:[5,10,15],grab:[3,15],grammar:18,grand:7,great:[0,7,17],greater:20,group:0,gsra:8,guard:10,had:[5,16],haiku:7,half:[5,16],hand:[7,13,15,17],handi:[8,15],handl:[10,15,20],happen:[7,15],hard:[15,16],hardwar:4,has:[0,2,6,7,8,9,10,12,15,16,20],hash:15,haskel:4,have:[2,3,5,6,7,8,9,12,13,15,16,17,20],head:20,help:[7,10,12,15],help_:3,helper:3,herd:7,here:[5,6,10,14,15,16],hide:10,hierarchi:15,higher:[7,10],highli:7,histori:19,hmm:10,hoist:3,hold:[5,15],hood:10,hope:[0,5,7,17],hopefulli:12,host:17,how:[0,4,8,10,12,15,16,17],howev:[12,13,15],html:[2,3,6,11,12,17],http:10,huet:16,huge:10,hugh:[8,14],human:7,hylomorph:17,hypothet:2,id_:3,idea:[4,5,7,15],ident:[3,12],identifi:[],if_not_empti:10,ift:[3,10,12,14],ignor:[3,10,15],illustr:12,imagin:16,imap:15,imit:14,immedi:12,immut:[7,10],imper:12,implement:[0,1,2,3,4,7,9,10,12,13,17],implicit:7,includ:[4,10,14],inclus:5,incom:20,incompat:9,incorpor:11,increas:5,increment:[3,4,5,9],index:[0,7,15,20],indexerror:20,indic:[14,15],ineffici:15,infer:[0,17],inform:[3,15],infra:[3,6,7,10,11,13,14,17],infrastructur:3,initi:[2,3,7,8,10],inlin:10,inner:15,inproceed:15,input:[1,8,15],inscrib:3,insight:12,inspect:7,instal:0,instanti:[4,19],instead:[5,6,10,12,15,16,20],integ:[2,3,7,12,14,15],integr:3,intend:[0,7],interact:[7,17],interest:[0,5,10,15,17],interlud:17,intermedi:12,intern:[0,15,19,20],interpret:[0,4,9,13,17,18,19],interrupt:7,interv:[4,5],intjoytyp:15,introduc:9,introduct:0,intuit:15,invari:3,invers:3,involv:15,ipf:7,isinst:15,isn:[10,16],issubclass:15,item:[2,3,7,10,12,14,15,17,20],iter:[1,3,7,12,14,15,17,20],iter_stack:[13,20],iteritem:15,itertool:15,its:[0,2,3,4,5,7,10,12,14,15,20],itself:[0,2,7,10,15],j05cmp:[2,3,12],jaanu:15,job:17,john:[8,14],joi:[2,4,9,10,11,13,15],join:15,joypi:[7,16],junk:15,jupyt:17,just:[0,2,3,6,7,9,10,12,14,15,16],keep:[10,11,15,16],kei:[14,17],kevin:0,key_n:10,keyerror:[10,15],kind:[2,4,7,10,12,14],kleen:14,know:[5,10],known:4,l_kei:10,l_left:10,l_right:10,l_valu:10,label:15,lambda:[4,15],languag:[4,7,9,10,13,15],larger:20,largest:3,last:[5,10,12,15],lastli:6,later:[7,14,15],law:2,lazi:15,lazili:8,lcm:5,lead:7,leaf:10,lean:7,learn:0,least:[2,5,12,15,20],least_fract:7,leav:5,left:[7,11,12,14,15,16,19,20],leftov:12,len:15,length:[3,5,20],lens:12,less:[5,6,7,12,15,20],let:[6,8,10,11,12,14,15,16],level:[4,10],librari:[0,13],like:[2,3,5,7,14,15,17,18],limit:15,line:[3,7,10,11,19],linear:20,link:0,linux:0,list:[0,3,5,7,8,10,12,14,16,19],list_to_stack:20,liter:[1,10,14,15,16,18],littl:[6,10,15,17],live:17,lkei:14,load:[5,7],local:15,locat:2,locu:19,log_2:10,logic:[0,5],longer:[10,15],look:[6,7,8,10,11,15],lookup:7,loop:[0,1,3,5],lose:15,lot:[7,10,16],love:5,low:4,lower:5,lowest:10,machin:0,machineri:[10,15],macro:7,made:[0,7,15,16],magic:15,mai:[2,12],mail:0,main:[0,3,7,11,15,16],mainloop:9,maintain:16,major:9,make:[2,3,4,5,7,10,12,13,14,15,16,17],make_gener:8,manfr:[0,2,3,4,12],mani:[0,7,15],manipul:15,manner:11,map:[1,3,5,7,9,12,14,15],map_:3,marker:7,mask:[5,6],match:[0,1],materi:0,math:[0,7,8,10,11,15],mathemat:7,matter:[5,8,10,14],max_:3,maximum:3,mayb:10,mean:[4,5,7,8,10,12,14,20],meant:[7,10,12,14],member:[2,3,12],mental:7,mention:2,mercuri:0,mess:15,meta:[7,10,13],method:[0,3,7,15,17,19],midpoint:5,might:[4,6,10,15],mike:10,million:6,min_:3,mind:15,minimum:3,minor:10,minu:3,mirror:0,miscellan:0,mix:7,mod:3,model:[4,7],modern:0,modif:6,modifi:[7,10,16],modul:[0,1,3,7,18],modulu:7,moment:15,month:7,more:[0,3,4,5,6,7,8,12,13,14,15,18,20],most:15,mostli:0,move:10,movement:2,much:[5,6,10,12,15],muck:10,mul:[7,11,16,19],multi:3,multipl:17,must:[2,3,5,9,12,14,15],myself:15,n1001:15,n1002:15,n1003:15,name:[1,3,7,9,10,12,15,16,17,18,20],natur:[5,6,10],navig:16,nearli:15,neat:10,neato:15,necessarili:15,need:[2,3,5,6,8,9,10,12,15],neg:[3,11],nest:[3,7,10,16],network:7,never:[9,12],new_def:15,new_kei:10,new_valu:10,newton:[0,17],next:[5,14,15],nice:[0,12,20],niether:2,node:[14,17],node_kei:10,node_valu:10,non:14,none:[1,3,15],nope:14,notat:[7,10],note:[2,5,8,10,12,15,20],notebook:[5,6,7,15,16,17],notebook_preambl:[2,5,6,8,10,11,12,13,14,15,16],noth:[2,10],notic:5,now:[5,6,7,12,13,14,15,17],nth:[3,20],nullari:[7,10],number:[1,2,3,5,6,8,20],numberjoytyp:15,numer:15,object:[15,18],observ:5,obviou:[6,15],occur:10,odd:[5,6],off:[2,3,5,6,11,16],old:[2,13],old_k:10,old_kei:10,old_valu:10,omit:[12,15],onc:[3,9,10],one:[2,3,5,6,10,12,14,15,19,20],ones:[6,15],onli:[2,3,5,10,12,15,16,20],onto:[1,2,3,7,12,20],open:[7,15],oper:[3,7,10,12,20],oppos:15,optim:10,option:[1,7,10,20],order:[0,2,3,7,12,15,17,20],org:[0,10],origin:[0,1,2,3,10,16],other:[0,2,3,4,7,10,12,14,15,20],otherwis:[3,5,6,10,14,15],our:[5,6,7,8,12,14,15],out:[2,3,4,5,6,7,8,10,11,12,15,16],outcom:14,output:[8,12,15],outsid:4,over:[3,4,5,6,7,8,10,11,14,15,17],overhaul:15,own:[10,15],pack:20,packag:[0,7],page:[0,10,15,20],pair:[2,3,5,6,10,15],palidrom:5,palindrom:5,pam:7,paper:[4,7,12,16],parallel:2,paramet:[1,2,3,12,13,18,19,20],parameter:17,paramorph:12,parenthes:[10,20],pariti:6,pars:[0,3,7],parse_definit:3,parseerror:18,parser:[0,15],part:[2,3,8,12,14,15],partial:15,particular:16,pass:[0,10,15,19],path:17,pattern:[5,14,17],pe1:[5,6],pe2:6,pearl:16,pend:[3,7,12,16,19],peopl:17,per:[7,14],perform:15,perhap:6,period:7,permit:[15,20],permut:15,persist:10,phase:2,pick:[5,6,20],pickl:7,pictur:10,piec:12,pip:0,place:[3,5,7],plai:0,plu:3,plug:[6,12,14],point:[4,7,10,12],pointless:2,pop:[3,5,6,7,10,12,13,14,20],popd:[3,7,8,10,13,15],popdd:[3,6,11,15],popop:[3,5,6,7,8,10,14,15],posit:[3,5,7,12],possibilit:10,possibl:[10,14,15,17],post:7,poswrd:15,poswro:[],potenti:3,power:7,pragmat:5,preambl:8,precis:[0,1],pred:[3,15],predic:[2,3,6,12],prefix:[15,19],preserv:[4,14],pretti:[8,10,11,14,15,19,20],pretty_print:0,previou:7,prime:8,primit:[2,3,15,17],primrec:[3,6,7,8,12],print:[0,1,2,3,15,19,20],probabl:[6,7,10,15],problem:[7,15,17],proc_curr:10,proc_left:10,proc_right:10,proce:5,process:[7,14,15,19],produc:[5,10,12,14,15],product:[6,7],program:[0,2,3,6,7,8,10,12,16],programm:15,project:17,prompt:7,proper:[2,3,12],properti:0,provid:[0,3,4,7],psrd:[],pun:[0,7],punctuat:15,pure:0,puriti:7,purpos:7,push:[2,3,7,12,16,20],pushback:7,put:[1,2,6,7,15,17,20],pypi:0,python:[0,2,3,10,12,16,17,18,20],quadrat:[0,17],queri:[10,14],query_kei:14,queu:12,quit:[0,1,14],quot:[0,3,6,7,10,11,12,14,15,16,19],quotat:[2,3,12],quotient:3,r_kei:10,r_left:10,r_right:10,r_valu:10,rais:[10,15,18,20],rang:[7,15],range_revers:12,range_to_zero:7,ranger:12,ranger_revers:12,raphson:8,rather:[5,7,12,14],ratio:7,reach:[5,6,12],read:[0,1,5,6,10,15,16],readabl:13,reader:10,readi:15,real:10,realiz:[4,10],rearrang:[2,10,15],reason:[5,7,15],rebuild:[14,16],rec1:[2,3,12],rec2:[2,3,12],recogn:18,record:[7,19],recur:[12,15],recurs:[0,2,3,6,7,8,15,17,20],recus:7,redefin:17,redistribut:[3,7],reduc:[2,15],redund:20,refactor:[7,9],refer:[0,2],regist:2,regular:18,reimplement:17,rel:[],relabel:[],relat:15,releas:9,remain:[2,3,7,9],remaind:[3,8],remind:15,remov:[3,10,15,20],render:17,repeat:5,repeatedli:5,repl:[0,1],replac:[0,2,3,6,11,12,14,15,16,17,20],repositori:0,repr:15,repres:[2,7,10,18,19],represent:20,reprod:6,repurpos:15,requir:20,resembl:7,respect:5,rest:[3,5,6,7,10,12,16,17,20],rest_two:10,restor:2,restrict:15,result:[1,2,3,5,10,11,12,14,15,16],resum:7,retain:15,retir:2,retri:7,reus:[10,15],revers:[3,5,6,12,15,16,20],revisit:15,rewrit:[3,7,15],rewritten:7,rid:10,right:[6,7,11,14,15,17,19,20],rightest:10,rightmost:5,rkei:14,roll:[3,8,10,14],roll_dn:15,roll_down:15,roll_up:15,rolldown:3,rollup:3,root:[3,8,11],round:15,rrest:15,rule:17,run:[0,1,3,5,7,8,10,11,12,14,16],runtimeerror:20,sai:[6,10,11,14,15],same:[2,4,5,10,15,20],sandwich:[2,3,12],save:[2,5,7],scan:3,scanner:[7,18],scenario:16,scope:[6,10],search:[0,10],second:[3,7,10,12,14,20],section:12,see:[0,6,7,8,9,11,12,13,15,16,19],seem:[0,5,7,14,15],seen:[15,16],select:3,self:15,semant:[2,3,7,9,10,15],semi:7,send:7,sens:[0,2,5,15,16],separ:[7,15],seq:15,sequenc:[0,1,2,3,5,7,10,12,13,15,16,17,18],sequence_to_stack:15,seri:[5,6,10,16],set:[2,3,12,17],seven:[5,6],sever:[0,4,7,12],share:[3,7],shelf:2,shift:[5,6],shorter:17,shorthand:10,should:[2,3,5,10,12,15],shouldn:7,show:[4,16],shunt:[3,16],side:[10,15],signifi:[7,10],similar:[10,14,15],simon:7,simpl:[7,12,15,20],simplefunctionwrapp:[3,13,15],simpler:14,simplest:[15,17],simpli:4,simplifi:[5,10,16],sinc:[2,5,10],singl:[3,6,7,13,15,18],situ:10,situat:10,six:[5,6,7],sixti:[5,6],size:[7,17],skeptic:7,skip:15,slight:8,slightli:[10,12,15],smallest:3,smart:10,softwar:7,solei:2,solut:[5,6],solvabl:7,some:[2,3,6,7,10,12,14,15,17,20],somehow:[10,15],someth:[2,9,10,17],sometim:10,somewher:[10,17],sort:[3,10,15],sort_:3,sourc:[0,1,3,15,17,18,19,20],space:[5,19],span:5,special:[6,10,15,17],specif:[0,4],specifi:10,speed:13,spell:14,sphinx:[17,20],spirit:[0,1,14],sqr:[7,8,11,16],sqrt:[3,8,15],squar:[3,8,15,18],stack:[0,1,3,5,6,8,10,11,12,13,14,16,17,18,19],stack_:3,stack_concat:15,stack_effect_com:15,stack_to_str:20,stacki:15,stackjoytyp:15,stage:14,stai:[0,1],stand:4,standard:[7,10],star:14,stare:10,start:[5,6,7,8,10,12,14],state:7,statement:3,step:[3,5,7,10,13,15,16,17],still:[10,15],stop:10,storag:[5,10],store:[5,12],stori:12,str:[1,15,18,19,20],straightforward:[1,6,8,17],stream:5,stretch:10,string:[1,2,3,7,15,16,18,19,20],structur:[7,14,15,16,17,20],stuff:[10,15],style:[0,4,15],sub:9,subclass:7,subject:[15,16],subset:15,substitut:[10,15],subtract:5,subtyp:17,succ:[3,15],success:8,suffic:15,suffici:10,suffix:15,suggest:[4,10],suitabl:[3,4,5],sum:[3,6,7,11,12,13,14],sum_:3,summand:5,sumtre:14,suppli:[10,18],support:[7,19,20],suspect:2,swaack:[3,11,13,16],swap:[3,5,6,7,8,10,12,13,14,16],swon:[3,6,7,12,14,15,16],swoncat:[6,7,8,12,14],swuncon:12,symbol:[2,3,15,16,17,18],symmetr:[5,10],sympi:[],syntact:7,syntax:[7,20],sys:20,system:[7,10],tabl:15,tag:15,tail:[10,15,17,20],take:[3,5,7,8,10,12,15,20],talk:[7,10,20],target:16,tast:4,tbd:[7,15],tear:12,technic:2,techniqu:[4,16],technolog:2,temporari:16,ten:5,term:[1,2,7,8,12,15,17,18,20],termin:[2,3,12],ternari:7,test:[2,3,12],text:[0,1,3,15],text_to_express:[7,18],textual:7,than:[0,3,5,6,7,8,12,14,20],thei:[2,5,6,7,10,12,15,16,18,20],them:[2,3,5,6,10,12,15,16,17],themselv:15,theori:[2,3,12],therefor:6,thi:[0,1,2,3,4,5,6,7,8,11,12,14,15,16,17,18,19,20],thing:[2,6,10,12,15,16,18,20],think:[2,5,7,10,12,14],third:[3,6,7,10],thirti:5,those:[2,3,10,12,15,17],though:5,thought:7,thousand:5,thread:2,three:[2,3,5,7,10,11,14,15,17],through:[1,5,7,14,15,16,20],thun:[2,3,4,9,12],thunder:7,time:[3,5,7,8,10,12,15,16],titl:15,to_set:10,todai:7,todo:[7,18],togeth:[6,7,15,17],token:18,toler:17,too:[12,15],tool:[7,15],top:[2,3,7,12,15,19,20],total:5,tower:15,trace:[0,7,11,12,16,17,20],traceprint:19,track:[11,15,16],tracker:0,transform:4,translat:[4,11,15],travers:[0,17],treasur:0,treat:[0,2,3,12,17],treatment:6,tree:[0,7,17],treegrind:17,treestep:[0,17],tri:5,triangular_numb:12,trick:[5,15],tricki:15,trobe:0,trove:0,truediv:[],truthi:[3,7],tuck:[3,7,15],tupl:[3,7,15,20],turn:[2,3],twice:[10,12],two:[2,3,5,7,8,10,11,12,14,15,16,17,20],type:[0,1,4,7,10,12,17,18,19,20],typeerror:15,typeless:15,typic:[2,3,11,12],unari:7,unarybuiltinwrapp:3,unbalanc:[10,18],unchang:10,uncompil:15,uncon:[3,6,7,10,12,14,16],under:[2,3,7,10],underli:15,underscor:15,understand:[0,10],undistinguish:10,undocu:7,unfortun:20,unif:15,uniqu:[3,10,15],unit:[7,12],univers:[0,7],unnecessari:17,unnecesssari:15,unpack:[2,3,10,20],unpair:5,unquot:[7,14],unstack:[3,15],untangl:12,until:6,unus:5,unusu:10,updat:[0,17],usag:7,use:[0,2,3,4,5,6,7,8,9,10,11,12,13,14,16,17,20],used:[3,4,7,10,12,16,18,20],useful:0,user:14,uses:[2,5,12],using:[3,6,10,11,12,14,16],usual:[0,2,12],util:[0,13],valid:15,valu:[0,2,3,5,7,8,11,12,13,14,15,17,20],value_n:10,valueerror:[15,20],variabl:17,variant:10,variat:[12,17],varieti:[4,7],variou:0,vener:20,verbos:4,veri:[0,1,4,7,10,20],versa:[2,15],version:[0,1,2,6,9,14,16,17],via:7,vice:[2,15],view:[10,17],viewer:[1,7,9,19],von:[0,2,3,4,12],wai:[0,2,3,4,5,7,12,13,15],want:[2,5,6,8,10,12,15],warranti:[3,7],wash:7,wast:7,web:20,websit:[0,5],welcom:7,well:[0,4,7,8,10,15,18],were:[7,15,16],what:[2,3,4,7,10,12,14,15,19],whatev:[2,3,12,14,20],when:[5,6,7,10,12,15,16,18,20],where:[2,3,7,10,12,17,20],whether:12,which:[0,1,3,5,7,8,10,12,14,15,16,20],whole:[2,3,5,12,14,15],whose:6,why:[8,14],wiki:10,wikipedia:[0,10,16],wildli:7,wind:7,wire:12,within:[7,10,13,17],without:[2,7,10,11],won:[10,15,20],word:[0,3,5,7,12,16],work:[0,3,5,6,7,8,10,11,12,14,15,16,20],worth:5,would:[2,5,6,7,8,10,12,15,16,20],wrap:[3,7],wrapper:15,write:[4,8,10,12,14,15,16,17,20],written:[0,1,8,10,13,15,20],wrong:2,wrote:15,xrang:15,year:[7,15],yet:[10,15,16],yield:[2,3,12,20],you:[0,2,3,5,6,7,9,10,11,12,13,14,15,16,19,20],your:[2,3,7,12,15],yourself:[7,10],zero:[3,10,12,14,18,20],zip:[5,15],zip_:3,zipper:[0,17],zstr:16},titles:["Thun 0.2.0 Documentation","Joy Interpreter","Functions Grouped by, er, Function with Examples","Function Reference","Categorical Programming","Developing a Program in Joy","Using <code class=\"docutils literal notranslate\"><span class=\"pre\">x</span></code> to Generate Values","Thun: Joy in Python","Newton\u2019s method","No Updates","Treating Trees I: Ordered Binary Trees","Quadratic formula","Recursive Combinators","Replacing Functions in the Dictionary","Treating Trees II: <code class=\"docutils literal notranslate\"><span class=\"pre\">treestep</span></code>","Type Inference","Traversing Datastructures with Zippers","Essays about Programming in Joy","Parsing Text into Joy Expressions","Tracing Joy Execution","Stack or Quote or Sequence or List\u2026"],titleterms:{"abstract":15,"case":[8,10],"function":[2,3,7,8,10,12,13,14,15],"long":13,"new":10,"p\u00f6ial":15,"void":2,"while":2,Adding:10,One:[6,10],The:[5,7,10,12,14],There:7,Using:6,With:14,about:17,add:[2,10],adding:10,address:16,altern:14,ana:12,analysi:5,anamorph:[2,12],app1:2,app2:2,app3:2,appendix:[10,12],approxim:8,argument:15,averag:2,base:[8,10],binari:[2,10,14],both:10,branch:[2,10],can:10,cata:12,catamorph:12,categor:4,chatter:2,check:[],child:10,choic:2,cleanup:[],clear:2,cleav:2,cmp:10,code:[7,10],combin:[2,10,12,15],comment:15,compar:10,comparison:2,compil:[6,15],compile_:15,compos:15,comput:8,con:[2,15],concat:[2,15],conclus:12,consecut:8,continu:7,current:10,datastructur:[7,10,16],deal:15,defin:[10,14],definit:11,delabel:15,delet:10,deriv:[11,12,14],design:12,determin:16,develop:5,dialect:0,dictionari:13,dip:[2,16],dipd:2,dipdd:2,direco:6,disenstacken:2,distinguish:15,div:2,doc_from_stack_effect:15,document:0,doe:10,down_to_zero:2,drop:2,dup:[2,15],dupd:2,dupdip:2,effect:15,els:[10,15],empti:10,enstacken:2,equal:10,essai:17,euler:[5,6],eval:7,even:6,exampl:[2,7,10,12,14,15],execut:19,express:[7,18],extract:14,factori:12,fibonacci:6,filter:5,find:[8,10,12],first:[2,5,15],five:6,flatten:2,flexibl:14,floordiv:2,formula:11,found:10,four:12,fun:12,further:5,gcd:2,gener:[5,6,8],genrec:2,get:[10,14],getitem:2,given:14,greater:10,group:2,have:[10,14],help:2,highest:10,host:0,how:[5,6],hylo:12,hylomorph:12,identifi:15,ift:2,implement:15,indic:0,infer:15,inferenc:15,inform:0,infra:[2,16],integ:5,interest:6,interlud:10,intern:18,interpret:[1,7,15],item:16,iter:[5,10],joi:[0,1,3,5,7,12,16,17,18,19,20],just:5,kei:10,languag:0,least_fract:2,left:10,less:10,let:5,librari:[3,7,15],like:10,list:[2,15,20],literari:7,littl:5,logic:2,loop:[2,7],lower:10,lshift:2,make:[6,8],mani:5,map:2,math:2,method:8,min:2,miscellan:2,mod:2,modifi:15,modulu:2,more:10,most:10,mul:[2,15],multipl:[5,6],must:10,name:11,nativ:[],neg:2,newton:8,next:8,node:10,non:10,now:10,nullari:2,number:[12,15],one:7,onli:7,order:[10,14],osdn:0,our:10,over:2,pack:5,pam:2,para:12,parameter:[10,14],pars:[2,18],parser:[7,18],pass:7,path:16,pattern:12,per:10,pop:[2,15],popd:2,popop:2,pow:2,power:6,pred:2,predic:[5,8,10,14],pretty_print:19,primit:12,primrec:2,print:7,problem:[5,6],process:10,product:2,program:[4,5,11,14,17],project:[0,5,6],pure:7,put:[10,11,14],python:[7,13,15],quadrat:11,quick:0,quot:[2,20],rang:[2,5,12],range_to_zero:2,read:7,recur:[8,10],recurs:[10,12,14],redefin:[10,14],refactor:[5,10],refer:3,regular:7,reimplement:14,relabel:15,rem:2,remaind:2,remov:2,render:5,repl:7,replac:[10,13],repres:15,reset:6,rest:[2,15],revers:2,right:[10,16],rightmost:10,roll:[2,15],rolldown:2,rollup:2,rshift:2,rule:15,run:[2,6],second:[2,15],select:2,sequenc:[6,20],set:[8,10,15],shorter:13,should:7,shunt:2,simplest:5,simplifi:[],size:[2,13],someth:15,sourc:10,special:12,sqr:[2,15],sqrt:[2,11],stack:[2,7,15,20],start:0,step:[2,12,14],straightforward:11,structur:10,style:7,sub:[2,10],subtyp:15,succ:2,sum:[2,5],swaack:2,swap:[2,15],swon:2,swoncat:2,symbol:[7,12],tabl:0,tail:12,take:2,term:[5,6,14],ternari:2,text:18,than:10,them:11,thi:10,thing:[],third:[2,15],three:6,thun:[0,7],time:[2,6],togeth:[10,11,14],token:7,toler:8,trace:[13,19],traceprint:7,travers:[10,14,16],treat:[10,14],tree:[10,14,16],treegrind:14,treestep:14,triangular:12,truediv:2,truthi:2,tuck:2,two:6,type:15,unari:2,uncon:[2,15],unifi:15,unit:2,unnecessari:5,unquot:2,unstack:2,updat:[9,15],use:15,util:[19,20],valu:[6,10],variabl:11,variat:6,version:[5,10,13,15],view:7,within:8,word:2,write:11,xor:2,zero:6,zip:2,zipper:16}})
\ No newline at end of file
index ce88245..5329c20 100644 (file)
@@ -81,6 +81,31 @@ one-by-one in order.  There are also two functions to generate string representa
 of stacks.  They only differ in that one prints the terms in stack from left-to-right while the other prints from right-to-left.  In both functions <em>internal stacks</em> are
 printed left-to-right.  These functions are written to support <a class="reference internal" href="pretty.html"><span class="doc">Tracing Joy Execution</span></a>.</p>
 <dl class="function">
+<dt id="joy.utils.stack.concat">
+<code class="descclassname">joy.utils.stack.</code><code class="descname">concat</code><span class="sig-paren">(</span><em>quote</em>, <em>expression</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/joy/utils/stack.html#concat"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#joy.utils.stack.concat" title="Permalink to this definition">¶</a></dt>
+<dd><p>Concatinate quote onto expression.</p>
+<p>In joy [1 2] [3 4] would become [1 2 3 4].</p>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
+<li><strong>quote</strong> (<em>stack</em>) – A stack.</li>
+<li><strong>expression</strong> (<em>stack</em>) – A stack.</li>
+</ul>
+</td>
+</tr>
+<tr class="field-even field"><th class="field-name">Raises:</th><td class="field-body"><p class="first"><strong>RuntimeError</strong> – if quote is larger than sys.getrecursionlimit().</p>
+</td>
+</tr>
+<tr class="field-odd field"><th class="field-name">Return type:</th><td class="field-body"><p class="first last">stack</p>
+</td>
+</tr>
+</tbody>
+</table>
+</dd></dl>
+
+<dl class="function">
 <dt id="joy.utils.stack.expression_to_string">
 <code class="descclassname">joy.utils.stack.</code><code class="descname">expression_to_string</code><span class="sig-paren">(</span><em>expression</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/joy/utils/stack.html#expression_to_string"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#joy.utils.stack.expression_to_string" title="Permalink to this definition">¶</a></dt>
 <dd><p>Return a “pretty print” string for a expression.</p>
@@ -169,31 +194,6 @@ won’t work because <code class="docutils literal notranslate"><span class="pre
 </dd></dl>
 
 <dl class="function">
-<dt id="joy.utils.stack.pushback">
-<code class="descclassname">joy.utils.stack.</code><code class="descname">pushback</code><span class="sig-paren">(</span><em>quote</em>, <em>expression</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/joy/utils/stack.html#pushback"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#joy.utils.stack.pushback" title="Permalink to this definition">¶</a></dt>
-<dd><p>Concatinate quote onto expression.</p>
-<p>In joy [1 2] [3 4] would become [1 2 3 4].</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
-<li><strong>quote</strong> (<em>stack</em>) – A stack.</li>
-<li><strong>expression</strong> (<em>stack</em>) – A stack.</li>
-</ul>
-</td>
-</tr>
-<tr class="field-even field"><th class="field-name">Raises:</th><td class="field-body"><p class="first"><strong>RuntimeError</strong> – if quote is larger than sys.getrecursionlimit().</p>
-</td>
-</tr>
-<tr class="field-odd field"><th class="field-name">Return type:</th><td class="field-body"><p class="first last">stack</p>
-</td>
-</tr>
-</tbody>
-</table>
-</dd></dl>
-
-<dl class="function">
 <dt id="joy.utils.stack.stack_to_string">
 <code class="descclassname">joy.utils.stack.</code><code class="descname">stack_to_string</code><span class="sig-paren">(</span><em>stack</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/joy/utils/stack.html#stack_to_string"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#joy.utils.stack.stack_to_string" title="Permalink to this definition">¶</a></dt>
 <dd><p>Return a “pretty print” string for a stack.</p>
index 9975abb..60e312f 100644 (file)
 
-`Quadratic formula <https://en.wikipedia.org/wiki/Quadratic_formula>`__
-=======================================================================
-
 .. code:: ipython2
 
     from notebook_preamble import J, V, define
 
+`Quadratic formula <https://en.wikipedia.org/wiki/Quadratic_formula>`__
+=======================================================================
+
 Cf.
 `jp-quadratic.html <http://www.kevinalbrecht.com/code/joy-mirror/jp-quadratic.html>`__
 
 ::
 
-             -b  +/- sqrt(b^2 - 4 * a * c)
-             -----------------------------
-                        2 * a
+       -b ± sqrt(b^2 - 4 * a * c)
+    --------------------------------
+                2 * a
 
 :math:`\frac{-b \pm \sqrt{b^2 - 4ac}}{2a}`
 
 Write a straightforward program with variable names.
 ----------------------------------------------------
 
-::
-
-    b neg b sqr 4 a c * * - sqrt [+] [-] cleave a 2 * [truediv] cons app2
-
-We use ``cleave`` to compute the sum and difference and then ``app2`` to
-finish computing both roots using a quoted program ``[2a truediv]``
-built with ``cons``.
+This math translates to Joy code in a straightforward manner. We are
+going to use named variables to keep track of the arguments, then write
+a definition without them.
 
-Check it.
-~~~~~~~~~
-
-Evaluating by hand:
+``-b``
+~~~~~~
 
 ::
 
-     b neg b sqr 4 a c * * - sqrt [+] [-] cleave a 2 * [truediv] cons app2
-    -b     b sqr 4 a c * * - sqrt [+] [-] cleave a 2 * [truediv] cons app2
-    -b     b^2   4 a c * * - sqrt [+] [-] cleave a 2 * [truediv] cons app2
-    -b     b^2 4ac         - sqrt [+] [-] cleave a 2 * [truediv] cons app2
-    -b     b^2-4ac           sqrt [+] [-] cleave a 2 * [truediv] cons app2
-    -b sqrt(b^2-4ac)              [+] [-] cleave a 2 * [truediv] cons app2
-
-    -b -b+sqrt(b^2-4ac)    -b-sqrt(b^2-4ac)    a 2 * [truediv] cons app2
-    -b -b+sqrt(b^2-4ac)    -b-sqrt(b^2-4ac)    2a    [truediv] cons app2
-    -b -b+sqrt(b^2-4ac)    -b-sqrt(b^2-4ac)    [2a truediv]         app2
-    -b -b+sqrt(b^2-4ac)/2a -b-sqrt(b^2-4ac)/2a
+    b neg
 
-(Eventually we’ll be able to use e.g. Sympy versions of the Joy commands
-to do this sort of thing symbolically. This is part of what is meant by
-a “categorical” language.)
-
-Cleanup
-~~~~~~~
+``sqrt(b^2 - 4 * a * c)``
+~~~~~~~~~~~~~~~~~~~~~~~~~
 
 ::
 
-    -b -b+sqrt(b^2-4ac)/2a -b-sqrt(b^2-4ac)/2a                          roll< pop
-       -b+sqrt(b^2-4ac)/2a -b-sqrt(b^2-4ac)/2a -b                             pop
-       -b+sqrt(b^2-4ac)/2a -b-sqrt(b^2-4ac)/2a
+    b sqr 4 a c * * - sqrt
 
-Derive a definition.
---------------------
+``/2a``
+~~~~~~~
 
 ::
 
-    b neg b           sqr 4 a c        * * - sqrt [+] [-] cleave a       2 * [truediv] cons app2 roll< pop
-    b    [neg] dupdip sqr 4 a c        * * - sqrt [+] [-] cleave a       2 * [truediv] cons app2 roll< pop
-    b a c    [[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave a       2 * [truediv] cons app2 roll< pop
-    b a c a    [[[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave] dip 2 * [truediv] cons app2 roll< pop
-    b a c over [[[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave] dip 2 * [truediv] cons app2 roll< pop
+    a 2 * /
 
-.. code:: ipython2
+``±``
+~~~~~
 
-    define('quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt [+] [-] cleave] dip 2 * [truediv] cons app2 roll< pop')
+There is a function ``pm`` that accepts two values on the stack and
+replaces them with their sum and difference.
 
-.. code:: ipython2
+::
 
-    J('3 1 1 quadratic')
+    pm == [+] [-] cleave popdd
 
+Putting Them Together
+~~~~~~~~~~~~~~~~~~~~~
 
-.. parsed-literal::
+::
 
-    -0.3819660112501051 -2.618033988749895
+    b neg b sqr 4 a c * * - sqrt pm a 2 * [/] cons app2
 
+We use ``app2`` to compute both roots by using a quoted program
+``[2a /]`` built with ``cons``.
 
-Simplify
---------
+Derive a definition.
+--------------------
 
-We can define a ``pm`` plus-or-minus function:
+Working backwards we use ``dip`` and ``dipd`` to extract the code from
+the variables:
 
 ::
 
-    pm == [+] [-] cleave popdd
+    b             neg  b      sqr 4 a c   * * - sqrt pm a    2 * [/] cons app2
+    b            [neg] dupdip sqr 4 a c   * * - sqrt pm a    2 * [/] cons app2
+    b a c       [[neg] dupdip sqr 4] dipd * * - sqrt pm a    2 * [/] cons app2
+    b a c a    [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2
+    b a c over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2
 
-Then ``quadratic`` becomes:
+The three arguments are to the left, so we can "chop off" everything to
+the right and say it's the definition of the ``quadratic`` function:
 
 .. code:: ipython2
 
-    define('quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [truediv] cons app2')
+    define('quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2')
+
+Let's try it out:
 
 .. code:: ipython2
 
@@ -110,74 +98,61 @@ Then ``quadratic`` becomes:
     -0.3819660112501051 -2.618033988749895
 
 
-Define a "native" ``pm`` function.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The definition of ``pm`` above is pretty elegant, but the implementation
-takes a lot of steps relative to what it's accomplishing. Since we are
-likely to use ``pm`` more than once in the future, let's write a
-primitive in Python and add it to the dictionary. (This has been done
-already.)
-
-.. code:: ipython2
-
-    def pm(stack):
-        a, (b, stack) = stack
-        p, m, = b + a, b - a
-        return m, (p, stack)
-
-The resulting trace is short enough to fit on a page.
+If you look at the Joy evaluation trace you can see that the first few
+lines are the ``dip`` and ``dipd`` combinators building the main program
+by incorporating the values on the stack. Then that program runs and you
+get the results. This is pretty typical of Joy code.
 
 .. code:: ipython2
 
-    V('3 1 1 quadratic')
+    V('-5 1 4 quadratic')
 
 
 .. parsed-literal::
 
-                                                        . 3 1 1 quadratic
-                                                      3 . 1 1 quadratic
-                                                    3 1 . 1 quadratic
-                                                  3 1 1 . quadratic
-                                                  3 1 1 . over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [truediv] cons app2
-                                                3 1 1 1 . [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [truediv] cons app2
-      3 1 1 1 [[[neg] dupdip sqr 4] dipd * * - sqrt pm] . dip 2 * [truediv] cons app2
-                                                  3 1 1 . [[neg] dupdip sqr 4] dipd * * - sqrt pm 1 2 * [truediv] cons app2
-                             3 1 1 [[neg] dupdip sqr 4] . dipd * * - sqrt pm 1 2 * [truediv] cons app2
-                                                      3 . [neg] dupdip sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                3 [neg] . dupdip sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                      3 . neg 3 sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                     -3 . 3 sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                   -3 3 . sqr 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                   -3 3 . dup mul 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                 -3 3 3 . mul 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                   -3 9 . 4 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                                 -3 9 4 . 1 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                               -3 9 4 1 . 1 * * - sqrt pm 1 2 * [truediv] cons app2
-                                             -3 9 4 1 1 . * * - sqrt pm 1 2 * [truediv] cons app2
-                                               -3 9 4 1 . * - sqrt pm 1 2 * [truediv] cons app2
-                                                 -3 9 4 . - sqrt pm 1 2 * [truediv] cons app2
-                                                   -3 5 . sqrt pm 1 2 * [truediv] cons app2
-                                    -3 2.23606797749979 . pm 1 2 * [truediv] cons app2
-                  -0.7639320225002102 -5.23606797749979 . 1 2 * [truediv] cons app2
-                -0.7639320225002102 -5.23606797749979 1 . 2 * [truediv] cons app2
-              -0.7639320225002102 -5.23606797749979 1 2 . * [truediv] cons app2
-                -0.7639320225002102 -5.23606797749979 2 . [truediv] cons app2
-      -0.7639320225002102 -5.23606797749979 2 [truediv] . cons app2
-      -0.7639320225002102 -5.23606797749979 [2 truediv] . app2
-                      [-0.7639320225002102] [2 truediv] . infra first [-5.23606797749979] [2 truediv] infra first
-                                    -0.7639320225002102 . 2 truediv [] swaack first [-5.23606797749979] [2 truediv] infra first
-                                  -0.7639320225002102 2 . truediv [] swaack first [-5.23606797749979] [2 truediv] infra first
-                                    -0.3819660112501051 . [] swaack first [-5.23606797749979] [2 truediv] infra first
-                                 -0.3819660112501051 [] . swaack first [-5.23606797749979] [2 truediv] infra first
-                                  [-0.3819660112501051] . first [-5.23606797749979] [2 truediv] infra first
-                                    -0.3819660112501051 . [-5.23606797749979] [2 truediv] infra first
-                -0.3819660112501051 [-5.23606797749979] . [2 truediv] infra first
-    -0.3819660112501051 [-5.23606797749979] [2 truediv] . infra first
-                                      -5.23606797749979 . 2 truediv [-0.3819660112501051] swaack first
-                                    -5.23606797749979 2 . truediv [-0.3819660112501051] swaack first
-                                     -2.618033988749895 . [-0.3819660112501051] swaack first
-               -2.618033988749895 [-0.3819660112501051] . swaack first
-               -0.3819660112501051 [-2.618033988749895] . first
-                 -0.3819660112501051 -2.618033988749895 . 
+                                                       . -5 1 4 quadratic
+                                                    -5 . 1 4 quadratic
+                                                  -5 1 . 4 quadratic
+                                                -5 1 4 . quadratic
+                                                -5 1 4 . over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2
+                                              -5 1 4 1 . [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2
+    -5 1 4 1 [[[neg] dupdip sqr 4] dipd * * - sqrt pm] . dip 2 * [/] cons app2
+                                                -5 1 4 . [[neg] dupdip sqr 4] dipd * * - sqrt pm 1 2 * [/] cons app2
+                           -5 1 4 [[neg] dupdip sqr 4] . dipd * * - sqrt pm 1 2 * [/] cons app2
+                                                    -5 . [neg] dupdip sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                              -5 [neg] . dupdip sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                                    -5 . neg -5 sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                                     5 . -5 sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                                  5 -5 . sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                                  5 -5 . dup mul 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                               5 -5 -5 . mul 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                                  5 25 . 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                                5 25 4 . 1 4 * * - sqrt pm 1 2 * [/] cons app2
+                                              5 25 4 1 . 4 * * - sqrt pm 1 2 * [/] cons app2
+                                            5 25 4 1 4 . * * - sqrt pm 1 2 * [/] cons app2
+                                              5 25 4 4 . * - sqrt pm 1 2 * [/] cons app2
+                                               5 25 16 . - sqrt pm 1 2 * [/] cons app2
+                                                   5 9 . sqrt pm 1 2 * [/] cons app2
+                                                 5 3.0 . pm 1 2 * [/] cons app2
+                                               8.0 2.0 . 1 2 * [/] cons app2
+                                             8.0 2.0 1 . 2 * [/] cons app2
+                                           8.0 2.0 1 2 . * [/] cons app2
+                                             8.0 2.0 2 . [/] cons app2
+                                         8.0 2.0 2 [/] . cons app2
+                                         8.0 2.0 [2 /] . app2
+                                           [8.0] [2 /] . infra first [2.0] [2 /] infra first
+                                                   8.0 . 2 / [] swaack first [2.0] [2 /] infra first
+                                                 8.0 2 . / [] swaack first [2.0] [2 /] infra first
+                                                   4.0 . [] swaack first [2.0] [2 /] infra first
+                                                4.0 [] . swaack first [2.0] [2 /] infra first
+                                                 [4.0] . first [2.0] [2 /] infra first
+                                                   4.0 . [2.0] [2 /] infra first
+                                             4.0 [2.0] . [2 /] infra first
+                                       4.0 [2.0] [2 /] . infra first
+                                                   2.0 . 2 / [4.0] swaack first
+                                                 2.0 2 . / [4.0] swaack first
+                                                   1.0 . [4.0] swaack first
+                                             1.0 [4.0] . swaack first
+                                             4.0 [1.0] . first
+                                               4.0 1.0 . 
 
diff --git a/docs/sphinx_docs/notebooks/Recursion_Combinators.rst b/docs/sphinx_docs/notebooks/Recursion_Combinators.rst
new file mode 100644 (file)
index 0000000..b4dc1a7
--- /dev/null
@@ -0,0 +1,695 @@
+
+.. code:: ipython2
+
+    from notebook_preamble import D, DefinitionWrapper, J, V, define
+
+Recursive Combinators
+=====================
+
+This article describes the ``genrec`` combinator, how to use it, and
+several generic specializations.
+
+::
+
+                          [if] [then] [rec1] [rec2] genrec
+    ---------------------------------------------------------------------
+       [if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte
+
+From "Recursion Theory and Joy" (j05cmp.html) by Manfred von Thun:
+
+    "The genrec combinator takes four program parameters in addition to
+    whatever data parameters it needs. Fourth from the top is an
+    if-part, followed by a then-part. If the if-part yields true, then
+    the then-part is executed and the combinator terminates. The other
+    two parameters are the rec1-part and the rec2-part. If the if-part
+    yields false, the rec1-part is executed. Following that the four
+    program parameters and the combinator are again pushed onto the
+    stack bundled up in a quoted form. Then the rec2-part is executed,
+    where it will find the bundled form. Typically it will then execute
+    the bundled form, either with i or with app2, or some other
+    combinator."
+
+Designing Recursive Functions
+-----------------------------
+
+The way to design one of these is to fix your base case and test and
+then treat ``R1`` and ``R2`` as an else-part "sandwiching" a quotation
+of the whole function.
+
+For example, given a (general recursive) function ``F``:
+
+::
+
+    F == [I] [T] [R1]   [R2] genrec
+      == [I] [T] [R1 [F] R2] ifte
+
+If the ``[I]`` predicate is false you must derive ``R1`` and ``R2``
+from:
+
+::
+
+    ... R1 [F] R2
+
+Set the stack arguments in front and figure out what ``R1`` and ``R2``
+have to do to apply the quoted ``[F]`` in the proper way.
+
+Primitive Recursive Functions
+-----------------------------
+
+Primitive recursive functions are those where ``R2 == i``.
+
+::
+
+    P == [I] [T] [R] primrec
+      == [I] [T] [R [P] i] ifte
+      == [I] [T] [R P] ifte
+
+`Hylomorphism <https://en.wikipedia.org/wiki/Hylomorphism_%28computer_science%29>`__
+------------------------------------------------------------------------------------
+
+A
+`hylomorphism <https://en.wikipedia.org/wiki/Hylomorphism_%28computer_science%29>`__
+is a recursive function ``H :: A -> C`` that converts a value of type
+``A`` into a value of type ``C`` by means of:
+
+-  A generator ``G :: A -> (B, A)``
+-  A combiner ``F :: (B, C) -> C``
+-  A predicate ``P :: A -> Bool`` to detect the base case
+-  A base case value ``c :: C``
+-  Recursive calls (zero or more); it has a "call stack in the form of a
+   cons list".
+
+It may be helpful to see this function implemented in imperative Python
+code.
+
+.. code:: ipython2
+
+    def hylomorphism(c, F, P, G):
+        '''Return a hylomorphism function H.'''
+    
+        def H(a):
+            if P(a):
+                result = c
+            else:
+                b, aa = G(a)
+                result = F(b, H(aa))  # b is stored in the stack frame during recursive call to H().
+            return result
+    
+        return H
+
+Cf. `"Bananas, Lenses, & Barbed
+Wire" <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125>`__
+
+Note that during evaluation of ``H()`` the intermediate ``b`` values are
+stored in the Python call stack. This is what is meant by "call stack in
+the form of a cons list".
+
+Hylomorphism in Joy
+-------------------
+
+We can define a combinator ``hylomorphism`` that will make a
+hylomorphism combinator ``H`` from constituent parts.
+
+::
+
+    H == [P] c [G] [F] hylomorphism
+
+The function ``H`` is recursive, so we start with ``ifte`` and set the
+else-part to some function ``J`` that will contain a quoted copy of
+``H``. (The then-part just discards the leftover ``a`` and replaces it
+with the base case value ``c``.)
+
+::
+
+    H == [P] [pop c] [J] ifte
+
+The else-part ``J`` gets just the argument ``a`` on the stack.
+
+::
+
+    a J
+    a G              The first thing to do is use the generator G
+    aa b             which produces b and a new aa
+    aa b [H] dip     we recur with H on the new aa
+    aa H b F         and run F on the result.
+
+This gives us a definition for ``J``.
+
+::
+
+    J == G [H] dip F
+
+Plug it in and convert to genrec.
+
+::
+
+    H == [P] [pop c] [G [H] dip F] ifte
+    H == [P] [pop c] [G]   [dip F] genrec
+
+This is the form of a hylomorphism in Joy, which nicely illustrates that
+it is a simple specialization of the general recursion combinator.
+
+::
+
+    H == [P] c [G] [F] hylomorphism == [P] [pop c] [G] [dip F] genrec
+
+Derivation of ``hylomorphism`` combinator
+-----------------------------------------
+
+Now we just need to derive a definition that builds the ``genrec``
+arguments out of the pieces given to the ``hylomorphism`` combinator.
+
+::
+
+       [P]      c  [G]     [F] hylomorphism
+    ------------------------------------------
+       [P] [pop c] [G] [dip F] genrec
+
+Working in reverse:
+
+-  Use ``swoncat`` twice to decouple ``[c]`` and ``[F]``.
+-  Use ``unit`` to dequote ``c``.
+-  Use ``dipd`` to untangle ``[unit [pop] swoncat]`` from the givens.
+
+So:
+
+::
+
+    H == [P] [pop c]              [G]                  [dip F] genrec
+         [P] [c]    [pop] swoncat [G]        [F] [dip] swoncat genrec
+         [P] c unit [pop] swoncat [G]        [F] [dip] swoncat genrec
+         [P] c [G] [F] [unit [pop] swoncat] dipd [dip] swoncat genrec
+
+At this point all of the arguments (givens) to the hylomorphism are to
+the left so we have a definition for ``hylomorphism``:
+
+::
+
+    hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec
+
+.. code:: ipython2
+
+    define('hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec')
+
+Example: Finding `Triangular Numbers <https://en.wikipedia.org/wiki/Triangular_number>`__
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Let's write a function that, given a positive integer, returns the sum
+of all positive integers less than that one. (In this case the types
+``A``, ``B`` and ``C`` are all ``int``.)
+
+To sum a range of integers from 0 to *n* - 1:
+
+-  ``[P]`` is ``[1 <=]``
+-  ``c`` is ``0``
+-  ``[G]`` is ``[-- dup]``
+-  ``[F]`` is ``[+]``
+
+.. code:: ipython2
+
+    define('triangular_number == [1 <=] 0 [-- dup] [+] hylomorphism')
+
+Let's try it:
+
+.. code:: ipython2
+
+    J('5 triangular_number')
+
+
+.. parsed-literal::
+
+    10
+
+
+.. code:: ipython2
+
+    J('[0 1 2 3 4 5 6] [triangular_number] map')
+
+
+.. parsed-literal::
+
+    [0 0 1 3 6 10 15]
+
+
+Four Specializations
+--------------------
+
+There are at least four kinds of recursive combinator, depending on two
+choices. The first choice is whether the combiner function ``F`` should
+be evaluated during the recursion or pushed into the pending expression
+to be "collapsed" at the end. The second choice is whether the combiner
+needs to operate on the current value of the datastructure or the
+generator's output, in other words, whether ``F`` or ``G`` should run
+first in the recursive branch.
+
+::
+
+    H1 ==        [P] [pop c] [G             ] [dip F] genrec
+    H2 == c swap [P] [pop]   [G [F]    dip  ] [i]     genrec
+    H3 ==        [P] [pop c] [  [G] dupdip  ] [dip F] genrec
+    H4 == c swap [P] [pop]   [  [F] dupdip G] [i]     genrec
+
+The working of the generator function ``G`` differs slightly for each.
+Consider the recursive branches:
+
+::
+
+    ... a G [H1] dip F                w/ a G == a′ b
+
+    ... c a G [F] dip H2                 a G == b  a′
+
+    ... a [G] dupdip [H3] dip F          a G == a′
+
+    ... c a [F] dupdip G H4              a G == a′
+
+The following four sections illustrate how these work, omitting the
+predicate evaluation.
+
+``H1``
+~~~~~~
+
+::
+
+    H1 == [P] [pop c] [G] [dip F] genrec
+
+Iterate n times.
+
+::
+
+    ... a  G [H1] dip F
+    ... a′ b [H1] dip F
+    ... a′ H1 b F
+    ... a′ G [H1] dip F b F
+    ... a″ b′ [H1] dip F b F
+    ... a″ H1 b′ F b F
+    ... a″ G [H1] dip F b′ F b F
+    ... a‴ b″ [H1] dip F b′ F b F
+    ... a‴ H1 b″ F b′ F b F
+    ... a‴ pop c b″ F b′ F b F
+    ... c b″ F b′ F b F
+    ... d      b′ F b F
+    ... d′          b F
+    ... d″
+
+This form builds up a pending expression (continuation) that contains
+the intermediate results along with the pending combiner functions. When
+the base case is reached the last term is replaced by the identity value
+``c`` and the continuation "collapses" into the final result using the
+combiner ``F``.
+
+``H2``
+~~~~~~
+
+When you can start with the identity value ``c`` on the stack and the
+combiner ``F`` can operate as you go using the intermediate results
+immediately rather than queuing them up, use this form. An important
+difference is that the generator function must return its results in the
+reverse order.
+
+::
+
+    H2 == c swap [P] [pop] [G [F] dip] primrec
+
+    ... c a G  [F] dip H2
+    ... c b a′ [F] dip H2
+    ... c b F a′ H2
+    ... d     a′ H2
+    ... d a′ G  [F] dip H2
+    ... d b′ a″ [F] dip H2
+    ... d b′ F a″ H2
+    ... d′     a″ H2
+    ... d′ a″ G  [F] dip H2
+    ... d′ b″ a‴ [F] dip H2
+    ... d′ b″ F a‴ H2
+    ... d″      a‴ H2
+    ... d″ a‴ pop
+    ... d″
+
+``H3``
+~~~~~~
+
+If you examine the traces above you'll see that the combiner ``F`` only
+gets to operate on the results of ``G``, it never "sees" the first value
+``a``. If the combiner and the generator both need to work on the
+current value then ``dup`` must be used, and the generator must produce
+one item instead of two (the b is instead the duplicate of a.)
+
+::
+
+    H3 == [P] [pop c] [[G] dupdip] [dip F] genrec
+
+    ... a [G] dupdip [H3] dip F
+    ... a  G  a      [H3] dip F
+    ... a′    a      [H3] dip F
+    ... a′ H3 a               F
+    ... a′ [G] dupdip [H3] dip F a F
+    ... a′  G  a′     [H3] dip F a F
+    ... a″     a′     [H3] dip F a F
+    ... a″ H3  a′              F a F
+    ... a″ [G] dupdip [H3] dip F a′ F a F
+    ... a″  G    a″   [H3] dip F a′ F a F
+    ... a‴       a″   [H3] dip F a′ F a F
+    ... a‴ H3    a″            F a′ F a F
+    ... a‴ pop c a″ F a′ F a F
+    ...        c a″ F a′ F a F
+    ...        d      a′ F a F
+    ...        d′          a F
+    ...        d″
+
+``H4``
+~~~~~~
+
+And, last but not least, if you can combine as you go, starting with
+``c``, and the combiner ``F`` needs to work on the current item, this is
+the form:
+
+::
+
+    H4 == c swap [P] [pop] [[F] dupdip G] primrec
+
+    ... c  a  [F] dupdip G H4
+    ... c  a   F  a      G H4
+    ... d         a      G H4
+    ... d  a′              H4
+    ... d  a′ [F] dupdip G H4
+    ... d  a′  F  a′     G H4
+    ... d′        a′     G H4
+    ... d′ a″              H4
+    ... d′ a″ [F] dupdip G H4
+    ... d′ a″  F  a″     G H4
+    ... d″        a″     G H4
+    ... d″ a‴              H4
+    ... d″ a‴ pop
+    ... d″
+
+Anamorphism
+-----------
+
+An anamorphism can be defined as a hylomorphism that uses ``[]`` for
+``c`` and ``swons`` for ``F``. An anamorphic function builds a list of
+values.
+
+::
+
+    A == [P] [] [G] [swons] hylomorphism
+
+``range`` et. al.
+~~~~~~~~~~~~~~~~~
+
+An example of an anamorphism is the ``range`` function which generates
+the list of integers from 0 to *n* - 1 given *n*.
+
+Each of the above variations can be used to make four slightly different
+``range`` functions.
+
+``range`` with ``H1``
+^^^^^^^^^^^^^^^^^^^^^
+
+::
+
+    H1 == [P]    [pop c]  [G]      [dip F]     genrec
+       == [0 <=] [pop []] [-- dup] [dip swons] genrec
+
+.. code:: ipython2
+
+    define('range == [0 <=] [] [-- dup] [swons] hylomorphism')
+
+.. code:: ipython2
+
+    J('5 range')
+
+
+.. parsed-literal::
+
+    [4 3 2 1 0]
+
+
+``range`` with ``H2``
+^^^^^^^^^^^^^^^^^^^^^
+
+::
+
+    H2 == c  swap [P]    [pop] [G      [F]     dip] primrec
+       == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec
+
+.. code:: ipython2
+
+    define('range_reverse == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec')
+
+.. code:: ipython2
+
+    J('5 range_reverse')
+
+
+.. parsed-literal::
+
+    [0 1 2 3 4]
+
+
+``range`` with ``H3``
+^^^^^^^^^^^^^^^^^^^^^
+
+::
+
+    H3 == [P]    [pop c]  [[G]  dupdip] [dip F]     genrec
+       == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec
+
+.. code:: ipython2
+
+    define('ranger == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec')
+
+.. code:: ipython2
+
+    J('5 ranger')
+
+
+.. parsed-literal::
+
+    [5 4 3 2 1]
+
+
+``range`` with ``H4``
+^^^^^^^^^^^^^^^^^^^^^
+
+::
+
+    H4 == c  swap [P]    [pop] [[F]     dupdip G ] primrec
+       == [] swap [0 <=] [pop] [[swons] dupdip --] primrec
+
+.. code:: ipython2
+
+    define('ranger_reverse == [] swap [0 <=] [pop] [[swons] dupdip --] primrec')
+
+.. code:: ipython2
+
+    J('5 ranger_reverse')
+
+
+.. parsed-literal::
+
+    [1 2 3 4 5]
+
+
+Hopefully this illustrates the workings of the variations. For more
+insight you can run the cells using the ``V()`` function instead of the
+``J()`` function to get a trace of the Joy evaluation.
+
+Catamorphism
+------------
+
+A catamorphism can be defined as a hylomorphism that uses
+``[uncons swap]`` for ``[G]`` and ``[[] =]`` (or just ``[not]``) for the
+predicate ``[P]``. A catamorphic function tears down a list term-by-term
+and makes some new value.
+
+::
+
+    C == [not] c [uncons swap] [F] hylomorphism
+
+.. code:: ipython2
+
+    define('swuncons == uncons swap')  # Awkward name.
+
+An example of a catamorphism is the sum function.
+
+::
+
+    sum == [not] 0 [swuncons] [+] hylomorphism
+
+.. code:: ipython2
+
+    define('sum == [not] 0 [swuncons] [+] hylomorphism')
+
+.. code:: ipython2
+
+    J('[5 4 3 2 1] sum')
+
+
+.. parsed-literal::
+
+    15
+
+
+The ``step`` combinator
+~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``step`` combinator will usually be better to use than
+``catamorphism``.
+
+.. code:: ipython2
+
+    J('[step] help')
+
+
+.. parsed-literal::
+
+    Run a quoted program on each item in a sequence.
+    ::
+    
+            ... [] [Q] . step
+         -----------------------
+                   ... .
+    
+    
+           ... [a] [Q] . step
+        ------------------------
+                 ... a . Q
+    
+    
+         ... [a b c] [Q] . step
+      ----------------------------------------
+                   ... a . Q [b c] [Q] step
+    
+    The step combinator executes the quotation on each member of the list
+    on top of the stack.
+    
+
+
+.. code:: ipython2
+
+    define('sum == 0 swap [+] step')
+
+.. code:: ipython2
+
+    J('[5 4 3 2 1] sum')
+
+
+.. parsed-literal::
+
+    15
+
+
+Example: Factorial Function
+---------------------------
+
+For the Factorial function:
+
+::
+
+    H4 == c swap [P] [pop] [[F] dupdip G] primrec
+
+With:
+
+::
+
+    c == 1
+    F == *
+    G == --
+    P == 1 <=
+
+.. code:: ipython2
+
+    define('factorial == 1 swap [1 <=] [pop] [[*] dupdip --] primrec')
+
+.. code:: ipython2
+
+    J('5 factorial')
+
+
+.. parsed-literal::
+
+    120
+
+
+Example: ``tails``
+------------------
+
+An example of a paramorphism for lists given in the `"Bananas..."
+paper <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125>`__
+is ``tails`` which returns the list of "tails" of a list.
+
+::
+
+        [1 2 3] tails
+    --------------------
+       [[] [3] [2 3]]
+
+We can build as we go, and we want ``F`` to run after ``G``, so we use
+pattern ``H2``:
+
+::
+
+    H2 == c swap [P] [pop] [G [F] dip] primrec
+
+We would use:
+
+::
+
+    c == []
+    F == swons
+    G == rest dup
+    P == not
+
+.. code:: ipython2
+
+    define('tails == [] swap [not] [pop] [rest dup [swons] dip] primrec')
+
+.. code:: ipython2
+
+    J('[1 2 3] tails')
+
+
+.. parsed-literal::
+
+    [[] [3] [2 3]]
+
+
+Conclusion: Patterns of Recursion
+---------------------------------
+
+Our story so far...
+
+Hylo-, Ana-, Cata-
+~~~~~~~~~~~~~~~~~~
+
+::
+
+    H == [P  ] [pop c ] [G          ] [dip F        ] genrec
+    A == [P  ] [pop []] [G          ] [dip swap cons] genrec
+    C == [not] [pop c ] [uncons swap] [dip F        ] genrec
+
+Para-, ?-, ?-
+~~~~~~~~~~~~~
+
+::
+
+    P == c  swap [P  ] [pop] [[F        ] dupdip G          ] primrec
+    ? == [] swap [P  ] [pop] [[swap cons] dupdip G          ] primrec
+    ? == c  swap [not] [pop] [[F        ] dupdip uncons swap] primrec
+
+Appendix: Fun with Symbols
+--------------------------
+
+::
+
+    |[ (c, F), (G, P) ]| == (|c, F|) • [(G, P)]
+
+`"Bananas, Lenses, & Barbed
+Wire" <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125>`__
+
+::
+
+    (|...|)  [(...)]  [<...>]
+
+I think they are having slightly too much fun with the symbols. However,
+"Too much is always better than not enough."
diff --git a/docs/sphinx_docs/notebooks/Types.rst b/docs/sphinx_docs/notebooks/Types.rst
new file mode 100644 (file)
index 0000000..971fdfc
--- /dev/null
@@ -0,0 +1,2206 @@
+
+Type Inference
+==============
+
+Pöial's Rules
+-------------
+
+`"Typing Tools for Typeless Stack Languages" by Jaanus
+Pöial <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.212.6026>`__
+
+::
+
+    @INPROCEEDINGS{Pöial06typingtools,
+        author = {Jaanus Pöial},
+        title = {Typing tools for typeless stack languages},
+        booktitle = {In 23rd Euro-Forth Conference},
+        year = {2006},
+        pages = {40--46}
+    }
+
+First Rule
+~~~~~~~~~~
+
+This rule deals with functions (and literals) that put items on the
+stack ``(-- d)``:
+
+::
+
+       (a -- b)∘(-- d)
+    ---------------------
+         (a -- b d)
+
+Second Rule
+~~~~~~~~~~~
+
+This rule deals with functions that consume items from the stack
+``(a --)``:
+
+::
+
+       (a --)∘(c -- d)
+    ---------------------
+         (c a -- d)
+
+Third Rule
+~~~~~~~~~~
+
+The third rule is actually two rules. These two rules deal with
+composing functions when the second one will consume one of items the
+first one produces. The two types must be *unified* or a type conflict
+declared.
+
+::
+
+       (a -- b t[i])∘(c u[j] -- d)   t <= u (t is subtype of u)
+    -------------------------------
+       (a -- b     )∘(c      -- d)   t[i] == t[k] == u[j]
+                                             ^
+
+       (a -- b t[i])∘(c u[j] -- d)   u <= t (u is subtype of t)
+    -------------------------------
+       (a -- b     )∘(c      -- d)   t[i] == u[k] == u[j]
+
+Examples
+--------
+
+Let's work through some examples by hand to develop an intuition for the
+algorithm.
+
+There's a function in one of the other notebooks.
+
+::
+
+    F == pop swap roll< rest rest cons cons
+
+It's all "stack chatter" and list manipulation so we should be able to
+deduce its type.
+
+Stack Effect Comments
+~~~~~~~~~~~~~~~~~~~~~
+
+Joy function types will be represented by Forth-style stack effect
+comments. I'm going to use numbers instead of names to keep track of the
+stack arguments. (A little bit like `De Bruijn
+index <https://en.wikipedia.org/wiki/De_Bruijn_index>`__, at least it
+reminds me of them):
+
+::
+
+    pop (1 --)
+
+    swap (1 2 -- 2 1)
+
+    roll< (1 2 3 -- 2 3 1)
+
+These commands alter the stack but don't "look at" the values so these
+numbers represent an "Any type".
+
+``pop swap``
+~~~~~~~~~~~~
+
+::
+
+    (1 --) (1 2 -- 2 1)
+
+Here we encounter a complication. The argument numbers need to be made
+unique among both sides. For this let's change ``pop`` to use 0:
+
+::
+
+    (0 --) (1 2 -- 2 1)
+
+Following the second rule:
+
+::
+
+    (1 2 0 -- 2 1)
+
+``pop∘swap roll<``
+~~~~~~~~~~~~~~~~~~
+
+::
+
+    (1 2 0 -- 2 1) (1 2 3 -- 2 3 1)
+
+Let's re-label them:
+
+::
+
+    (1a 2a 0a -- 2a 1a) (1b 2b 3b -- 2b 3b 1b)
+
+Now we follow the rules.
+
+We must unify ``1a`` and ``3b``, and ``2a`` and ``2b``, replacing the
+terms in the forms:
+
+::
+
+    (1a 2a 0a -- 2a 1a) (1b 2b 3b -- 2b 3b 1b)
+                                                w/  {1a: 3b}
+    (3b 2a 0a -- 2a   ) (1b 2b    -- 2b 3b 1b)
+                                                w/  {2a: 2b}
+    (3b 2b 0a --      ) (1b       -- 2b 3b 1b)
+
+Here we must apply the second rule:
+
+::
+
+       (3b 2b 0a --) (1b -- 2b 3b 1b)
+    -----------------------------------
+         (1b 3b 2b 0a -- 2b 3b 1b)
+
+Now we de-label the type, uh, labels:
+
+::
+
+    (1b 3b 2b 0a -- 2b 3b 1b)
+
+    w/ {
+        1b: 1,
+        3b: 2,
+        2b: 3,
+        0a: 0,
+        }
+
+    (1 2 3 0 -- 3 2 1)
+
+And now we have the stack effect comment for ``pop∘swap∘roll<``.
+
+Compiling ``pop∘swap∘roll<``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The simplest way to "compile" this function would be something like:
+
+.. code:: ipython2
+
+    def poswrd(s, e, d):
+        return roll_down(*swap(*pop(s, e, d)))
+
+However, internally this function would still be allocating tuples
+(stack cells) and doing other unnecesssary work.
+
+Looking ahead for a moment, from the stack effect comment:
+
+::
+
+    (1 2 3 0 -- 3 2 1)
+
+We should be able to directly write out a Python function like:
+
+.. code:: ipython2
+
+    def poswrd(stack):
+        (_, (a, (b, (c, stack)))) = stack
+        return (c, (b, (a, stack)))
+
+This eliminates the internal work of the first version. Because this
+function only rearranges the stack and doesn't do any actual processing
+on the stack items themselves all the information needed to implement it
+is in the stack effect comment.
+
+Functions on Lists
+~~~~~~~~~~~~~~~~~~
+
+These are slightly tricky.
+
+::
+
+    rest ( [1 ...] -- [...] )
+
+    cons ( 1 [...] -- [1 ...] )
+
+``pop∘swap∘roll< rest``
+~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    (1 2 3 0 -- 3 2 1) ([1 ...] -- [...])
+
+Re-label (instead of adding left and right tags I'm just taking the next
+available index number for the right-side stack effect comment):
+
+::
+
+    (1 2 3 0 -- 3 2 1) ([4 ...] -- [...])
+
+Unify and update:
+
+::
+
+    (1       2 3 0 -- 3 2 1) ([4 ...] -- [...])
+                                                 w/ {1: [4 ...]}
+    ([4 ...] 2 3 0 -- 3 2  ) (        -- [...])
+
+Apply the first rule:
+
+::
+
+       ([4 ...] 2 3 0 -- 3 2) (-- [...])
+    ---------------------------------------
+         ([4 ...] 2 3 0 -- 3 2 [...])
+
+And there we are.
+
+``pop∘swap∘roll<∘rest rest``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Let's do it again.
+
+::
+
+    ([4 ...] 2 3 0 -- 3 2 [...]) ([1 ...] -- [...])
+
+Re-label (the tails of the lists on each side each get their own label):
+
+::
+
+    ([4 .0.] 2 3 0 -- 3 2 [.0.]) ([5 .1.] -- [.1.])
+
+Unify and update (note the opening square brackets have been omited in
+the substitution dict, this is deliberate and I'll explain below):
+
+::
+
+    ([4 .0.]   2 3 0 -- 3 2 [.0.]  ) ([5 .1.] -- [.1.])
+                                                        w/ { .0.] : 5 .1.] }
+    ([4 5 .1.] 2 3 0 -- 3 2 [5 .1.]) ([5 .1.] -- [.1.])
+
+How do we find ``.0.]`` in ``[4 .0.]`` and replace it with ``5 .1.]``
+getting the result ``[4 5 .1.]``? This might seem hard, but because the
+underlying structure of the Joy list is a cons-list in Python it's
+actually pretty easy. I'll explain below.
+
+Next we unify and find our two terms are the same already: ``[5 .1.]``:
+
+::
+
+    ([4 5 .1.] 2 3 0 -- 3 2 [5 .1.]) ([5 .1.] -- [.1.])
+
+Giving us:
+
+::
+
+    ([4 5 .1.] 2 3 0 -- 3 2) (-- [.1.])
+
+From here we apply the first rule and get:
+
+::
+
+    ([4 5 .1.] 2 3 0 -- 3 2 [.1.])
+
+Cleaning up the labels:
+
+::
+
+    ([4 5 ...] 2 3 1 -- 3 2 [...])
+
+This is the stack effect of ``pop∘swap∘roll<∘rest∘rest``.
+
+``pop∘swap∘roll<∘rest∘rest cons``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    ([4 5 ...] 2 3 1 -- 3 2 [...]) (1 [...] -- [1 ...])
+
+Re-label:
+
+::
+
+    ([4 5 .1.] 2 3 1 -- 3 2 [.1.]) (6 [.2.] -- [6 .2.])
+
+Unify:
+
+::
+
+    ([4 5 .1.] 2 3 1 -- 3 2 [.1.]) (6 [.2.] -- [6 .2.])
+                                                         w/ { .1.] : .2.] }
+    ([4 5 .2.] 2 3 1 -- 3 2      ) (6       -- [6 .2.])
+                                                         w/ {2: 6}
+    ([4 5 .2.] 6 3 1 -- 3        ) (        -- [6 .2.])
+
+First rule:
+
+::
+
+    ([4 5 .2.] 6 3 1 -- 3 [6 .2.])
+
+Re-label:
+
+::
+
+    ([4 5 ...] 2 3 1 -- 3 [2 ...])
+
+Done.
+
+``pop∘swap∘roll<∘rest∘rest∘cons cons``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+One more time.
+
+::
+
+    ([4 5 ...] 2 3 1 -- 3 [2 ...]) (1 [...] -- [1 ...])
+
+Re-label:
+
+::
+
+    ([4 5 .1.] 2 3 1 -- 3 [2 .1.]) (6 [.2.] -- [6 .2.])
+
+Unify:
+
+::
+
+    ([4 5 .1.] 2 3 1 -- 3 [2 .1.]) (6 [.2.] -- [6 .2.]  )
+                                                           w/ { .2.] : 2 .1.] }
+    ([4 5 .1.] 2 3 1 -- 3        ) (6       -- [6 2 .1.])
+                                                           w/ {3: 6}
+    ([4 5 .1.] 2 6 1 --          ) (        -- [6 2 .1.])
+
+First or second rule:
+
+::
+
+    ([4 5 .1.] 2 6 1 -- [6 2 .1.])
+
+Clean up the labels:
+
+::
+
+    ([4 5 ...] 2 3 1 -- [3 2 ...])
+
+And there you have it, the stack effect for
+``pop∘swap∘roll<∘rest∘rest∘cons∘cons``.
+
+::
+
+    ([4 5 ...] 2 3 1 -- [3 2 ...])
+
+From this stack effect comment it should be possible to construct the
+following Python code:
+
+.. code:: ipython2
+
+    def F(stack):
+        (_, (d, (c, ((a, (b, S0)), stack)))) = stack
+        return (d, (c, S0)), stack
+
+Implementation
+--------------
+
+Representing Stack Effect Comments in Python
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+I'm going to use pairs of tuples of type descriptors, which will be
+integers or tuples of type descriptors:
+
+.. code:: ipython2
+
+    roll_dn = (1, 2, 3), (2, 3, 1)
+    
+    pop = (1,), ()
+    
+    swap = (1, 2), (2, 1)
+
+``compose()``
+~~~~~~~~~~~~~
+
+.. code:: ipython2
+
+    def compose(f, g):
+    
+        (f_in, f_out), (g_in, g_out) = f, g
+    
+        # First rule.
+        #
+        #       (a -- b) (-- d)
+        #    ---------------------
+        #         (a -- b d)
+    
+        if not g_in:
+    
+            fg_in, fg_out = f_in, f_out + g_out
+    
+        # Second rule.
+        #
+        #       (a --) (c -- d)
+        #    ---------------------
+        #         (c a -- d)
+    
+        elif not f_out:
+    
+            fg_in, fg_out = g_in + f_in, g_out
+    
+        else: # Unify, update, recur.
+    
+            fo, gi = f_out[-1], g_in[-1]
+    
+            s = unify(gi, fo)
+    
+            if s == False:  # s can also be the empty dict, which is ok.
+                raise TypeError('Cannot unify %r and %r.' % (fo, gi))
+    
+            f_g = (f_in, f_out[:-1]), (g_in[:-1], g_out)
+    
+            if s: f_g = update(s, f_g)
+    
+            fg_in, fg_out = compose(*f_g)
+    
+        return fg_in, fg_out
+
+``unify()``
+~~~~~~~~~~~
+
+.. code:: ipython2
+
+    def unify(u, v, s=None):
+        if s is None:
+            s = {}
+    
+        if u == v:
+            return s
+    
+        if isinstance(u, int):
+            s[u] = v
+            return s
+    
+        if isinstance(v, int):
+            s[v] = u
+            return s
+    
+        return False
+
+``update()``
+~~~~~~~~~~~~
+
+.. code:: ipython2
+
+    def update(s, term):
+        if not isinstance(term, tuple):
+            return s.get(term, term)
+        return tuple(update(s, inner) for inner in term)
+
+``relabel()``
+~~~~~~~~~~~~~
+
+.. code:: ipython2
+
+    def relabel(left, right):
+        return left, _1000(right)
+    
+    def _1000(right):
+        if not isinstance(right, tuple):
+            return 1000 + right
+        return tuple(_1000(n) for n in right)
+    
+    relabel(pop, swap)
+
+
+
+
+.. parsed-literal::
+
+    (((1,), ()), ((1001, 1002), (1002, 1001)))
+
+
+
+``delabel()``
+~~~~~~~~~~~~~
+
+.. code:: ipython2
+
+    def delabel(f):
+        s = {u: i for i, u in enumerate(sorted(_unique(f)))}
+        return update(s, f)
+    
+    def _unique(f, seen=None):
+        if seen is None:
+            seen = set()
+        if not isinstance(f, tuple):
+            seen.add(f)
+        else:
+            for inner in f:
+                _unique(inner, seen)
+        return seen
+    
+    delabel(relabel(pop, swap))
+
+
+
+
+.. parsed-literal::
+
+    (((0,), ()), ((1, 2), (2, 1)))
+
+
+
+``C()``
+~~~~~~~
+
+At last we put it all together in a function ``C()`` that accepts two
+stack effect comments and returns their composition (or raises and
+exception if they can't be composed due to type conflicts.)
+
+.. code:: ipython2
+
+    def C(f, g):
+        f, g = relabel(f, g)
+        fg = compose(f, g)
+        return delabel(fg)
+
+Let's try it out.
+
+.. code:: ipython2
+
+    C(pop, swap)
+
+
+
+
+.. parsed-literal::
+
+    ((1, 2, 0), (2, 1))
+
+
+
+.. code:: ipython2
+
+    C(C(pop, swap), roll_dn)
+
+
+
+
+.. parsed-literal::
+
+    ((3, 1, 2, 0), (2, 1, 3))
+
+
+
+.. code:: ipython2
+
+    C(swap, roll_dn)
+
+
+
+
+.. parsed-literal::
+
+    ((2, 0, 1), (1, 0, 2))
+
+
+
+.. code:: ipython2
+
+    C(pop, C(swap, roll_dn))
+
+
+
+
+.. parsed-literal::
+
+    ((3, 1, 2, 0), (2, 1, 3))
+
+
+
+.. code:: ipython2
+
+    poswrd = reduce(C, (pop, swap, roll_dn))
+    poswrd
+
+
+
+
+.. parsed-literal::
+
+    ((3, 1, 2, 0), (2, 1, 3))
+
+
+
+List Functions
+~~~~~~~~~~~~~~
+
+Here's that trick to represent functions like ``rest`` and ``cons`` that
+manipulate lists. We use a cons-list of tuples and give the tails their
+own numbers. Then everything above already works.
+
+.. code:: ipython2
+
+    rest = ((1, 2),), (2,)
+    
+    cons = (1, 2), ((1, 2),)
+
+.. code:: ipython2
+
+    C(poswrd, rest)
+
+
+
+
+.. parsed-literal::
+
+    (((3, 4), 1, 2, 0), (2, 1, 4))
+
+
+
+Compare this to the stack effect comment we wrote above:
+
+::
+
+    ((  (3, 4), 1, 2, 0 ), ( 2, 1,   4  ))
+    (   [4 ...] 2  3  0  --  3  2  [...])
+
+The translation table, if you will, would be:
+
+::
+
+    {
+    3: 4,
+    4: ...],
+    1: 2,
+    2: 3,
+    0: 0,
+    }
+
+.. code:: ipython2
+
+    F = reduce(C, (pop, swap, roll_dn, rest, rest, cons, cons))
+    
+    F
+
+
+
+
+.. parsed-literal::
+
+    (((3, (4, 5)), 1, 2, 0), ((2, (1, 5)),))
+
+
+
+Compare with the stack effect comment and you can see it works fine:
+
+::
+
+    ([4 5 ...] 2 3 1 -- [3 2 ...])
+
+Dealing with ``cons`` and ``uncons``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+However, if we try to compose e.g. ``cons`` and ``uncons`` it won't
+work:
+
+.. code:: ipython2
+
+    uncons = ((1, 2),), (1, 2)
+
+.. code:: ipython2
+
+    try:
+        C(cons, uncons)
+    except Exception, e:
+        print e
+
+
+.. parsed-literal::
+
+    Cannot unify (1, 2) and (1001, 1002).
+
+
+``unify()`` version 2
+^^^^^^^^^^^^^^^^^^^^^
+
+The problem is that the ``unify()`` function as written doesn't handle
+the case when both terms are tuples. We just have to add a clause to
+deal with this recursively:
+
+.. code:: ipython2
+
+    def unify(u, v, s=None):
+        if s is None:
+            s = {}
+        else:
+            u = update(s, u)
+            v = update(s, v)
+    
+        if u == v:
+            return s
+    
+        if isinstance(u, int):
+            s[u] = v
+            return s
+    
+        if isinstance(v, int):
+            s[v] = u
+            return s
+    
+        if isinstance(u, tuple) and isinstance(v, tuple):
+            if len(u) != len(v) != 2:
+                raise ValueError(repr((u, v)))
+            for uu, vv in zip(u, v):
+                s = unify(uu, vv, s)
+                if s == False: # (instead of a substitution dict.)
+                    break
+            return s
+     
+        return False
+
+.. code:: ipython2
+
+    C(cons, uncons)
+
+
+
+
+.. parsed-literal::
+
+    ((0, 1), (0, 1))
+
+
+
+Compiling
+---------
+
+Now consider the Python function we would like to derive:
+
+.. code:: ipython2
+
+    def F_python(stack):
+        (_, (d, (c, ((a, (b, S0)), stack)))) = stack
+        return (d, (c, S0)), stack
+
+And compare it to the input stack effect comment tuple we just computed:
+
+.. code:: ipython2
+
+    F[0]
+
+
+
+
+.. parsed-literal::
+
+    ((3, (4, 5)), 1, 2, 0)
+
+
+
+The stack-de-structuring tuple has nearly the same form as our input
+stack effect comment tuple, just in the reverse order:
+
+::
+
+    (_, (d, (c, ((a, (b, S0)), stack))))
+
+Remove the punctuation:
+
+::
+
+     _   d   c   (a, (b, S0))
+
+Reverse the order and compare:
+
+::
+
+     (a, (b, S0))   c   d   _
+    ((3, (4, 5 )),  1,  2,  0)
+
+Eh?
+
+And the return tuple
+
+.. code:: ipython2
+
+    F[1]
+
+
+
+
+.. parsed-literal::
+
+    ((2, (1, 5)),)
+
+
+
+is similar to the output stack effect comment tuple:
+
+::
+
+    ((d, (c, S0)), stack)
+    ((2, (1, 5 )),      )
+
+This should make it pretty easy to write a Python function that accepts
+the stack effect comment tuples and returns a new Python function
+(either as a string of code or a function object ready to use) that
+performs the semantics of that Joy function (described by the stack
+effect.)
+
+Python Identifiers
+~~~~~~~~~~~~~~~~~~
+
+We want to substitute Python identifiers for the integers. I'm going to
+repurpose ``joy.parser.Symbol`` class for this:
+
+.. code:: ipython2
+
+    from collections import defaultdict
+    from joy.parser import Symbol
+    
+    
+    def _names_for():
+        I = iter(xrange(1000))
+        return lambda: Symbol('a%i' % next(I))
+    
+    
+    def identifiers(term, s=None):
+        if s is None:
+            s = defaultdict(_names_for())
+        if isinstance(term, int):
+            return s[term]
+        return tuple(identifiers(inner, s) for inner in term)
+
+``doc_from_stack_effect()``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+As a convenience I've implemented a function to convert the Python stack
+effect comment tuples to reasonable text format. There are some details
+in how this code works that related to stuff later in the notebook, so
+you should skip it for now and read it later if you're interested.
+
+.. code:: ipython2
+
+    def doc_from_stack_effect(inputs, outputs):
+        return '(%s--%s)' % (
+            ' '.join(map(_to_str, inputs + ('',))),
+            ' '.join(map(_to_str, ('',) + outputs))
+        )
+    
+    
+    def _to_str(term):
+        if not isinstance(term, tuple):
+            try:
+                t = term.prefix == 's'
+            except AttributeError:
+                return str(term)
+            return '[.%i.]' % term.number if t else str(term)
+    
+        a = []
+        while term and isinstance(term, tuple):
+            item, term = term
+            a.append(_to_str(item))
+    
+        try:
+            n = term.number
+        except AttributeError:
+            n = term
+        else:
+            if term.prefix != 's':
+                raise ValueError('Stack label: %s' % (term,))
+    
+        a.append('.%s.' % (n,))
+        return '[%s]' % ' '.join(a)
+
+``compile_()``
+~~~~~~~~~~~~~~
+
+Now we can write a compiler function to emit Python source code. (The
+underscore suffix distiguishes it from the built-in ``compile()``
+function.)
+
+.. code:: ipython2
+
+    def compile_(name, f, doc=None):
+        if doc is None:
+            doc = doc_from_stack_effect(*f)
+        inputs, outputs = identifiers(f)
+        i = o = Symbol('stack')
+        for term in inputs:
+            i = term, i
+        for term in outputs:
+            o = term, o
+        return '''def %s(stack):
+        """%s"""
+        %s = stack
+        return %s''' % (name, doc, i, o)
+
+Here it is in action:
+
+.. code:: ipython2
+
+    source = compile_('F', F)
+    
+    print source
+
+
+.. parsed-literal::
+
+    def F(stack):
+        """([3 4 .5.] 1 2 0 -- [2 1 .5.])"""
+        (a5, (a4, (a3, ((a0, (a1, a2)), stack)))) = stack
+        return ((a4, (a3, a2)), stack)
+
+
+Compare:
+
+.. code:: ipython2
+
+    def F_python(stack):
+        (_, (d, (c, ((a, (b, S0)), stack)))) = stack
+        return ((d, (c, S0)), stack)
+
+Next steps:
+
+.. code:: ipython2
+
+    L = {}
+    
+    eval(compile(source, '__main__', 'single'), {}, L)
+    
+    L['F']
+
+
+
+
+.. parsed-literal::
+
+    <function F>
+
+
+
+Let's try it out:
+
+.. code:: ipython2
+
+    from notebook_preamble import D, J, V
+    from joy.library import SimpleFunctionWrapper
+
+.. code:: ipython2
+
+    D['F'] = SimpleFunctionWrapper(L['F'])
+
+.. code:: ipython2
+
+    J('[4 5 ...] 2 3 1 F')
+
+
+.. parsed-literal::
+
+    [3 2 ...]
+
+
+With this, we have a partial Joy compiler that works on the subset of
+Joy functions that manipulate stacks (both what I call "stack chatter"
+and the ones that manipulate stacks on the stack.)
+
+I'm probably going to modify the definition wrapper code to detect
+definitions that can be compiled by this partial compiler and do it
+automatically. It might be a reasonable idea to detect sequences of
+compilable functions in definitions that have uncompilable functions in
+them and just compile those. However, if your library is well-factored
+this might be less helpful.
+
+Compiling Library Functions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+We can use ``compile_()`` to generate many primitives in the library
+from their stack effect comments:
+
+.. code:: ipython2
+
+    def defs():
+    
+        roll_down = (1, 2, 3), (2, 3, 1)
+    
+        roll_up = (1, 2, 3), (3, 1, 2)
+    
+        pop = (1,), ()
+    
+        swap = (1, 2), (2, 1)
+    
+        rest = ((1, 2),), (2,)
+        
+        rrest = C(rest, rest)
+    
+        cons = (1, 2), ((1, 2),)
+    
+        uncons = ((1, 2),), (1, 2)
+        
+        swons = C(swap, cons)
+    
+        return locals()
+
+.. code:: ipython2
+
+    for name, stack_effect_comment in sorted(defs().items()):
+        print
+        print compile_(name, stack_effect_comment)
+        print
+
+
+.. parsed-literal::
+
+    
+    def cons(stack):
+        """(1 2 -- [1 .2.])"""
+        (a1, (a0, stack)) = stack
+        return ((a0, a1), stack)
+    
+    
+    def pop(stack):
+        """(1 --)"""
+        (a0, stack) = stack
+        return stack
+    
+    
+    def rest(stack):
+        """([1 .2.] -- 2)"""
+        ((a0, a1), stack) = stack
+        return (a1, stack)
+    
+    
+    def roll_down(stack):
+        """(1 2 3 -- 2 3 1)"""
+        (a2, (a1, (a0, stack))) = stack
+        return (a0, (a2, (a1, stack)))
+    
+    
+    def roll_up(stack):
+        """(1 2 3 -- 3 1 2)"""
+        (a2, (a1, (a0, stack))) = stack
+        return (a1, (a0, (a2, stack)))
+    
+    
+    def rrest(stack):
+        """([0 1 .2.] -- 2)"""
+        ((a0, (a1, a2)), stack) = stack
+        return (a2, stack)
+    
+    
+    def swap(stack):
+        """(1 2 -- 2 1)"""
+        (a1, (a0, stack)) = stack
+        return (a0, (a1, stack))
+    
+    
+    def swons(stack):
+        """(0 1 -- [1 .0.])"""
+        (a1, (a0, stack)) = stack
+        return ((a1, a0), stack)
+    
+    
+    def uncons(stack):
+        """([1 .2.] -- 1 2)"""
+        ((a0, a1), stack) = stack
+        return (a1, (a0, stack))
+    
+
+
+Types and Subtypes of Arguments
+-------------------------------
+
+So far we have dealt with types of functions, those dealing with simple
+stack manipulation. Let's extend our machinery to deal with types of
+arguments.
+
+"Number" Type
+~~~~~~~~~~~~~
+
+Consider the definition of ``sqr``:
+
+::
+
+    sqr == dup mul
+
+The ``dup`` function accepts one *anything* and returns two of that:
+
+::
+
+    dup (1 -- 1 1)
+
+And ``mul`` accepts two "numbers" (we're ignoring ints vs. floats vs.
+complex, etc., for now) and returns just one:
+
+::
+
+    mul (n n -- n)
+
+So we're composing:
+
+::
+
+    (1 -- 1 1)∘(n n -- n)
+
+The rules say we unify 1 with ``n``:
+
+::
+
+       (1 -- 1 1)∘(n n -- n)
+    ---------------------------  w/  {1: n}
+       (1 -- 1  )∘(n   -- n)
+
+This involves detecting that "Any type" arguments can accept "numbers".
+If we were composing these functions the other way round this is still
+the case:
+
+::
+
+       (n n -- n)∘(1 -- 1 1)
+    ---------------------------  w/  {1: n}
+       (n n --  )∘(  -- n n) 
+
+The important thing here is that the mapping is going the same way in
+both cases, from the "any" integer to the number
+
+Distinguishing Numbers
+~~~~~~~~~~~~~~~~~~~~~~
+
+We should also mind that the number that ``mul`` produces is not
+(necessarily) the same as either of its inputs, which are not
+(necessarily) the same as each other:
+
+::
+
+    mul (n2 n1 -- n3)
+
+
+       (1  -- 1  1)∘(n2 n1 -- n3)
+    --------------------------------  w/  {1: n2}
+       (n2 -- n2  )∘(n2    -- n3)
+
+
+       (n2 n1 -- n3)∘(1 -- 1  1 )
+    --------------------------------  w/  {1: n3}
+       (n2 n1 --   )∘(  -- n3 n3) 
+
+Distinguishing Types
+~~~~~~~~~~~~~~~~~~~~
+
+So we need separate domains of "any" numbers and "number" numbers, and
+we need to be able to ask the order of these domains. Now the notes on
+the right side of rule three make more sense, eh?
+
+::
+
+       (a -- b t[i])∘(c u[j] -- d)   t <= u (t is subtype of u)
+    -------------------------------
+       (a -- b     )∘(c      -- d)   t[i] == t[k] == u[j]
+                                             ^
+
+       (a -- b t[i])∘(c u[j] -- d)   u <= t (u is subtype of t)
+    -------------------------------
+       (a -- b     )∘(c      -- d)   t[i] == u[k] == u[j]
+
+The indices ``i``, ``k``, and ``j`` are the number part of our labels
+and ``t`` and ``u`` are the domains.
+
+By creative use of Python's "double underscore" methods we can define a
+Python class hierarchy of Joy types and use the ``issubclass()`` method
+to establish domain ordering, as well as other handy behaviour that will
+make it fairly easy to reuse most of the code above.
+
+.. code:: ipython2
+
+    class AnyJoyType(object):
+    
+        prefix = 'a'
+    
+        def __init__(self, number):
+            self.number = number
+    
+        def __repr__(self):
+            return self.prefix + str(self.number)
+    
+        def __eq__(self, other):
+            return (
+                isinstance(other, self.__class__)
+                and other.prefix == self.prefix
+                and other.number == self.number
+            )
+    
+        def __ge__(self, other):
+            return issubclass(other.__class__, self.__class__)
+    
+        def __add__(self, other):
+            return self.__class__(self.number + other)
+        __radd__ = __add__
+        
+        def __hash__(self):
+            return hash(repr(self))
+    
+    
+    class NumberJoyType(AnyJoyType): prefix = 'n'
+    class FloatJoyType(NumberJoyType): prefix = 'f'
+    class IntJoyType(FloatJoyType): prefix = 'i'
+    
+    
+    class StackJoyType(AnyJoyType):
+        prefix = 's'
+    
+    
+    _R = range(10)
+    A = map(AnyJoyType, _R)
+    N = map(NumberJoyType, _R)
+    S = map(StackJoyType, _R)
+
+Mess with it a little:
+
+.. code:: ipython2
+
+    from itertools import permutations
+
+"Any" types can be specialized to numbers and stacks, but not vice
+versa:
+
+.. code:: ipython2
+
+    for a, b in permutations((A[0], N[0], S[0]), 2):
+        print a, '>=', b, '->', a >= b
+
+
+.. parsed-literal::
+
+    a0 >= n0 -> True
+    a0 >= s0 -> True
+    n0 >= a0 -> False
+    n0 >= s0 -> False
+    s0 >= a0 -> False
+    s0 >= n0 -> False
+
+
+Our crude `Numerical
+Tower <https://en.wikipedia.org/wiki/Numerical_tower>`__ of *numbers* >
+*floats* > *integers* works as well (but we're not going to use it yet):
+
+.. code:: ipython2
+
+    for a, b in permutations((A[0], N[0], FloatJoyType(0), IntJoyType(0)), 2):
+        print a, '>=', b, '->', a >= b
+
+
+.. parsed-literal::
+
+    a0 >= n0 -> True
+    a0 >= f0 -> True
+    a0 >= i0 -> True
+    n0 >= a0 -> False
+    n0 >= f0 -> True
+    n0 >= i0 -> True
+    f0 >= a0 -> False
+    f0 >= n0 -> False
+    f0 >= i0 -> True
+    i0 >= a0 -> False
+    i0 >= n0 -> False
+    i0 >= f0 -> False
+
+
+Typing ``sqr``
+~~~~~~~~~~~~~~
+
+.. code:: ipython2
+
+    dup = (A[1],), (A[1], A[1])
+    
+    mul = (N[1], N[2]), (N[3],)
+
+.. code:: ipython2
+
+    dup
+
+
+
+
+.. parsed-literal::
+
+    ((a1,), (a1, a1))
+
+
+
+.. code:: ipython2
+
+    mul
+
+
+
+
+.. parsed-literal::
+
+    ((n1, n2), (n3,))
+
+
+
+Modifying the Inferencer
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Re-labeling still works fine:
+
+.. code:: ipython2
+
+    foo = relabel(dup, mul)
+    
+    foo
+
+
+
+
+.. parsed-literal::
+
+    (((a1,), (a1, a1)), ((n1001, n1002), (n1003,)))
+
+
+
+``delabel()`` version 2
+^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``delabel()`` function needs an overhaul. It now has to keep track
+of how many labels of each domain it has "seen".
+
+.. code:: ipython2
+
+    from collections import Counter
+    
+    
+    def delabel(f, seen=None, c=None):
+        if seen is None:
+            assert c is None
+            seen, c = {}, Counter()
+    
+        try:
+            return seen[f]
+        except KeyError:
+            pass
+    
+        if not isinstance(f, tuple):
+            seen[f] = f.__class__(c[f.prefix])
+            c[f.prefix] += 1
+            return seen[f]
+    
+        return tuple(delabel(inner, seen, c) for inner in f)
+
+.. code:: ipython2
+
+    delabel(foo)
+
+
+
+
+.. parsed-literal::
+
+    (((a0,), (a0, a0)), ((n0, n1), (n2,)))
+
+
+
+``unify()`` version 3
+^^^^^^^^^^^^^^^^^^^^^
+
+.. code:: ipython2
+
+    def unify(u, v, s=None):
+        if s is None:
+            s = {}
+        else:
+            u = update(s, u)
+            v = update(s, v)
+    
+        if u == v:
+            return s
+    
+        if isinstance(u, AnyJoyType) and isinstance(v, AnyJoyType):
+            if u >= v:
+                s[u] = v
+                return s
+            if v >= u:
+                s[v] = u
+                return s
+            raise ValueError('Cannot unify %r and %r.' % (u, v))
+    
+        if isinstance(u, tuple) and isinstance(v, tuple):
+            if len(u) != len(v) != 2:
+                raise ValueError(repr((u, v)))
+            for uu, vv in zip(u, v):
+                s = unify(uu, vv, s)
+                if s == False: # (instead of a substitution dict.)
+                    break
+            return s
+     
+        if isinstance(v, tuple):
+            if not stacky(u):
+                raise ValueError('Cannot unify %r and %r.' % (u, v))
+            s[u] = v
+            return s
+    
+        if isinstance(u, tuple):
+            if not stacky(v):
+                raise ValueError('Cannot unify %r and %r.' % (v, u))
+            s[v] = u
+            return s
+    
+        return False
+    
+    
+    def stacky(thing):
+        return thing.__class__ in {AnyJoyType, StackJoyType}
+
+Rewrite the stack effect comments:
+
+.. code:: ipython2
+
+    def defs():
+    
+        roll_down = (A[1], A[2], A[3]), (A[2], A[3], A[1])
+    
+        roll_up = (A[1], A[2], A[3]), (A[3], A[1], A[2])
+    
+        pop = (A[1],), ()
+    
+        popop = (A[2], A[1],), ()
+    
+        popd = (A[2], A[1],), (A[1],)
+    
+        popdd = (A[3], A[2], A[1],), (A[2], A[1],)
+    
+        swap = (A[1], A[2]), (A[2], A[1])
+    
+        rest = ((A[1], S[1]),), (S[1],)
+    
+        rrest = C(rest, rest)
+    
+        cons = (A[1], S[1]), ((A[1], S[1]),)
+    
+        ccons = C(cons, cons)
+    
+        uncons = ((A[1], S[1]),), (A[1], S[1])
+    
+        swons = C(swap, cons)
+    
+        dup = (A[1],), (A[1], A[1])
+    
+        dupd = (A[2], A[1]), (A[2], A[2], A[1])
+    
+        mul = (N[1], N[2]), (N[3],)
+        
+        sqrt = C(dup, mul)
+    
+        first = ((A[1], S[1]),), (A[1],)
+    
+        second = C(rest, first)
+    
+        third = C(rest, second)
+    
+        tuck = (A[2], A[1]), (A[1], A[2], A[1])
+    
+        over = (A[2], A[1]), (A[2], A[1], A[2])
+        
+        succ = pred = (N[1],), (N[2],)
+        
+        divmod_ = pm = (N[2], N[1]), (N[4], N[3])
+    
+        return locals()
+
+.. code:: ipython2
+
+    DEFS = defs()
+
+.. code:: ipython2
+
+    for name, stack_effect_comment in sorted(DEFS.items()):
+        print name, '=', doc_from_stack_effect(*stack_effect_comment)
+
+
+.. parsed-literal::
+
+    ccons = (a0 a1 [.0.] -- [a0 a1 .0.])
+    cons = (a1 [.1.] -- [a1 .1.])
+    divmod_ = (n2 n1 -- n4 n3)
+    dup = (a1 -- a1 a1)
+    dupd = (a2 a1 -- a2 a2 a1)
+    first = ([a1 .1.] -- a1)
+    mul = (n1 n2 -- n3)
+    over = (a2 a1 -- a2 a1 a2)
+    pm = (n2 n1 -- n4 n3)
+    pop = (a1 --)
+    popd = (a2 a1 -- a1)
+    popdd = (a3 a2 a1 -- a2 a1)
+    popop = (a2 a1 --)
+    pred = (n1 -- n2)
+    rest = ([a1 .1.] -- [.1.])
+    roll_down = (a1 a2 a3 -- a2 a3 a1)
+    roll_up = (a1 a2 a3 -- a3 a1 a2)
+    rrest = ([a0 a1 .0.] -- [.0.])
+    second = ([a0 a1 .0.] -- a1)
+    sqrt = (n0 -- n1)
+    succ = (n1 -- n2)
+    swap = (a1 a2 -- a2 a1)
+    swons = ([.0.] a0 -- [a0 .0.])
+    third = ([a0 a1 a2 .0.] -- a2)
+    tuck = (a2 a1 -- a1 a2 a1)
+    uncons = ([a1 .1.] -- a1 [.1.])
+
+
+.. code:: ipython2
+
+    globals().update(DEFS)
+
+Compose ``dup`` and ``mul``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code:: ipython2
+
+    C(dup, mul)
+
+
+
+
+.. parsed-literal::
+
+    ((n0,), (n1,))
+
+
+
+Revisit the ``F`` function, works fine.
+
+.. code:: ipython2
+
+    F = reduce(C, (pop, swap, roll_down, rest, rest, cons, cons))
+    F
+
+
+
+
+.. parsed-literal::
+
+    (((a0, (a1, s0)), a2, a3, a4), ((a3, (a2, s0)),))
+
+
+
+.. code:: ipython2
+
+    print doc_from_stack_effect(*F)
+
+
+.. parsed-literal::
+
+    ([a0 a1 .0.] a2 a3 a4 -- [a3 a2 .0.])
+
+
+Some otherwise inefficient functions are no longer to be feared. We can
+also get the effect of combinators in some limited cases.
+
+.. code:: ipython2
+
+    def neato(*funcs):
+        print doc_from_stack_effect(*reduce(C, funcs))
+
+.. code:: ipython2
+
+    # e.g. [swap] dip
+    neato(roll_up, swap, roll_down)
+
+
+.. parsed-literal::
+
+    (a0 a1 a2 -- a1 a0 a2)
+
+
+.. code:: ipython2
+
+    # e.g. [popop] dip
+    neato(popdd, roll_down, pop)
+
+
+.. parsed-literal::
+
+    (a0 a1 a2 a3 -- a2 a3)
+
+
+.. code:: ipython2
+
+    # Reverse the order of the top three items.
+    neato(roll_up, swap)
+
+
+.. parsed-literal::
+
+    (a0 a1 a2 -- a2 a1 a0)
+
+
+``compile_()`` version 2
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Because the type labels represent themselves as valid Python identifiers
+the ``compile_()`` function doesn't need to generate them anymore:
+
+.. code:: ipython2
+
+    def compile_(name, f, doc=None):
+        inputs, outputs = f
+        if doc is None:
+            doc = doc_from_stack_effect(inputs, outputs)
+        i = o = Symbol('stack')
+        for term in inputs:
+            i = term, i
+        for term in outputs:
+            o = term, o
+        return '''def %s(stack):
+        """%s"""
+        %s = stack
+        return %s''' % (name, doc, i, o)
+
+.. code:: ipython2
+
+    print compile_('F', F)
+
+
+.. parsed-literal::
+
+    def F(stack):
+        """([a0 a1 .0.] a2 a3 a4 -- [a3 a2 .0.])"""
+        (a4, (a3, (a2, ((a0, (a1, s0)), stack)))) = stack
+        return ((a3, (a2, s0)), stack)
+
+
+But it cannot magically create new functions that involve e.g. math and
+such. Note that this is *not* a ``sqr`` function implementation:
+
+.. code:: ipython2
+
+    print compile_('sqr', C(dup, mul))
+
+
+.. parsed-literal::
+
+    def sqr(stack):
+        """(n0 -- n1)"""
+        (n0, stack) = stack
+        return (n1, stack)
+
+
+``compilable()``
+^^^^^^^^^^^^^^^^
+
+The functions that *can* be compiled are the ones that have only
+``AnyJoyType`` and ``StackJoyType`` labels in their stack effect
+comments. We can write a function to check that:
+
+.. code:: ipython2
+
+    from itertools import imap
+    
+    
+    def compilable(f):
+        return isinstance(f, tuple) and all(imap(compilable, f)) or stacky(f)
+
+.. code:: ipython2
+
+    for name, stack_effect_comment in sorted(defs().items()):
+        if compilable(stack_effect_comment):
+            print name, '=', doc_from_stack_effect(*stack_effect_comment)
+
+
+.. parsed-literal::
+
+    ccons = (a0 a1 [.0.] -- [a0 a1 .0.])
+    cons = (a1 [.1.] -- [a1 .1.])
+    dup = (a1 -- a1 a1)
+    dupd = (a2 a1 -- a2 a2 a1)
+    first = ([a1 .1.] -- a1)
+    over = (a2 a1 -- a2 a1 a2)
+    pop = (a1 --)
+    popd = (a2 a1 -- a1)
+    popdd = (a3 a2 a1 -- a2 a1)
+    popop = (a2 a1 --)
+    rest = ([a1 .1.] -- [.1.])
+    roll_down = (a1 a2 a3 -- a2 a3 a1)
+    roll_up = (a1 a2 a3 -- a3 a1 a2)
+    rrest = ([a0 a1 .0.] -- [.0.])
+    second = ([a0 a1 .0.] -- a1)
+    swap = (a1 a2 -- a2 a1)
+    swons = ([.0.] a0 -- [a0 .0.])
+    third = ([a0 a1 a2 .0.] -- a2)
+    tuck = (a2 a1 -- a1 a2 a1)
+    uncons = ([a1 .1.] -- a1 [.1.])
+
+
+Functions that use the Stack
+----------------------------
+
+Consider the ``stack`` function which grabs the whole stack, quotes it,
+and puts it on itself:
+
+::
+
+    stack (...     -- ... [...]        )
+    stack (... a   -- ... a [a ...]    )
+    stack (... b a -- ... b a [a b ...])
+
+We would like to represent this in Python somehow. To do this we use a
+simple, elegant trick.
+
+::
+
+    stack         S   -- (         S,           S)
+    stack     (a, S)  -- (     (a, S),      (a, S))
+    stack (a, (b, S)) -- ( (a, (b, S)), (a, (b, S)))
+
+Instead of representing the stack effect comments as a single tuple
+(with N items in it) we use the same cons-list structure to hold the
+sequence and ``unify()`` the whole comments.
+
+``stack∘uncons``
+~~~~~~~~~~~~~~~~
+
+Let's try composing ``stack`` and ``uncons``. We want this result:
+
+::
+
+    stack∘uncons (... a -- ... a a [...])
+
+The stack effects are:
+
+::
+
+    stack = S -- (S, S)
+
+    uncons = ((a, Z), S) -- (Z, (a, S))
+
+Unifying:
+
+::
+
+      S    -- (S, S) ∘ ((a, Z), S) -- (Z, (a,   S   ))
+                                                        w/ { S: (a, Z) }
+    (a, Z) --        ∘             -- (Z, (a, (a, Z)))
+
+So:
+
+::
+
+    stack∘uncons == (a, Z) -- (Z, (a, (a, Z)))
+
+It works.
+
+``stack∘uncons∘uncons``
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Let's try ``stack∘uncons∘uncons``:
+
+::
+
+    (a, S     ) -- (S,      (a, (a, S     ))) ∘ ((b, Z),  S`             ) -- (Z, (b,   S`   ))
+
+                                                                                    w/ { S: (b, Z) }
+                                                                                    
+    (a, (b, Z)) -- ((b, Z), (a, (a, (b, Z)))) ∘ ((b, Z),  S`             ) -- (Z, (b,   S`   ))
+
+                                                                                    w/ { S`: (a, (a, (b, Z))) }
+                                                                                    
+    (a, (b, Z)) -- ((b, Z), (a, (a, (b, Z)))) ∘ ((b, Z), (a, (a, (b, Z)))) -- (Z, (b, (a, (a, (b, Z)))))
+
+    (a, (b, Z)) -- (Z, (b, (a, (a, (b, Z)))))
+
+It works.
+
+``compose()`` version 2
+^^^^^^^^^^^^^^^^^^^^^^^
+
+This function has to be modified to use the new datastructures and it is
+no longer recursive, instead recursion happens as part of unification.
+
+.. code:: ipython2
+
+    def compose(f, g):
+    
+        (f_in, f_out), (g_in, g_out) = f, g
+    
+        if not g_in:
+            fg_in, fg_out = f_in, stack_concat(g_out, f_out)
+    
+        elif not f_out:
+            fg_in, fg_out = stack_concat(f_in, g_in), g_out
+    
+        else: # Unify and update.
+    
+            s = unify(g_in, f_out)
+    
+            if s == False:  # s can also be the empty dict, which is ok.
+                raise TypeError('Cannot unify %r and %r.' % (fo, gi))
+    
+            fg_in, fg_out = update(s, (f_in, g_out))
+    
+        return fg_in, fg_out
+    
+    
+    stack_concat = lambda q, e: (q[0], stack_concat(q[1], e)) if q else e
+
+I don't want to rewrite all the defs myself, so I'll write a little
+conversion function instead. This is programmer's laziness.
+
+.. code:: ipython2
+
+    def sequence_to_stack(seq, stack=StackJoyType(23)):
+        for item in seq: stack = item, stack
+        return stack
+    
+    NEW_DEFS = {
+        name: (sequence_to_stack(i), sequence_to_stack(o))
+        for name, (i, o) in DEFS.iteritems()
+    }
+    
+    globals().update(NEW_DEFS)
+
+.. code:: ipython2
+
+    stack = S[0], (S[0], S[0])
+
+.. code:: ipython2
+
+    C(stack, uncons)
+
+
+
+
+.. parsed-literal::
+
+    ((a0, s0), (s0, (a0, (a0, s0))))
+
+
+
+.. code:: ipython2
+
+    C(C(stack, uncons), uncons)
+
+
+
+
+.. parsed-literal::
+
+    ((a0, (a1, s0)), (s0, (a1, (a0, (a0, (a1, s0))))))
+
+
+
+The display function should be changed too.
+
+``doc_from_stack_effect()`` version 2
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Clunky junk, but it will suffice for now.
+
+.. code:: ipython2
+
+    def doc_from_stack_effect(inputs, outputs):
+        switch = [False]  # Do we need to display the '...' for the rest of the main stack?
+        i, o = _f(inputs, switch), _f(outputs, switch)
+        if switch[0]:
+            i.append('...')
+            o.append('...')
+        return '(%s--%s)' % (
+            ' '.join(reversed([''] + i)),
+            ' '.join(reversed(o + [''])),
+        )
+    
+    
+    def _f(term, switch):
+        a = []
+        while term and isinstance(term, tuple):
+            item, term = term
+            a.append(item)
+        assert isinstance(term, StackJoyType), repr(term)
+        a = [_to_str(i, term, switch) for i in a]
+        return a
+    
+    
+    def _to_str(term, stack, switch):
+        if not isinstance(term, tuple):
+            if term == stack:
+                switch[0] = True
+                return '[...]'
+            return (
+                '[.%i.]' % term.number
+                if isinstance(term, StackJoyType)
+                else str(term)
+            )
+    
+        a = []
+        while term and isinstance(term, tuple):
+            item, term = term
+            a.append(_to_str(item, stack, switch))
+        assert isinstance(term, StackJoyType), repr(term)
+        if term == stack:
+            switch[0] = True
+            end = '...'
+        else:
+            end = '.%i.' % term.number
+        a.append(end)
+        return '[%s]' % ' '.join(a)
+
+.. code:: ipython2
+
+    for name, stack_effect_comment in sorted(NEW_DEFS.items()):
+        print name, '=', doc_from_stack_effect(*stack_effect_comment)
+
+
+.. parsed-literal::
+
+    ccons = (a0 a1 [.0.] -- [a0 a1 .0.])
+    cons = (a1 [.1.] -- [a1 .1.])
+    divmod_ = (n2 n1 -- n4 n3)
+    dup = (a1 -- a1 a1)
+    dupd = (a2 a1 -- a2 a2 a1)
+    first = ([a1 .1.] -- a1)
+    mul = (n1 n2 -- n3)
+    over = (a2 a1 -- a2 a1 a2)
+    pm = (n2 n1 -- n4 n3)
+    pop = (a1 --)
+    popd = (a2 a1 -- a1)
+    popdd = (a3 a2 a1 -- a2 a1)
+    popop = (a2 a1 --)
+    pred = (n1 -- n2)
+    rest = ([a1 .1.] -- [.1.])
+    roll_down = (a1 a2 a3 -- a2 a3 a1)
+    roll_up = (a1 a2 a3 -- a3 a1 a2)
+    rrest = ([a0 a1 .0.] -- [.0.])
+    second = ([a0 a1 .0.] -- a1)
+    sqrt = (n0 -- n1)
+    succ = (n1 -- n2)
+    swap = (a1 a2 -- a2 a1)
+    swons = ([.0.] a0 -- [a0 .0.])
+    third = ([a0 a1 a2 .0.] -- a2)
+    tuck = (a2 a1 -- a1 a2 a1)
+    uncons = ([a1 .1.] -- a1 [.1.])
+
+
+.. code:: ipython2
+
+    print ; print doc_from_stack_effect(*stack)
+    print ; print doc_from_stack_effect(*C(stack, uncons))
+    print ; print doc_from_stack_effect(*C(C(stack, uncons), uncons))
+    print ; print doc_from_stack_effect(*C(C(stack, uncons), cons))
+
+
+.. parsed-literal::
+
+    
+    (... -- ... [...])
+    
+    (... a0 -- ... a0 a0 [...])
+    
+    (... a1 a0 -- ... a1 a0 a0 a1 [...])
+    
+    (... a0 -- ... a0 [a0 ...])
+
+
+.. code:: ipython2
+
+    print doc_from_stack_effect(*C(ccons, stack))
+
+
+.. parsed-literal::
+
+    (... a1 a0 [.0.] -- ... [a1 a0 .0.] [[a1 a0 .0.] ...])
+
+
+.. code:: ipython2
+
+    Q = C(ccons, stack)
+    
+    Q
+
+
+
+
+.. parsed-literal::
+
+    ((s0, (a0, (a1, s1))), (((a1, (a0, s0)), s1), ((a1, (a0, s0)), s1)))
+
+
+
+``compile_()`` version 3
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+This makes the ``compile_()`` function pretty simple as the stack effect
+comments are now already in the form needed for the Python code:
+
+.. code:: ipython2
+
+    def compile_(name, f, doc=None):
+        i, o = f
+        if doc is None:
+            doc = doc_from_stack_effect(i, o)
+        return '''def %s(stack):
+        """%s"""
+        %s = stack
+        return %s''' % (name, doc, i, o)
+
+.. code:: ipython2
+
+    print compile_('Q', Q)
+
+
+.. parsed-literal::
+
+    def Q(stack):
+        """(... a1 a0 [.0.] -- ... [a1 a0 .0.] [[a1 a0 .0.] ...])"""
+        (s0, (a0, (a1, s1))) = stack
+        return (((a1, (a0, s0)), s1), ((a1, (a0, s0)), s1))
+
+
+.. code:: ipython2
+
+    unstack = (S[1], S[0]), S[1]
+    enstacken = S[0], (S[0], S[1])
+
+.. code:: ipython2
+
+    print doc_from_stack_effect(*unstack)
+
+
+.. parsed-literal::
+
+    ([.1.] --)
+
+
+.. code:: ipython2
+
+    print doc_from_stack_effect(*enstacken)
+
+
+.. parsed-literal::
+
+    (-- [.0.])
+
+
+.. code:: ipython2
+
+    print doc_from_stack_effect(*C(cons, unstack))
+
+
+.. parsed-literal::
+
+    (a0 [.0.] -- a0)
+
+
+.. code:: ipython2
+
+    print doc_from_stack_effect(*C(cons, enstacken))
+
+
+.. parsed-literal::
+
+    (a0 [.0.] -- [[a0 .0.] .1.])
+
+
+.. code:: ipython2
+
+    C(cons, unstack)
+
+
+
+
+.. parsed-literal::
+
+    ((s0, (a0, s1)), (a0, s0))
+
+
+
+Sets of Stack Effects
+---------------------
+
+...
+
+``concat``
+----------
+
+How to deal with ``concat``?
+
+::
+
+    concat ([.0.] [.1.] -- [.0. .1.])
+
+We would like to represent this in Python somehow...
+
+.. code:: ipython2
+
+    concat = (S[0], S[1]), ((S[0], S[1]),)
+
+But this is actually ``cons`` with the first argument restricted to be a
+stack:
+
+::
+
+    ([.0.] [.1.] -- [[.0.] .1.])
+
+What we have implemented so far would actually only permit:
+
+::
+
+    ([.0.] [.1.] -- [.2.])
+
+.. code:: ipython2
+
+    concat = (S[0], S[1]), (S[2],)
+
+Which works but can lose information. Consider ``cons concat``, this is
+how much information we *could* retain:
+
+::
+
+    (1 [.0.] [.1.] -- [1 .0. .1.])
+
+As opposed to just:
+
+::
+
+    (1 [.0.] [.1.] -- [.2.])
+
+Which works but can lose information. Consider ``cons concat``, this is
+how much information we *could* retain:
+
+::
+
+    (1 [.0.] [.1.] -- [1 .0. .1.]) uncons uncons
+
+    (1 [.0.] [.1.] -- 1 [.0. .1.])        uncons
+                                                    So far so good...
+    (1 [2 .2.] [.1.] -- 1 2 [.2. .1.])
+
+
+
+
+    (1 [.0.] [.1.] -- 1 [.0. .1.]) ([a1 .10.] -- a1 [.10.])
+                                                             w/ { [a1 .10.] : [  .0.   .1.] }
+                                                           -or-
+                                                             w/ { [  .0.   .1.] : [a1 .10.    ] }
+
+Typing Combinators
+------------------
+
+TBD
+
+This is an open subject.
+
+The obvious thing is that you now need two pairs of tuples to describe
+the combinators' effects, a stack effect comment and an expression
+effect comment:
+
+::
+
+    dip (a [F] --)--(-- F a)
+
+One thing that might help is...
+
+Abstract Interpretation
+-----------------------
+
+Something else...
+-----------------
+
+::
+
+    [4 5 ...] 2 1 0 pop∘swap∘roll<∘rest∘rest∘cons∘cons
+    [4 5 ...] 2 1       swap∘roll<∘rest∘rest∘cons∘cons
+    [4 5 ...] 1 2            roll<∘rest∘rest∘cons∘cons
+    1 2 [4 5 ...]                  rest∘rest∘cons∘cons
+    1 2   [5 ...]                       rest∘cons∘cons
+    1 2     [...]                            cons∘cons
+    1     [2 ...]                                 cons
+        [1 2 ...]
+
+Eh?
index d36d883..dc390b9 100644 (file)
@@ -9,13 +9,15 @@ These essays are adapted from Jupyter notebooks.  I hope to have those hosted so
    :maxdepth: 2
 
    Developing
+   Quadratic
    Replacing
+   Recursion_Combinators
    Ordered_Binary_Trees
    Treestep
    Generator_Programs
    Newton-Raphson
-   Quadratic
    Zipper
+   Types
    NoUpdates
    Categorical
 
index f754093..c3e00c7 100644 (file)
@@ -25,12 +25,15 @@ function.
 '''
 from inspect import getdoc
 from functools import wraps
+from inspect import getmembers, isfunction
 import operator, math
 
 from .parser import text_to_expression, Symbol
 from .utils.stack import list_to_stack, iter_stack, pick, concat
 from .utils.brutal_hackery import rename_code_object
 
+from .utils import generated_library as genlib
+
 
 _dictionary = {}
 
@@ -88,12 +91,8 @@ def add_aliases(D, A):
 
 
 definitions = ('''\
-second == rest first
-third == rest rest first
 of == swap at
 product == 1 swap [*] step
-swons == swap cons
-swoncat == swap concat
 flatten == [] swap [concat] step
 unit == [] cons
 quoted == [unit] dip
@@ -128,6 +127,10 @@ codireco == cons dip rest cons
 make_generator == [codireco] ccons
 ccons == cons cons
 '''
+##second == rest first
+##third == rest rest first
+##swons == swap cons
+##swoncat == swap concat
 
 ##Zipper
 ##z-down == [] swap uncons swap
@@ -258,6 +261,11 @@ def _text_to_defs(text):
 #
 
 
+# Load the auto-generated primitives into the dictionary.
+for name, primitive in getmembers(genlib, isfunction):
+  inscribe(SimpleFunctionWrapper(primitive))
+
+
 @inscribe
 @SimpleFunctionWrapper
 def parse(stack):
@@ -267,30 +275,30 @@ def parse(stack):
   return expression, stack
 
 
-@inscribe
-@SimpleFunctionWrapper
-def first(stack):
-  '''
-  ::
-
-    first == uncons pop
-
-  '''
-  ((head, tail), stack) = stack
-  return head, stack
-
-
-@inscribe
-@SimpleFunctionWrapper
-def rest(stack):
-  '''
-  ::
+##@inscribe
+##@SimpleFunctionWrapper
+##def first(stack):
+##  '''
+##  ::
+##
+##    first == uncons pop
+##
+##  '''
+##  ((head, tail), stack) = stack
+##  return head, stack
 
-    rest == uncons popd
 
-  '''
-  ((head, tail), stack) = stack
-  return tail, stack
+##@inscribe
+##@SimpleFunctionWrapper
+##def rest(stack):
+##  '''
+##  ::
+##
+##    rest == uncons popd
+##
+##  '''
+##  ((head, tail), stack) = stack
+##  return tail, stack
 
 
 @inscribe
@@ -479,28 +487,28 @@ def sort_(S):
   return list_to_stack(sorted(iter_stack(tos))), stack
 
 
-@inscribe
-@SimpleFunctionWrapper
-def cons(S):
-  '''
-  The cons operator expects a list on top of the stack and the potential
-  member below. The effect is to add the potential member into the
-  aggregate.
-  '''
-  (tos, (second, stack)) = S
-  return (second, tos), stack
+##@inscribe
+##@SimpleFunctionWrapper
+##def cons(S):
+##  '''
+##  The cons operator expects a list on top of the stack and the potential
+##  member below. The effect is to add the potential member into the
+##  aggregate.
+##  '''
+##  (tos, (second, stack)) = S
+##  return (second, tos), stack
 
 
-@inscribe
-@SimpleFunctionWrapper
-def uncons(S):
-  '''
-  Inverse of cons, removes an item from the top of the list on the stack
-  and places it under the remaining list.
-  '''
-  (tos, stack) = S
-  item, tos = tos
-  return tos, (item, stack)
+##@inscribe
+##@SimpleFunctionWrapper
+##def uncons(S):
+##  '''
+##  Inverse of cons, removes an item from the top of the list on the stack
+##  and places it under the remaining list.
+##  '''
+##  (tos, stack) = S
+##  item, tos = tos
+##  return tos, (item, stack)
 
 
 @inscribe
@@ -516,52 +524,52 @@ def clear(stack):
   return ()
 
 
-@inscribe
-@SimpleFunctionWrapper
-def dup(S):
-  '''Duplicate the top item on the stack.'''
-  (tos, stack) = S
-  return tos, (tos, stack)
-
-
-@inscribe
-@SimpleFunctionWrapper
-def over(S):
-  '''
-  Copy the second item down on the stack to the top of the stack.
-  ::
-
-       a b over
-    --------------
-        a b a
-
-  '''
-  second = S[1][0]
-  return second, S
-
-
-@inscribe
-@SimpleFunctionWrapper
-def tuck(S):
-  '''
-  Copy the item at TOS under the second item of the stack.
-  ::
-
-       a b tuck
-    --------------
-        b a b
-
-  '''
-  (tos, (second, stack)) = S
-  return tos, (second, (tos, stack))
-
-
-@inscribe
-@SimpleFunctionWrapper
-def swap(S):
-  '''Swap the top two items on stack.'''
-  (tos, (second, stack)) = S
-  return second, (tos, stack)
+##@inscribe
+##@SimpleFunctionWrapper
+##def dup(S):
+##  '''Duplicate the top item on the stack.'''
+##  (tos, stack) = S
+##  return tos, (tos, stack)
+
+
+##@inscribe
+##@SimpleFunctionWrapper
+##def over(S):
+##  '''
+##  Copy the second item down on the stack to the top of the stack.
+##  ::
+##
+##       a b over
+##    --------------
+##        a b a
+##
+##  '''
+##  second = S[1][0]
+##  return second, S
+
+
+##@inscribe
+##@SimpleFunctionWrapper
+##def tuck(S):
+##  '''
+##  Copy the item at TOS under the second item of the stack.
+##  ::
+##
+##       a b tuck
+##    --------------
+##        b a b
+##
+##  '''
+##  (tos, (second, stack)) = S
+##  return tos, (second, (tos, stack))
+
+
+##@inscribe
+##@SimpleFunctionWrapper
+##def swap(S):
+##  '''Swap the top two items on stack.'''
+##  (tos, (second, stack)) = S
+##  return second, (tos, stack)
 
 
 @inscribe
@@ -572,14 +580,14 @@ def swaack(stack):
   return stack, old_stack
 
 
-@inscribe
-@SimpleFunctionWrapper
-def stack_(stack):
-  '''
-  The stack operator pushes onto the stack a list containing all the
-  elements of the stack.
-  '''
-  return stack, stack
+##@inscribe
+##@SimpleFunctionWrapper
+##def stack_(stack):
+##  '''
+##  The stack operator pushes onto the stack a list containing all the
+##  elements of the stack.
+##  '''
+##  return stack, stack
 
 
 @inscribe
@@ -592,42 +600,42 @@ def unstack(stack):
   return stack[0]
 
 
-@inscribe
-@SimpleFunctionWrapper
-def pop(stack):
-  '''Pop and discard the top item from the stack.'''
-  return stack[1]
+##@inscribe
+##@SimpleFunctionWrapper
+##def pop(stack):
+##  '''Pop and discard the top item from the stack.'''
+##  return stack[1]
 
 
-@inscribe
-@SimpleFunctionWrapper
-def popd(stack):
-  '''Pop and discard the second item from the stack.'''
-  (tos, (_, stack)) = stack
-  return tos, stack
+##@inscribe
+##@SimpleFunctionWrapper
+##def popd(stack):
+##  '''Pop and discard the second item from the stack.'''
+##  (tos, (_, stack)) = stack
+##  return tos, stack
 
 
-@inscribe
-@SimpleFunctionWrapper
-def popdd(stack):
-  '''Pop and discard the third item from the stack.'''
-  (tos, (second, (_, stack))) = stack
-  return tos, (second, stack)
+##@inscribe
+##@SimpleFunctionWrapper
+##def popdd(stack):
+##  '''Pop and discard the third item from the stack.'''
+##  (tos, (second, (_, stack))) = stack
+##  return tos, (second, stack)
 
 
-@inscribe
-@SimpleFunctionWrapper
-def popop(stack):
-  '''Pop and discard the first and second items from the stack.'''
-  return stack[1][1]
+##@inscribe
+##@SimpleFunctionWrapper
+##def popop(stack):
+##  '''Pop and discard the first and second items from the stack.'''
+##  return stack[1][1]
 
 
-@inscribe
-@SimpleFunctionWrapper
-def dupd(S):
-  '''Duplicate the second item on the stack.'''
-  (tos, (second, stack)) = S
-  return tos, (second, (second, stack))
+##@inscribe
+##@SimpleFunctionWrapper
+##def dupd(S):
+##  '''Duplicate the second item on the stack.'''
+##  (tos, (second, stack)) = S
+##  return tos, (second, (second, stack))
 
 
 @inscribe
@@ -760,34 +768,34 @@ def sqrt(a):
   return r
 
 
-@inscribe
-@SimpleFunctionWrapper
-def rollup(S):
-  '''
-  ::
-
-       a b c
-    -----------
-       b c a
-
-  '''
-  (a, (b, (c, stack))) = S
-  return b, (c, (a, stack))
-
-
-@inscribe
-@SimpleFunctionWrapper
-def rolldown(S):
-  '''
-  ::
-
-       a b c
-    -----------
-       c a b
-
-  '''
-  (a, (b, (c, stack))) = S
-  return c, (a, (b, stack))
+##@inscribe
+##@SimpleFunctionWrapper
+##def rollup(S):
+##  '''
+##  ::
+##
+##       a b c
+##    -----------
+##       b c a
+##
+##  '''
+##  (a, (b, (c, stack))) = S
+##  return b, (c, (a, stack))
+
+
+##@inscribe
+##@SimpleFunctionWrapper
+##def rolldown(S):
+##  '''
+##  ::
+##
+##       a b c
+##    -----------
+##       c a b
+##
+##  '''
+##  (a, (b, (c, stack))) = S
+##  return c, (a, (b, stack))
 
 
 #def execute(S):