<commit_before>// Copyright (c) 2013 Ryan Clark
    // https://gist.github.com/rclark/5779673
    L.TopoJSON = L.GeoJSON.extend({
        addData: function (jsonData) {
            if (jsonData.type === "Topology") {
                for (key in jsonData.objects) {
                    geojson = topojson.feature(jsonData, jsonData.objects[key]);
                    L.GeoJSON.prototype.addData.call(this, geojson);
                }
            }
            else {
                L.GeoJSON.prototype.addData.call(this, jsonData);
            }
        }
    });

var spreadsheetID = "1mxcmAbjrVTU9c3zDy-Mz7PfziEtKNI1PejGuvwD4PW4";
var jsonurl = "https://spreadsheets.google.com/feeds/list/" + spreadsheetID + "/1/public/values?alt=json";
$.getJSON(jsonurl, function(datas) {
    $entrys = datas.feed.entry;
     $($entrys).each(function(){
        if(this.gsx$district.$t.toLowerCase()=="total") {
            if (this.gsx$nagarpalika.$t == '') {
                this.gsx$nagarpalika.$t = 0
            }
            if (this.gsx$gaupalika.$t == '') {
                this.gsx$gaupalika.$t = 0
            }
            if (this.gsx$upamahanarpalika.$t == '') {
                this.gsx$upamahanarpalika.$t = 0

            }
            if (this.gsx$mahanarpalika.$t == '') {
                this.gsx$mahanarpalika.$t = 0
            }
              if (this.gsx$totalnumberofregisteredvoters.$t == '') {
                this.gsx$mahanarpalika.$t = "NULL"
            }
            document.getElementById("nagar").innerHTML = this.gsx$nagarpalika.$t;
            document.getElementById("upnagar").innerHTML = this.gsx$upamahanarpalika.$t;
            document.getElementById("mahanagar").innerHTML = this.gsx$mahanarpalika.$t;
            document.getElementById("gau").innerHTML = this.gsx$gaupalika.$t;
            document.getElementById("tp").innerHTML = this.gsx$totalpopulation.$t;
            document.getElementById("rpp").innerHTML = this.gsx$registeredpoliticalparties.$t;
            document.getElementById("trv").innerHTML = this.gsx$totalnumberofregisteredvoters.$t;

        }

    });

});

function getUpdate(e) {
    $($entrys).each(function(){
        if(this.gsx$district.$t.toLowerCase()==e.toLowerCase()) {
            if (this.gsx$nagarpalika.$t == '') {
                this.gsx$nagarpalika.$t = 0
            }
            if (this.gsx$gaupalika.$t == '') {
                this.gsx$gaupalika.$t = 0
            }
            if (this.gsx$upamahanarpalika.$t == '') {
                this.gsx$upamahanarpalika.$t = 0

            }
            if (this.gsx$mahanarpalika.$t == '') {
                this.gsx$mahanarpalika.$t = 0
            }
            if (this.gsx$totalnumberofregisteredvoters.$t == '') {
                this.gsx$mahanarpalika.$t = "NULL"
            }            document.getElementById("nagar").innerHTML = this.gsx$nagarpalika.$t;
            document.getElementById("upnagar").innerHTML = this.gsx$upamahanarpalika.$t;
            document.getElementById("mahanagar").innerHTML = this.gsx$mahanarpalika.$t;
            document.getElementById("gau").innerHTML = this.gsx$gaupalika.$t;
            document.getElementById("district").innerHTML = e;
            document.getElementById("tp").innerHTML = this.gsx$totalpopulation.$t;
            document.getElementById("rpp").innerHTML = this.gsx$registeredpoliticalparties.$t;
            document.getElementById("trv").innerHTML = this.gsx$totalnumberofregisteredvoters.$t;

        }

    });

    }

     (function () {
        var map = L.map('map', {maxZoom:  6.9, minZoom:  6.9 }),
            topoLayer = new L.TopoJSON(),
            colorScale = chroma
                .scale(['#D5E3FF', '#003171'])
                .domain([0, 1]);
        map.setView([28.1999999, 85.300140],  6.9);

        $.getJSON('static/assets/javascripts/nepal-districts.topo.json').done(addTopoData);

        function addTopoData(topoData) {
            topoLayer.addData(topoData);
            topoLayer.addTo(map);
            topoLayer.eachLayer(handleLayer);
        }

        function highlightFeature(e) {
            var layer = e.target;
            layer.setStyle(
                {
                    weight: 1,
                    color: 'black',
                    fillColor: 'blue',
                }
            );
            if (!L.Browser.ie && !L.Browser.opera) {
                layer.bringToFront();
            }
        }

        function resetHighlight(e) {
            var layer = e.target;
            var setColor=layer.feature.properties.pradesh_no
            layer.setStyle(
                {
                    fillColor: getProvinceColor(setColor),
                    weight: 2,
                    opacity: 1,
                    color: 'white',
                    dashArray: 3,
                    fillOpacity: 0.7
                }
            );

            if (!L.Browser.ie && !L.Browser.opera) {
                layer.bringToFront();
            }
        }

        function handleLayer(layer) {
            layer.bindLabel(layer.feature.properties.name, {noHide: true})
            var code = layer.feature.properties.name;
            var setColor=layer.feature.properties.pradesh_no;
            layer.setStyle({
                fillColor: getProvinceColor(setColor),
                weight: 2,
                opacity: 1,
                color: 'white',
                dashArray: 3,
                fillOpacity: 0.7
            });
            layer.on({
                mouseover: highlightFeature,
                mouseout: resetHighlight,

            });

            layer.on('click', function (e) {
                 getUpdate(layer.feature.properties.name);
            });
        }

        function getProvinceColor(state) {
            if (state == 7) {
                return 'red';
            } else if (state == 6) {
                return '#c1a73e';
            } else if (state == 5) {
                return '#da8b4a';
            }
            else if (state == 4) {
                return '#26a9e8';
            }
            else if (state == 3) {
                return '#40a500';
            }
            else if (state == 2) {
                return '#e271a1';
            }
            else if (state == 1) {
                return '#900e94';
            }

        }

        var legend = L.control({position: 'topright'});
        legend.onAdd = function (map) {
            var div = L.DomUtil.create('div', 'legend');
            var labels = [
                "Province No. 1",
                "Province No. 2",
                "Province No. 3",
                "Province No. 4",
                "Province No. 5",
                "Province No. 6",
                "Province No. 7"
            ];
            var grades = [1, 2, 3, 4, 5, 6, 7];
            div.innerHTML = '

Province Index

';
            for (var i = 0; i < grades.length; i++) {
                div.innerHTML += '      '
                    + labels[i] + '
';
            }
            return div;
        }
        legend.addTo(map);

    }());
<commit_msg>Update setView to make map centered<commit_after>// Copyright (c) 2013 Ryan Clark
    // https://gist.github.com/rclark/5779673
    L.TopoJSON = L.GeoJSON.extend({
        addData: function (jsonData) {
            if (jsonData.type === "Topology") {
                for (key in jsonData.objects) {
                    geojson = topojson.feature(jsonData, jsonData.objects[key]);
                    L.GeoJSON.prototype.addData.call(this, geojson);
                }
            }
            else {
                L.GeoJSON.prototype.addData.call(this, jsonData);
            }
        }
    });

var spreadsheetID = "1mxcmAbjrVTU9c3zDy-Mz7PfziEtKNI1PejGuvwD4PW4";
var jsonurl = "https://spreadsheets.google.com/feeds/list/" + spreadsheetID + "/1/public/values?alt=json";
$.getJSON(jsonurl, function(datas) {
    $entrys = datas.feed.entry;
     $($entrys).each(function(){
        if(this.gsx$district.$t.toLowerCase()=="total") {
            if (this.gsx$nagarpalika.$t == '') {
                this.gsx$nagarpalika.$t = 0
            }
            if (this.gsx$gaupalika.$t == '') {
                this.gsx$gaupalika.$t = 0
            }
            if (this.gsx$upamahanarpalika.$t == '') {
                this.gsx$upamahanarpalika.$t = 0

            }
            if (this.gsx$mahanarpalika.$t == '') {
                this.gsx$mahanarpalika.$t = 0
            }
              if (this.gsx$totalnumberofregisteredvoters.$t == '') {
                this.gsx$mahanarpalika.$t = "NULL"
            }
            document.getElementById("nagar").innerHTML = this.gsx$nagarpalika.$t;
            document.getElementById("upnagar").innerHTML = this.gsx$upamahanarpalika.$t;
            document.getElementById("mahanagar").innerHTML = this.gsx$mahanarpalika.$t;
            document.getElementById("gau").innerHTML = this.gsx$gaupalika.$t;
            document.getElementById("tp").innerHTML = this.gsx$totalpopulation.$t;
            document.getElementById("rpp").innerHTML = this.gsx$registeredpoliticalparties.$t;
            document.getElementById("trv").innerHTML = this.gsx$totalnumberofregisteredvoters.$t;

        }

    });

});

