Archives de catégorie : SharePoint Server

Comment configurer Google Analytics dans SharePoint sans avoir un domaine complet (FQDN) ?

Voici mon dernier vidéo publié sur le site Channel 9 :

Dans plusieurs déploiements SharePoint On-Premise, des URL comme ceux-ci sont utilisés :

Bon nombre d’articles indiquent qu’il n’est pas possible de configurer Google Analytics lorsque le URL ne contient pas un nom de domaine complètement qualifié (FQDN) :

Pour pouvoir générer des rapports dans Analytics aux fins de l’utilisation par votre intranet d’entreprise, votre réseau d’entreprise doit pouvoir accéder au fichier JavaScript de Analytics (analytics.js). Essayez de charger le fichier dans votre navigateur à l’aide de l’un des liens suivants :

Si vous pouvez accéder à l’une de ces URL à partir de votre réseau interne, vous pouvez utiliser Analytics pour collecter les données provenant de votre intranet. Ce dernier doit également être accessible via un nom de domaine complet tel que http://intranet.example.com. Le fichier JavaScript de Analytics ne fonctionnera pas si votre intranet est uniquement accessible à l’aide d’un nom de domaine incomplet, tel que http://intranet.

Source : https://support.google.com/analytics/answer/1009688?hl=fr

Malgré tout cela, je vous rassure c’est possible d’obtenir des statistiques malgré cette contrainte. Il suffit de « flouer » Google Analytics afin qu’il pense que notre URL est un FQDN lors de l’ajout d’une propriété.

Technologies utilisées

  • SharePoint 2016 On-Premise (Hébergé dans Azure)
  • SharePoint Designer 2013
  • Google Analytics

Meilleurs pratiques

À des fins de démonstration seulement, la page maître a été modifié directement. Sachez toutefois que la meilleure pratique consiste plutôt à effectuer l’injection JavaScript du script de suivi afin d’éviter d’avoir à maintenir une page maître personnalisé.

Si vous avez apprécié, je vous invite à commenter et à évaluer ce vidéo !

Publicités

Retour sur le SharePoint Saturday Québec 2016

Introduction

Le 1er octobre 2016 avait lieu a l’Université Laval l’événement SharePoint Saturday Québec. J’ai contribué à l’organisation de cet événement en plus d’y participer en tant que conférencier.

Ma session

Titre : [Étude de cas] L’intranet de la Ville de Québec

Track: Business

Dans le cadre de cette session, nous examinerons une étude de cas sur la façon dont un intranet continue de transformer une organisation municipale. Bien que réalisé il y a quelque années sous la plateforme SharePoint 2010 Server, plusieurs concepts peuvent être réutilisés de nos jours afin de contribuer à l’amélioration de l’engagement des employés, à la collaboration et aux échanges. Au cours de cette session, je présenterai différentes fonctionnalités de l’intranet, quelque statistiques d’utilisation, les enjeux, une démonstration et plus!

Si vous ne pouviez y être voici la présentation :
telecharger-bouton

 

Les autres sessions

Plusieurs autres conférenciers on présentés des sessions très intéressante et si vous ne pouviez pas y assister, la majorité de leur présentation est disponible sur le site du SharePoint Saturday Québec !

Pour ma part, j’ai particulièrement apprécié la présentation de Franck « [Retour d’expérience] Votre intranet Client-Side en SharePoint Online/O365 », dans laquel il a présenté une solution d’intranet très bien packagé avec les dernières technologies clientes.

Plusieurs photos sont disponible sur le blog de Sébastien.

Conclusion

Un succès pour la premiere édition de l’événement avec plein de goodies, un bon repas et des gens passionnés. Merci à tous les commanditaires, participants et au comité organisateurs.

Alternative à Silverlight pour afficher des vidéos dans SharePoint 2010

Introduction

Depuis un bon moment déjà, Chrome à cesser de supporter les plugins NPAPI. Ceci a pour effet que le composant WebPart multimédia qui utilise Silverlight dans SharePoint 2010 ne fonctionne plus dans Chrome. Puisqu’il fonctionne encore dans Internet Explorer, cela occasionne des comportements différents entre les navigateurs. Dans certaines entreprises, YouTube et Vimeo ne sont pas une option alors dans ce billet je vous propose une solution permettant l’affichage de vidéo autant dans Chrome que dans Internet Explorer.

