ZdS ne se lance plus sous Windows
Comme vu dans la PR #1322 ZdS ne se lance plus sous Windows mais crache une erreur :

```
Validating models...

0 errors found
Unhandled exception in thread started by <function wrapper at 0x0000000003F33B38>
Traceback (most recent call last):
  File "C:\Users\SpaceFox\.virtualenvs\zdsenv\lib\site-packages\django\utils\autoreload.py", line 93, in wrapper
    fn(*args, **kwargs)
  File "C:\Users\SpaceFox\.virtualenvs\zdsenv\lib\site-packages\django\core\management\commands\runserver.py", line 104,
 in inner_run
    now = now.decode('utf-8')
  File "C:\Users\SpaceFox\.virtualenvs\zdsenv\lib\encodings\utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode byte 0xfb in position 2: invalid start byte
```

Le bug n'est pas présent sous Linux, et reste présent si on remonte dans les versions aussi loin que le tag v1.0-RC1 (base neuve, fichiers .pyc supprimés), qui lui fonctionnait très bien sous Windows à l'époque.

Ceci ressemble donc très fortement à un bug apporté par l'une de nos dépendances.

diff --git a/templates/tutorial/chapter/view.html b/templates/tutorial/chapter/view.html
index a2444f90d..b4665bdf7 100644
--- a/templates/tutorial/chapter/view.html
+++ b/templates/tutorial/chapter/view.html
@@ -148,28 +148,22 @@
             <div class="mobile-menu-bloc mobile-all-links mobile-show-ico" data-title="Suppression">
                 <h3>Suppression</h3>
                 <ul>
-                    {% if not tutorial.on_line %}
-                        <li>
-                            <a href="#delete-chapter" class="open-modal ico-after cross red">
-                                Supprimer le chapitre
-                            </a>
-                            <form action="{% url "zds.tutorial.views.modify_chapter" %}" method="post" id="delete-chapter" class="modal modal-medium">
-                                <p>
-                                    Attention, vous vous apprêtez à supprimer définitivement le chapitre "<em>{{ chapter.title }}</em>".
-                                </p>
-                                <input type="hidden" name="chapter" value="{{ chapter.pk }}">
-
-                                {% csrf_token %}
-                                <button type="submit" name="delete">
-                                    Confirmer
-                                </button>
-                            </form>
-                        </li>
-                    {% else %}
-                        <li class="inactive">
-                            <span>Impossible car publié</span>
-                        </li>
-                    {% endif %}
+                    <li>
+                        <a href="#delete-chapter" class="open-modal ico-after cross red">
+                            Supprimer le chapitre
+                        </a>
+                        <form action="{% url "zds.tutorial.views.modify_chapter" %}" method="post" id="delete-chapter" class="modal modal-medium">
+                            <p>
+                                Attention, vous vous apprêtez à supprimer définitivement le chapitre "<em>{{ chapter.title }}</em>".
+                            </p>
+                            <input type="hidden" name="chapter" value="{{ chapter.pk }}">
+
+                            {% csrf_token %}
+                            <button type="submit" name="delete">
+                                Confirmer
+                            </button>
+                        </form>
+                    </li>
                 </ul>
             </div>
         {% endif %}
diff --git a/templates/tutorial/tutorial/view.html b/templates/tutorial/tutorial/view.html
index fc20bb0a8..516edc17c 100644
--- a/templates/tutorial/tutorial/view.html
+++ b/templates/tutorial/tutorial/view.html
@@ -96,51 +96,48 @@
 {% endblock %}
 
 
-
 {% block content %}
-    {% with tuto_version=tutorial|repo_tuto:version %}
-        {% if tuto_version.introduction and tuto_version.introduction != "None" %}
-            {{ tuto_version.introduction|emarkdown }}
-        {% elif not tutorial.in_beta %}
-            <p class="ico-after warning">
-                Il n'y a pas d'introduction.
-            </p>
-        {% endif %}
+    {% if tutorial.get_introduction and tutorial.get_introduction != "None" %}
+        {{ tutorial.get_introduction|emarkdown }}
+    {% elif not tutorial.in_beta %}
+        <p class="ico-after warning">
+            Il n'y a pas d'introduction.
+        </p>
+    {% endif %}
 