function getUpdate(e) {
    $($entrys).each(function(){
        if(this.gsx$district.$t.toLowerCase()==e.toLowerCase()) {
            if (this.gsx$nagarpalika.$t == '') {
                this.gsx$nagarpalika.$t = 0
            }
            if (this.gsx$gaupalika.$t == '') {
                this.gsx$gaupalika.$t = 0
            }
            if (this.gsx$upamahanarpalika.$t == '') {
                this.gsx$upamahanarpalika.$t = 0

            }
            if (this.gsx$mahanarpalika.$t == '') {
                this.gsx$mahanarpalika.$t = 0
            }
            if (this.gsx$totalnumberofregisteredvoters.$t == '') {
                this.gsx$mahanarpalika.$t = "NULL"
            }            document.getElementById("nagar").innerHTML = this.gsx$nagarpalika.$t;
            document.getElementById("upnagar").innerHTML = this.gsx$upamahanarpalika.$t;
            document.getElementById("mahanagar").innerHTML = this.gsx$mahanarpalika.$t;
            document.getElementById("gau").innerHTML = this.gsx$gaupalika.$t;
            document.getElementById("district").innerHTML = e;
            document.getElementById("tp").innerHTML = this.gsx$totalpopulation.$t;
            document.getElementById("rpp").innerHTML = this.gsx$registeredpoliticalparties.$t;
            document.getElementById("trv").innerHTML = this.gsx$totalnumberofregisteredvoters.$t;

        }

    });

    }

     (function () {
        var map = L.map('map', {maxZoom:  6.9, minZoom:  6.9 }),
            topoLayer = new L.TopoJSON(),
            colorScale = chroma
                .scale(['#D5E3FF', '#003171'])
                .domain([0, 1]);
        map.setView([28.1999999, 84.100140],  6.9);

        $.getJSON('static/assets/javascripts/nepal-districts.topo.json').done(addTopoData);

        function addTopoData(topoData) {
            topoLayer.addData(topoData);
            topoLayer.addTo(map);
            topoLayer.eachLayer(handleLayer);
        }

        function highlightFeature(e) {
            var layer = e.target;
            layer.setStyle(
                {
                    weight: 1,
                    color: 'black',
                    fillColor: 'blue',
                }
            );
            if (!L.Browser.ie && !L.Browser.opera) {
                layer.bringToFront();
            }
        }

        function resetHighlight(e) {
            var layer = e.target;
            var setColor=layer.feature.properties.pradesh_no
            layer.setStyle(
                {
                    fillColor: getProvinceColor(setColor),
                    weight: 2,
                    opacity: 1,
                    color: 'white',
                    dashArray: 3,
                    fillOpacity: 0.7
                }
            );

            if (!L.Browser.ie && !L.Browser.opera) {
                layer.bringToFront();
            }
        }

        function handleLayer(layer) {
            layer.bindLabel(layer.feature.properties.name, {noHide: true})
            var code = layer.feature.properties.name;
            var setColor=layer.feature.properties.pradesh_no;
            layer.setStyle({
                fillColor: getProvinceColor(setColor),
                weight: 2,
                opacity: 1,
                color: 'white',
                dashArray: 3,
                fillOpacity: 0.7
            });
            layer.on({
                mouseover: highlightFeature,
                mouseout: resetHighlight,

            });

            layer.on('click', function (e) {
                 getUpdate(layer.feature.properties.name);
            });
        }

        function getProvinceColor(state) {
            if (state == 7) {
                return 'red';
            } else if (state == 6) {
                return '#c1a73e';
            } else if (state == 5) {
                return '#da8b4a';
            }
            else if (state == 4) {
                return '#26a9e8';
            }
            else if (state == 3) {
                return '#40a500';
            }
            else if (state == 2) {
                return '#e271a1';
            }
            else if (state == 1) {
                return '#900e94';
            }

        }

        var legend = L.control({position: 'topright'});
        legend.onAdd = function (map) {
            var div = L.DomUtil.create('div', 'legend');
            var labels = [
                "Province No. 1",
                "Province No. 2",
                "Province No. 3",
                "Province No. 4",
                "Province No. 5",
                "Province No. 6",
                "Province No. 7"
            ];
            var grades = [1, 2, 3, 4, 5, 6, 7];
            div.innerHTML = '

Province Index

';
            for (var i = 0; i < grades.length; i++) {
                div.innerHTML += '      '
                    + labels[i] + '
';
            }
            return div;
        }
        legend.addTo(map);

    }());
<|endoftext|>


<commit_before>const fr_FR = {}

fr_FR.strings = {
  addBulkFilesFailed: {
    '0': 'L\'ajout de %{smart_count} fichier a échoué',
    '1': 'L\'ajout de %{smart_count} fichiers a échoué'
  },
  addMore: 'Ajouter d\'autres',
  addMoreFiles: 'Ajouter d\'autres fichiers',
  addingMoreFiles: 'En train d\'ajouter des fichiers',
  allowAccessDescription: 'Pour prendre des photos ou enregistrer une vidéo avec votre caméra, veuillez autoriser l\'accès à votre caméra pour ce site.',
  allowAccessTitle: 'Veuillez autoriser l\'accès à votre caméra',
  authenticateWith: 'Se connecter à %{pluginName}',
  authenticateWithTitle: 'Veuillez vous authentifier avec %{pluginName} pour sélectionner les fichiers',
  back: 'Retour',
  browse: 'naviguer',
  cancel: 'Annuler',
  cancelUpload: 'Annuler téléchargement',
  chooseFiles: 'Choisir des fichiers',
  closeModal: 'Fermer Fenêtre',
  companionError: 'Connexion à Companion a échoué',
  companionUnauthorizeHint: 'Pour vous déconnecter de votre compte %{provider}, veuillez aller à %{url}',
  complete: 'Terminé',
  connectedToInternet: 'Connecté à Internet',
  copyLink: 'Copier lien',
  copyLinkToClipboardFallback: 'Copier le lien ci-dessous',
  copyLinkToClipboardSuccess: 'Lien copié',
  creatingAssembly: 'Préparation du téléchargement...',
  creatingAssemblyFailed: 'Transloadit: Impossible de créer Assembly',
  dashboardTitle: 'Téléchargeur de fichier',
  dashboardWindowTitle: 'Fenêtre de téléchargeur de fichier (Appuyez sur echap pour fermer)',
  dataUploadedOfTotal: '%{complete} sur %{total}',
  done: 'Terminé',
  dropHereOr: 'Déposer les fichiers ici ou %{browse}',
  dropHint: 'Déposez vos fichiers ici',
  dropPaste: 'Déposer les fichiers ici, coller ou %{browse}',
  dropPasteImport: 'Déposer les fichiers ici, coller, %{browse} ou importer de',
  editFile: 'Modifier fichier',
  editing: 'Modification en cours de %{file}',
  emptyFolderAdded: 'Aucun fichier n\'a été ajouté depuis un dossier vide',
  encoding: 'Traitement...',
  enterCorrectUrl: 'Lien incorrect: Assurez-vous que vous entrez un lien direct vers le fichier',
  enterUrlToImport: 'Entrez le lien pour importer un fichier',
  exceedsSize: 'Ce fichier dépasse la taille maximale autorisée de',
  failedToFetch: 'Companion a échoué à récupérer ce lien, assurez-vous qu\'il est correct',
  failedToUpload: 'Le téléchargement de %{file} a échoué',
  fileSource: 'Fichier source: %{name}',
  filesUploadedOfTotal: {
    '0': '%{complete} sur %{smart_count} fichier téléchargé',
    '1': '%{complete} sur %{smart_count} fichiers téléchargés',
    '2': '%{complete} sur %{smart_count} fichiers téléchargés'
  },
  filter: 'Filtrer',
  finishEditingFile: 'Terminer l\'édition du fichier',
  folderAdded: {
    '0': '%{smart_count} fichier ajouté de %{folder}',
    '1': '%{smart_count} fichiers ajoutés de %{folder}',
    '2': '%{smart_count} fichiers ajoutés de %{folder}'
  },
  generatingThumbnails: 'Generating thumbnails...',
  import: 'Importer',
  importFrom: 'Importer de %{name}',
  loading: 'Chargement...',
  logOut: 'Déconnexion',
  micDisabled: 'Accès au micro refusé par l\'utilisateur',
  micIsOn: 'Micro actif',
  myDevice: 'Mon Appareil',
  noDuplicates: 'Impossible d\'ajouter le fichier "%{fileName}", il existe déjà',
  noFilesFound: 'Vous n\'avez aucun fichier ou dossier ici',
  noInternetConnection: 'Pas de connexion à Internet',
  noNewAlreadyUploading: 'Impossible d\'ajouter de nouveaux fichiers: en cours de chargement ',
  openFolderNamed: 'Ouvrir %{name}',
  pause: 'Pause',
  pauseUpload: 'Mettre en pause le téléchargement',
  paused: 'En pause',
  poweredBy: 'Propulsé par',
  preparingUpload: 'Préparation du téléchargement...',
  processingXFiles: {
    '0': 'Traitement de %{smart_count} fichier',
    '1': 'Traitement de %{smart_count} fichiers',
    '2': 'Traitement de %{smart_count} fichiers'
  },
  recording: 'Enregistrement',
  recordingLength: 'Durée d\'enregistrement %{recording_length}',
  recordingStoppedMaxSize: 'L\'enregistrement s\'est arrété car la taille du fichier dépasse la limite',
  removeFile: 'Effacer le fichier',
  resetFilter: 'Réinitialiser filtre',
  resume: 'Reprendre',
  resumeUpload: 'Reprendre le téléchargement',
  retry: 'Réessayer',
  retryUpload: 'Réessayer le téléchargement',
  saveChanges: 'Sauvegarder les modifications',
  selectAllFilesFromFolderNamed: 'Sélectionner tous les fichiers du dossier %{name}',
  selectFileNamed: 'Sélectionner le fichier %{name}',
  selectSourceDescription: 'Afin de réaliser une vidéo de votre écran, veuillez autoriser l\'accès à ce site.',
  selectSourceTitle: 'Veuillez autoriser l\'accès à votre écran',
  selectX: {
    '0': 'Sélectionner %{smart_count}',
    '1': 'Sélectionner %{smart_count}',
    '2': 'Sélectionner %{smart_count}'
  },
  smile: 'Souriez !',
  startRecording: 'Commencer l\'enregistrement vidéo',
  stopRecording: 'Arrêter l\'enregistrement vidéo',
  streamActive: 'Stream actif',
  streamPassive: 'Stream passif',
  submitRecordedFile: 'Envoyer la vidéo enregistrée',
  takePicture: 'Prendre une photo',
  timedOut: 'Téléchargement bloqué durant %{seconds} secondes, annulation.',
  unselectAllFilesFromFolderNamed: 'Désélectionner tous les fichiers du dossier %{name}',
  unselectFileNamed: 'Désélectionner le fichier %{name}',
  upload: 'Télécharger',
  uploadComplete: 'Téléchargement terminé',
  uploadFailed: 'Le téléchargement a échoué',
  uploadPaused: 'Téléchargement mis en pause',
  uploadXFiles: {
    '0': 'Télécharger %{smart_count} fichier',
    '1': 'Télécharger %{smart_count} fichiers',
    '2': 'Télécharger %{smart_count} fichiers'
  },
  uploadXNewFiles: {
    '0': 'Télécharger +%{smart_count} fichier',
    '1': 'Télécharger +%{smart_count} fichiers',
    '2': 'Télécharger +%{smart_count} fichiers'
  },
  uploading: 'Téléchargement en cours',
  uploadingXFiles: {
    '0': 'Uploading %{smart_count} file',
    '1': 'Uploading %{smart_count} files',
    '2': 'Uploading %{smart_count} files'
  },
  xFilesSelected: {
    '0': '%{smart_count} fichier sélectionné',
    '1': '%{smart_count} fichiers sélectionnés',
    '2': '%{smart_count} fichiers sélectionnés'
  },
  xMoreFilesAdded: {
    '0': '%{smart_count} autre fichier ajouté',
    '1': '%{smart_count} autres fichiers ajoutés',
    '2': '%{smart_count} autres fichiers ajoutés'
  },
  xTimeLeft: '%{time} restantes',
  youCanOnlyUploadFileTypes: 'Vous pouvez seulement télécharger: %{types}',
  youCanOnlyUploadX: {
    '0': 'Vous pouvez seulement télécharger %{smart_count} fichier',
    '1': 'Vous pouvez seulement télécharger %{smart_count} fichiers',
    '2': 'Vous pouvez seulement télécharger %{smart_count} fichiers'
  },
  youHaveToAtLeastSelectX: {
    '0': 'Vous devez sélectionner au moins %{smart_count} fichier',
    '1': 'Vous devez sélectionner au moins %{smart_count} fichiers',
    '2': 'Vous devez sélectionner au moins %{smart_count} fichiers'
  }
}