Utilisation d’un lecteur vidéo qui imite celui de HTML 5

Le lecteur vidéo MediaElementJs permet d’afficher des vidéos dans un seul interface visuel dans tous les navigateurs avec uniquement du JavaScript/CSS.

Il utilise le HTML5 pour les navigateurs récents et Flash/SilverLight afin d’imiter les balises HTML5 pour les anciens navigateurs.

L’intégration du lecteur vidéo dans SharePoint est relativement simple via une WebPart éditeur de contenu. Référez-vous au site de MediaElementJs pour les balises à insérer.

Si jamais les boutons ne s’affiche pas dans le lecteur vidéo, il vous suffit d’ajouter un MIME dans IIS sur vos serveurs SharePoint :

MIME_SVG

  1. Ouvrir IIS Manager et sélectionner votre Application Web.
  2. Dans Features View, double cliquer sur MIME Types.
  3. Dans l’onglet Actions, cliquer sur Add.
  4. Dans la boîte de dialogue « Add MIME Type » inscrire « .svg » dans le champ « File name extension ».
  5. Inscrire « image/svg+xml » dans le champ « MIME type » .
  6. Cliquer sur  OK.Source : http://technet.microsoft.com/en-us/library/cc725608(v=ws.10).aspx

Résultat

Chrome (HTML 5 player):

mediaElementsChrome

Internet Explorer 8.0 (Flash Player) :

mediaElementIE8

Conclusion

Bien évidemment, il s’agit d’une solution de contournement pour SharePoint 2010 car déjà dans SharePoint 2013, le lecteur vidéo permet d’afficher des vidéos en HTML 5 puis dans SilverLight pour les anciens navigateurs.

Références

Mediaelementjs.com

Comparatif des lecteurs vidéo HTML 5

 

Microsoft Most Valuable Professional (MVP) pour 2016

J’ai été très heureux de recevoir ce courriel m’informant qu’on m’octroyait le titre de MVP dans la catégorie Office Servers and Services (Anciennement SharePoint Server). 

unnamed

Congratulations! We are pleased to present you with the 2016 Microsoft® MVP Award! This award is given to exceptional technical community leaders who actively share their high quality, real world expertise with others. We appreciate your outstanding contributions in Office Servers and Services technical communities during the past year.

C’est la première fois qu’on m’accorde ce titre alors je tiens à remercier Microsoft, mes collègues et amis de Victrix ainsi que la communauté SharePoint qui sont pour moi une source d’inspiration me permettant de m’améliorer.

Ce sera une année très intéressante avec les dernières annonces concernant Office 365 et SharePoint. Je me réjouis des défis et des opportunités qui en découleront.

Comparatif des différentes possibilités pour afficher des tableaux de bord dans SharePoint

Introduction

Il existe plusieurs façons d’afficher des tableaux de bord dans SharePoint. Cependant, les possibilités peuvent varier selon la version (2010/2013/2016) et le type de déploiement sur site (On Premise) ou dans SharePoint Online. Il est donc facile de passer plusieurs heures avant de se rendre compte que la solution envisagée n’est pas compatible avec la version en place. Dans ce billet, je vais mettre en évidence les différentes possibilités pour afficher des tableaux de bords (dashboard) puis fournir un comparatif par fonctionnalité et par version.

Power BI

PowerBI

Source : PowerBI

Il s’agit de l’offre BI de Microsoft en tant que service hébergé dans le cloud. Malgré que la solution repose dans le cloud, il est possible de s’alimenter de données sur site (On Premise) et il est possible d’incorporer un tableau de bord dans presque toute les plateformes Web. Microsoft investit beaucoup d’argent dans cette plateforme et pour cette raison, il y a des mises à jours régulièrement. Une communauté très active permet entre autre d’avoir accès à une galerie de visuels pour vos tableaux de bord.

Outils tiers

sales-dashboard_Collabion

Source : Collabion

Plusieurs outils tiers sont disponibles pour ajouter la possibilité d’afficher des tableaux de bord dans SharePoint. Les fonctionnalités sont différente selon le produit sélectionné. Par exemple : le nombre de visualisation disponible ou le nombre de connexion à des sources de données. Pour n’en nommer que quelque uns : Collabion, Bamboo et Kwizcom.

Solution personnalisé avec du code client

GoogleChart.PNG

