diff --git a/images/jenkins-tap.png b/images/jenkins-tap.png
new file mode 100644
index 0000000..3d48d26
Binary files /dev/null and b/images/jenkins-tap.png differ
diff --git a/slides.ipynb b/slides.ipynb
index 9854a76..9ae8107 100644
--- a/slides.ipynb
+++ b/slides.ipynb
@@ -1,787 +1,946 @@
 {
  "cells": [
   {
    "cell_type": "code",
    "execution_count": 1,
    "metadata": {
     "slideshow": {
      "slide_type": "skip"
     }
    },
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
       "Switched to branch 'master'\n",
       "Your branch is up to date with 'origin/master'.\n",
       "Already up to date.\n"
      ]
     }
    ],
    "source": [
     "cd ../so-workshop\n",
     "git checkout master\n",
     "git pull"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {
     "slideshow": {
      "slide_type": "slide"
     }
    },
    "source": [
     "# So, you want to go open Science ?\n",
     "## Testing, testing, testing !\n",
     "\n",
     "<br/>\n",
     "\n",
     "- https://c4science.ch/source/so-workshop/\n",
     "- https://c4science.ch/source/so-slides/\n",
     "\n",
     "<br/><br/><br/>\n",
     "SCITAS training with expertise from the EPFL Library<br/>\n",
     "Nicolas Richart and Jean-Baptiste Aubort - SCITAS"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {
     "slideshow": {
      "slide_type": "slide"
     }
    },
    "source": [
     "# Continuous Integration (CI)"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {
     "slideshow": {
      "slide_type": "fragment"
     }
    },
    "source": [
     "## What is CI ?\n",
     "\n",
     "- Automation of build and tests\n",
     "- Run tests at each commit\n",
     "- You need to write tests !"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {
     "slideshow": {
      "slide_type": "fragment"
     }
    },
    "source": [
     "## Why use CI ?\n",
     "\n",
     "- Detect bugs when they are introduced\n",
     "- Detect when fixed bugs appear again (regression)\n",
     "- Publish code that works"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {
     "slideshow": {
      "slide_type": "fragment"
     }
    },
    "source": [
     "Ensure code has a certain quality level\n",
     "- Linters\n",
     "- Test Coverage"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {
     "slideshow": {
      "slide_type": "slide"
     }
    },
    "source": [
     "# Jenkins on c4science"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {
     "slideshow": {
      "slide_type": "subslide"
     }
    },
    "source": [
     "## https://c4science.ch/jobs\n",
     "![](images/c4s-jenkinsjob.png)"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {
     "slideshow": {
      "slide_type": "subslide"
     }
    },
    "source": [
     "## https://jenkins.c4science.ch/\n",
     "![](images/c4s-jenkins.png)"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {
     "slideshow": {
      "slide_type": "slide"
     }
    },
    "source": [
     "# Example\n",
     "## Jenkins base"
    ]
   },
   {
    "cell_type": "code",
    "execution_count": 15,
    "metadata": {
     "slideshow": {
      "slide_type": "subslide"
     }
    },
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
       "Switched to branch 'feature/jenkins-base'\n",
       "Your branch is up to date with 'origin/feature/jenkins-base'.\n",
       "\u001b[01;34m.\u001b[00m\n",
       "├── \u001b[01;34mcode\u001b[00m\n",
       "│   ├── mylib.py\n",
       "│   └── \u001b[01;32mtest.py\u001b[00m\n",
       "├── Jenkinsfile\n",
       "└── README\n",
       "\n",
       "1 directory, 4 files\n"
      ]
     }
    ],
    "source": [
     "git checkout feature/jenkins-base\n",
     "tree"
    ]
   },
   {
    "cell_type": "code",
    "execution_count": 11,
    "metadata": {
     "slideshow": {
      "slide_type": "subslide"
     }
    },
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
       "#!/usr/bin/env python3\n",
       "\n",
       "class MyLib():\n",
       "\n",
       "    def __init__(self):\n",
       "        pass\n",
       "\n",
       "    def MyFunc(self):\n",
       "        return 'test'\n",
       "\n",
       "if __name__ == '__main__':\n",
       "    pass\n"
      ]
     }
    ],
    "source": [
     "cat code/mylib.py"
    ]
   },
   {
    "cell_type": "code",
    "execution_count": 10,
    "metadata": {
     "slideshow": {
      "slide_type": "subslide"
     }
    },
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
       "#!/usr/bin/env python3\n",
       "import unittest, pytest\n",
       "import mylib\n",
       "\n",
       "class Test(unittest.TestCase):\n",
       "\n",
       "    def test_return(self):\n",
       "        m = mylib.MyLib()\n",
       "        self.assertTrue(m.MyFunc() == 'test')\n",
       "\n",
       "if __name__ == '__main__':\n",
       "    pytest.main(['./test.py'])\n"
      ]
     }
    ],
    "source": [
     "cat code/test.py"
    ]
   },
   {
    "cell_type": "code",
    "execution_count": 9,
    "metadata": {
     "slideshow": {
      "slide_type": "subslide"
     }
    },
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
       "pipeline {\n",
       "\n",
       "    agent {\n",
       "        docker {\n",
       "            image 'python:3.7'\n",
       "        }\n",
       "    }\n",
       "\n",
       "    environment {\n",
       "        HOME = \"$WORKSPACE\"\n",
       "    }\n",
       "\n",
       "    stages {\n",
       "        stage('install dependencies') {\n",
       "            steps {\n",
       "                sh 'pip3 install --user pytest'\n",
       "            }\n",
       "        }\n",
       "        stage('run tests') {\n",
       "            steps {\n",
       "                sh '$HOME/.local/bin/pytest code/test.py'\n",
       "            }\n",
       "        }\n",
       "    }\n",
       "\n",
       "}\n"
      ]
     }
    ],
    "source": [
     "cat Jenkinsfile"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {
     "slideshow": {
      "slide_type": "subslide"
     }
    },
    "source": [
     "![](images/jenkins-base.png)"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {
     "slideshow": {
      "slide_type": "slide"
     }
    },
    "source": [
     "# Example\n",
     "## Jenkins dockerfile"
    ]
   },
   {
    "cell_type": "code",
    "execution_count": 16,
    "metadata": {
     "slideshow": {
      "slide_type": "subslide"
     }
    },
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
       "Switched to branch 'feature/jenkins-dockerfile'\n",
       "Your branch is up to date with 'origin/feature/jenkins-dockerfile'.\n",
       "\u001b[01;34m.\u001b[00m\n",
       "├── \u001b[01;34mcode\u001b[00m\n",
       "│   ├── mylib.py\n",
       "│   └── \u001b[01;32mtest.py\u001b[00m\n",
       "├── Dockerfile\n",
       "├── Jenkinsfile\n",
       "└── README\n",
       "\n",
       "1 directory, 5 files\n"
      ]
     }
    ],
    "source": [
     "git checkout feature/jenkins-dockerfile\n",
     "tree"
    ]
   },
   {
    "cell_type": "code",
    "execution_count": 19,
    "metadata": {
     "slideshow": {
      "slide_type": "subslide"
     }
    },
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
       "FROM python:3.7\n",
       "RUN pip3 install --no-cache-dir pytest\n"
      ]
     }
    ],
    "source": [
     "cat Dockerfile"
    ]
   },
   {
    "cell_type": "code",
    "execution_count": 17,
    "metadata": {
     "slideshow": {
      "slide_type": "subslide"
     }
    },
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
       "pipeline {\n",
       "\n",
       "    agent {\n",
       "        dockerfile true \n",
       "    }\n",
       "\n",
       "    stages {\n",
       "        stage('run tests') {\n",
       "            steps {\n",
       "                sh 'pytest code/test.py'\n",
       "            }\n",
       "        }\n",
       "    }\n",
       "\n",
       "}\n"
      ]
     }
    ],
    "source": [
     "cat Jenkinsfile"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {
     "slideshow": {
      "slide_type": "slide"
     }
    },
    "source": [
     "## Example\n",
     "### Jenkins junit"
    ]
   },
   {
    "cell_type": "code",
    "execution_count": 8,
    "metadata": {
     "slideshow": {
      "slide_type": "subslide"
     }
    },
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
       "Switched to branch 'feature/jenkins-junit'\n",
       "Your branch is up to date with 'origin/feature/jenkins-junit'.\n",
       "\u001b[01;34m.\u001b[00m\n",
       "├── \u001b[01;34mcode\u001b[00m\n",
       "│   ├── mylib.py\n",
       "│   └── \u001b[01;32mtest.py\u001b[00m\n",
       "├── Dockerfile\n",
       "├── Jenkinsfile\n",
       "└── README\n",
       "\n",
       "1 directory, 5 files\n"
      ]
     }
    ],
    "source": [
     "git checkout feature/jenkins-junit\n",
     "tree"
    ]
   },
   {
    "cell_type": "code",
    "execution_count": 21,
    "metadata": {
     "slideshow": {
      "slide_type": "subslide"
     }
    },
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
       "pipeline {\n",
       "\n",
       "    agent {\n",
       "        dockerfile true \n",
       "    }\n",
       "\n",
       "    stages {\n",
       "        stage('run tests') {\n",
       "            steps {\n",
       "                sh 'pytest --junitxml results.xml code/test.py'\n",
       "            }\n",
       "        }\n",
       "    }\n",
       "\n",
       "    post {\n",
       "        always {\n",
       "            junit 'results.xml'\n",
       "        }\n",
       "    }\n",
       "\n",
       "}\n"
      ]
     }
    ],
    "source": [
     "cat Jenkinsfile"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {
     "slideshow": {
      "slide_type": "subslide"
     }
    },
    "source": [
     "![](images/jenkins-junit.png)"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {
     "slideshow": {
      "slide_type": "subslide"
     }
    },
    "source": [
     "![](images/jenkins-junit2.png)"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {
     "slideshow": {
      "slide_type": "slide"
     }
    },
    "source": [
     "# C4science\n",
     "## Arcanist\n",
     "Command line tool to interact with c4science"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {
     "slideshow": {
      "slide_type": "fragment"
     }
    },
    "source": [
     "### Linters\n",
     "\n",
     "> A linter or lint refers to tools that analyze source code to flag programming errors, bugs, stylistic errors, and suspicious constructs.\n",
     "\n",
     "- https://en.wikipedia.org/wiki/Lint_(software)\n",
     "- https://c4science.ch/w/c4science/lint/"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 18,
+   "execution_count": 23,
    "metadata": {
     "slideshow": {
      "slide_type": "subslide"
     }
    },
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
       "Switched to branch 'feature/arcanist-linter'\n",
       "Your branch is up to date with 'origin/feature/arcanist-linter'.\n",
       "\u001b[01;34m.\u001b[00m\n",
       "├── .arclint\n",
       "├── \u001b[01;34mcode\u001b[00m\n",
       "│   ├── mylib.py\n",
       "│   └── \u001b[01;32mtest.py\u001b[00m\n",
       "├── Dockerfile\n",
       "├── .gitignore\n",
       "├── Jenkinsfile\n",
       "└── README\n",
       "\n",
       "1 directory, 7 files\n"
      ]
     }
    ],
    "source": [
     "git checkout feature/arcanist-linter\n",
     "tree -a -I \".git\""
    ]
   },
   {
    "cell_type": "code",
    "execution_count": 12,
    "metadata": {
     "slideshow": {
      "slide_type": "subslide"
     }
    },
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
       "\u001b[42m\u001b[1m CONFIGURED \u001b[m\u001b[49m \u001b[1mtext\u001b[m (Basic Text Linter)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mcsharp\u001b[m (C#)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mcpplint\u001b[m (C++ Google's Styleguide)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mcppcheck\u001b[m (C++ linter)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mlessc\u001b[m (CSS pre-processor)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mcsslint\u001b[m (CSSLint)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mchmod\u001b[m (Chmod)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mgjslint\u001b[m (Closure Linter)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mcoffeelint\u001b[m (CoffeeLint)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mcomposer\u001b[m (Composer Dependency Manager)\n",
       "\u001b[42m\u001b[1m CONFIGURED \u001b[m\u001b[49m \u001b[1mfilename\u001b[m (Filename)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mgenerated\u001b[m (Generated Code)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mgolint\u001b[m (Golint)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mhlint\u001b[m (Haskell Linter)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mjsonlint\u001b[m (JSON Lint)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mjson\u001b[m (JSON Lint)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mjscs\u001b[m (JavaScript Code Style)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mjshint\u001b[m (JavaScript error checking)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mnolint\u001b[m (Lint Disabler)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mmerge-conflict\u001b[m (Merge Conflicts)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mphpcs\u001b[m (PHP_CodeSniffer)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mphutil-library\u001b[m (Phutil Library Linter)\n",
       "\u001b[42m\u001b[1m CONFIGURED \u001b[m\u001b[49m \u001b[1mpylint\u001b[m (PyLint)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mflake8\u001b[m (Python Flake8 multi-linter)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mpep8\u001b[m (Python PEP 8)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mpyflakes\u001b[m (Python PyFlakes)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mruby\u001b[m (Ruby)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mrubocop\u001b[m (Ruby static code analyzer)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mscript-and-regex\u001b[m (Script and Regex)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mxml\u001b[m (SimpleXML Linter)\n",
       "\u001b[42m\u001b[1m CONFIGURED \u001b[m\u001b[49m \u001b[1mspelling\u001b[m (Spellchecker)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mxhpast\u001b[m (XHPAST Lint)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mphp\u001b[m (php -l)\n",
       "\u001b[43m\u001b[1m AVAILABLE  \u001b[m\u001b[49m \u001b[1mpuppet-lint\u001b[m (puppet-lint)\n",
       "(Run `arc linters --verbose` for more details.)\n"
      ]
     }
    ],
    "source": [
     "arc linters"
    ]
   },
   {
    "cell_type": "code",
    "execution_count": 3,
    "metadata": {
     "slideshow": {
      "slide_type": "subslide"
     }
    },
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
       "{\n",
       "  \"linters\": {\n",
       "    \"spelling-linter\": {\n",
       "      \"type\": \"spelling\"\n",
       "    },\n",
       "    \"filename-linter\": {\n",
       "      \"type\": \"filename\"\n",
       "    },\n",
       "    \"text-linter\": {\n",
       "      \"type\": \"text\"\n",
       "    },\n",
       "    \"python-checks\": {\n",
       "      \"type\": \"pylint\",\n",
       "      \"include\": \"(\\\\.py$)\"\n",
       "    }\n",
       "  }\n",
       "}\n"
      ]
     }
    ],
    "source": [
     "cat .arclint"
    ]
   },
   {
    "cell_type": "code",
    "execution_count": 4,
    "metadata": {
     "slideshow": {
      "slide_type": "subslide"
     }
    },
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
       "Jenkinsfile:4:Auto-Fix: Trailing Whitespace\n",
       "README:3:Auto-Fix: Trailing Whitespace at EOF\n",
       "code/mylib.py:1:Advice: Missing Docstring\n",
       "code/mylib.py:3:Advice: Missing Docstring\n",
       "code/mylib.py:3:Advice: Old Style Class\n",
       "code/mylib.py:8:Advice: Invalid Name\n",
       "code/mylib.py:8:Advice: Missing Docstring\n",
       "code/mylib.py:8:Advice: No Self Use\n",
       "code/mylib.py:11:Advice: Invalid Name\n",
       "code/mylib.py:11:Advice: Missing Docstring\n",
       "code/mylib.py:11:Advice: No Self Use\n",
       "code/test.py:1:Advice: Missing Docstring\n",
       "code/test.py:5:Advice: Missing Docstring\n",
       "code/test.py:9:Advice: Missing Docstring\n",
       "code/test.py:12:Warning: Mixed Indentation\n",
       "code/test.py:12:Error: Tab Literal\n",
       "code/test.py:12:Advice: Missing Docstring\n",
       "code/test.py:12:Warning: Unused Variable\n",
       "code/test.py:13:Warning: Mixed Indentation\n"
      ]
     },
     {
      "ename": "",
      "evalue": "2",
      "output_type": "error",
      "traceback": []
     }
    ],
    "source": [
     "arc lint --never-apply-patches --output summary --everything"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {
     "slideshow": {
      "slide_type": "slide"
     }
    },
    "source": [
-    "### Unit-Tests\n"
+    "### Unit-Tests\n",
+    "Using the TAP (Test Anything Protocol) extension of Arcanist, we can report test units result to c4science"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 17,
-   "metadata": {},
+   "execution_count": 28,
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
       "Switched to branch 'feature/arcanist-unittests'\n",
       "Your branch is up to date with 'origin/feature/arcanist-unittests'.\n",
+      "Submodule path '.arcanist-extensions': checked out 'b89c749a90154676967a1601b62563fed0cbd572'\n",
       "\u001b[01;34m.\u001b[00m\n",
       "├── .arcconfig\n",
       "├── .arclint\n",
       "├── \u001b[01;34mcode\u001b[00m\n",
       "│   ├── mylib.py\n",
       "│   └── \u001b[01;32mtest.py\u001b[00m\n",
       "├── Dockerfile\n",
       "├── .gitignore\n",
       "├── .gitmodules\n",
       "├── Jenkinsfile\n",
       "└── README\n",
       "\n",
       "1 directory, 9 files\n"
      ]
     }
    ],
    "source": [
     "git checkout feature/arcanist-unittests\n",
+    "git submodule update --init\n",
     "tree -a -I \".git|.arcanist-extensions\""
    ]
   },
   {
-   "cell_type": "raw",
+   "cell_type": "code",
+   "execution_count": 21,
    "metadata": {
     "slideshow": {
-     "slide_type": "slide"
+     "slide_type": "subslide"
+    }
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\n",
+      "  \"load\": [\n",
+      "    \".arcanist-extensions/tap_test_engine\"\n",
+      "  ],\n",
+      "\n",
+      "  \"unit.engine\": \"TAPTestEngine\",\n",
+      "  \"unit.engine.tap.command\": \"code/test.py\"\n",
+      "}\n"
+     ]
+    }
+   ],
+   "source": [
+    "cat .arcconfig"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 25,
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
     }
    },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "ok 1 - Test.test_capitalize\n",