fr_FR.pluralize = function (n) {
  if (n === 1) {
    return 0
  }
  return 1
}

if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
  window.Uppy.locales.fr_FR = fr_FR
}

module.exports = fr_FR
<commit_msg>remove unused strings<commit_after>const fr_FR = {}

fr_FR.strings = {
  addBulkFilesFailed: {
    '0': 'L\'ajout de %{smart_count} fichier a échoué',
    '1': 'L\'ajout de %{smart_count} fichiers a échoué'
  },
  addMore: 'Ajouter d\'autres',
  addMoreFiles: 'Ajouter d\'autres fichiers',
  addingMoreFiles: 'En train d\'ajouter des fichiers',
  allowAccessDescription: 'Pour prendre des photos ou enregistrer une vidéo avec votre caméra, veuillez autoriser l\'accès à votre caméra pour ce site.',
  allowAccessTitle: 'Veuillez autoriser l\'accès à votre caméra',
  authenticateWith: 'Se connecter à %{pluginName}',
  authenticateWithTitle: 'Veuillez vous authentifier avec %{pluginName} pour sélectionner les fichiers',
  back: 'Retour',
  browse: 'naviguer',
  cancel: 'Annuler',
  cancelUpload: 'Annuler téléchargement',
  chooseFiles: 'Choisir des fichiers',
  closeModal: 'Fermer Fenêtre',
  companionError: 'Connexion à Companion a échoué',
  companionUnauthorizeHint: 'Pour vous déconnecter de votre compte %{provider}, veuillez aller à %{url}',
  complete: 'Terminé',
  connectedToInternet: 'Connecté à Internet',
  copyLink: 'Copier lien',
  copyLinkToClipboardFallback: 'Copier le lien ci-dessous',
  copyLinkToClipboardSuccess: 'Lien copié',
  creatingAssembly: 'Préparation du téléchargement...',
  creatingAssemblyFailed: 'Transloadit: Impossible de créer Assembly',
  dashboardTitle: 'Téléchargeur de fichier',
  dashboardWindowTitle: 'Fenêtre de téléchargeur de fichier (Appuyez sur echap pour fermer)',
  dataUploadedOfTotal: '%{complete} sur %{total}',
  done: 'Terminé',
  dropHereOr: 'Déposer les fichiers ici ou %{browse}',
  dropHint: 'Déposez vos fichiers ici',
  dropPaste: 'Déposer les fichiers ici, coller ou %{browse}',
  dropPasteImport: 'Déposer les fichiers ici, coller, %{browse} ou importer de',
  editFile: 'Modifier fichier',
  editing: 'Modification en cours de %{file}',
  emptyFolderAdded: 'Aucun fichier n\'a été ajouté depuis un dossier vide',
  encoding: 'Traitement...',
  enterCorrectUrl: 'Lien incorrect: Assurez-vous que vous entrez un lien direct vers le fichier',
  enterUrlToImport: 'Entrez le lien pour importer un fichier',
  exceedsSize: 'Ce fichier dépasse la taille maximale autorisée de',
  failedToFetch: 'Companion a échoué à récupérer ce lien, assurez-vous qu\'il est correct',
  failedToUpload: 'Le téléchargement de %{file} a échoué',
  fileSource: 'Fichier source: %{name}',
  filesUploadedOfTotal: {
    '0': '%{complete} sur %{smart_count} fichier téléchargé',
    '1': '%{complete} sur %{smart_count} fichiers téléchargés',
    '2': '%{complete} sur %{smart_count} fichiers téléchargés'
  },
  filter: 'Filtrer',
  finishEditingFile: 'Terminer l\'édition du fichier',
  folderAdded: {
    '0': '%{smart_count} fichier ajouté de %{folder}',
    '1': '%{smart_count} fichiers ajoutés de %{folder}',
    '2': '%{smart_count} fichiers ajoutés de %{folder}'
  },
  generatingThumbnails: 'Generating thumbnails...',
  import: 'Importer',
  importFrom: 'Importer de %{name}',
  loading: 'Chargement...',
  logOut: 'Déconnexion',
  micDisabled: 'Accès au micro refusé par l\'utilisateur',
  myDevice: 'Mon Appareil',
  noDuplicates: 'Impossible d\'ajouter le fichier "%{fileName}", il existe déjà',
  noFilesFound: 'Vous n\'avez aucun fichier ou dossier ici',
  noInternetConnection: 'Pas de connexion à Internet',
  noNewAlreadyUploading: 'Impossible d\'ajouter de nouveaux fichiers: en cours de chargement ',
  openFolderNamed: 'Ouvrir %{name}',
  pause: 'Pause',
  pauseUpload: 'Mettre en pause le téléchargement',
  paused: 'En pause',
  poweredBy: 'Propulsé par',
  preparingUpload: 'Préparation du téléchargement...',
  processingXFiles: {
    '0': 'Traitement de %{smart_count} fichier',
    '1': 'Traitement de %{smart_count} fichiers',
    '2': 'Traitement de %{smart_count} fichiers'
  },
  recording: 'Enregistrement',
  recordingLength: 'Durée d\'enregistrement %{recording_length}',
  recordingStoppedMaxSize: 'L\'enregistrement s\'est arrété car la taille du fichier dépasse la limite',
  removeFile: 'Effacer le fichier',
  resetFilter: 'Réinitialiser filtre',
  resume: 'Reprendre',
  resumeUpload: 'Reprendre le téléchargement',
  retry: 'Réessayer',
  retryUpload: 'Réessayer le téléchargement',
  saveChanges: 'Sauvegarder les modifications',
  selectAllFilesFromFolderNamed: 'Sélectionner tous les fichiers du dossier %{name}',
  selectFileNamed: 'Sélectionner le fichier %{name}',
  selectX: {
    '0': 'Sélectionner %{smart_count}',
    '1': 'Sélectionner %{smart_count}',
    '2': 'Sélectionner %{smart_count}'
  },
  smile: 'Souriez !',
  startRecording: 'Commencer l\'enregistrement vidéo',
  stopRecording: 'Arrêter l\'enregistrement vidéo',
  streamActive: 'Stream actif',
  streamPassive: 'Stream passif',
  submitRecordedFile: 'Envoyer la vidéo enregistrée',
  takePicture: 'Prendre une photo',
  timedOut: 'Téléchargement bloqué durant %{seconds} secondes, annulation.',
  unselectAllFilesFromFolderNamed: 'Désélectionner tous les fichiers du dossier %{name}',
  unselectFileNamed: 'Désélectionner le fichier %{name}',
  upload: 'Télécharger',
  uploadComplete: 'Téléchargement terminé',
  uploadFailed: 'Le téléchargement a échoué',
  uploadPaused: 'Téléchargement mis en pause',
  uploadXFiles: {
    '0': 'Télécharger %{smart_count} fichier',
    '1': 'Télécharger %{smart_count} fichiers',
    '2': 'Télécharger %{smart_count} fichiers'
  },
  uploadXNewFiles: {
    '0': 'Télécharger +%{smart_count} fichier',
    '1': 'Télécharger +%{smart_count} fichiers',
    '2': 'Télécharger +%{smart_count} fichiers'
  },
  uploading: 'Téléchargement en cours',
  uploadingXFiles: {
    '0': 'Uploading %{smart_count} file',
    '1': 'Uploading %{smart_count} files',
    '2': 'Uploading %{smart_count} files'
  },
  xFilesSelected: {
    '0': '%{smart_count} fichier sélectionné',
    '1': '%{smart_count} fichiers sélectionnés',
    '2': '%{smart_count} fichiers sélectionnés'
  },
  xMoreFilesAdded: {
    '0': '%{smart_count} autre fichier ajouté',
    '1': '%{smart_count} autres fichiers ajoutés',
    '2': '%{smart_count} autres fichiers ajoutés'
  },
  xTimeLeft: '%{time} restantes',
  youCanOnlyUploadFileTypes: 'Vous pouvez seulement télécharger: %{types}',
  youCanOnlyUploadX: {
    '0': 'Vous pouvez seulement télécharger %{smart_count} fichier',
    '1': 'Vous pouvez seulement télécharger %{smart_count} fichiers',
    '2': 'Vous pouvez seulement télécharger %{smart_count} fichiers'
  },
  youHaveToAtLeastSelectX: {
    '0': 'Vous devez sélectionner au moins %{smart_count} fichier',
    '1': 'Vous devez sélectionner au moins %{smart_count} fichiers',
    '2': 'Vous devez sélectionner au moins %{smart_count} fichiers'
  }
}

fr_FR.pluralize = function (n) {
  if (n === 1) {
    return 0
  }
  return 1
}

if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
  window.Uppy.locales.fr_FR = fr_FR
}

module.exports = fr_FR
<|endoftext|>