Source : Google Charts

Le nombre de librairie client disponible pour afficher des tableaux de bord est grandissant. Une solution personnalisée peut ainsi facilement utiliser une de ces librairies afin d’afficher des tableaux de bord très intéressant via un Add-In ou une WebPart Éditeur de contenu. Pour n’en nommer que quelque unes : Google Charts, jqPlot Charts et Chartjs.

Solution personnalisé avec du code serveur

Telerik

 

Source : Telerik

Il existe aussi quelque librairies serveur pour afficher des tableaux de bord. On peut alors réaliser une solution personnalisée en utilisant une de ces librairies via une Visual WebPart et généralement un service Web. Pour n’en nommer que quelque unes : Telerik, ComponentOne et Crystal report.

 

SQL Reporting Services (SSRS)

ssrs

Source : SSRS

SSRS est un logiciel de génération de rapport serveur de Microsoft qui fait partit de la suite SQL Serveur. Un générateur de rapport peut permettre à quelqu’un qui n’est pas technique de réaliser des tableaux de bord. Autrement, des interfaces dans Visual Studio permettent de réaliser des rapports plus complexe. Il existe aussi des WebParts pour afficher les rapports directement dans une page SharePoint.

PerformancePoint

PerformancePoint

Source : cdhtalkstech.com

PerformancePoint est un outil de Microsoft disponible dans la version Entreprise de SharePoint 2010-2016 mais qui n’a pas vraiment évolué depuis la première version. Il est possible de créer des tableaux de bords à partir de quelque sources de données dont des cubes provenant de SSAS. Des WebParts spécifique à PerformancePoint sont aussi disponible pour un affichage directement dans SharePoint.

Excel BI / Power View

PowerView

Source : blogs.msdn.microsoft.com

Power View constitue une expérience d’exploration, de visualisation et de présentation interactives des données qui encourage la génération intuitive de rapports ad hoc. Power View est une fonctionnalité de Microsoft Excel 2013 et Microsoft SharePoint Server 2010 et 2013 disponible avec le complément SQL Server 2012 Service Pack 1 Reporting Services de Microsoft SharePoint Server Enterprise Edition.

PowerPivot

PowerPivot

Source : Youtube.com

PowerPivot est un complément pour Microsoft Excel 2010 qui vous permet d’importer des millions de lignes de données à partir de plusieurs sources de données dans un classeur Excel unique, de créer des relations entre les données hétérogènes, de créer des mesures et des colonnes calculées à l’aide de formules, de créer des tableaux croisés dynamiques et des graphiques croisés dynamiques, puis d’analyser ces données afin de pouvoir prendre des décisions opportunes sans nécessiter d’assistance informatique.

Visio Services dans SharePoint 2013

Visio.png

Source : Sharepointpromag.com

Visio Services permet aux utilisateurs de partager et d’afficher des diagrammes Visio dans SharePoint. Il permet également l’actualisation et la mise à jour des diagrammes Visio connectés à des données à l’aide de différentes sources de données. Visio Services s’exécute en tant qu’application de SharePoint Server 2013.

SharePoint 2010 Composant WebPart Graphique (Chart Web Part)

Pie ChartBar Chart

Source : Support.office.com

Le composant WebPart Graphique est un composant WebPart qui peut être créé et ajouté à un site SharePoint pour permettre aux utilisateurs d’afficher un tableau de bord. Cette WebPart n’a pas évolué depuis la version 2010 mais il est encore possible de l’utiliser dans SharePoint 2010-2016.

Comparatif des solutions par fonctionnalité

Visualisation personnalisée
Incorporer dans d’autres outils
Impression et exportation
Connexion à plusieurs source de données
Aucun codage requis
Power BI ~20 types Mark Mark ~ 60 sources Mark
Outils tiers ~1-50 types Mark Mark ~ 10 sources Mark
Solution personnalisé avec du code client warning-icon warning-icon
Solution personnalisé avec du code serveur warning-icon warning-icon
SQL Reporting Services (SSRS) 12 types Mark Mark ~10 sources warning-icon
PerformancePoint 8 types Mark  ~5 sources
Excel BI / Power View ~11 types Mark Mark 5 sources
PowerPivot ~10 types Mark Mark 4 sources Mark
Visio Services dans SharePoint 2013 Mark warning-icon 5 sources Mark
SharePoint 2010 Composant WebPart Graphique (Chart Web Part)  13 types ~3 sources Mark

 Mark Supporté