-        {% if tutorial.is_mini %}
-            {# Small tutorial #}
+    {% if tutorial.is_mini %}
+        {# Small tutorial #}
 
-            {% include "tutorial/includes/chapter.part.html" with authors=tutorial.authors.all %}
-        {% else %}
-            {# Large tutorial #}
+        {% include "tutorial/includes/chapter.part.html" with authors=tutorial.authors.all %}
+    {% else %}
+        {# Large tutorial #}
 
-            <hr />
+        <hr />
 
-            {% for part in parts %}
-                <h2>
-                    <a href="{% url "view-part-url" tutorial.pk tutorial.slug part.pk part.slug %}{% if version %}?version={{ version }}{% endif %}">
-                        Partie {{ part.position_in_tutorial }} : {{ part.title }}
-                    </a>
-                </h2>
-                {% include "tutorial/includes/part.part.html" %}
-            {% empty %}
-                <p class="ico-after warning">
-                    Il n'y a actuellement aucune partie dans ce tutoriel.
-                </p>
-            {% endfor %}
+        {% for part in parts %}
+            <h2>
+                <a href="{% url "view-part-url" tutorial.pk tutorial.slug part.pk part.slug %}{% if version %}?version={{ version }}{% endif %}">
+                    Partie {{ part.position_in_tutorial }} : {{ part.title }}
+                </a>
+            </h2>
+            {% include "tutorial/includes/part.part.html" %}
+        {% empty %}
+            <p class="ico-after warning">
+                Il n'y a actuellement aucune partie dans ce tutoriel.
+            </p>
+        {% endfor %}
 
-            <hr />
+        <hr />
 
-        {% endif %}
+    {% endif %}
 
-        {% if tuto_version.conclusion and tuto_version.conclusion != "None" %}
-            {{ tuto_version.conclusion|emarkdown }}
-        {% elif not tutorial.in_beta %}
-            <p class="ico-after warning">
-                Il n'y a pas de conclusion.
-            </p>
-        {% endif %}
-    {% endwith %}
+    {% if tutorial.get_conclusion and tutorial.get_conclusion != "None" %}
+        {{ tutorial.get_conclusion|emarkdown }}
+    {% elif not tutorial.in_beta %}
+        <p class="ico-after warning">
+            Il n'y a pas de conclusion.
+        </p>
+    {% endif %}
 {% endblock %}
 
 
@@ -153,7 +150,7 @@
                     Ajouter une partie
                 </a>
             {% else %}
-                <a href="{% url "zds.tutorial.views.add_extract" %}?chapitre={{ tutorial.get_chapter.pk }}" class="ico-after more blue new-btn">
+                <a href="{% url "zds.tutorial.views.add_extract" %}?chapitre={{ chapter.pk }}" class="ico-after more blue new-btn">
                     Ajouter un extrait
                 </a>
             {% endif %}
diff --git a/zds/member/views.py b/zds/member/views.py
index 45387bfbf..b100f40d6 100644
--- a/zds/member/views.py
+++ b/zds/member/views.py
@@ -126,12 +126,12 @@ def details(request, user_name):
     my_tuto_versions = []
     for my_tutorial in my_tutorials:
         mandata = my_tutorial.load_json_for_public()
-        mandata = my_tutorial.load_dic(mandata)
+        my_tutorial.load_dic(mandata)
         my_tuto_versions.append(mandata)
     my_article_versions = []
     for my_article in my_articles:
         article_version = my_article.load_json_for_public()
-        article_version = my_article.load_dic(article_version)
+        my_article.load_dic(article_version)
         my_article_versions.append(article_version)
 
     my_topics = \
diff --git a/zds/pages/views.py b/zds/pages/views.py
index 14b0e961e..4c920db3e 100644
--- a/zds/pages/views.py
+++ b/zds/pages/views.py
@@ -29,7 +29,7 @@ def home(request):
     tutos = []
     for tuto in get_last_tutorials():
         data = tuto.load_json_for_public()
-        data = tuto.load_dic(data)
+        tuto.load_dic(data)
         tutos.append(data)
     
     articles = []
diff --git a/zds/tutorial/models.py b/zds/tutorial/models.py
index f6869bbe1..04a68d6e6 100644
--- a/zds/tutorial/models.py
+++ b/zds/tutorial/models.py
@@ -182,34 +182,73 @@ class Tutorial(models.Model):
             settings.REPO_PATH_PROD,
             str(self.pk) + '_' + slugify(data['title']))
 
-    def load_dic(self, mandata):
-        mandata['get_absolute_url_online'] = reverse('zds.tutorial.views.view_tutorial_online',
-                                                     args=[self.pk, slugify(mandata["title"])])
-        mandata['get_absolute_url_beta'] = self.get_absolute_url_beta()
-        mandata['get_absolute_url'] = self.get_absolute_url()
-        mandata['get_introduction_online'] = self.get_introduction_online()
-        mandata['get_conclusion_online'] = self.get_conclusion_online()
-
+    def load_dic(self, mandata, sha=None):
+        '''fill mandata with informations from database model'''
+
+        fns = [
+            'is_big', 'is_mini', 'have_markdown','have_html', 'have_pdf', 
+            'have_epub', 'get_path'
+            ]
+
+        attrs = [
+            'pk', 'authors', 'subcategory', 'image', 'pubdate', 'update',
+            'source', 'sha_draft', 'sha_beta', 'sha_validation', 'sha_public'
+            ]
+
+        #load functions and attributs in tree
+        for fn in fns: 
+            mandata[fn] = getattr(self,fn)
+        for attr in attrs: 
+            mandata[attr] = getattr(self,attr)
+
+        # general information
         mandata['slug'] = slugify(mandata['title'])
-        mandata['pk'] = self.pk
-        mandata['on_line'] = self.on_line
-        mandata['authors'] = self.authors
-        mandata['subcategory'] = self.subcategory
-        mandata['image'] = self.image
-        mandata['pubdate'] = self.pubdate
-        mandata['source'] = self.source
-        mandata['have_markdown'] = self.have_markdown()
-        mandata['have_html'] = self.have_html()
-        mandata['have_pdf'] = self.have_pdf()
-        mandata['have_epub'] = self.have_epub()
-
-        return mandata
+        mandata['in_beta'] = self.in_beta() and self.sha_beta == sha
+        mandata['in_validation'] = self.in_validation() \
+            and self.sha_validation == sha
+        mandata['on_line'] = self.on_line() and self.sha_public == sha
+
+        #url:
+        mandata['get_absolute_url'] = reverse(
+                'zds.tutorial.views.view_tutorial',
+                args=[self.pk, mandata['slug']]
+            )
+
+        if self.in_beta():
+            mandata['get_absolute_url_beta'] = reverse(
+                    'zds.tutorial.views.view_tutorial',
+                    args=[self.pk, mandata['slug']]
+               ) + '?version=' + self.sha_beta
+
+        else:
+            mandata['get_absolute_url_beta'] = reverse(
+                    'zds.tutorial.views.view_tutorial',
+                    args=[self.pk, mandata['slug']]
+                )
+
+        mandata['get_absolute_url_online'] = reverse(
+                'zds.tutorial.views.view_tutorial_online',
+                args=[self.pk, mandata['slug']]
+            )
+
+    def load_introduction_and_conclusion(self, mandata, sha=None, public=False):
+        '''Explicitly load introduction and conclusion to avoid useless disk
+        access in load_dic()
+        '''
+
+        if public:
+            mandata['get_introduction_online'] = self.get_introduction_online()
+            mandata['get_conclusion_online'] = self.get_conclusion_online()
+        else:
+            mandata['get_introduction'] = self.get_introduction(sha)
+            mandata['get_conclusion'] = self.get_conclusion(sha)
+        
 
     def load_json_for_public(self, sha=None):
         if sha is None:
             sha = self.sha_public
         repo = Repo(self.get_path())
-        mantuto = get_blob(repo.commit(self.sha_public).tree, 'manifest.json')
+        mantuto = get_blob(repo.commit(sha).tree, 'manifest.json')
         data = json_reader.loads(mantuto)
 
         return data
@@ -230,8 +269,6 @@ class Tutorial(models.Model):
             json_data.close()
 
             return data
-        else:
-            return None
 
     def dump_json(self, path=None):
         if path is None:
@@ -258,20 +295,19 @@ class Tutorial(models.Model):
 
         if path_tuto:
             return get_blob(repo.commit(sha).tree, path_tuto)
-        else:
-            return None
 
     def get_introduction_online(self):
-        intro = open(
-            os.path.join(
-                self.get_prod_path(),
-                self.introduction +
-                '.html'),
-            "r")
-        intro_contenu = intro.read()
-        intro.close()
+        if self.on_line():
+            intro = open(
+                os.path.join(
+                    self.get_prod_path(),
+                    self.introduction +
+                    '.html'),
+                "r")
+            intro_contenu = intro.read()
+            intro.close()
 
-        return intro_contenu.decode('utf-8')
+            return intro_contenu.decode('utf-8')
 
     def get_conclusion(self, sha=None):
         # find hash code
@@ -286,20 +322,19 @@ class Tutorial(models.Model):
 
         if path_tuto:
             return get_blob(repo.commit(sha).tree, path_tuto)
-        else:
-            return None
 
     def get_conclusion_online(self):
-        conclu = open(
-            os.path.join(
-                self.get_prod_path(),
-                self.conclusion +
-                '.html'),
-            "r")
-        conclu_contenu = conclu.read()
-        conclu.close()
+        if self.on_line():
+            conclu = open(
+                os.path.join(
+                    self.get_prod_path(),
+                    self.conclusion +
+                    '.html'),
+                "r")
+            conclu_contenu = conclu.read()
+            conclu.close()
 
-        return conclu_contenu.decode('utf-8')
+            return conclu_contenu.decode('utf-8')
 
     def save(self, *args, **kwargs):
         self.slug = slugify(self.title)
diff --git a/zds/tutorial/tests.py b/zds/tutorial/tests.py
index b54efefd4..b8894412c 100644
--- a/zds/tutorial/tests.py
+++ b/zds/tutorial/tests.py
@@ -6,7 +6,7 @@ import HTMLParser
 from django.conf import settings
 from django.core import mail
 from django.core.urlresolvers import reverse
-from django.test import TestCase
+from django.test import TestCase, RequestFactory
 from django.test.utils import override_settings
 from django.utils import html
 
@@ -20,7 +20,6 @@ from zds.gallery.factories import GalleryFactory
 from zds.tutorial.models import Note, Tutorial, Validation, Extract, Part, Chapter
 from zds.utils.models import SubCategory, Licence, Alert
 from zds.utils.misc import compute_hash
-
 @override_settings(MEDIA_ROOT=os.path.join(SITE_ROOT, 'media-test'))
 @override_settings(REPO_PATH=os.path.join(SITE_ROOT, 'tutoriels-private-test'))
 @override_settings(
@@ -1004,6 +1003,21 @@ class BigTutorialTests(TestCase):
                 'source': 'http://zestedesavoir.com',
             },
             follow=False)
+            
+        # then active the beta on tutorial :
+        sha_draft = Tutorial.objects.get(pk=tuto.pk).sha_draft
+        response = self.client.post(
+                reverse('zds.tutorial.views.modify_tutorial'),
+                {
+                    'tutorial': tuto.pk,
+                    'activ_beta': True,
+                    'version': sha_draft
+                },
+                follow=False
+        )
+        self.assertEqual(302, response.status_code)
+        sha_beta = Tutorial.objects.get(pk=tuto.pk).sha_beta
+        self.assertEqual(sha_draft, sha_beta)
 
         #delete part 1
         result = self.client.post(
@@ -1023,6 +1037,81 @@ class BigTutorialTests(TestCase):
             follow=True)
         self.assertEqual(Chapter.objects.filter(part__tutorial=tuto.pk).count(), 2)
         self.assertEqual(Part.objects.filter(tutorial=tuto.pk).count(), 2)
+
+        #check view delete part and chapter (draft version)
+        result = self.client.get(
+            reverse(
+                'zds.tutorial.views.view_part',
+                args=[
+                    tuto.pk,
+                    tuto.slug,
+                    p1.pk,
+                    p1.slug]),
+            follow=True)
+        self.assertEqual(result.status_code, 404)
+
+        result = self.client.get(
+            reverse(
+                'zds.tutorial.views.view_chapter',
+                args=[
+                    tuto.pk,
+                    tuto.slug,
+                    p2.pk,
+                    p2.slug,
+                    c3.pk,
+                    c3.slug]),
+            follow=True)
+        self.assertEqual(result.status_code, 404)
+
+        #deleted part and section HAVE TO be accessible on beta (get 200)
+        result = self.client.get(
+            reverse(
+                'zds.tutorial.views.view_part',
+                args=[
+                    tuto.pk,
+                    tuto.slug,
+                    p1.pk,
+                    p1.slug]) + '?version={}'.format(sha_beta),
+            follow=True)
+        self.assertEqual(result.status_code, 200)
+
+        result = self.client.get(
+            reverse(
+                'zds.tutorial.views.view_chapter',
+                args=[
+                    tuto.pk,
+                    tuto.slug,
+                    p2.pk,
+                    p2.slug,
+                    c3.pk,
+                    c3.slug]) + '?version={}'.format(sha_beta),
+            follow=True)
+        self.assertEqual(result.status_code, 200)
+
+        #deleted part and section HAVE TO be accessible online (get 200)
+        result = self.client.get(
+            reverse(
+                'zds.tutorial.views.view_part_online',
+                args=[
+                    tuto.pk,
+                    tuto.slug,
+                    p1.pk,
+                    p1.slug]),
+            follow=True)
+        self.assertEqual(result.status_code, 200)
+
+        result = self.client.get(
+            reverse(
+                'zds.tutorial.views.view_chapter_online',
+                args=[
+                    tuto.pk,
+                    tuto.slug,
+                    p2.pk,
+                    p2.slug,
+                    c3.pk,
+                    c3.slug]),
+            follow=True)
+        self.assertEqual(result.status_code, 200)
         
         # ask public tutorial
         tuto = Tutorial.objects.get(pk=tuto.pk)
@@ -1055,7 +1144,7 @@ class BigTutorialTests(TestCase):
                 'source': 'http://zestedesavoir.com',
             },
             follow=False)