<commit_before>(function() {
    'use strict';

    var sendToGA = function(eventCategory, eventLabel, eventAction='click') {
        ga('send', {
            hitType: 'event',
            eventCategory: eventCategory,
            eventAction: eventAction,
            eventLabel: eventLabel
        });
    };

    var addEventListener = function(selector, label, buttonLabel) {
        $(document).on('click', selector, function() {
            if (buttonLabel) {
                sendToGA('button', $(this).data('analytics-label'));
            } else {
                sendToGA('button', label);
            }
        });
        if (buttonLabel) {
            $(document).on('contextmenu', selector, function() {
                sendToGA('button', $(this).data('analytics-label'), 'contextmenu');
            });
        }
    };

    var addNavItemsToGA = function() {
        addEventListener('.side-nav-item', '', true);
        addEventListener('.nav-dropdown', '', true);
        addEventListener('#help-us-continue', 'Donate');
    };

    var addSubmissionPageButtonsToGA = function() {
        addEventListener('.download-submission-button', 'Submission Download');
        addEventListener('#final-download-button', 'Download button from Modal');
        addEventListener('.view-submission-button', 'View submission button');
        addEventListener('#copy-to-clipboard', 'Copy to Clipboard');
        addEventListener('#final-view-download-button', 'Download button View Modal');
        addEventListener('#link-to-site', 'View submission on Site');
        addEventListener('.problem-listing', 'Problem in widget');
        addEventListener('.add-to-todo-list', 'Add to todo list');
        addEventListener('.submission-user-name', 'User\'s name on submission page');
        addEventListener('.submission-site-profile', 'User\'s site profile on submission page');
    };

    var addProfilePageButtonsToGA = function() {
        addEventListener('#profile-institute-leaderboard', 'Profile Institute Leaderboard')
        addEventListener('#profile-user-submissions', 'Profile User Submissions');
        addEventListener('#profile-add-friend', 'Profile Add Friend');
        addEventListener('#profile-add-to-my-custom-friend', 'Profile Add to my Custom Friend');
        addEventListener('#profile-add-to-my-custom-friend-logged-out', 'Profile Add to my Custom Friend (Logged out)');
        addEventListener('#profile-unfriend', 'Profile Unfriend');
        addEventListener('#profile-custom-user-of', 'Profile Custom User of');
        // @ToDo: Generalize this
        addEventListener('#codechef-profile-url', 'Codechef profile URL');
        addEventListener('#codeforces-profile-url', 'CodeForces profile URL');
        addEventListener('#hackerrank-profile-url', 'HackerRank profile URL');
        addEventListener('#hackerearth-profile-url', 'HackerEarth profile URL');
        addEventListener('#spoj-profile-url', 'Spoj profile URL');
        addEventListener('#uva-profile-url', 'UVa profile URL');
        addEventListener('#toggle-submission-graph', 'Toggle Submission Graph');
        addEventListener('.popup-contest-page', 'Contest Page button on User Profile');
        addEventListener('.custom-user-count-profile-page', 'Custom user count on User Profile');
        addEventListener('#update-my-submissions', 'Refresh my submissions');
        addEventListener('#disabled-update-my-submissions', 'Disabled refresh my submissions');
    };

    var addMiscellaneousToGA = function() {
        addEventListener('#heart-button', 'Heart Button');
        addEventListener('#heart-facebook-group', 'Heart Facebook Group');
        addEventListener('#heart-facebook', 'Heart Facebook');
        addEventListener('#heart-twitter', 'Heart Twitter');
        addEventListener('#heart-google-plus', 'Heart Google Plus');
        addEventListener('#heart-github', 'Heart Github');
        addEventListener('#footer-faqs', 'Footer FAQs');
        addEventListener('#footer-contact-us', 'Footer Contact Us');
        addEventListener('#footer-license', 'Footer MIT License');
        addEventListener('#footer-contributors', 'Footer Contributors');
        addEventListener('#footer-raj454raj', 'Footer raj454raj');
        addEventListener('#first-friend-search', 'First friend search');
        addEventListener('#first-custom-friend', 'First custom friend');
        addEventListener('.remove-from-todo', 'Remove from todo');
        addEventListener('#testimonials-page', 'Write a Testimonial');
        addEventListener('.custom-user-count', 'Open custom user list');
        addEventListener('.custom-user-list-name', 'Custom user name in Modal');
        addEventListener('.custom-user-modal-site-profile', 'Custom user Site Profile in Modal');
        addEventListener('#open-side-nav', 'Open Side Navbar');
    };

    var addProblemPageButtonsToGA = function() {
        addEventListener('#my-submissions-tab', 'My Submissions Tab');
        addEventListener('#friends-submissions-tab', 'Friends Submissions Tab');
        addEventListener('#global-submissions-tab', 'Global Submissions Tab');
        addEventListener('.problem-page-site-link', 'Problem page problem link');
        addEventListener('.problem-page-editorials', 'Problem page editorials link');
        addEventListener('.suggest-tags-plus-logged-out', 'Suggest tags plus (Logged out)');
        addEventListener('.suggest-tags-plus', 'Suggest tags plus');
        addEventListener('#show-tags', 'Show tags');
        addEventListener('.problem-page-tag', 'Problem page tag');
    };

    var addUserEditorialsButtonsToGA = function() {
        addEventListener('#all-editorials-button', 'Read editorial page All Editorials');
        addEventListener('#site-editorial-link', 'Site editorial link');
        addEventListener('#show-editor', 'Write Editorial button');
        addEventListener('#submit-editorial', 'Submit Editorial button');
        addEventListener('#cancel-editorial', 'Cancel Editorial button');
    };

    var addFriendsPageButtonsToGA = function() {
        addEventListener('.friends-name', 'Friends name');
        addEventListener('.friends-unfriend', 'Friends unfriend');
        addEventListener('.friends-add-friend', 'Friends add friend');
    };

    var addSearchPageButtonsToGA = function() {
        addEventListener('.search-add-friend', 'Search add friend');
        addEventListener('.search-unfriend', 'Search unfriend');
        addEventListener('.search-site-profile', 'Search site profile');
        addEventListener('.search-user-name', 'Search user name');
    };

    var addContestPageButtonsToGA = function() {
        addEventListener('.view-contest', 'View Contest');
        addEventListener('.set-reminder', 'Set reminder');

    };

    var addLeaderboardPageButtonsToGA = function() {
        addEventListener('.leaderboard-institute', 'Leaderboard Institute');
        addEventListener('.leaderboard-country-flag', 'Leaderboard Country');
        addEventListener('.leaderboard-stopstalk-handle', 'Leaderboard StopStalk handle');
        addEventListener('#leaderboard-switch', 'Leaderboard Switch');
    };

    var addTagsPageButtonsToGA = function() {
        addEventListener('.tag-problem-link', 'Tags problem link');
        addEventListener('.tags-chip', 'Tags page chip');
    };

    $(document).ready(function() {
        addNavItemsToGA();
        addSubmissionPageButtonsToGA();
        addProblemPageButtonsToGA();
        addProfilePageButtonsToGA();
        addFriendsPageButtonsToGA();
        addSearchPageButtonsToGA();
        addContestPageButtonsToGA();
        addLeaderboardPageButtonsToGA();
        addTagsPageButtonsToGA();
        addMiscellaneousToGA();
    });
})(jQuery);
<commit_msg>Default parameter removed<commit_after>(function() {
    'use strict';

    var sendToGA = function(eventCategory, eventLabel, eventAction) {
        ga('send', {
            hitType: 'event',
            eventCategory: eventCategory,
            eventAction: eventAction,
            eventLabel: eventLabel
        });
    };

    var addEventListener = function(selector, label, buttonLabel) {
        $(document).on('click', selector, function() {
            if (buttonLabel) {
                sendToGA('button', $(this).data('analytics-label'));
            } else {
                sendToGA('button', label);
            }
        });
        if (buttonLabel) {
            $(document).on('contextmenu', selector, function() {
                sendToGA('button', $(this).data('analytics-label'), 'contextmenu');
            });
        }
    };

    var addNavItemsToGA = function() {
        addEventListener('.side-nav-item', '', true);
        addEventListener('.nav-dropdown', '', true);
        addEventListener('#help-us-continue', 'Donate');
    };

    var addSubmissionPageButtonsToGA = function() {
        addEventListener('.download-submission-button', 'Submission Download');
        addEventListener('#final-download-button', 'Download button from Modal');
        addEventListener('.view-submission-button', 'View submission button');
        addEventListener('#copy-to-clipboard', 'Copy to Clipboard');
        addEventListener('#final-view-download-button', 'Download button View Modal');
        addEventListener('#link-to-site', 'View submission on Site');
        addEventListener('.problem-listing', 'Problem in widget');
        addEventListener('.add-to-todo-list', 'Add to todo list');
        addEventListener('.submission-user-name', 'User\'s name on submission page');
        addEventListener('.submission-site-profile', 'User\'s site profile on submission page');
    };

    var addProfilePageButtonsToGA = function() {
        addEventListener('#profile-institute-leaderboard', 'Profile Institute Leaderboard')
        addEventListener('#profile-user-submissions', 'Profile User Submissions');
        addEventListener('#profile-add-friend', 'Profile Add Friend');
        addEventListener('#profile-add-to-my-custom-friend', 'Profile Add to my Custom Friend');
        addEventListener('#profile-add-to-my-custom-friend-logged-out', 'Profile Add to my Custom Friend (Logged out)');
        addEventListener('#profile-unfriend', 'Profile Unfriend');
        addEventListener('#profile-custom-user-of', 'Profile Custom User of');
        // @ToDo: Generalize this
        addEventListener('#codechef-profile-url', 'Codechef profile URL');
        addEventListener('#codeforces-profile-url', 'CodeForces profile URL');
        addEventListener('#hackerrank-profile-url', 'HackerRank profile URL');
        addEventListener('#hackerearth-profile-url', 'HackerEarth profile URL');
        addEventListener('#spoj-profile-url', 'Spoj profile URL');
        addEventListener('#uva-profile-url', 'UVa profile URL');
        addEventListener('#toggle-submission-graph', 'Toggle Submission Graph');
        addEventListener('.popup-contest-page', 'Contest Page button on User Profile');
        addEventListener('.custom-user-count-profile-page', 'Custom user count on User Profile');
        addEventListener('#update-my-submissions', 'Refresh my submissions');
        addEventListener('#disabled-update-my-submissions', 'Disabled refresh my submissions');
    };

    var addMiscellaneousToGA = function() {
        addEventListener('#heart-button', 'Heart Button');
        addEventListener('#heart-facebook-group', 'Heart Facebook Group');
        addEventListener('#heart-facebook', 'Heart Facebook');
        addEventListener('#heart-twitter', 'Heart Twitter');
        addEventListener('#heart-google-plus', 'Heart Google Plus');
        addEventListener('#heart-github', 'Heart Github');
        addEventListener('#footer-faqs', 'Footer FAQs');
        addEventListener('#footer-contact-us', 'Footer Contact Us');
        addEventListener('#footer-license', 'Footer MIT License');
        addEventListener('#footer-contributors', 'Footer Contributors');
        addEventListener('#footer-raj454raj', 'Footer raj454raj');
        addEventListener('#first-friend-search', 'First friend search');
        addEventListener('#first-custom-friend', 'First custom friend');
        addEventListener('.remove-from-todo', 'Remove from todo');
        addEventListener('#testimonials-page', 'Write a Testimonial');
        addEventListener('.custom-user-count', 'Open custom user list');
        addEventListener('.custom-user-list-name', 'Custom user name in Modal');
        addEventListener('.custom-user-modal-site-profile', 'Custom user Site Profile in Modal');
        addEventListener('#open-side-nav', 'Open Side Navbar');
    };

    var addProblemPageButtonsToGA = function() {
        addEventListener('#my-submissions-tab', 'My Submissions Tab');
        addEventListener('#friends-submissions-tab', 'Friends Submissions Tab');
        addEventListener('#global-submissions-tab', 'Global Submissions Tab');
        addEventListener('.problem-page-site-link', 'Problem page problem link');
        addEventListener('.problem-page-editorials', 'Problem page editorials link');
        addEventListener('.suggest-tags-plus-logged-out', 'Suggest tags plus (Logged out)');
        addEventListener('.suggest-tags-plus', 'Suggest tags plus');
        addEventListener('#show-tags', 'Show tags');
        addEventListener('.problem-page-tag', 'Problem page tag');
    };

    var addUserEditorialsButtonsToGA = function() {
        addEventListener('#all-editorials-button', 'Read editorial page All Editorials');
        addEventListener('#site-editorial-link', 'Site editorial link');
        addEventListener('#show-editor', 'Write Editorial button');
        addEventListener('#submit-editorial', 'Submit Editorial button');
        addEventListener('#cancel-editorial', 'Cancel Editorial button');
    };

    var addFriendsPageButtonsToGA = function() {
        addEventListener('.friends-name', 'Friends name');
        addEventListener('.friends-unfriend', 'Friends unfriend');
        addEventListener('.friends-add-friend', 'Friends add friend');
    };

    var addSearchPageButtonsToGA = function() {
        addEventListener('.search-add-friend', 'Search add friend');
        addEventListener('.search-unfriend', 'Search unfriend');
        addEventListener('.search-site-profile', 'Search site profile');
        addEventListener('.search-user-name', 'Search user name');
    };

    var addContestPageButtonsToGA = function() {
        addEventListener('.view-contest', 'View Contest');
        addEventListener('.set-reminder', 'Set reminder');

    };

    var addLeaderboardPageButtonsToGA = function() {
        addEventListener('.leaderboard-institute', 'Leaderboard Institute');
        addEventListener('.leaderboard-country-flag', 'Leaderboard Country');
        addEventListener('.leaderboard-stopstalk-handle', 'Leaderboard StopStalk handle');
        addEventListener('#leaderboard-switch', 'Leaderboard Switch');
    };

    var addTagsPageButtonsToGA = function() {
        addEventListener('.tag-problem-link', 'Tags problem link');
        addEventListener('.tags-chip', 'Tags page chip');
    };

    $(document).ready(function() {
        addNavItemsToGA();
        addSubmissionPageButtonsToGA();
        addProblemPageButtonsToGA();
        addProfilePageButtonsToGA();
        addFriendsPageButtonsToGA();
        addSearchPageButtonsToGA();
        addContestPageButtonsToGA();
        addLeaderboardPageButtonsToGA();
        addTagsPageButtonsToGA();
        addMiscellaneousToGA();
    });
})(jQuery);
<|endoftext|>