warning-icon Possible avec contournement

∞   Illimité

Comparatif des solutions par version

SP2010 SP2013 SP2016 SharePoint Online
Power BI Mark Mark Mark Mark
Outils tiers Mark Mark Mark Mark
Solution personnalisé avec du code client Mark Mark Mark Mark
Solution personnalisé avec du code serveur Mark Mark Mark warning-icon
SQL Reporting Services (SSRS) Mark Mark Mark
PerformancePoint Mark Mark Mark
Excel BI / Power View Mark Mark
PowerPivot Mark Mark Mark
Visio Services dans SharePoint 2013 Mark Mark Mark Mark
SharePoint 2010 Composant WebPart Graphique (Chart Web Part) Mark warning-icon warning-icon

Légende

 Mark Supporté

warning-icon Possible avec contournement

∞    Illimité

Conclusion

Les possibilités sont nombreuses pour afficher des tableaux de bord dans SharePoint. Certaines solutions n’ont pas évoluées depuis quelques versions ce qui en dit long concernant leur pérennité. Dans ce sens, je crois que PowerBI se démarque du lot au niveau des fonctionnalités et en second je considère que les outils tiers comme Collabion sont une bonne alternative au développement personnalisé.

Les solutions évoluent très rapidement alors si vous voyez des erreurs n’hésitez pas à m’en faire part et j’apporterai les ajustements.

Quelles solutions de tableau de bord utilisez-vous dans votre entreprise ?

Créer des filtres dynamiques sur vos List View WebPart avec du JS + KnockoutJS

Introduction

Jusqu’à tout récemment, j’utilisait une WebPart de filtre avec une connexion afin de filtrer l’année de publication des nouvelles :

Actualites

Cependant, ça ne fonctionne pas lorsqu’on utilise la pagination ET le filtre.  Le problème c’est que la pagination ajoute les paramètres de filtre directement dans le Querystring Ex : FilterField1=PublishedDateYear&FilterValue1=2016. Par la suite, même si on change de valeur via la WebPart de filtre, la valeur qui sera appliqué sera toujours celle du Querystring.

Je n’ai malheureusement pas trouvé de solution élégante à cette problématique alors j’ai plutôt opté pour une solution en JavaScript qui m’offre plus de flexibilité.

Une solution 100 % JS

Je me suis basé sur un article que j’ai trouvé sur le blog de Phil Harding et je l’ai adapté à mon besoin. Le résultat est très intéressant et nous allons voir en détail comment mettre le tout en place dans ce billet. Voici tout d’abord un bref aperçu :

ActualitesFiltreDynamique

Le code peut être exécuté autant dans SP2010 que SP2013 mais il y a quelque subtilité au niveau du code.

Intégration du code

La solution utilise une WebPart Éditeur de contenu pointant vers un fichier « txt » qui contient le balisage HTML. Ce fichier « txt » contient des références vers un fichier JS, CSS et au Framework Knockout JS v3.1.0.

La structure des fichiers est la suivante :

  • /Style Library/txt/script_actualites_filtre_html.txt (Gist)
  • /Style Library/css/app_filtre.css (Gist)
  • /Style Library/scripts/app_filtre.js (Gist)
  • /Style Library/scripts/knockout-3.1.0.js (Source)

La première étape consiste à copier vos fichiers dans votre dossier Style Library et à ajuster les références.

Ensuite, dans une page contenant une List View WebPart ajouter une WebPart Éditeur de contenu avec un lien vers le fichier : /Style Library/txt/script_actualites_filtre_html.txt.

Puis, adapter le fichier app_filtre.js (Voir les TODO dans le code) afin que vos filtres correspondent à vos colonnes et à votre liste.

app_filtre.js