+      "ok 2 - Test.test_return\n",
+      "1..2\n"
+     ]
+    }
+   ],
+   "source": [
+    "pytest --tap-stream ./code/test.py"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 32,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "ok 1 - Test.test_capitalize\n",
+      "not ok 2 - Test.test_capitalize_fail\n",
+      "# \n",
+      "# self = <test.Test testMethod=test_capitalize_fail>\n",
+      "# \n",
+      "#     def test_capitalize_fail(self):\n",
+      "# >       self.assertTrue(self.m.Capitalize('TeSt') == 'test')\n",
+      "# E       AssertionError: False is not true\n",
+      "# \n",
+      "# code/test.py:16: AssertionError\n",
+      "ok 3 - Test.test_return\n",
+      "1..3\n",
+      "  \u001b[42m\u001b[1m PASS \u001b[m\u001b[49m \u001b[32m <1ms\u001b[39m\u001b[33m★\u001b[39m  Test.test_capitalize\n",
+      "  \u001b[41m\u001b[1m FAIL \u001b[m\u001b[49m Test.test_capitalize_fail\n",
+      "#\n",
+      "  \u001b[42m\u001b[1m PASS \u001b[m\u001b[49m \u001b[32m <1ms\u001b[39m\u001b[33m★\u001b[39m  Test.test_return\n"
+     ]
+    },
+    {
+     "ename": "",
+     "evalue": "2",
+     "output_type": "error",
+     "traceback": []
+    }
+   ],
+   "source": [
+    "arc unit --rev HEAD^"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 31,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "FROM dkdde/arcanist\n",
+      "RUN apk add --update bash \\\n",
+      "                     git \\\n",
+      "                     php7 \\\n",
+      "                     php7-curl \\\n",
+      "                     php7-json \\\n",
+      "                     py2-pip \\\n",
+      "    && pip install pytest pytest-tap tap.py \\\n",
+      "    && rm -rf /var/cache/apk/*\n",
+      "RUN ln -s /arc/arcanist/bin/arc /bin/arc\n",
+      "\n",
+      "ENTRYPOINT []\n"
+     ]
+    }
+   ],
+   "source": [
+    "cat Dockerfile"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 30,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "pipeline {\n",
+      "\n",
+      "    agent {\n",
+      "        dockerfile true\n",
+      "    }\n",
+      "\n",
+      "    stages {\n",
+      "        stage('run tests') {\n",
+      "            steps {\n",
+      "                sh 'git submodule update --init'\n",
+      "                sh 'arc unit --rev HEAD^'\n",
+      "            }\n",
+      "        }\n",
+      "    }\n",
+      "\n",
+      "    post {\n",
+      "        always {\n",
+      "            archiveArtifacts artifacts: '*.tap'\n",
+      "            step([$class: \"TapPublisher\", testResults: \"*.tap\"])\n",
+      "        }\n",
+      "    }\n",
+      "\n",
+      "}\n"
+     ]
+    }
+   ],
+   "source": [
+    "cat Jenkinsfile"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
    "source": [
-    "### Jenkins and Arcanist"
+    "![](images/jenkins-tap.png)"
    ]
   }
  ],
  "metadata": {
   "celltoolbar": "Slideshow",
   "kernelspec": {
    "display_name": "Bash",
    "language": "bash",
    "name": "bash"
   },
   "language_info": {
    "codemirror_mode": "shell",
    "file_extension": ".sh",
    "mimetype": "text/x-sh",
    "name": "bash"
   },
   "livereveal": {
    "height": 768,
    "theme": "serif",
    "transition": "none",
    "width": 1024
   }
  },
  "nbformat": 4,
  "nbformat_minor": 2
 }