<commit_before>var nr = require('newrelic')
var slSystems = require('./slSystemsCrawler')
var Bacon = require('baconjs').Bacon
var _ = require('lodash')
var webTimmi = require('./webTimmiCrawler')
var DateTime = require('dateutils').DateTime
var MongoClient = require('mongodb').MongoClient
var mongoUri = process.env.MONGOLAB_URI || process.env.MONGOHQ_URL || 'mongodb://localhost/test';
var rates = require('../../generated/rates')
var format = require('../format')

module.exports = {
    sendFreeCourts: sendFreeCourts,
    freeCourts:     freeCourts,
    refresh:        refresh,
    fetch:          fetch,
    getHistoryData: getHistoryData
}

function sendFreeCourts(req, res) {
    var forceRefresh = req.query.refresh === 'true' || false
    freeCourts(req.query.date, Number(req.query.days) || 1, forceRefresh,
        data => res.send(data),
        err => res.status(500).send(err))
}

function freeCourts(isoDate, days, forceRefresh, callback, errCallback) {
    if (forceRefresh) {
        refresh(isoDate, days, data => { doCallback(data) })
    } else {
        getFromMongo(isoDate, days, (err, data) => {
            if (err) {
                errCallback(err)
            } else if (data.length > 0) {
                console.log('fetching from db for date', isoDate, days, data.length)
                doCallback(data)
            } else {
                refresh(isoDate, days, (data) => { doCallback(data) })
            }
        })
    }

    function doCallback(data) {
        callback(data.timestamp ? [data] : data)
    }
}

function refresh(isoDate, days, callback) {
    console.log('fetching from servers for date', isoDate)
    nr.createBackgroundTransaction('fetch:reservations', fetch(isoDate).onValue((obj) => {
        upsertToMongo(isoDate, obj)
        nr.endTransaction()
        callback(obj)
    }))

}

function getHistoryData(callback) {
    var start = DateTime.fromDate(2015,10,5)
    var end = new DateTime()
    mongoQuery({date: {$gte: start.date, $lte:end.date}}, (err, data) => callback(err, transform(data)) )
}

function transform(data) {
    return _.flatten(data.map(row => row.freeCourts))
}

function getFromMongo(isoDate, days, callback) {
    var start = DateTime.fromIsoDate(isoDate)
    var end = start.plusDays(days - 1)
    var filter = {date: {$gte: start.date, $lte: end.date}}
    mongoQuery(filter, callback)
}

function mongoQuery(filter, callback) {
    MongoClient.connect(mongoUri, (err, db) => {
        var collection = db.collection('tennishelsinki')
        collection.find(filter).sort({date: 1}).toArray((err, docs) => {
            var transformedDoc = docs.map((doc) => {
                doc.created = doc._id.getTimestamp && doc._id.getTimestamp().toISOString()
                return doc
            })
            callback(err, transformedDoc)
            db.close()
        })
    })
}

function upsertToMongo(isoDate, obj) {
    MongoClient.connect(mongoUri, (err, db) => {
        const collection = db.collection('tennishelsinki')
        const date = new Date(isoDate)
        collection.updateOne({date: date}, {
            date:       date,
            freeCourts: obj.freeCourts,
            timestamp:  obj.timestamp
        }, {
            upsert: true
        }, (err, rs) => {
            db.close()
        })
    })
}

function getType(reservation) {
    var isBubble = /kupla/i.test(reservation.field) || /kupla/i.test(reservation.res) || /Kaarihalli.*/i.test(reservation.field)
    var isOutdoor = /ulko/i.test(reservation.field) || /ulko/i.test(reservation.res)
    return isBubble ? 'bubble' : (isOutdoor ? 'outdoor' : 'indoor')
}
function fetch(isoDate) {
    return Bacon.combineAsArray([
            slSystems.getMeilahti,
            slSystems.getHerttoniemi,
            slSystems.getKulosaari,
            slSystems.getMerihaka,
            slSystems.getTapiola,
            slSystems.getLaajasalo,
            slSystems.getHiekkaharju,
            webTimmi.getAll].map(function (fn) { return fn(isoDate) }))
        .map(function (allData) {
            var freeCourts = _.flatten(allData).filter(function (reservation) {
                if (!reservation || !reservation.field) return false
                return reservation.date === isoDate
            }).map(function (reservation) {
                var dateTime = DateTime.fromIsoDateTime(reservation.date + 'T' + reservation.time)
                var type = getType(reservation)
                reservation.type = type
                reservation.price = getPrice(dateTime, reservation.time, reservation.location, type)
                return reservation
            })
            return {
                freeCourts: withDoubleLessonInfo(freeCourts),
                timestamp:  new Date().getTime(),
                date:       isoDate
            }
        })
}

function getPrice(dateTime, time, location, type) {
    var hm = time.split(':')
    var timeKey = format.formatTimeKey(hm)
    var weekDay = (dateTime.getDay() + 6) % 7
    var priceByType = _.get(rates, [location, type, timeKey, weekDay], 0)
    var commonPrice = _.get(rates, [location, timeKey, weekDay], 0)
    return priceByType || commonPrice
}

function withDoubleLessonInfo(freeCourts) {
    var timeAndPlace = {}
    freeCourts.forEach(function (court) {
        timeAndPlace[court.date + 'T' + court.time + court.location + court.field] = true
    })
    return freeCourts.map(function (court) {
        var nextTime = nextHour(court.time)
        court.doubleLesson = (court.date + 'T' + nextTime + court.location + court.field) in timeAndPlace
        return court
    })
}

function nextHour(time) {
    var hm = time.split(':')
    var next = Number(hm[0]) + 1
    return (next > 9 ? '' : '0') + next + ':' + hm[1]
}
<commit_msg>Make Mongo client work faster<commit_after>var nr = require('newrelic')
var slSystems = require('./slSystemsCrawler')
var Bacon = require('baconjs').Bacon
var _ = require('lodash')
var webTimmi = require('./webTimmiCrawler')
var DateTime = require('dateutils').DateTime
var MongoClient = require('mongodb').MongoClient
var mongoUri = process.env.MONGOLAB_URI || process.env.MONGOHQ_URL || 'mongodb://localhost/test';
var rates = require('../../generated/rates')
var format = require('../format')
var db = null

module.exports = {
    sendFreeCourts: sendFreeCourts,
    freeCourts:     freeCourts,
    refresh:        refresh,
    fetch:          fetch,
    getHistoryData: getHistoryData
}

function sendFreeCourts(req, res) {
    var forceRefresh = req.query.refresh === 'true' || false
    freeCourts(req.query.date, Number(req.query.days) || 1, forceRefresh,
        data => res.send(data),
        err => res.status(500).send(err))
}

function freeCourts(isoDate, days, forceRefresh, callback, errCallback) {
    if (forceRefresh) {
        refresh(isoDate, days, data => { doCallback(data) })
    } else {
        getFromMongo(isoDate, days, (err, data) => {
            if (err) {
                errCallback(err)
            } else if (data.length > 0) {
                console.log('fetching from db for date', isoDate, days, data.length)
                doCallback(data)
            } else {
                refresh(isoDate, days, (data) => { doCallback(data) })
            }
        })
    }

    function doCallback(data) {
        callback(data.timestamp ? [data] : data)
    }
}