(function(module,$j) {
"use strict";

window.pd = window.pd || {};

pd.MeetingsViewModel = function() {
   /* observable state */
   this.FilterTextIm = ko.observable('');
   this.FilterText = ko.computed(this.FilterTextIm)
                        .extend({ throttle: 400 });
   this.LibraryTitle = ko.observable('');
   this.LibrarySubTitle = ko.observable('');
   this.FilterYears = new ko.observableArray([]);
   this.FilterMonths = new ko.observableArray(['Janvier','Février','Mars','Avril','Mai','Juin','Juillet','Août','Septembre','Octobre','Novembre','Décembre']);
   this.SelectedYear = ko.observable('');
   this.SelectedMonth = ko.observable('');
   this.Working = ko.observable(true);

   /* populate years filter as Current Year..-=4 */
   for(var cy = parseInt(new Date().getFullYear()), y = cy; y > (cy-3); y--) { this.FilterYears.push(y.toString()); }

   /* model actions */
   this.filterByYear = function(year) {
      this.FilterTextIm('');   // zap the filter text
      year = (year === this.SelectedYear()) ? '' : year;
      this.SelectedYear(year);
   }.bind(this);
   this.filterByMonth = function(month) {
      this.FilterTextIm('');   // zap the filter text
      month = (month === this.SelectedMonth()) ? '' : month;
      this.SelectedMonth(month);
   }.bind(this);

   /* model behaviour */
   this.isSelectedYear = function (year) {
      var y = this.SelectedYear();
      return (y == year);
   }.bind(this);
   this.isSelectedMonth = function (month) {
      var m = this.SelectedMonth();
      return (m == month);
   }.bind(this);
}


pd.FilterLibraryApp = function() {
   var
      viewModel = new pd.MeetingsViewModel(),
      debug = true,
      wpCtx = null,
      wpEvent = null,
      
      filterControlId = null,
      listViewTableId = null,
      _module = {
         start: start
      };
   return _module;

   function locateListView() {
      var fn = function() {
         InitAllClvps();

         // find the CTX for the LVWP
         for(var k in g_ctxDict) {
           if (debug && window.console) console.log(g_ctxDict[k]);
           
           if (g_ctxDict[k].ListTitle === module.LibraryTitle) {
             wpCtx = window['ctx'+g_ctxDict[k].ctxId];
             break;
           }
         }
         if (debug && window.console) {
            console.log(wpCtx.clvp);
            console.log(wpCtx.clvp.ctx);
            console.log(wpCtx.clvp.ctx.view);
         }
         /* this isn't used in the 2010 version, not figured out if/how to use it yet 
         var clvp = (wpCtx && wpCtx.clvp) ? wpCtx.clvp : null;
         wpEvent = { clvp: clvp, event: { currentCtx: { clvp: clvp } } };
         */
         
         // find the LVWP and table containing the rows
         var 
            $wpnode = $j('#'+wpCtx.clvp.wpq).first(),
            $wpTableNode = $wpnode.find("table[id^='onetidDoclibViewTbl']");
         listViewTableId = $wpTableNode.attr('id');

		 //Il faut avoir préalablement coché la case "Afficher le bouton de raffraichisement" sur la LVWP

         // find the postback control id; e.g. ctl00$m$g_109629d4_d78b_4c9e_8ec0_90078b6e444e$ctl02
         var
            $wpinput = $wpnode.find('> :first-child > input:first-child'),
            ctrlid = $wpinput.attr('id');
         ctrlid = ctrlid && ctrlid.length
                     ?  ctrlid.replace(/^(ctl\d\d)_/gi,'$1$')
                               .replace(/_g_/g,'$g_')
                               .replace(/_(ctl\d\d)$/gi,'$$$1')
                     : '';
         if (debug && window.console) { console.log(">>locateListView: controlid="+ctrlid); }
         filterControlId = ctrlid;
         viewModel.LibraryTitle(wpCtx.ListTitle);
         viewModel.LibrarySubTitle('All');
         viewModel.Working(false);
      };
      EnsureScript("inplview", typeof InitAllClvps, fn);
   }

   function onFilterChange(filterType) {
      if (!filterControlId) {
         alert('Unable to filter: the list view webpart could not be located or the list view contains a Person/Group column!');
         return;
      }

      var
         filterColumn = null,
         filterValue = '';

      if (filterType.match(/year/gi)) {
         filterValue = this.SelectedYear();
         filterColumn = 'PublishedDateYear'; //TODO ajuster votre filtre
      } else if (filterType.match(/month/gi)) {
         filterValue = this.SelectedMonth();
         filterColumn = 'PublishedDateMonth'; //TODO ajuster votre filtre
      }

      if (!filterValue) filterValue = '##dvt_all##';
      var filterCall = "__doPostBack('"+filterControlId+"','NotUTF8;__filter={"+filterColumn+"="+filterValue+"}')"

      if (debug && window.console) {
         console.log(">>Filter by " + filterType + " on ["+filterColumn+"] = ["+filterValue+"]");
         console.log("  >> " + filterCall);
      }
      eval(filterCall);
   }

   function start() {
      ko.applyBindings(viewModel, $j('#cdtm').get(0));
      viewModel.SelectedYear.subscribe(onFilterChange.bind(viewModel, 'year'));
      viewModel.SelectedMonth.subscribe(onFilterChange.bind(viewModel, 'month'));

      locateListView();
   }
}();

$j(pd.FilterLibraryApp.start);

})({ Name: 'Module', LibraryTitle: 'Billets' },jQuery); //TODO Ajuster le titre de votre liste