-        #check view online delete part and chapter
+        #check view delete part and chapter (draft version, get 404)
         result = self.client.get(
             reverse(
                 'zds.tutorial.views.view_part',
@@ -1080,6 +1169,56 @@ class BigTutorialTests(TestCase):
             follow=True)
         self.assertEqual(result.status_code, 404)
 
+        #deleted part and section no longer accessible online (get 404)
+        result = self.client.get(
+            reverse(
+                'zds.tutorial.views.view_part_online',
+                args=[
+                    tuto.pk,
+                    tuto.slug,
+                    p1.pk,
+                    p1.slug]),
+            follow=True)
+        self.assertEqual(result.status_code, 404)
+
+        result = self.client.get(
+            reverse(
+                'zds.tutorial.views.view_chapter_online',
+                args=[
+                    tuto.pk,
+                    tuto.slug,
+                    p2.pk,
+                    p2.slug,
+                    c3.pk,
+                    c3.slug]),
+            follow=True)
+        self.assertEqual(result.status_code, 404)
+
+        #deleted part and section still accessible on beta (get 200)
+        result = self.client.get(
+            reverse(
+                'zds.tutorial.views.view_part',
+                args=[
+                    tuto.pk,
+                    tuto.slug,
+                    p1.pk,
+                    p1.slug]) + '?version={}'.format(sha_beta),
+            follow=True)
+        self.assertEqual(result.status_code, 200)
+
+        result = self.client.get(
+            reverse(
+                'zds.tutorial.views.view_chapter',
+                args=[
+                    tuto.pk,
+                    tuto.slug,
+                    p2.pk,
+                    p2.slug,
+                    c3.pk,
+                    c3.slug]) + '?version={}'.format(sha_beta),
+            follow=True)
+        self.assertEqual(result.status_code, 200)
+
     def test_conflict_does_not_destroy(self):
         """tests that simultaneous edition does not conflict"""
         sub = SubCategory()
@@ -1548,12 +1687,32 @@ class BigTutorialTests(TestCase):
 
         # logout before
         self.client.logout()
-        # first, login with author :
+
+        # check if acess to page with beta tutorial (with guest)
+        response = self.client.get(
+                reverse(
+                    'zds.tutorial.views.find_tuto', 
+                    args=[self.user_author.pk]
+                ) + '?type=beta'
+        )
+        self.assertEqual(200, response.status_code)
+
+        # then, login with author :
         self.assertEqual(
             self.client.login(
                 username=self.user_author.username,
                 password='hostel77'),
             True)
+
+        # check if acess to page with beta tutorial (with author)
+        response = self.client.get(
+                reverse(
+                    'zds.tutorial.views.find_tuto', 
+                    args=[self.user_author.pk]
+                ) + '?type=beta'
+        )
+        self.assertEqual(200, response.status_code)
+        
         # then active the beta on tutorial :
         sha_draft = Tutorial.objects.get(pk=self.bigtuto.pk).sha_draft
         response = self.client.post(
@@ -1566,6 +1725,15 @@ class BigTutorialTests(TestCase):
                 follow=False
         )
         self.assertEqual(302, response.status_code)
+
+        # check if acess to page with beta tutorial (with author)
+        response = self.client.get(
+                reverse(
+                    'zds.tutorial.views.find_tuto', 
+                    args=[self.user_author.pk]
+                ) + '?type=beta'
+        )
+        self.assertEqual(200, response.status_code)
         # test beta :
         self.assertEqual(
             Tutorial.objects.get(pk=self.bigtuto.pk).sha_beta, 
@@ -1581,12 +1749,28 @@ class BigTutorialTests(TestCase):
         self.assertEqual(
             self.client.get(url).status_code,
             302)
-        # test access for random user (get 200)
+        # check if acess to page with beta tutorial (with guest, get 200)
+        response = self.client.get(
+                reverse(
+                    'zds.tutorial.views.find_tuto', 
+                    args=[self.user_author.pk]
+                ) + '?type=beta'
+        )
+        self.assertEqual(200, response.status_code)
+        # test tutorial acess for random user
         self.assertEqual(
             self.client.login(
                 username=self.user.username,
                 password='hostel77'),
             True)
+        # check if acess to page with beta tutorial (with random user, get 200)
+        response = self.client.get(
+                reverse(
+                    'zds.tutorial.views.find_tuto', 
+                    args=[self.user_author.pk]
+                ) + '?type=beta'
+        )
+        # test access (get 200)
         self.assertEqual(
             self.client.get(url).status_code,
             200)
@@ -2498,6 +2682,16 @@ class MiniTutorialTests(TestCase):
 
         # logout before
         self.client.logout()
+
+        # check if acess to page with beta tutorial (with guest)
+        response = self.client.get(
+                reverse(
+                    'zds.tutorial.views.find_tuto', 
+                    args=[self.user_author.pk]
+                ) + '?type=beta'
+        )
+        self.assertEqual(200, response.status_code)
+
         # first, login with author :
         self.assertEqual(
             self.client.login(
@@ -2516,6 +2710,15 @@ class MiniTutorialTests(TestCase):
                 follow=False
         )
         self.assertEqual(302, response.status_code)
+
+        # check if acess to page with beta tutorial (with author)
+        response = self.client.get(
+                reverse(
+                    'zds.tutorial.views.find_tuto', 
+                    args=[self.user_author.pk]
+                ) + '?type=beta'
+        )
+        self.assertEqual(200, response.status_code)
         # test beta :
         self.assertEqual(
             Tutorial.objects.get(pk=self.minituto.pk).sha_beta, 
@@ -2540,6 +2743,15 @@ class MiniTutorialTests(TestCase):
         self.assertEqual(
             self.client.get(url).status_code,
             200)
+
+        # check if acess to page with beta tutorial (with random user)
+        response = self.client.get(
+                reverse(
+                    'zds.tutorial.views.find_tuto', 
+                    args=[self.user_author.pk]
+                ) + '?type=beta'
+        )
+        self.assertEqual(200, response.status_code)
         
         # then modify tutorial
         self.assertEqual(
diff --git a/zds/tutorial/views.py b/zds/tutorial/views.py
index db783eb45..9eb628633 100644
--- a/zds/tutorial/views.py
+++ b/zds/tutorial/views.py
@@ -93,7 +93,7 @@ def index(request):
     tuto_versions = []
     for tutorial in tutorials:
         mandata = tutorial.load_json_for_public()
-        mandata = tutorial.load_dic(mandata)
+        tutorial.load_dic(mandata)
         tuto_versions.append(mandata)
     return render_template("tutorial/index.html", {"tutorials": tuto_versions, "tag": tag})
 
@@ -666,14 +666,19 @@ def view_tutorial(request, tutorial_pk, tutorial_slug):
 
     manifest = get_blob(repo.commit(sha).tree, "manifest.json")
     mandata = json_reader.loads(manifest)
+    tutorial.load_dic(mandata, sha)
+    tutorial.load_introduction_and_conclusion(mandata, sha)
+    
+    #print mandata
 
     # If it's a small tutorial, fetch its chapter
 
     if tutorial.type == "MINI":
-        if "chapter" in mandata:
+        if 'chapter' in mandata:
             chapter = mandata["chapter"]
             chapter["path"] = tutorial.get_path()
             chapter["type"] = "MINI"
+            chapter["pk"] = Chapter.objects.get(tutorial=tutorial).pk
             chapter["intro"] = get_blob(repo.commit(sha).tree,
                                         "introduction.md")
             chapter["conclu"] = get_blob(repo.commit(sha).tree, "conclusion.md"
@@ -724,7 +729,7 @@ def view_tutorial(request, tutorial_pk, tutorial_slug):
         formValid = ValidForm()
     formReject = RejectForm()
     return render_template("tutorial/tutorial/view.html", {
-        "tutorial": tutorial,
+        "tutorial": mandata,
         "chapter": chapter,
         "parts": parts,
         "version": sha,
@@ -753,7 +758,8 @@ def view_tutorial_online(request, tutorial_pk, tutorial_slug):
     # find the good manifest file
 
     mandata = tutorial.load_json_for_public()
-    mandata = tutorial.load_dic(mandata)
+    tutorial.load_dic(mandata, sha=tutorial.sha_public)
+    tutorial.load_introduction_and_conclusion(mandata, public=True)
     mandata["update"] = tutorial.update
     mandata["get_note_count"] = tutorial.get_note_count()
 
@@ -1166,7 +1172,7 @@ def view_part_online(
     # find the good manifest file
 
     mandata = tutorial.load_json_for_public()
-    mandata = tutorial.load_dic(mandata)
+    tutorial.load_dic(mandata, sha=tutorial.sha_public)
     mandata["update"] = tutorial.update
 
     mandata["get_parts"] = mandata["parts"]
@@ -1518,7 +1524,7 @@ def view_chapter_online(
     # find the good manifest file
 
     mandata = tutorial.load_json_for_public()
-    mandata = tutorial.load_dic(mandata)
+    tutorial.load_dic(mandata, sha=tutorial.sha_public)
     mandata["update"] = tutorial.update
 
     mandata['get_parts'] = mandata["parts"]
@@ -2097,7 +2103,7 @@ def find_tuto(request, pk_user):
         tuto_versions = []
         for tutorial in tutorials:
             mandata = tutorial.load_json_for_public(sha=tutorial.sha_beta)
-            mandata = tutorial.load_dic(mandata)
+            tutorial.load_dic(mandata, sha=tutorial.sha_beta)
             tuto_versions.append(mandata)
 
         return render_template("tutorial/member/beta.html",
@@ -2110,7 +2116,7 @@ def find_tuto(request, pk_user):
         tuto_versions = []
         for tutorial in tutorials:
             mandata = tutorial.load_json_for_public()
-            mandata = tutorial.load_dic(mandata)
+            tutorial.load_dic(mandata)
             tuto_versions.append(mandata)
 
         return render_template("tutorial/member/online.html", {"tutorials": tuto_versions,
['zds/pages/views.py', 'zds/tutorial/tests.py', 'zds/tutorial/models.py', 'zds/tutorial/views.py', 'templates/tutorial/chapter/view.html', 'zds/member/views.py', 'templates/tutorial/tutorial/view.html']