function refresh(isoDate, days, callback) {
    console.log('fetching from servers for date', isoDate)
    nr.createBackgroundTransaction('fetch:reservations', fetch(isoDate).onValue((obj) => {
        upsertToMongo(isoDate, obj)
        nr.endTransaction()
        callback(obj)
    }))

}

function getHistoryData(callback) {
    var start = DateTime.fromDate(2015,10,5)
    var end = new DateTime()
    mongoQuery({date: {$gte: start.date, $lte:end.date}}, (err, data) => callback(err, transform(data)) )
}

function transform(data) {
    return _.flatten(data.map(row => row.freeCourts))
}

function getFromMongo(isoDate, days, callback) {
    var start = DateTime.fromIsoDate(isoDate)
    var end = start.plusDays(days - 1)
    var filter = {date: {$gte: start.date, $lte: end.date}}
    mongoQuery(filter, callback)
}

function mongoQuery(filter, callback) {
    mongoConnect((err, db) => {
        var collection = db.collection('tennishelsinki')
        collection.find(filter).sort({date: 1}).toArray((err, docs) => {
            var transformedDoc = docs.map((doc) => {
                doc.created = doc._id.getTimestamp && doc._id.getTimestamp().toISOString()
                return doc
            })
            callback(err, transformedDoc)
            //db.close()
        })
    })
}

function upsertToMongo(isoDate, obj) {
    mongoConnect((err, db) => {
        const collection = db.collection('tennishelsinki')
        const date = new Date(isoDate)
        collection.updateOne({date: date}, {
            date:       date,
            freeCourts: obj.freeCourts,
            timestamp:  obj.timestamp
        }, {
            upsert: true
        }, (err, rs) => {
            db.close()
        })
    })
}

function getType(reservation) {
    var isBubble = /kupla/i.test(reservation.field) || /kupla/i.test(reservation.res) || /Kaarihalli.*/i.test(reservation.field)
    var isOutdoor = /ulko/i.test(reservation.field) || /ulko/i.test(reservation.res)
    return isBubble ? 'bubble' : (isOutdoor ? 'outdoor' : 'indoor')
}
function fetch(isoDate) {
    return Bacon.combineAsArray([
            slSystems.getMeilahti,
            slSystems.getHerttoniemi,
            slSystems.getKulosaari,
            slSystems.getMerihaka,
            slSystems.getTapiola,
            slSystems.getLaajasalo,
            slSystems.getHiekkaharju,
            webTimmi.getAll].map(function (fn) { return fn(isoDate) }))
        .map(function (allData) {
            var freeCourts = _.flatten(allData).filter(function (reservation) {
                if (!reservation || !reservation.field) return false
                return reservation.date === isoDate
            }).map(function (reservation) {
                var dateTime = DateTime.fromIsoDateTime(reservation.date + 'T' + reservation.time)
                var type = getType(reservation)
                reservation.type = type
                reservation.price = getPrice(dateTime, reservation.time, reservation.location, type)
                return reservation
            })
            return {
                freeCourts: withDoubleLessonInfo(freeCourts),
                timestamp:  new Date().getTime(),
                date:       isoDate
            }
        })
}

function getPrice(dateTime, time, location, type) {
    var hm = time.split(':')
    var timeKey = format.formatTimeKey(hm)
    var weekDay = (dateTime.getDay() + 6) % 7
    var priceByType = _.get(rates, [location, type, timeKey, weekDay], 0)
    var commonPrice = _.get(rates, [location, timeKey, weekDay], 0)
    return priceByType || commonPrice
}

function withDoubleLessonInfo(freeCourts) {
    var timeAndPlace = {}
    freeCourts.forEach(function (court) {
        timeAndPlace[court.date + 'T' + court.time + court.location + court.field] = true
    })
    return freeCourts.map(function (court) {
        var nextTime = nextHour(court.time)
        court.doubleLesson = (court.date + 'T' + nextTime + court.location + court.field) in timeAndPlace
        return court
    })
}

function nextHour(time) {
    var hm = time.split(':')
    var next = Number(hm[0]) + 1
    return (next > 9 ? '' : '0') + next + ':' + hm[1]
}

function mongoConnect(cb) {
    if(db) cb(null, db)
    else {
        MongoClient.connect(mongoUri, (err, dbConn) => {
            if(db) {
                dbConn.close()
            } else {
                db = dbConn
            }
            cb(err, db)
        })
    }
}
<|endoftext|>


<commit_before>describe('Backbone Polling Methods', function() {

    /**
     * Helper function that creates a spy and associates it with an object mixed with the backbone polling plugin and a
     * plugin event
     * @param objectMixedWithPlugin the object mixed with the plugin
     * @param eventName the name of the event that when triggered will call the spy
     * @returns {*}
     */
    var createSpyForPluginEvent = function(objectMixedWithPlugin, eventName) {
        var callbackForEvent = jasmine.createSpy();
        objectMixedWithPlugin.listenTo(objectMixedWithPlugin, eventName, callbackForEvent);
        return callbackForEvent;
    };

    beforeEach(function() {
        this.BackboneCollection = Backbone.Collection.extend({
            url: '/processes'
        });

        // Add backbone polling mixin
        _.extend(this.BackboneCollection.prototype, window.BackbonePolling);
        this.collection = new this.BackboneCollection();

        this.BackboneModel = Backbone.Model.extend({
            url: '/process'
        });

        // Add backbone polling mixin
        _.extend(this.BackboneModel.prototype, window.BackbonePolling);
        this.model = new this.BackboneModel();
    });

    afterEach(function() {
        this.collection.stopFetching();
        this.model.stopFetching();
        this.collection.stopListening();
        delete this.model;
        delete this.collection;
    });

    it('can stop start and stop fetching', function() {
        this.collection.startFetching();
        expect(this.collection.isFetching()).toBe(true);
        this.collection.stopFetching();
        expect(this.collection.isFetching()).toBe(false);
    });

    it('can query the data source multiple times', function() {
        var counter = 1;
        var continueFlag = false;
        var numberOfTimesToCallBeforeContinuing = 3;

        spyOn(this.collection, 'fetch').andCallFake(function() {
            var dfd = $.Deferred();
            dfd.resolve();
            return dfd.promise();
        });

        this.collection.configure({ refresh: 10 });

        this.collection.listenTo(this.collection, 'refresh:done', function() {
            continueFlag = (counter++ === numberOfTimesToCallBeforeContinuing);
        });

        var callbackAlways = createSpyForPluginEvent(this.collection, 'refresh:always');

        this.collection.startFetching();

        waitsFor(function(){
            return continueFlag;
        });

        runs(function () {
            expect(this.collection.isFetching()).toBe(true);
            expect(callbackAlways).toHaveBeenCalled();
            expect(callbackAlways.callCount).toBe(numberOfTimesToCallBeforeContinuing);
        });
    });

    it('can configure callback functions', function() {
        var counter = 1;
        var continueFlag = false;
        var numberOfTimesToCallBeforeContinuing = 3;

        spyOn(this.collection, 'fetch').andCallFake(function() {
            var dfd = $.Deferred();
            if(counter < numberOfTimesToCallBeforeContinuing) {
                dfd.resolve();
            } else {
                dfd.reject();
            }
            return dfd.promise();
        });

        this.collection.configure({ refresh: 10 });

        var callbackFail = createSpyForPluginEvent(this.collection, 'refresh:fail');
        var callbackDone = createSpyForPluginEvent(this.collection, 'refresh:done');

        this.collection.listenTo(this.collection, 'refresh:always', function() {
            continueFlag = (counter++ === numberOfTimesToCallBeforeContinuing);
        });

        this.collection.startFetching();

        waitsFor(function(){
            return continueFlag;
        });

        runs(function () {
            expect(this.collection.isFetching()).toBe(true);
            expect(callbackDone).toHaveBeenCalled();
            expect(callbackFail).toHaveBeenCalled();
            expect(callbackDone.callCount).toBe(2);
            expect(callbackFail.callCount).toBe(1);
        });
    });

    it('can automatically retry a failed fetch', function() {
        var counter = 1;
        var continueFlag = false;
        var numberOfTimesToCallBeforeContinuing = 2;

        spyOn(this.collection, 'fetch').andCallFake(function() {
            var dfd = $.Deferred();
            dfd.reject();
            return dfd.promise();
        });

        this.collection.configure({
            refresh: 10,
            retryRequestOnFetchFail: true
        });

        var callbackFail = createSpyForPluginEvent(this.collection, 'refresh:fail');

        this.collection.listenTo(this.collection, 'refresh:always', function() {
            continueFlag = (counter++ === numberOfTimesToCallBeforeContinuing);
        });

        this.collection.startFetching();

        waitsFor(function(){
            return continueFlag;
        });

        runs(function () {
            expect(this.collection.isFetching()).toBe(true);
            expect(callbackFail).toHaveBeenCalled();
            expect(callbackFail.callCount).toBe(numberOfTimesToCallBeforeContinuing);
        });
    });

    it('can disable an automatic retry of a failed fetch', function() {
        var self = this;
        var counter = 1;
        var continueFlag = false;
        var numberOfTimesToCallBeforeContinuing = 2;

        spyOn(this.collection, 'fetch').andCallFake(function() {
            var dfd = $.Deferred();
            dfd.reject();
            return dfd.promise();
        });

        this.collection.configure({
            refresh: 10,
            retryRequestOnFetchFail: false
        });

        var callbackFail = createSpyForPluginEvent(this.collection, 'refresh:fail');

        this.collection.listenTo(this.collection, 'refresh:always', function() {
            continueFlag = (counter++ === numberOfTimesToCallBeforeContinuing) ||
                (self.collection.isFetching() === false);
        });

        this.collection.startFetching();

        waitsFor(function(){
            return continueFlag;
        });

        runs(function () {
            expect(this.collection.isFetching()).toBe(false);
            expect(callbackFail).toHaveBeenCalled();
            expect(callbackFail.callCount).toBe(1);
        });

    });

});
<commit_msg>Fixed a description of a test<commit_after>describe('Backbone Polling Methods', function() {

    /**
     * Helper function that creates a spy and associates it with an object mixed with the backbone polling plugin and a
     * plugin event
     * @param objectMixedWithPlugin the object mixed with the plugin
     * @param eventName the name of the event that when triggered will call the spy
     * @returns {*}
     */
    var createSpyForPluginEvent = function(objectMixedWithPlugin, eventName) {
        var callbackForEvent = jasmine.createSpy();
        objectMixedWithPlugin.listenTo(objectMixedWithPlugin, eventName, callbackForEvent);
        return callbackForEvent;
    };

    beforeEach(function() {
        this.BackboneCollection = Backbone.Collection.extend({
            url: '/processes'
        });

        // Add backbone polling mixin
        _.extend(this.BackboneCollection.prototype, window.BackbonePolling);
        this.collection = new this.BackboneCollection();

        this.BackboneModel = Backbone.Model.extend({
            url: '/process'
        });

        // Add backbone polling mixin
        _.extend(this.BackboneModel.prototype, window.BackbonePolling);
        this.model = new this.BackboneModel();
    });

    afterEach(function() {
        this.collection.stopFetching();
        this.model.stopFetching();
        this.collection.stopListening();
        delete this.model;
        delete this.collection;
    });

    it('can start and stop fetching', function() {
        this.collection.startFetching();
        expect(this.collection.isFetching()).toBe(true);
        this.collection.stopFetching();
        expect(this.collection.isFetching()).toBe(false);
    });

    it('can query the data source multiple times', function() {
        var counter = 1;
        var continueFlag = false;
        var numberOfTimesToCallBeforeContinuing = 3;

        spyOn(this.collection, 'fetch').andCallFake(function() {
            var dfd = $.Deferred();
            dfd.resolve();
            return dfd.promise();
        });

        this.collection.configure({ refresh: 10 });

        this.collection.listenTo(this.collection, 'refresh:done', function() {
            continueFlag = (counter++ === numberOfTimesToCallBeforeContinuing);
        });

        var callbackAlways = createSpyForPluginEvent(this.collection, 'refresh:always');

        this.collection.startFetching();

        waitsFor(function(){
            return continueFlag;
        });

        runs(function () {
            expect(this.collection.isFetching()).toBe(true);
            expect(callbackAlways).toHaveBeenCalled();
            expect(callbackAlways.callCount).toBe(numberOfTimesToCallBeforeContinuing);
        });
    });

    it('can configure callback functions', function() {
        var counter = 1;
        var continueFlag = false;
        var numberOfTimesToCallBeforeContinuing = 3;

        spyOn(this.collection, 'fetch').andCallFake(function() {
            var dfd = $.Deferred();
            if(counter < numberOfTimesToCallBeforeContinuing) {
                dfd.resolve();
            } else {
                dfd.reject();
            }
            return dfd.promise();
        });

        this.collection.configure({ refresh: 10 });

        var callbackFail = createSpyForPluginEvent(this.collection, 'refresh:fail');
        var callbackDone = createSpyForPluginEvent(this.collection, 'refresh:done');

        this.collection.listenTo(this.collection, 'refresh:always', function() {
            continueFlag = (counter++ === numberOfTimesToCallBeforeContinuing);
        });

        this.collection.startFetching();

        waitsFor(function(){
            return continueFlag;
        });

        runs(function () {
            expect(this.collection.isFetching()).toBe(true);
            expect(callbackDone).toHaveBeenCalled();
            expect(callbackFail).toHaveBeenCalled();
            expect(callbackDone.callCount).toBe(2);
            expect(callbackFail.callCount).toBe(1);
        });
    });

    it('can automatically retry a failed fetch', function() {
        var counter = 1;
        var continueFlag = false;
        var numberOfTimesToCallBeforeContinuing = 2;

        spyOn(this.collection, 'fetch').andCallFake(function() {
            var dfd = $.Deferred();
            dfd.reject();
            return dfd.promise();
        });

        this.collection.configure({
            refresh: 10,
            retryRequestOnFetchFail: true
        });

        var callbackFail = createSpyForPluginEvent(this.collection, 'refresh:fail');

        this.collection.listenTo(this.collection, 'refresh:always', function() {
            continueFlag = (counter++ === numberOfTimesToCallBeforeContinuing);
        });

        this.collection.startFetching();

        waitsFor(function(){
            return continueFlag;
        });

        runs(function () {
            expect(this.collection.isFetching()).toBe(true);
            expect(callbackFail).toHaveBeenCalled();
            expect(callbackFail.callCount).toBe(numberOfTimesToCallBeforeContinuing);
        });
    });

    it('can disable an automatic retry of a failed fetch', function() {
        var self = this;
        var counter = 1;
        var continueFlag = false;
        var numberOfTimesToCallBeforeContinuing = 2;

        spyOn(this.collection, 'fetch').andCallFake(function() {
            var dfd = $.Deferred();
            dfd.reject();
            return dfd.promise();
        });

        this.collection.configure({
            refresh: 10,
            retryRequestOnFetchFail: false
        });

        var callbackFail = createSpyForPluginEvent(this.collection, 'refresh:fail');

        this.collection.listenTo(this.collection, 'refresh:always', function() {
            continueFlag = (counter++ === numberOfTimesToCallBeforeContinuing) ||
                (self.collection.isFetching() === false);
        });

        this.collection.startFetching();

        waitsFor(function(){
            return continueFlag;
        });

        runs(function () {
            expect(this.collection.isFetching()).toBe(false);
            expect(callbackFail).toHaveBeenCalled();
            expect(callbackFail.callCount).toBe(1);
        });

    });

});
<|endoftext|>


