diff --git a/shiny_tutorial.Rmd b/shiny_tutorial.Rmd
index fdb4ff8c673d9435aa1a720429a238d2e0aee481..bae35dfa5c8bfc4f31419aa1f60028faf24d0bd9 100644
--- a/shiny_tutorial.Rmd
+++ b/shiny_tutorial.Rmd
@@ -24,6 +24,8 @@ library(learnr)
 
 ## Introduction
 
+### Iris dataset
+
 Pour le tutoriel, nous allons utiliser un jeu de données intégré à R, nommé Iris. Il recense les tailles de pétales et de sépales pour un ensemble d'individus "iris" de trois espèces différentes, setosa, versicolor et virginica.
 
 Exécuter le code suivant, bouton `Run code`, pour afficher les premières lignes du jeu de données:
@@ -32,16 +34,34 @@ Exécuter le code suivant, bouton `Run code`, pour afficher les premières ligne
 head(iris)
 ```
 
+## Développer une application Shiny
+
+### Créer une application Shiny
+
+Créer un répertoire pour l’application avec **RStudio**.
 
-## Base d'une application Shiny
+```bash
+File -> New Project -> New Directory -> Shiny Web Application
+```
+
+Choisir une application **Multiple File**.
 
-La base de notre application Shiny de départ est comprise dans deux fichiers obligatoires au fonctionnement d'une application Shiny, `ui.R` et `server.R`.
+Si cette option n’est pas disponible (ça peut dépendre des versions de Rstudio), on pourra utiliser
 
+```bash
+File -> New File -> Shiny Web App -> Multiple File
+```
+
+Deux fichier sont automatiquement générés : `ui.R` et `server.R`. Lancer l’application en cliquant sur le bouton `Run App`.
+
+  * Changer le titre de l’application. On pourra l’appeler My first application.
+  * Mettre à jour et vérifier que le titre a bien été changé.
+    
 ### ui.R
 
-Voici un exemple de `ui.R` que nous allons utiliser.
+Voici un exemple de `ui.R` que nous allons utiliser. Lancer le code avec le bouton `Run code` pour voir le rendu.
 
-```{r ui_R, exercise=TRUE}
+```{r ui_R, exercise=TRUE, exercise.lines=20, eval=FALSE}
 # k-means only works with numerical variables,
 # so don't give the user the option to select
 # a categorical variable
@@ -80,103 +100,498 @@ Il s'agit maintenant de remplir le fichier server.R pour obtenir des résultats
 
 Créer une reactive avec reactive({}) pour générer un tableau dynamique récupérant les 2 colonnes correspondant aux variables X et Y sélectionnées par l’utilisateur sur les données iris et ranger ce tableau dans une variable « selectedData »
 
-```{r server_R_selected_data, exercise=TRUE}
-function(input, output, session) {
+```{r server_R_selected_data, exercise=TRUE, exercise.warn_invisible=TRUE}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
 
-}
+# }
+```
+
+```{r server_R_selected_data-hint-1}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+
+  # Combine the selected variables into a new data frame
+  selectedData <- reactive({...})
+
+# }
+```
+
+```{r server_R_selected_data-hint-2}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+
+  # Combine the selected variables into a new data frame
+  selectedData <- reactive({
+    iris[, ... ]
+})
+
+# }
+```
+
+```{r server_R_selected_data-hint-3}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+
+  # Combine the selected variables into a new data frame
+  selectedData <- reactive({
+    iris[, c(input$xcol, input$ycol)]
+})
+
+# }
 ```
 
 ```{r server_R_selected_data-solution}
-function(input, output, session) {
-  
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+
   # Combine the selected variables into a new data frame
   selectedData <- reactive({
     iris[, c(input$xcol, input$ycol)]
   })
-}
+
+# }
 ```
 
-### Générer le clustering k-means dasn une fonction reactive({})
+### Solution
 
-Créer une reactive avec reactive({}) pour générer un cluster sur le tableau dynamique précédent, utilisant la variable « Cluster count » comme nombre de clusters à créer et ranger ce résultat dans une variable « clusters ». Utiliser la fonction kmeans() pour générer ces clusters.
+Et voilà ce que contient `selectedData`:
 
-```{r server_R_clusters, exercise=TRUE}
-function(input, output, session) {
+```{r server_R_selected_data-display, echo=FALSE}
+vars <- setdiff(names(iris), "Species")
 
-}
+pageWithSidebar(
+  headerPanel('Iris: select data'),
+  sidebarPanel(
+    selectInput('xcol_sd', 'X Variable', vars),
+    selectInput('ycol_sd', 'Y Variable', vars, selected = vars[[2]]),
+    numericInput('clusters_sd', 'Cluster count', 3, min = 1, max = 9)
+  ),
+  mainPanel(
+    tabsetPanel(type = "tabs",
+                tabPanel("Selected data", DT::dataTableOutput("sd_selectedData"))
+    )
+  )
+)
 ```
 
-```{r server_R_clusters-solution}
-function(input, output, session) {
-  
+```{r server_R_selected_data-print, echo=TRUE, context = "server"}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+
   # Combine the selected variables into a new data frame
   selectedData <- reactive({
-    iris[, c(input$xcol, input$ycol)]
+    iris[, c(input$xcol_sd, input$ycol_sd)]
   })
+
+  output$sd_selectedData <- DT::renderDataTable(
+    DT::datatable(
+      selectedData(),
+      options = list(
+        dom = 'Bfrtip',
+        lengthMenu = list(c(5, 15, -1), c('5', '15', 'All')),
+        pageLength = 15,
+        buttons = list(
+            list(
+              extend = "collection",
+              text = 'Show All',
+              action = DT::JS("function ( e, dt, node, config ) {
+                                    dt.page.len(-1);
+                                    dt.ajax.reload();
+                                }")
+            )
+          )
+        )
+    )
+  )
   
-  clusters <- reactive({
-    kmeans(selectedData(), input$clusters)
-  })
-}
+# }
 ```
 
-### Générer le plot dynamique du clustering kmeans  
+### Générer un tableau des données sélectionnées pour le graphique
 
-Générer un graphique dynamique avec renderPlot{()} représentant le tableau dynamique avec la fonction plot() et colorer les points selon le cluster auquel ils appartiennent avec le paramètre « col ». Pour récupérer les clusters depuis la variable « clusters », utiliser clusters()\$cluster. Ranger le résultat dans output\$plot1 et le représenter côté UI dans le tabPanel « Plot ».
+Afficher le tableau dynamique avec renderTable{()} représentant le tableau utilisé pour générer le graphique et ranger le résultat dans output$table. Représenter cette table côté UI dans le tabPanel « Table ».  
 
-```{r server_R_render_plot, exercise=TRUE}
-function(input, output, session) {
+```{r server_R_render_table, exercise=TRUE, context = "server", exercise.warn_invisible=TRUE}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
 
-}
+# }
 ```
 
-```{r server_R_render_plot-solution}
-function(input, output, session) {
-  
-  # Combine the selected variables into a new data frame
-  selectedData <- reactive({
-    iris[, c(input$xcol, input$ycol)]
+```{r server_R_render_table-hint-1}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+
+  output$table <- renderTable({...})
+
+# }
+```
+
+```{r server_R_render_table-hint-2}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+
+  output$table <- renderTable({
+    selectedData()
   })
+
+# }
+```
+
+```{r server_R_render_table-solution}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
   
-  clusters <- reactive({
-    kmeans(selectedData(), input$clusters)
+  output$table <- renderTable({
+    selectedData()
   })
-  
-  output$plot1 <- renderPlot({
-    palette(c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3",
-              "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999"))
-    
-    par(mar = c(5.1, 4.1, 0, 1))
-    plot(selectedData(),
-         col = clusters()$cluster,
-         pch = 20, cex = 3)
-    points(clusters()$centers, pch = 4, cex = 4, lwd = 4)
+
+# }
+```
+
+### Solution
+
+Et voilà ce que contient `output$table`:
+
+```{r server_R_render_table-display, echo=FALSE}
+vars <- setdiff(names(iris), "Species")
+
+pageWithSidebar(
+  headerPanel('Iris: print selected data table'),
+  sidebarPanel(
+    selectInput('xcol_tbl', 'X Variable', vars),
+    selectInput('ycol_tbl', 'Y Variable', vars, selected = vars[[2]]),
+    numericInput('clusters_tbl', 'Cluster count', 3, min = 1, max = 9)
+  ),
+  mainPanel(
+    tabsetPanel(type = "tabs",
+                  tabPanel("Table", DT::dataTableOutput("tbl_selectedData"))
+    )
+  )
+)
+```
+
+```{r server_R_render_table-print, context = "server"}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+
+  # Combine the selected variables into a new data frame
+  tblselectedData <- reactive({
+    iris[, c(input$xcol_tbl, input$ycol_tbl)]
   })
-}
+
+  output$tbl_selectedData <- DT::renderDataTable(
+    DT::datatable(
+      tblselectedData(),
+      options = list(
+        dom = 'Bfrtip',
+        lengthMenu = list(c(5, 15, -1), c('5', '15', 'All')),
+        pageLength = 15,
+        buttons = list(
+            list(
+              extend = "collection",
+              text = 'Show All',
+              action = DT::JS("function ( e, dt, node, config ) {
+                                    dt.page.len(-1);
+                                    dt.ajax.reload();
+                                }")
+            )
+          )
+        )
+    )
+  )
+
+# }
 ```
 
 ### Générer un résumé statistique du tableau dynamique
 
 Générer un texte dynamique avec renderPrint({}) représentant un résumé statistique du tableau dynamique généré précédemment avec la fonction summary() et ranger le résultat dans output$summary, puis le représenter côté UI dans le tabPanel « Summary ».
 
-```{r server_R_render_print, exercise=TRUE}
-function(input, output, session) {
+```{r server_R_render_print, exercise=TRUE, context = "server", exercise.warn_invisible=TRUE}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
 
-}
+# }
+```
+
+```{r server_R_render_print-hint-1}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+
+  # Generate a summary of the data ----
+  output$summary <- renderPrint({...})
+
+# }
+```
+
+```{r server_R_render_print-hint-2}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+
+  # Generate a summary of the data ----
+  output$summary <- renderPrint({
+    summary(...)
+  })
+
+# }
+```
+
+```{r server_R_render_print-hint-3}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+
+  # Generate a summary of the data ----
+  output$summary <- renderPrint({
+    summary(selectedData())
+  })
+
+# }
 ```
 
 ```{r server_R_render_print-solution}
-function(input, output, session) {
+# function(input, output, session) {
+# ajouter votre code ci-dessous
   
+  # Generate a summary of the data ----
+  output$summary <- renderPrint({
+    summary(selectedData())
+  })
+  
+# }
+```
+
+### Solution
+
+Et voilà ce que contient `output$summary`:
+
+```{r server_R_render_print-display, echo=FALSE}
+vars <- setdiff(names(iris), "Species")
+
+pageWithSidebar(
+  headerPanel('Iris k-means clustering'),
+  sidebarPanel(
+    selectInput('xcol_smry', 'X Variable', vars),
+    selectInput('ycol_smry', 'Y Variable', vars, selected = vars[[2]]),
+    numericInput('clusters_smry', 'Cluster count', 3, min = 1, max = 9)
+  ),
+  mainPanel(
+    tabsetPanel(type = "tabs",
+                  tabPanel("Summary", verbatimTextOutput("print_summary"))
+    )
+  )
+)
+```
+
+```{r server_R_render_print-print, context = "server"}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+
   # Combine the selected variables into a new data frame
-  selectedData <- reactive({
-    iris[, c(input$xcol, input$ycol)]
+  smryselectedData <- reactive({
+    iris[, c(input$xcol_smry, input$ycol_smry)]
+  })
+
+  smryclusters <- reactive({
+    kmeans(smryselectedData(), input$clusters_smry)
+  })
+
+  output$print_summary <- renderPrint({
+    summary(smryselectedData())
   })
   
+# }
+```
+
+### Générer le clustering k-means dans une fonction reactive({})
+
+Créer une reactive avec reactive({}) pour générer un cluster sur le tableau dynamique précédent, utilisant la variable « Cluster count » comme nombre de clusters à créer et ranger ce résultat dans une variable « clusters ». Utiliser la fonction kmeans() pour générer ces clusters.
+
+```{r server_R_clusters, exercise=TRUE, exercise.warn_invisible=TRUE}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+
+# }
+```
+
+```{r server_R_clusters-hint-1}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+
+  clusters <- reactive({...})
+
+# }
+```
+
+```{r server_R_clusters-hint-2}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+
+  clusters <- reactive({
+    kmeans(...)
+  })
+
+# }
+```
+
+```{r server_R_clusters-hint-3}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+  
   clusters <- reactive({
     kmeans(selectedData(), input$clusters)
   })
+
+# }
+```
+
+```{r server_R_clusters-solution}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
   
+  clusters <- reactive({
+    kmeans(selectedData(), input$clusters)
+  })
+
+# }
+```
+
+### Solution
+
+Et voilà ce que contient `clusters`:
+
+```{r server_R_clusters-display, echo=FALSE}
+vars <- setdiff(names(iris), "Species")
+
+pageWithSidebar(
+  headerPanel('Iris print k-means clustering results'),
+  sidebarPanel(
+    selectInput('xcol_km', 'X Variable', vars),
+    selectInput('ycol_km', 'Y Variable', vars, selected = vars[[2]]),
+    numericInput('clusters_km', 'Cluster count', 3, min = 1, max = 9)
+  ),
+  mainPanel(
+    tabsetPanel(type = "tabs",
+                  tabPanel("K-means clusters", verbatimTextOutput("km_clusters"))
+    )
+  )
+)
+```
+
+```{r server_R_clusters-print, context = "server"}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+
+  # Combine the selected variables into a new data frame
+  kmselectedData <- reactive({
+    iris[, c(input$xcol_km, input$ycol_km)]
+  })
+
+  kmclusters <- reactive({
+    kmeans(kmselectedData(), input$clusters_km)
+  })
+
+  output$km_clusters <- renderPrint({
+    kmclusters()
+  })
+  
+# }
+```
+
+### Générer le plot dynamique du clustering kmeans  
+
+Générer un graphique dynamique avec renderPlot{()} représentant le tableau dynamique avec la fonction plot() et colorer les points selon le cluster auquel ils appartiennent avec le paramètre « col ». Pour récupérer les clusters depuis la variable « clusters », utiliser clusters()\$cluster. Ranger le résultat dans output\$plot1 et le représenter côté UI dans le tabPanel « Plot ».
+
+```{r server_R_render_plot, exercise=TRUE, exercise.warn_invisible=TRUE}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+
+# }
+```
+
+```{r server_R_render_plot-hint-1}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+
+  output$plot1 <- renderPlot({...})
+
+# }
+```
+
+```{r server_R_render_plot-hint-2}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+
+  output$plot1 <- renderPlot({
+    # create a 9 colors palette
+    palette(...)
+    
+  })
+
+# }
+```
+
+```{r server_R_render_plot-hint-3}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+
+  output$plot1 <- renderPlot({
+    # create a 9 colors palette
+    palette(...)
+    
+    # define margins: replace *_margin placeholders by real values
+    par(mar = c(bottom_margin, left_margin, top_margin, right_margin))
+  })
+
+# }
+```
+
+```{r server_R_render_plot-hint-4}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+
+  output$plot1 <- renderPlot({
+    # create a 9 colors palette
+    palette(...)
+    
+    # define margins: replace *_margin placeholders by real values
+    par(mar = c(bottom_margin, left_margin, top_margin, right_margin))
+    
+    # create the plot
+    plot(selectedData(),
+         ...)
+    
+  })
+
+# }
+```
+
+```{r server_R_render_plot-hint-5}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+
+  output$plot1 <- renderPlot({
+    # create a 9 colors palette
+    palette(...)
+    
+    # define margins: replace *_margin placeholders by real values
+    par(mar = c(bottom_margin, left_margin, top_margin, right_margin))
+    
+    # create the plot: set the points color, shape, etc.
+    plot(selectedData(),
+         ...)
+    # add the cluster centers: set the points color, shape, etc. 
+    points(clusters()$centers, ...)
+  })
+
+# }
+```
+
+```{r server_R_render_plot-hint-6}
+# function(input, output, session) {
+# full solution
+
   output$plot1 <- renderPlot({
     palette(c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3",
               "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999"))
@@ -188,55 +603,79 @@ function(input, output, session) {
     points(clusters()$centers, pch = 4, cex = 4, lwd = 4)
   })
 
-  # Generate a summary of the data ----
-  output$summary <- renderPrint({
-    summary(selectedData())
+# }
+```
+
+```{r server_R_render_plot-solution, context="server"}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+  
+  output$plot1 <- renderPlot({
+    palette(c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3",
+              "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999"))
+    
+    par(mar = c(5.1, 4.1, 0, 1))
+    plot(selectedData(),
+         col = clusters()$cluster,
+         pch = 20, cex = 3)
+    points(clusters()$centers, pch = 4, cex = 4, lwd = 4)
   })
-}
+
+# }
 ```
 
-### Générer un tableau des données sélectionnées pour le graphique
+### Solution
 
-Afficher le tableau dynamique avec renderTable{()} représentant le tableau utilisé pour générer le graphique et ranger le résultat dans output$table. Représenter cette table côté UI dans le tabPanel « Table ».  
+Et voilà ce que contient `output$plot1`:
 
-```{r server_R_render_table, exercise=TRUE}
-function(input, output, session) {
+```{r server_R_render_plot-display, echo=FALSE}
+vars <- setdiff(names(iris), "Species")
 
-}
+pageWithSidebar(
+  headerPanel('Iris plot k-means clustering results'),
+  sidebarPanel(
+    selectInput('xcol_plot', 'X Variable', vars),
+    selectInput('ycol_plot', 'Y Variable', vars, selected = vars[[2]]),
+    numericInput('clusters_plot', 'Cluster count', 3, min = 1, max = 9)
+  ),
+  mainPanel(
+    tabsetPanel(type = "tabs",
+                  tabPanel("K-means clusters plot", plotOutput("km_plot")),
+                tabPanel("K-means clusters", verbatimTextOutput("print_clusters"))
+    )
+  )
+)
 ```
 
-```{r server_R_render_table-solution}
-function(input, output, session) {
-  
+```{r server_R_render_plot-print, context = "server"}
+# function(input, output, session) {
+# ajouter votre code ci-dessous
+
   # Combine the selected variables into a new data frame
-  selectedData <- reactive({
-    iris[, c(input$xcol, input$ycol)]
+  plotselectedData <- reactive({
+    iris[, c(input$xcol_plot, input$ycol_plot)]
   })
-  
-  clusters <- reactive({
-    kmeans(selectedData(), input$clusters)
+
+  plotclusters <- reactive({
+    kmeans(plotselectedData(), input$clusters_plot)
+  })
+
+  output$print_clusters <- renderPrint({
+    plotclusters()
   })
   
-  output$plot1 <- renderPlot({
+  output$km_plot <- renderPlot({
     palette(c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3",
               "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999"))
     
     par(mar = c(5.1, 4.1, 0, 1))
     plot(selectedData(),
-         col = clusters()$cluster,
+         col = plotclusters()$cluster,
          pch = 20, cex = 3)
-    points(clusters()$centers, pch = 4, cex = 4, lwd = 4)
-  })
-
-  # Generate a summary of the data ----
-  output$summary <- renderPrint({
-    summary(selectedData())
+    points(plotclusters()$centers, pch = 4, cex = 4, lwd = 4)
   })
   
-  output$table <- renderTable({
-    selectedData()
-  })
-}
+# }
 ```
 
 ## Application Shiny complète
@@ -251,7 +690,7 @@ shiny::runApp(".")
 
 ### L'application shiny en démo live  
 
-Si vous avez exécuter la commande ``shiny::runApp(".")`` dans la console, vous pouvez voir l'application en démo live ci-dessous.
+Si vous avez exécuter la commande `shiny::runApp(".")` dans la console, vous pouvez voir l'application en démo live ci-dessous.
 
 ```{r shiny_run_app_demo, echo=FALSE}
 # k-means only works with numerical variables,
@@ -268,7 +707,7 @@ pageWithSidebar(
   ),
   mainPanel(
     tabsetPanel(type = "tabs",
-                tabPanel("Plot", plotOutput('plot1')),
+                tabPanel("K-means clusters plot", plotOutput('plot1')),
                 tabPanel("Summary", verbatimTextOutput("summary")),
                 tabPanel("Table", tableOutput("table"))
     )