Dernier détail

Afin de pouvoir lier les filtres à la vue, pour ma part j’ai été contraint de cocher la case suivante :

ActualitesFiltreDynamiqueLVWP

Sans cela, le controlid était toujours vide. Si vous avez une erreur vérifier tout d’abord votre console (F12) :

ActualitesFiltreDynamiqueLVWPConsole

Conclusion

Seulement avec du JS on a réussi à ajouter des filtres dynamiques sur une List View WebPart et cela fonctionne correctement avec la pagination. Donc, beaucoup de flexibilité au niveau du déploiement et de la personnalisation visuelle.

Référence

Dynamically Filtering SharePoint List Views using Javascript

Comment récuperer le code source de vos projets SharePoint perdu à partir d’un WSP?

Introduction

Un de mes collègues a récemment perdu une partie de son code source suite à un problème technique avec un poste virtualisé. Il n’avait pas eu le temps d’archiver le code dans le gestionnaire de code source et tout ce dont il disposait était le code compilé (WSP). Après avoir essayé de recréer sont code à partir de rien, il s’est résolu à venir me voir pour trouver une solution à sont problème.

Dans ce billet nous allons voir comment il est possible de recréer un projet SharePoint à partir d’un fichier WSP et si requis de dé-compiler les DLL d’un projet.

Recréer un projet SharePoint à partir d’un WSP

Pour importer un fichier .wsp

  1. Dans Visual Studio, dans la barre de menus, choisissez Fichier, Nouveau, Projet pour afficher la boîte de dialogue Nouveau projet.  Si votre interface IDE est définie pour utiliser les paramètres de développement Visual Basic, dans la barre de menu cliquez sur Fichier, puis Nouveau Projet.

  2. Développez le nœud SharePoint sous Visual C# ou Visual Basic,

  3. Choisissez le modèle Importer le package de solution SharePoint dans le volet Modèles, puis cliquez sur OK.

    L’Assistant Personnalisation de SharePoint s’affiche.

  4. Dans la page Spécifier le site et le niveau de sécurité pour le débogage, spécifier un site existant.

  5. Dans la section Quel est le niveau de confiance de cette solution SharePoint ?, sélectionner une des deux options.

  6. Dans la page Spécifier la nouvelle source de projet, accédez à l’emplacement du système où vous avez stocké le fichier .wsp, puis cliquez sur le bouton Suivant.

    123012_2133_importingsh6

  7. Dans la zone Sélectionner les éléments à importer, sélectionner tous les éléments que vous voulez récupérer, puis cliquez sur Terminer.

    123012_2133_importingsh8

    Une fois l’opération d’importation terminée, un nouveau projet appelé WspImportProject1 dans lequel figure un dossier nommé Champs est alors créé.  Ce dossier contient les colonnes de site personnalisée.

    123012_2133_importingsh9

Cette opération vous permet de recréer un projet avec les différents artefacts. Cependant, certains éléments comme les DLL peuvent se retrouver dans les « éléments non importés ».

Décompiler les DLL

Ensuite, pour les éléments qui n’ont pas pu être importés, il est possible de dé-compiler les DLL à l’aide d’un outil comme ILSpy ou Reflector :

Capture

Vous pourrez ensuite, extraire le code et recréer vos classes dans votre projet.

Conclusion

Bien évidemment, ça ne permet pas de reproduire exactement le projet dans le même état initial mais on peut tout de même récupérer le code source perdu. Idéalement, pensez à archiver vos sources régulièrement dans votre gestionnaire de code source afin d’éviter de vous retrouver dans cette fâcheuse situation.