<commit_before>/** @jsx React.DOM */

var React = require('react');

var C = require('../constants');
var routesStore = require('../stores/routes');
var Selector = require('./selector');
var PersonPicker = require('./person_picker');
var actions = require('../actions/me_actions');

module.exports = React.createClass({
  getInitialState: function() {
    return {routes: routesStore.routes, route: null}
  },
  _onRoutesChange: function() {
    this.setState( {routes: routesStore.routes} );
  },
  _handleNewLog: function() {
    if (!this.state.route) {
      alert ("Please make sure you selected route");
      return
    }
    actions.newLog(this.state.route, this.refs.personPicker ? this.refs.personPicker.state.selected : null);
    $('#dialogNewLog').modal('hide');
  },
  _handleRouteOnSelect: function(e) {
    this.setState({route: e.selectedRef});
  },
  componentDidMount: function() {
    routesStore.addChangeListener(this._onRoutesChange);
  },
  componentWillUnmount: function() {
    routesStore.removeChangeListener(this._onRoutesChange);
  },
  render: function() {
    var routeOptions = [];
    if (this.state.routes && this.state.routes.length) {
      for (var i = 0; i < this.state.routes.length; ++i) {
        var route = this.state.routes[i];
        if (!route || !route.enabled) {
          continue;
        }
        var style = {
          backgroundColor: route.background_color,
          color: route.color,
          padding: "4px 8px 4px 8px",
        };
        routeOptions.push({
          dom: (

                  {route.setter} | {route.name} | {route.is_half ? "Half" : "Full"} | {route.rating} | {route.ff ? "FF" : "AF"} | {C.Nats.all[route.nats]}

               ),
          ref: route,
        });
      }
      routeOptions.sort(function(a, b) {
        return C.Ratings[a.ref.rating] - C.Ratings[b.ref.rating];
      });
    }
    var info_tip;
    if (this.state.route && this.state.route.is_half) {
      info_tip = (

You have selected a route on one of the inside walls. Inside-wall routes count as half pitches. Remember to climb it twice before recording.

          );
    } else {
      info_tip = (

For routes on inside walls, you need to climb twice to count as one pitch.

          );
    }
    return (

        <button key="newpitch" type="button" className="btn btn-warning pull-right" data-toggle="modal" data-target="#dialogNewLog">New Pitch</button>

                <button key="button" type="button" className="close" data-dismiss="modal">×Close</button>

Record a New Pitch

                <form role="form">

                    Route

<Selector options={routeOptions} selectedRef={this.state.route} ref="routeSelector" onSelect={this._handleRouteOnSelect} />

                    {info_tip}

                  {/* Uncomment this to enable partners

                    Partner
                    <PersonPicker key="picker" ref="personPicker"/>

                  */}

                </form>

By clicking submit, I swear to Mr. Aubie that I did climb the route at Auburn University Recreation Center following the route specs.

                <button key="close" type="button" className="btn btn-default" data-dismiss="modal">Close</button>
                <button key="create" type="button" className="btn btn-primary" onClick={this._handleNewLog}>Create</button>

    )
  },
});
<commit_msg>clarification about inside walls<commit_after>/** @jsx React.DOM */

var React = require('react');

var C = require('../constants');
var routesStore = require('../stores/routes');
var Selector = require('./selector');
var PersonPicker = require('./person_picker');
var actions = require('../actions/me_actions');

module.exports = React.createClass({
  getInitialState: function() {
    return {routes: routesStore.routes, route: null}
  },
  _onRoutesChange: function() {
    this.setState( {routes: routesStore.routes} );
  },
  _handleNewLog: function() {
    if (!this.state.route) {
      alert ("Please make sure you selected route");
      return
    }
    actions.newLog(this.state.route, this.refs.personPicker ? this.refs.personPicker.state.selected : null);
    $('#dialogNewLog').modal('hide');
  },
  _handleRouteOnSelect: function(e) {
    this.setState({route: e.selectedRef});
  },
  componentDidMount: function() {
    routesStore.addChangeListener(this._onRoutesChange);
  },
  componentWillUnmount: function() {
    routesStore.removeChangeListener(this._onRoutesChange);
  },
  render: function() {
    var routeOptions = [];
    if (this.state.routes && this.state.routes.length) {
      for (var i = 0; i < this.state.routes.length; ++i) {
        var route = this.state.routes[i];
        if (!route || !route.enabled) {
          continue;
        }
        var style = {
          backgroundColor: route.background_color,
          color: route.color,
          padding: "4px 8px 4px 8px",
        };
        routeOptions.push({
          dom: (

                  {route.setter} | {route.name} | {route.is_half ? "Half" : "Full"} | {route.rating} | {route.ff ? "FF" : "AF"} | {C.Nats.all[route.nats]}

               ),
          ref: route,
        });
      }
      routeOptions.sort(function(a, b) {
        return C.Ratings[a.ref.rating] - C.Ratings[b.ref.rating];
      });
    }
    var info_tip;
    if (this.state.route && this.state.route.is_half) {
      info_tip = (

You have selected a route on one of the inside walls. Inside-wall routes count as half pitches. Remember to climb it twice before recording. (You only need to record the pitch once for the two climbs.)

          );
    } else {
      info_tip = (

For routes on inside walls, you need to climb twice to count as one pitch.

          );
    }
    return (

        <button key="newpitch" type="button" className="btn btn-warning pull-right" data-toggle="modal" data-target="#dialogNewLog">New Pitch</button>

                <button key="button" type="button" className="close" data-dismiss="modal">×Close</button>

Record a New Pitch

                <form role="form">

                    Route

<Selector options={routeOptions} selectedRef={this.state.route} ref="routeSelector" onSelect={this._handleRouteOnSelect} />

                    {info_tip}

                  {/* Uncomment this to enable partners

                    Partner
                    <PersonPicker key="picker" ref="personPicker"/>

                  */}

                </form>

By clicking submit, I swear to Mr. Aubie that I did climb the route at Auburn University Recreation Center following the route specs.

                <button key="close" type="button" className="btn btn-default" data-dismiss="modal">Close</button>
                <button key="create" type="button" className="btn btn-primary" onClick={this._handleNewLog}>Create</button>

    )
  },
});
<|endoftext|>


<commit_before>progressApp.factory("ProgressService", ["$uibModal", function($uibModal) {
	var obj = {};

	obj.open = function(progressTitle, cancel, update) {
		$uibModal.open({
			animation: true,
			ariaLabelledBy: 'modal-title',
			ariaDescribedBy: 'modal-body',
			templateUrl: '/static/progress/progressContent.html',
			controller: 'progressInstanceCtrl',
			controllerAs: 'progressCtrl',
			resolve: {
				progressTitle: function() {
					return progressTitle;
				},
				cancel: function() {
					return cancel;
				},
				update: function() {
					return update;
				}
			}
		});
	};

	return obj;
}]);<commit_msg>Made progress dialog modal.<commit_after>progressApp.factory("ProgressService", ["$uibModal", function($uibModal) {
	var obj = {};

	obj.open = function(progressTitle, cancel, update) {
		$uibModal.open({
			animation: true,
			ariaLabelledBy: 'modal-title',
			ariaDescribedBy: 'modal-body',
			templateUrl: '/static/progress/progressContent.html',
			controller: 'progressInstanceCtrl',
			controllerAs: 'progressCtrl',
			backdrop: 'static',
			keyboard: false,
			resolve: {
				progressTitle: function() {
					return progressTitle;
				},
				cancel: function() {
					return cancel;
				},
				update: function() {
					return update;
				}
			}
		});
	};

	return obj;
}]);<|endoftext|>


<commit_before>import {Form} from 'widget/form/form'
import {MosaicPreview} from '../../../mosaic/mosaicPreview'
import {NoData} from 'widget/noData'
import {Panel} from 'widget/panel/panel'
import {RecipeActions} from '../../classificationRecipe'
import {RecipeFormPanel, recipeFormPanel} from 'app/home/body/process/recipeFormPanel'
import {SuperButton} from 'widget/superButton'
import {activator} from 'widget/activation/activator'
import {compose} from 'compose'
import {connect} from 'store'
import {msg} from 'translate'
import {selectFrom} from 'stateUtils'
import InputImage from './inputImage'
import React from 'react'
import guid from 'guid'
import styles from './inputImagery.module.css'

const mapRecipeToProps = recipe => ({
    images: selectFrom(recipe, 'model.inputImagery.images') || []
})

const mapStateToProps = (state, ownProps) => {
    const {images} = ownProps
    const recipeNameById = {}
    images
        .filter(image => image.type === 'RECIPE_REF')
        .map(image => selectFrom(state, ['process.recipes', {id: image.id}]))
        .filter(recipe => recipe)
        .forEach(recipe => recipeNameById[recipe.id] = recipe.name)
    return {recipeNameById}
}

class InputImagery extends React.Component {
    constructor(props) {
        super(props)
        const {recipeId} = props
        this.preview = MosaicPreview(recipeId)
    }

    render() {
        const {images} = this.props
        return (
            <React.Fragment>
                <RecipeFormPanel
                    className={styles.panel}
                    placement='bottom-right'
                    onClose={() => this.preview.show()}>
                    <Panel.Header
                        icon='image'
                        title={msg('process.classification.panel.inputImagery.title')}/>
                    <Panel.Content>
                        {this.renderContent()}
                    </Panel.Content>
                    <Form.PanelButtons invalid={!images.length}>
                        <Panel.Buttons.Add onClick={() => this.addImage()}/>
                    </Form.PanelButtons>
                </RecipeFormPanel>
                <InputImage/>
            </React.Fragment>
        )
    }

    renderContent() {
        const {images = []} = this.props
        return images.length
            ? this.renderImages(images)
            : this.renderNoImageryMessage()
    }

    renderImages(images) {
        return images.map(image => this.renderImage(image))
    }

    renderImage(image) {
        const {recipeNameById} = this.props
        const name = image.type === 'RECIPE_REF'
            ? recipeNameById[image.id]
            : image.id
        if (!name)
            return null
        return (
            <SuperButton
                key={`${image.type}-${image.id}`}
                title={msg(`process.classification.panel.inputImagery.type.${image.type}`)}
                description={name}
                removeMessage={msg('process.classification.panel.inputImagery.remove.confirmationMessage', {name})}
                removeTooltip={msg('process.classification.panel.inputImagery.remove.tooltip')}
                onClick={() => this.editImage(image)}
                onRemove={() => this.removeImage(image)}
            />
        )
    }

    renderNoImageryMessage() {
        return (
            <NoData message={msg('process.classification.panel.inputImagery.noImagery')}></NoData>
        )
    }

    addImage() {
        const {activator: {activatables: {inputImage}}} = this.props
        inputImage.activate({imageId: guid()})
    }

    editImage(image) {
        const {activator: {activatables: {inputImage}}} = this.props
        inputImage.activate({imageId: image.imageId})
    }

    componentDidMount() {
        this.preview.hide()
    }

    removeImage(imageToRemove) {
        const {recipeId} = this.props

        RecipeActions(recipeId).removeInputImage(imageToRemove)
    }
}

InputImagery.propTypes = {}
const additionalPolicy = () => ({_: 'allow'})
// [HACK] This actually isn't a form, and we don't want to update the model. This prevents the selected images from
// being overridden.
const valuesToModel = null

export default compose(
    InputImagery,
    connect(mapStateToProps),
    recipeFormPanel({id: 'inputImagery', mapRecipeToProps, valuesToModel, additionalPolicy}),
    activator('inputImage')
)
<commit_msg>Removed confirmation message when removing a classification input image.<commit_after>import {Form} from 'widget/form/form'
import {MosaicPreview} from '../../../mosaic/mosaicPreview'
import {NoData} from 'widget/noData'
import {Panel} from 'widget/panel/panel'
import {RecipeActions} from '../../classificationRecipe'
import {RecipeFormPanel, recipeFormPanel} from 'app/home/body/process/recipeFormPanel'
import {SuperButton} from 'widget/superButton'
import {activator} from 'widget/activation/activator'
import {compose} from 'compose'
import {connect} from 'store'
import {msg} from 'translate'
import {selectFrom} from 'stateUtils'
import InputImage from './inputImage'
import React from 'react'
import guid from 'guid'
import styles from './inputImagery.module.css'

const mapRecipeToProps = recipe => ({
    images: selectFrom(recipe, 'model.inputImagery.images') || []
})

const mapStateToProps = (state, ownProps) => {
    const {images} = ownProps
    const recipeNameById = {}
    images
        .filter(image => image.type === 'RECIPE_REF')
        .map(image => selectFrom(state, ['process.recipes', {id: image.id}]))
        .filter(recipe => recipe)
        .forEach(recipe => recipeNameById[recipe.id] = recipe.name)
    return {recipeNameById}
}

class InputImagery extends React.Component {
    constructor(props) {
        super(props)
        const {recipeId} = props
        this.preview = MosaicPreview(recipeId)
    }

    render() {
        const {images} = this.props
        return (
            <React.Fragment>
                <RecipeFormPanel
                    className={styles.panel}
                    placement='bottom-right'
                    onClose={() => this.preview.show()}>
                    <Panel.Header
                        icon='image'
                        title={msg('process.classification.panel.inputImagery.title')}/>
                    <Panel.Content>
                        {this.renderContent()}
                    </Panel.Content>
                    <Form.PanelButtons invalid={!images.length}>
                        <Panel.Buttons.Add onClick={() => this.addImage()}/>
                    </Form.PanelButtons>
                </RecipeFormPanel>
                <InputImage/>
            </React.Fragment>
        )
    }

    renderContent() {
        const {images = []} = this.props
        return images.length
            ? this.renderImages(images)
            : this.renderNoImageryMessage()
    }

    renderImages(images) {
        return images.map(image => this.renderImage(image))
    }

    renderImage(image) {
        const {recipeNameById} = this.props
        const name = image.type === 'RECIPE_REF'
            ? recipeNameById[image.id]
            : image.id
        if (!name)
            return null
        return (
            <SuperButton
                key={`${image.type}-${image.id}`}
                title={msg(`process.classification.panel.inputImagery.type.${image.type}`)}
                description={name}
                removeTooltip={msg('process.classification.panel.inputImagery.remove.tooltip')}
                onClick={() => this.editImage(image)}
                onRemove={() => this.removeImage(image)}
            />
        )
    }

    renderNoImageryMessage() {
        return (
            <NoData message={msg('process.classification.panel.inputImagery.noImagery')}/>
        )
    }

    addImage() {
        const {activator: {activatables: {inputImage}}} = this.props
        inputImage.activate({imageId: guid()})
    }

    editImage(image) {
        const {activator: {activatables: {inputImage}}} = this.props
        inputImage.activate({imageId: image.imageId})
    }

    componentDidMount() {
        this.preview.hide()
    }

    removeImage(imageToRemove) {
        const {recipeId} = this.props

        RecipeActions(recipeId).removeInputImage(imageToRemove)
    }
}

InputImagery.propTypes = {}
const additionalPolicy = () => ({_: 'allow'})
// [HACK] This actually isn't a form, and we don't want to update the model. This prevents the selected images from
// being overridden.
const valuesToModel = null

export default compose(
    InputImagery,
    connect(mapStateToProps),
    recipeFormPanel({id: 'inputImagery', mapRecipeToProps, valuesToModel, additionalPolicy}),
    activator('inputImage')
)
<|endoftext|>