]> git.immae.eu Git - perso/Immae/Projets/Scripts/Public.git/commitdiff
Commit initial
authorIsmaël Bouya <ismael.bouya@normalesup.org>
Tue, 13 Jan 2015 22:35:48 +0000 (23:35 +0100)
committerIsmaël Bouya <ismael.bouya@normalesup.org>
Tue, 13 Jan 2015 22:35:48 +0000 (23:35 +0100)
12 files changed:
cmdtemp [new file with mode: 0755]
color-bash [new file with mode: 0755]
comptes [new file with mode: 0755]
execurl [new file with mode: 0755]
gen_html_documents [new file with mode: 0755]
git-latexdiff [new file with mode: 0755]
interrogations [new file with mode: 0755]
mails_iprof [new file with mode: 0755]
mutt_check_attachment [new file with mode: 0755]
parse_bibtex_html [new file with mode: 0755]
remove_attachements [new file with mode: 0755]
unicode_chars [new file with mode: 0755]

diff --git a/cmdtemp b/cmdtemp
new file mode 100755 (executable)
index 0000000..37bcc82
--- /dev/null
+++ b/cmdtemp
@@ -0,0 +1,68 @@
+#!/usr/bin/env bash
+# The MIT License (MIT)
+# 
+# Copyright (c) 2011-2015 Ismaël Bouya http://www.normalesup.org/~bouya/
+# 
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+# 
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+# cmdtemp
+#   List commands
+# cmdtemp <n>
+#   Execute command number <n>
+# cmdtemp <-n>
+#   Delete command number <n>
+# cmdtemp <...>
+#   Save command
+
+
+function is_negative() {
+    s=$(echo $1 | tr -d 0-9)
+    if [ "$s" == "-" ]; then
+        return 0
+    else
+        return 1
+    fi
+}
+
+function is_integer() {
+    s=$(echo $1 | tr -d 0-9)
+    if [ -z "$s" ]; then
+        return 0
+    else
+        return 1
+    fi
+}
+
+if [ $# -eq 0 ]; then
+   cat -n $HOME/.cmdtemp
+   exit
+fi
+
+if is_integer "$1"; then
+   ligne="$1"
+   shift
+   commande=`awk "FNR == $ligne" $HOME/.cmdtemp`
+   echo "*** "$commande
+   eval $commande
+elif is_negative "$1"; then
+    s=$(echo $1 | tr -d '-')
+    sed -i -e $s"d" $HOME/.cmdtemp
+else
+    echo "$*" >> $HOME/.cmdtemp
+fi
diff --git a/color-bash b/color-bash
new file mode 100755 (executable)
index 0000000..0331293
--- /dev/null
@@ -0,0 +1,53 @@
+#!/usr/bin/env bash
+# The MIT License (MIT)
+# 
+# Copyright (c) 2011-2015 Ismaël Bouya http://www.normalesup.org/~bouya/
+# 
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+# 
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+
+echo "   Bg   | Fg"
+printf -- '-%.0s' {1..122} ; echo ""
+for((bg=40;bg<=47;bg++)); do
+  for int in 0 60; do
+    for b in 0 1 4 7 9; do
+      if [ $bg -gt 40 -a "(" $b = 7 -o $b = 9 -o $b = 4 ")" ]; then
+        continue
+      fi
+
+      if [ $b = "0" ]; then
+        echo -en "\033[0m""ESC[$((${bg}+${int}))m"
+        if [ $int = 0 ]; then
+          echo -n " "
+        fi
+        echo -n "| "
+      else
+        echo -en "        | "
+      fi
+
+      for((fg=30;fg<=37;fg++)); do
+        echo -en "\033[$((${bg}+${int}))m\033[${b};${fg}m [${b};${fg}m"
+        echo -en "\033[$((${bg}+${int}))m\033[${b};$((${fg}+60))m [${b};$((${fg}+60))m"
+      done
+
+      echo -e "\033[0m"
+    done
+  done
+  printf -- '-%.0s' {1..122} ; echo ""
+done
diff --git a/comptes b/comptes
new file mode 100755 (executable)
index 0000000..0fbacf2
--- /dev/null
+++ b/comptes
@@ -0,0 +1,446 @@
+#!/usr/bin/en perl
+# The MIT License (MIT)
+# 
+# Copyright (c) 2011-2015 Ismaël Bouya http://www.normalesup.org/~bouya/
+# 
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+# 
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+use Switch;
+use strict;
+
+my $file = "comptes.data";
+
+my @actions=('Ajouter un participant');
+my %participants = ();
+my @transactions = ();
+my @descriptions = ();
+my $evenement_def;
+my $remboursements = "";
+
+if($#ARGV==0) {
+    open FILE, $ARGV[0] || die "Impossible de lire le fichier";
+    $evenement_def = <FILE>;
+    chomp($evenement_def);
+    while(my $noms = <FILE>) {
+       if($noms eq "\n") { last; }
+       my ($numero,$nom) = split(/ /,$noms,2);
+       chomp($nom);
+       $participants{$nom} = $numero;
+    }
+    while(my $transaction = <FILE>) {
+       if($transaction eq "\n") { last; }
+       chomp($transaction);
+       push(@transactions,$transaction);
+       my $description = <FILE>;
+       chomp($description);
+       push(@descriptions,$description);
+    }
+    $file = $ARGV[0];
+}
+
+GLOBALE: while(1) {
+    if(keys(%participants)>0) {
+       $actions[1]="Ajouter une dépense";
+       $actions[2]="Enregistrer";
+    }
+    if(scalar(@transactions)>0) {
+       $actions[3]="Voir les dépenses de quelqu'un";
+       $actions[2]="Enregistrer";
+       $actions[4]="Equilibrage";
+       $actions[5]="Voir une transaction";
+    }
+
+    my $action;
+    while(1) {
+       my $i = 1;
+       my $var;
+       my @vart = ( @actions, 'Sortir' );
+       my $message = '';
+       foreach $var ( @vart ) {
+           $message .= $i++.') '.$var."\n";
+       }
+       print $message;
+       $var = <STDIN>;
+       chop($var);
+       if(/\D/ || $var < 1 || $var > $i) {
+           print "Mauvaise entrée\n";
+           next;
+       }
+       $action = $vart[$var-1];
+       last;
+    }
+    switch ($action) {
+       case "Ajouter un participant" {
+           print "Nom du participant\n";
+           my $participant = <STDIN>;
+           chomp($participant);
+           $participants{$participant} = keys(%participants)+1;
+       }
+       case "Ajouter une dépense" {
+           print "Qui a payé ?\n";
+           my $paye;
+           while(1) {
+               my $i = 1;
+               my $var;
+               my @vart = ( keys(%participants), "Annuler" );
+               foreach $var ( @vart ) {
+                   print $i++.') '.$var."\n";
+               }
+               $var = <STDIN>;
+               chop($var);
+               if(/\D/ || $var < 1 || $var > $i) {
+                   print "Mauvaise entrée\n";
+                   next;
+               }
+               $paye = $vart[$var-1];
+               last;
+           }
+           if($paye eq "Annuler") {
+               next GLOBALE;
+           }
+           print "Quoi ?\n";
+           my $description = <STDIN>;
+           chomp($description);
+           print "Combien ?\n";
+           my $prix = <STDIN>;
+           chomp($prix);
+           print "Pour qui ?\n";
+           my $repartition = "";
+           my $total_parts = 0;
+         DESTS: while(1) {
+             my $dest;
+             while(1) {
+                 my $i = 1;
+                 my $var;
+                 my @vart = ( keys(%participants), "Ajouter à tous", "Fini" );
+                 foreach $var ( @vart ) {
+                     print $i++.') '.$var."\n";
+                 }
+                 $var = <STDIN>;
+                 chop($var);
+                 if(/\D/ || $var < 1 || $var > $i) {
+                     print "Mauvaise entrée\n";
+                     next;
+                 }
+                 $dest = $vart[$var-1];
+                 last;
+             }
+             switch($dest) {
+                 case "Fini" {
+                     if($repartition eq "") { print "Annulé\n"; }
+                     elsif($total_parts == 0) {
+                         print "Le nombre total de parts est nul, il faut en ajouter !\n";
+                         next DESTS;
+                     }
+                     else {
+                         push(@transactions, $participants{$paye}.' '.$prix.$repartition);
+                         push(@descriptions, $description);
+                     }
+                     last DESTS;
+                 }
+                 case "Ajouter à tous" {
+                     print "Nombre de parts ?\n";
+                     my $parts = <STDIN>;
+                     chomp($parts);
+                     if(!($parts == 0)) {
+                         foreach my $participant (keys(%participants)) {
+                             $repartition .= ' '.$participants{$participant}.':'.scalar($parts);
+                             $total_parts += scalar($parts);
+                         }
+                     }
+                 }
+                 else {
+                     print "Nombre de parts ?\n";
+                     my $parts = <STDIN>;
+                     chomp($parts);
+                     if(!($parts == 0)) {
+                         $repartition .= ' '.$participants{$dest}.':'.scalar($parts);
+                         $total_parts += scalar($parts);
+                     }
+                 }
+             }
+         }
+       }
+       case "Voir les dépenses de quelqu'un" {
+           my $personne;
+           while(1) {
+               my $i = 1;
+               my $var;
+               my @vart = ( keys(%participants), "Annuler" );
+               foreach $var ( @vart ) {
+                   print $i++.') '.$var."\n";
+               }
+               $var = <STDIN>;
+               chop($var);
+               if(/\D/ || $var < 1 || $var > $i) {
+                   print "Mauvaise entrée\n";
+                   next;
+               }
+               $personne = $vart[$var-1];
+               last;
+           }
+           if($personne eq "Annuler") {
+               next GLOBALE;
+           }
+           my $depenses = 0;
+           my $frais = 0;
+           foreach my $transaction (@transactions) {
+               my @table_trans = split(/ /,$transaction);
+               my $payeur = shift(@table_trans);
+               my $prix = shift(@table_trans);
+               if($payeur == $participants{$personne}) {
+                   $depenses += $prix;
+               }
+               my $parts = 0;
+               my $frac = 0;
+               my $repartition;
+               foreach $repartition (@table_trans) {
+                   my ($pers,$part) = split(/:/,$repartition);
+                   if($pers == $participants{$personne}) {
+                       $frac += $part;
+                   }
+                   $parts += $part;
+               }
+               $frais += $prix*$frac/$parts;
+           }
+           print $personne." a payé ".$depenses." EUR\n";
+           print "et a pour ".sprintf("%.2f",$frais)." EUR de frais au total.\n";
+           print "Il a donc un solde de ".sprintf("%.2f",$depenses-$frais)." EUR\n";
+           my $pause = <STDIN>;
+       }
+       case "Voir une transaction" {
+           my $transaction;
+           while(1) {
+               my $i = 1;
+               my $var;
+               my @vart = ( @descriptions, "Annuler" );
+               foreach $var ( @vart ) {
+                   print $i++.') '.$var."\n";
+               }
+               $var = <STDIN>;
+               chop($var);
+               if(/\D/ || $var < 1 || $var > $i) {
+                   print "Mauvaise entrée\n";
+                   next;
+               }
+               $transaction = $var-1;
+               last;
+           }
+           my @table_trans = split(/ /,$transactions[$transaction]);
+           my $payeur = shift(@table_trans);
+           my $prix = shift(@table_trans);
+           my $Tparts = 0;
+           my $repartition;
+           my %parts;
+           foreach my $pers (keys(%participants)) {
+               if($payeur == $participants{$pers}) {
+                   print $descriptions[$transaction]." (payé par ".$pers."), ".$prix." EUR\n";
+                   last
+               }
+           }
+           foreach $repartition (@table_trans) {
+               my ($pers,$part) = split(/:/,$repartition);
+               $Tparts += $part;
+               $parts{$pers} += $part;
+           }
+           foreach my $pers (keys(%participants)) {
+               if(!exists $parts{$participants{$pers}}) {
+                   next;
+               }
+               print $pers.", ".$parts{$participants{$pers}}." part(s), soit ". $prix*$parts{$participants{$pers}}/$Tparts." EUR\n";
+           }
+           my $pause = <STDIN>;
+       }
+       case "Enregistrer" {
+           print "Nom de l'événement ?";
+           if(!($evenement_def eq "")) {
+               print " [".$evenement_def."]";
+           }
+           print "\n";
+           my $evenement = <STDIN>;
+           chomp($evenement);
+           if($evenement eq "") {
+               $evenement = $evenement_def;
+           }
+           open FILE, ">".$file;
+           print FILE $evenement."\n";
+           my $key;
+           foreach $key (keys(%participants)) {
+               print FILE $participants{$key}." ".$key."\n";
+           }
+           print FILE "\n";
+           for(my $i=0;$i<scalar(@transactions);$i++) {
+               print FILE $transactions[$i]."\n";
+               print FILE $descriptions[$i]."\n";
+           }
+           print FILE "\n";
+           print FILE $remboursements;
+           close FILE;
+       }
+       case "Equilibrage" {
+           my %Tdepenses = ();
+           my %Tfrais = ();
+           my %Tsolde = ();
+           $remboursements = "";
+           foreach my $Ttransaction (@transactions) {
+               my @Ttable_trans = split(/ /,$Ttransaction);
+               my $Tpayeur = shift(@Ttable_trans);
+               my $Tprix = shift(@Ttable_trans);
+               $Tdepenses{$Tpayeur} = $Tdepenses{$Tpayeur} + $Tprix;
+               my $Tparts = 0;
+               my $Tfrac = 0;
+               my $Trepartition;
+               foreach $Trepartition (@Ttable_trans) {
+                   my ($Tpers,$Tpart) = split(/:/,$Trepartition);
+                   $Tparts += $Tpart;
+               }
+               foreach $Trepartition (@Ttable_trans) {
+                   my ($Tpers,$Tpart) = split(/:/,$Trepartition);
+                   $Tfrais{$Tpers} = $Tfrais{$Tpers} + $Tprix*$Tpart/$Tparts;
+               }
+           }
+           foreach my $Tpersonne (keys(%participants)) {
+               my $numero = $participants{$Tpersonne};
+               $Tsolde{$Tpersonne} = sprintf("%.2f",$Tdepenses{$numero}-$Tfrais{$numero});
+               print $Tpersonne." a un solde de ".$Tsolde{$Tpersonne}." EUR\n";
+           }
+           my $pause = <STDIN>;
+           print "Y-a-t-il des remboursements plus aisés ?\n";
+           my $ouinon;
+           while(1) {
+               my $i = 1;
+               my $var;
+               my @vart = ( "Oui", "Non" );
+               foreach $var ( @vart ) {
+                   print $i++.') '.$var."\n";
+               }
+               $var = <STDIN>;
+               chop($var);
+               if(/\D/ || $var < 1 || $var > $i) {
+                   print "Mauvaise entrée\n";
+                   next;
+               }
+               $ouinon = $vart[$var-1];
+               last;
+           }
+         AISE: while($ouinon eq "Oui") {
+             print "Qui ?\n";
+             my $personne;
+             while(1) {
+                 my $i = 1;
+                 my $var;
+                 my @vart = ( keys(%participants), "Fini" );
+                 foreach $var ( @vart ) {
+                     print $i++.') '.$var."\n";
+                 }
+                 $var = <STDIN>;
+                 chop($var);
+                 if(/\D/ || $var < 1 || $var > $i) {
+                     print "Mauvaise entrée\n";
+                     next;
+                 }
+                 $personne = $vart[$var-1];
+                 last;
+             }
+             if($personne eq "Fini") { last AISE; }
+             print "Avec qui ?\n";
+             my $personneb;
+             while(1) {
+                 my $i = 1;
+                 my $var;
+                 my @vart = ( keys(%participants), "Annuler" );
+                 foreach $var ( @vart ) {
+                     print $i++.') '.$var."\n";
+                 }
+                 $var = <STDIN>;
+                 chop($var);
+                 if(/\D/ || $var < 1 || $var > $i) {
+                     print "Mauvaise entrée\n";
+                     next;
+                 }
+                 $personneb = $vart[$var-1];
+                 last;
+             }
+             if($personneb eq "Annuler") { next AISE; }
+             if($Tsolde{$personne}*$Tsolde{$personneb}<0) {
+                 my $pers_inf = ($Tsolde{$personne}<0)?$personne:$personneb;
+                 my $pers_sup = ($Tsolde{$personne}>0)?$personne:$personneb;
+                 my $inf = (abs($Tsolde{$personne})<abs($Tsolde{$personneb}))?abs($Tsolde{$personne}):abs($Tsolde{$personneb});
+                 $remboursements .= $pers_inf." doit ".$inf." EUR à ".$pers_sup."\n";
+                 $Tsolde{$pers_inf} += $inf;
+                 $Tsolde{$pers_sup} -= $inf;
+             }
+         }
+           # Une boucle pour détecter si on a des couples qui s'annulent mutuellement
+         COUPLE: foreach my $personne (keys(%participants)) {
+             if($Tsolde{$personne} == 0) { next; }
+             foreach my $personneb (keys(%participants)) {
+                 if($Tsolde{$personneb} + $Tsolde{$personne} != 0) { next; }
+                 my $pers_inf = ($Tsolde{$personne}<0)?$personne:$personneb;
+                 my $pers_sup = ($Tsolde{$personne}>0)?$personne:$personneb;
+                 my $val = abs($Tsolde{$personne});
+                 $remboursements .= $pers_inf." doit ".$val." EUR à ".$pers_sup."\n";
+                 $Tsolde{$pers_inf} += $val;
+                 $Tsolde{$pers_sup} -= $val;
+                 next COUPLE;
+             }
+         }
+         REMB: while(1) {
+             # On supprime les 0, et on fait deux hashs
+             my %Tneg = ();
+             my %Tpos = ();
+             foreach my $personne (keys(%Tsolde)) {
+                 if($Tsolde{$personne} == 0) { delete $Tsolde{$personne}; }
+                 elsif($Tsolde{$personne} < 0) { $Tneg{$personne} = $Tsolde{$personne}; }
+                 elsif($Tsolde{$personne} > 0) { $Tpos{$personne} = $Tsolde{$personne}; }
+             }
+             if(keys(%Tneg) == 0) {
+                 last REMB;
+             }
+             foreach my $neg (sort { $Tneg{$a} cmp $Tneg{$b} } keys %Tneg) {
+                 my $max = 0;
+                 my $positif = 0;
+                 foreach my $pos (sort { $Tpos{$a} cmp $Tpos{$b} } keys %Tpos) {
+                     if($Tpos{$pos} + $Tneg{$neg}>0) {
+                         $positif = $pos;
+                         last;
+                     }
+                     $max = $pos;
+                 }
+                 if(!($max eq 0)) {
+                     $remboursements .= $neg." doit ".$Tsolde{$max}." EUR à ".$max."\n";
+                     $Tsolde{$neg} += $Tsolde{$max};
+                     delete $Tsolde{$max};
+                 }
+                 else {
+                     $remboursements .= $neg." doit ".-$Tsolde{$neg}." EUR à ".$positif."\n";
+                     $Tsolde{$positif} += $Tsolde{$neg};
+                     delete $Tsolde{$neg};
+                 }
+                 next REMB;
+             }
+         }
+           print $remboursements;
+           my $pause = <STDIN>;
+       }
+       case "Sortir" {
+           last GLOBALE;
+       }
+    }
+}
diff --git a/execurl b/execurl
new file mode 100755 (executable)
index 0000000..655d208
--- /dev/null
+++ b/execurl
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+# The MIT License (MIT)
+# 
+# Copyright (c) 2011-2015 Ismaël Bouya http://www.normalesup.org/~bouya/
+# 
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+# 
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+
+# To be used together with remove_attachements script in procmail and urlview to
+# visualize and keep some attachements once they are removed from the email
+# Example urlview updated configuration:
+# REGEXP ((((http|https|ftp|gopher)|mailto):(//)?[^ <>"\t]*|(www|ftp)[0-9]?\.[-a-z0-9.]+)[^ .,;\t\n\r<">\):]?[^, <>"\t]*[^ .,;\t\n\r<">\):]|(file|keepdir)://([^\t\n\r\\ ]+(\\ |\\)?)+)
+# COMMAND execurl
+
+export chemin=x"$1"
+if [ "${chemin:0:8}" = "xfile://" ]; then
+   fichier="${1:7}"
+   fichierlu="${fichier//\\ / }"
+   if [ ! -f "$fichierlu" ]; then
+       exec run-mailcap "${fichierlu//.attachements/Mail/.attachements}"
+   else
+       exec run-mailcap "$fichierlu"
+   fi
+elif [ "${chemin:0:11}" = "xkeepdir://" ]; then
+   mv "${1:10}" "$HOME/Mail/.attachements/"
+else
+   exec w3m "$1"
+fi
diff --git a/gen_html_documents b/gen_html_documents
new file mode 100755 (executable)
index 0000000..eb361ce
--- /dev/null
@@ -0,0 +1,135 @@
+#!/usr/bin/env perl
+# The MIT License (MIT)
+# 
+# Copyright (c) 2011-2015 Ismaël Bouya http://www.normalesup.org/~bouya/
+# 
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+# 
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+use strict;
+use File::Basename;
+
+sub parse_config_file {
+    my ($config_line, $Name, $Value, $Config);
+    (my $File, $Config) = @_;
+    if (!open (CONFIG, "$File")) {
+        print "ERROR: Config file not found : $File";
+        exit(0);
+    }
+    my $multiline = 0;
+
+    while (<CONFIG>) {
+        $config_line=$_;
+        chop ($config_line);
+        $config_line =~ s/^\s*//;
+        $config_line =~ s/\s*$//;
+        if ( ($config_line !~ /^#/) && ($config_line ne "") ){
+            if ($multiline) {
+              $$Config{$Name} =~ s/\\$//;
+              $$Config{$Name} .= $config_line;
+            } else {
+              ($Name, $Value) = split (/\s*=\s*/, $config_line);
+              $Value =~ s/^~/$ENV{"HOME"}/;
+              $$Config{$Name} = $Value;
+            }
+            $multiline = ($$Config{$Name} =~ /\\$/);
+        }
+    }
+    close(CONFIG);
+}
+
+my %Config;
+&parse_config_file ($ENV{"HOME"}."/.gen_html_documents.rc", \%Config);
+
+my $entete = $Config{"entete"};
+my $avant  = $Config{"avant"};
+my $milieu = $Config{"milieu"};
+my $apres  = $Config{"apres"};
+my $html   = $Config{"html"};
+
+my @ignore = split (/\s*,\s*/, $Config{"ignore"});
+my @ext    = split (/\s*,\s*/, $Config{"ext"});
+
+my $documents = $Config{"documents"};
+my $droot = $Config{"dossier_web"};
+
+$Config{"dossiers"} =~ s/^"//;
+$Config{"dossiers"} =~ s/"$//;
+my %dossiers = split (/"?\s*,\s*"?/, $Config{"dossiers"});
+
+my ($dossier,$description);
+
+open F, ">".$milieu;
+
+while(($dossier,$description) = each(%dossiers)) {
+       opendir(DIR, $documents.$dossier) || warn $documents.$dossier." coulnd't be opened\n";
+       my @content = grep {$_ !~ /^\.\.?$/} readdir(DIR);
+       my @sorted = sort { lc($a) cmp lc($b) } @content;
+       closedir(DIR);
+       
+       print F "<h3>".$description."</h3>\n";
+       print F "<ul>\n";
+       foreach my $subpath (grep { -d $documents.$dossier.'/'.$_} @sorted) {
+               subparse($dossier,$subpath,4);
+               }
+       foreach my $file (grep { -f $documents.$dossier.'/'.$_} @sorted) {
+               my($filename, $directories, $suffix) = fileparse($file,qr/\.[^\.]*/);
+               next if(!in_array(\@ext,lc($suffix)));
+               $filename =~ tr/_/ /;
+               print F "<li><a href='".$droot.$dossier.'/'.$file."'>".$filename."</a></li>\n";
+               }
+       print F "</ul>\n";
+       }
+
+sub subparse {
+       my $path = shift;
+       my $dossier = shift;
+       my $rang = shift;
+       
+       opendir(DIR, $documents.$path."/".$dossier);
+       my @content = grep {$_ !~ /^\.\.?$/} readdir(DIR);
+       my @sorted = sort { lc($a) cmp lc($b) } @content;
+       closedir(DIR);
+
+       return if(in_array(\@ignore,$dossier));
+       my $dossierspace = $dossier;
+       $dossierspace =~ tr/_/ /;
+       print F "<li>".$dossierspace."\n";
+       print F "<ul>\n";
+       foreach my $subpath (grep { -d $documents.$path."/".$dossier.'/'.$_} @sorted) {
+               subparse($path."/".$dossier,$subpath,$rang+1);
+               }
+       foreach my $file (grep { -f $documents.$path."/".$dossier.'/'.$_} @sorted) {
+               my($filename, $directories, $suffix) = fileparse($file,qr/\.[^\.]*/);
+               next if(!in_array(\@ext,lc($suffix)));
+               $filename =~ tr/_/ /;
+               print F "<li><a href='".$droot.$path.'/'.$dossier.'/'.$file."'>".$filename."</a></li>\n";
+               }
+       print F "</ul></li>\n";
+       }
+
+sub in_array {
+       my ($arr,$search_for) = @_;
+       my %items = map {$_ => 1} @$arr; # create a hash out of the array values
+       return (exists($items{$search_for}))?1:0;
+       }
+
+close F;
+
+exec "cat $entete $avant $milieu $apres 1> $html" or die "$!\n";
+exec "chmod -R go=rX,u=rwX $documents"
diff --git a/git-latexdiff b/git-latexdiff
new file mode 100755 (executable)
index 0000000..5d26d1b
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+# The MIT License (MIT)
+# 
+# Copyright (c) 2011-2015 Ismaël Bouya http://www.normalesup.org/~bouya/
+# 
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+# 
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+
+extension="${3##*.}"
+if [ $extension = "tex" ]; then
+    latexdiff "$1" "$2" > diff_$3
+fi
\ No newline at end of file
diff --git a/interrogations b/interrogations
new file mode 100755 (executable)
index 0000000..19c97e3
--- /dev/null
@@ -0,0 +1,739 @@
+#!/usr/local/bin/perl
+# The MIT License (MIT)
+# 
+# Copyright (c) 2011-2015 Ismaël Bouya http://www.normalesup.org/~bouya/
+# 
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+# 
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+use Switch;
+use strict;
+
+my @table = ();
+my @interros = ();
+my @tablequestion = ();
+my @points = ();
+my %corr_nom ;
+my $interro_courante = 0;
+my $fichier = "notes.dat";
+if($#ARGV == 0) {
+    $fichier = $ARGV[0];
+}
+
+sub ajout_interro {
+    print "Nom de l'interrogation\n";
+    my $interro = <STDIN>;
+    chomp($interro);
+    push(@interros,$interro);
+    push(@tablequestion,[]);
+    push(@table,[]);
+    push(@points,[]);
+    foreach my $key (keys %corr_nom) {
+       push(@{ $corr_nom{$key} }, "Absent" );
+    }
+}
+
+sub ajout_eleve {
+    print "Nom\n";
+    my $nom = <STDIN>;
+    chomp($nom);
+    print "Prénom\n";
+    my $prenom = <STDIN>;
+    chomp($prenom);
+    $corr_nom{$prenom."\n".$nom} = ();
+    for my $i (0..$#interros) {
+       push(@{ $corr_nom{$prenom."\n".$nom} }, "Absent" );
+    }
+}
+
+sub definir_exos {
+    my $interro = shift;
+    my $nbexos = "a";
+    while($nbexos =~ m/\D/) {
+       print "Nombre d'exercices\n";
+       $nbexos = <STDIN>;
+       chomp($nbexos);
+       if($nbexos =~ /\D/) {
+           print "Mauvaise entrée\n";
+       }
+    }
+    if($nbexos == "") {
+       $nbexos = 0;
+    }
+    push(@{ $table[$interro] }, $nbexos);
+    if($nbexos == 0) {
+       push(@{ $tablequestion[$interro] }, "");    
+    }
+    for(my $i = 1; $i <= $nbexos; $i++) {
+       my $questions = "a";
+       while($questions =~ m/\D/) {
+           print "Nombre de questions dans l'exercice ",$i,"\n";
+           $questions = <STDIN>;
+           chomp($questions);
+           if($questions =~ /\D/) {
+               print "Mauvaise entrée\n";
+           }
+       }
+       if($questions eq "") {
+           $questions = 0;
+       }
+       if($questions > 1) {
+           push(@{ $table[$interro] }, $questions);
+           for(my $j = 1; $j <= $questions; $j++) {
+               my $ssquestions = "a";
+               while($ssquestions =~ m/\D/) {
+                   print "Nombre de sous-questions dans la question ",$i,".",$j,"\n";
+                   $ssquestions = <STDIN>;
+                   chomp($ssquestions);
+                   if($ssquestions =~ /\D/) {
+                       print "Mauvaise entrée\n";
+                   }
+               }
+               if($ssquestions eq "") {
+                   $ssquestions = 0;
+               }
+               if($ssquestions > 1) {
+                   push(@{ $table[$interro] }, $j.".".$ssquestions);
+                   for(my $k = 1; $k<= $ssquestions; $k++) {
+                       push(@{ $tablequestion[$interro] }, $i.".".$j.".".$k);
+                   }
+               }
+               else {
+                   push(@{ $tablequestion[$interro] }, $i.".".$j);
+               }
+           }
+       }
+       else {
+           push(@{ $tablequestion[$interro] }, $i);
+       }
+    }
+}
+
+sub entrer_notes {
+    my $interro = shift;
+    my $eleve = shift;
+    my @boucle;
+    if($eleve) {
+       @boucle = ($eleve);
+    }
+    else {
+       @boucle = sort sort_alpha keys %corr_nom;
+    }
+    foreach my $key (@boucle) {
+       my $keyt = $key;
+       $keyt =~ s/\n/ /;
+       print $keyt." (mettre A pour indiquer une absence)\n";
+       my @int;
+       if(ref($corr_nom{$key}[$interro]) eq 'ARRAY') {
+           @int = @{$corr_nom{$key}[$interro]};
+       }
+       $corr_nom{$key}[$interro] = ();
+       Interro: for my $i (0..$#{$tablequestion[$interro]}) {
+           my $pourcentage = "a";
+           my $def = 0;
+           if(!@int && $i == 0) {
+               $def = "A";
+           }
+           if(scalar(@int) > 0) {
+               $def = $int[$i];
+           }
+           while($pourcentage =~ m/\D/ || $pourcentage > 100) {
+               if($tablequestion[$interro][$i] =~ m/\D/ ) {
+                   print "Pourcentage pour la question ".$tablequestion[$interro][$i]." [".$def."]\n";
+               }
+               else {
+                   print "Pourcentage pour l'exercice ".$tablequestion[$interro][$i]." [".$def."]\n";
+               }
+               $pourcentage = <STDIN>;
+               chomp($pourcentage);
+               if($pourcentage eq "") {
+                   $pourcentage = $def;
+               }
+               if($pourcentage =~ m/^a$/i) {
+                   $corr_nom{$key}[$interro] = "Absent";
+                   last Interro;
+               }
+               if($pourcentage =~ /\D/ || $pourcentage > 100) {
+                   print "Il faut un pourcentage entre 0 et 100\n";
+               }
+           }
+           push(@{ $corr_nom{$key}[$interro] },$pourcentage);
+       }
+    }
+}
+
+sub entrer_bareme {
+    my $interro = shift;
+    foreach my $nomquestion ( @{ $tablequestion[$interro] } ) {
+       my $point = "a";
+       while($point =~ /[^\d\.]/) {
+           if($nomquestion =~ m/\D/ ) {
+               print "Points pour la question ".$nomquestion."\n";
+           }
+           else {
+               print "Points pour l'exercice ".$nomquestion."\n";
+           }
+           $point = <STDIN>;
+           chomp($point);
+           if($point =~ /[^\d\.]/) {
+               print "Il faut donner un nombre de points\n";
+           }
+       }
+       if($point eq "") {
+           $point = 0;
+       }
+       push(@{ $points[$interro] },$point);
+    }
+}
+
+sub sauver {
+    open FILE, ">".$fichier;
+    foreach my $i (0..$#table) {
+       print FILE $interros[$i]."\n";
+       print FILE "@{ $table[$i] }\n";
+       print FILE "@{ $tablequestion[$i] }\n";
+       print FILE "@{ $points[$i] }\n";
+    }
+    print FILE "\n";
+    foreach my $ligne (keys(%corr_nom)) {
+       print FILE $ligne."\n";
+       foreach my $lig (@{ $corr_nom{$ligne} }) {
+           if($lig eq "Absent") {
+               print FILE "! \n";
+           }
+           else {
+               print FILE "* @$lig\n";
+           }
+       }
+    }
+    print FILE "\n";
+    close FILE;
+}
+
+sub charger {
+    open FILE, $fichier;
+    while(my $int = <FILE>) {
+       if($int eq "\n") { last };
+       chomp($int);
+       push(@interros,$int);
+       $int = <FILE>;
+       chomp($int);
+       push(@table, [ split(/ /, $int)  ] );
+       $int = <FILE>;
+       chomp($int);
+       push(@tablequestion, [ split(/ /, $int)  ] );
+       $int = <FILE>;
+       chomp($int);
+       push(@points, [ split(/ /, $int)  ] );
+
+    }
+    my $int = <FILE>;
+    while(1) {
+       if($int eq "\n") { last };
+       my $intn = <FILE>;
+       chomp($intn);
+       my $key = $int.$intn;
+       $corr_nom{$key} = ();
+       while($intn = <FILE>) {
+           if($intn =~ m/^\*/) {
+               chomp($intn);
+               push(@{ $corr_nom{$key} }, [ split(/ /, substr($intn,2)) ] );
+           }
+           elsif($intn =~ m/^!/) {
+               push(@{ $corr_nom{$key} }, "Absent" );          
+           }
+           else {
+               $int = $intn;
+               last;
+           }
+       }
+    }
+    close FILE;
+}
+
+sub sort_alpha {
+    my @p_na = split(/\n/,$a);
+    my @p_nb = split(/\n/,$b);
+    return $p_na[1] cmp $p_nb[1] || $p_na[0] cmp $p_nb[0];
+}
+
+sub export_latex {
+    print "Fichier ?\n";
+    my $f_export = <STDIN>;
+    chomp($f_export);
+    if($f_export eq "") { return 0 };
+    open FILE, ">".$f_export;
+    print FILE "\\documentclass[landscape]{article}\n";
+    print FILE "\\usepackage[T1]{fontenc}\n";
+    print FILE "\\usepackage[utf8]{inputenc}\n";
+    print FILE "\\usepackage{geometry}\n";
+    print FILE "\\geometry{margin=1cm}\n";
+    print FILE "\\begin{document}\n";
+    for my $interro (0..$#table) {
+       print FILE "\\begin{tabular}{|l|";
+       my @exosansq = grep(/^[1-9]\d*$/,@{ $tablequestion[$interro] });
+       print FILE "c|"x (scalar(@{ $tablequestion[$interro] })+$table[$interro][0] - scalar(@exosansq));
+       print FILE "|c|}\n";
+       my @ign = ();
+       my @pts = ();
+       my @max = ();
+       my @min = ();
+       my @somme = ();
+       print FILE "\\multicolumn{",(scalar(@{ $tablequestion[$interro] })+$table[$interro][0] - scalar(@exosansq) + 2),"}{c}{\\Large ".$interros[$interro]."}\\\\\n";
+       if($table[$interro][0] > 0) {
+           print FILE "\\hline\n\t ";
+           for(my $i = 1; $i <= $table[$interro][0]; $i++) {
+               my @b = grep(/^$i/,@{ $tablequestion[$interro] });
+               if(scalar(@b) == 1) {
+                   print FILE "& Exercice $i ";
+               }
+               else {
+                   print FILE "& \\multicolumn{",scalar(@b)+1,"}{c|}{Exercice ",$i,"} ";
+               }
+           }
+           print FILE "& Total ";
+           print FILE "\\\\\n";
+           print FILE "\\hline\n\t";
+           my $rank = -1;
+           for(my $i = 1; $i <= $table[$interro][0]; $i++) {
+               my @b = grep(/^$i(\D|$)/,@{ $tablequestion[$interro] });
+               for(my $j = 1; $j <= scalar(@b); $j++) {
+                   my @c = grep(/^$i\.$j(\D|$)/,@{ $tablequestion[$interro] });
+                   $rank += scalar(@c);
+                   if(scalar(@c) == 1) {
+                       print FILE "& $j) ";
+                   }
+                   elsif(scalar(@c) > 0) {
+                       print FILE "& \\multicolumn{",scalar(@c),"}{c|}{",$j,")} ";
+                   }
+                   elsif($j == 1) {
+                       $rank +=1;
+                       push(@ign,$rank+$i-1);
+                       #print FILE "& ";
+                   }
+               }
+               print FILE "& Total ";
+               push(@pts,$rank);
+           }
+           print FILE "& \\\\\n";
+       }
+       print FILE "\\hline\n\t";
+       print FILE "points ";
+       my $totalexo = 0;
+       my $total = 0;
+       my $nq = 0;
+       for my $i (0.. $#{ $points[$interro] }) {
+           print FILE "& $points[$interro][$i] ";
+           push(@min,$points[$interro][$i]);
+           push(@max,0);
+           push(@somme,0);
+           $totalexo += $points[$interro][$i];
+           $total += $points[$interro][$i];
+           $nq++;
+           if((grep {$_ == $i} @pts) > 0) {
+               if($nq > 1) {
+                   print FILE "& $totalexo ";
+               }
+               push(@min,$totalexo);
+               push(@max,0);
+               push(@somme,0);
+               $totalexo = 0;
+               $nq = 0;
+           }
+       }
+       print FILE "& $total ";
+       push(@min,$total);
+       push(@max,0);
+       push(@somme,0);
+       print FILE "\\\\\n";
+       print FILE "\\hline\n\t";
+       print FILE "\\hline\n\t";
+
+       my @sortednotes = sort sort_alpha (keys %corr_nom);
+       #print "@sortednotes";
+       #my $somme = 0;
+       my $nombre_eleves = 0;
+       for my $i (0.. $#sortednotes) {
+           my $np = $sortednotes[$i];
+           $np =~ s/\n/ /;
+           print FILE $np;
+           my @ligne = @{ $corr_nom{$sortednotes[$i]} };
+           if($ligne[$interro] eq "Absent") {
+               print FILE "& \\multicolumn{",scalar(@{ $tablequestion[$interro] })+$table[$interro][0]+1,"}{c|}{Absent}";
+           }
+           else {
+               my @ligneo = @{ $ligne[$interro] };
+               my $totalexo = 0;
+               my $total = 0;
+               $nombre_eleves++;
+               my $k = 0;
+               my $nq = 0;
+               foreach my $l (0.. $#ligneo ) {
+                   my $val = sprintf("%.0f",4.*$ligneo[$l]*$points[$interro][$l]/100)/4; 
+                   print FILE "& ",$val;
+                   if($min[$k] > $val) {
+                       $min[$k] = $val;
+                   }
+                   if($max[$k] < $val) {
+                       $max[$k] = $val;
+                   }
+                   $somme[$k] += $val;
+                   $k++;
+                   $nq++;
+                   $totalexo += $val;
+                   $total += $val;
+                   if((grep {$_ == $l} @pts) > 0) {
+                       if($min[$k] > $totalexo) {
+                           $min[$k] = $totalexo;
+                       }
+                       if($max[$k] < $totalexo) {
+                           $max[$k] = $totalexo;
+                       }
+                       $somme[$k] += $totalexo;
+                       if($nq > 1) {
+                           print FILE "& $totalexo ";
+                       }
+                       $k++;
+                       $totalexo = 0;
+                       $nq = 0;
+                   }
+               }
+               print FILE "& $total ";
+               if($min[$k] > $total) {
+                   $min[$k] = $total;
+               }
+               if($max[$k] < $total) {
+                   $max[$k] = $total;
+               }
+               $somme[$k] += $total;
+               $k++;
+           }
+           print FILE "\\\\\n";
+           print FILE "\\hline\n\t";
+       }
+       print FILE "\\hline\n\t";
+       print FILE "Moyenne";
+       for my $l (0.. $#somme) {
+           next if((grep {$_ == $l} @ign) > 0);
+           print FILE "& ".sprintf("%.0f",4.*$somme[$l]/$nombre_eleves)/4;
+       }
+       print FILE "\\\\\n";
+       print FILE "\\hline\n\t";
+       print FILE "Min";
+       for my $l (0.. $#min) {
+           next if((grep {$_ == $l} @ign) > 0);
+           print FILE "& $min[$l]";
+       }
+       print FILE "\\\\\n";
+       print FILE "\\hline\n\t";
+       print FILE "Max";
+       for my $l (0.. $#max) {
+           next if((grep {$_ == $l} @ign) > 0);
+           print FILE "& $max[$l]";
+       }
+       #print FILE "Moyenne & \\multicolumn{",scalar(@{ $tablequestion[$interro] })+$table[$interro][0],"}{c||}{ }";
+       #my $moyenne = sprintf("%.0f",4.*$somme/$nombre_eleves)/4;
+       #print FILE " & $moyenne\\\\\n";
+       print FILE "\\\\\n";
+       print FILE "\\hline\n\t";
+       print FILE "\\end{tabular}\n";
+       print FILE "\\vfill\n";
+       print FILE "\\newpage\n";
+    }
+    print FILE "\\end{document}\n";
+    close FILE;
+}
+
+sub export_csv {
+    my $interro = shift;
+    print "Fichier ?\n";
+    my $f_export = <STDIN>;
+    chomp($f_export);
+    if($f_export eq "") { return 0 };
+    open FILE, ">".$f_export;
+    for my $interro (0..$#table) {
+       print FILE "; ".$interros[$interro]."\n";
+       my @pts = ();
+       my @ign = ();
+       my @max = ();
+       my @min = ();
+       my @somme = ();
+       if($table[$interro][0] > 0) {
+           for(my $i = 1; $i <= $table[$interro][0]; $i++) {
+               my @b = grep(/^$i/,@{ $tablequestion[$interro] });
+               if(scalar(@b) == 1) {
+                   print FILE "; Exercice $i ";
+               }
+               else {
+                   print FILE "; Exercice $i","; "x scalar(@b);
+               }
+           }
+           print FILE "; Total \n";
+           my $rank = -1;
+           for(my $i = 1; $i <= $table[$interro][0]; $i++) {
+               my @b = grep(/^$i(\D|$)/,@{ $tablequestion[$interro] });
+               for(my $j = 1; $j <= scalar(@b); $j++) {
+                   my @c = grep(/^$i\.$j(\D|$)/,@{ $tablequestion[$interro] });
+                   $rank += scalar(@c);
+                   if(scalar(@c) == 1) {
+                       print FILE "; $j) ";
+                   }
+                   elsif(scalar(@c) > 0) {
+                       my $char = "a";
+                       for my $num (0..$#c) {
+                           print FILE "; $j) ".$char.") ";
+                           $char++;
+                       }
+                       #print FILE "; $j) ","; "x (scalar(@c)-1);
+                   }
+                   elsif($j == 1) {
+                       $rank += 1;
+                       push(@ign,$rank+$i-1);
+                       #print FILE "; ";
+                   }
+               }
+               print FILE "; Total ";
+               push(@pts,$rank);
+           }
+           print FILE "; \n";
+       }
+       print FILE "points ";
+       my $totalexo = 0;
+       my $total = 0;
+       my $nq = 0;
+       for my $i (0.. $#{ $points[$interro] }) {
+           print FILE "; $points[$interro][$i] ";
+           push(@min,$points[$interro][$i]);
+           push(@max,0);
+           push(@somme,0);
+           $totalexo += $points[$interro][$i];
+           $total += $points[$interro][$i];
+           $nq++;
+           if((grep {$_ == $i} @pts) > 0) {
+               if($nq > 1) {
+                   print FILE "; $totalexo ";
+               }
+               push(@min,$totalexo);
+               push(@max,0);
+               push(@somme,0);
+               $totalexo = 0;
+               $nq = 0;
+           }
+       }
+       print FILE "; $total ";
+       push(@min,$total);
+       push(@max,0);
+       push(@somme,0);
+       print FILE "\n";
+
+       my @sortednotes = sort sort_alpha (keys %corr_nom);
+       #print "@sortednotes";
+       #my $somme = 0;
+       my $nombre_eleves = 0;
+       for my $i (0.. $#sortednotes) {
+           my $np = $sortednotes[$i];
+           $np =~ s/\n/ /;
+           print FILE $np;
+           my @ligne = @{ $corr_nom{$sortednotes[$i]} };
+           if($ligne[$interro] eq "Absent") {
+               print FILE "; Absent","; "x (scalar(@{ $tablequestion[$interro] })+$table[$interro][0]);
+           }
+           else {
+               my @ligneo = @{ $ligne[$interro] };
+               my $totalexo = 0;
+               my $total = 0;
+               $nombre_eleves++;
+               my $k = 0;
+               my $nq = 0;
+               foreach my $l (0.. $#ligneo ) {
+                   my $val = sprintf("%.0f",4.*$ligneo[$l]*$points[$interro][$l]/100)/4; 
+                   print FILE "; ",$val;
+                   if($min[$k] > $val) {
+                       $min[$k] = $val;
+                   }
+                   if($max[$k] < $val) {
+                       $max[$k] = $val;
+                   }
+                   $somme[$k] += $val;
+                   $k++;
+                   $totalexo += $val;
+                   $total += $val;
+                   $nq++;
+                   if((grep {$_ == $l} @pts) > 0) {
+                       if($nq > 1) {
+                           print FILE "; $totalexo ";
+                       }
+                       if($min[$k] > $totalexo) {
+                           $min[$k] = $totalexo;
+                       }
+                       if($max[$k] < $totalexo) {
+                           $max[$k] = $totalexo;
+                       }
+                       $somme[$k] += $totalexo;
+                       $k++;
+                       $totalexo = 0;
+                       $nq = 0;
+                   }
+               }
+               print FILE "; $total ";
+               if($min[$k] > $total) {
+                   $min[$k] = $total;
+               }
+               if($max[$k] < $total) {
+                   $max[$k] = $total;
+               }
+               $somme[$k] += $total;
+               $k++;
+           }
+           print FILE "\n";
+       }
+       print FILE "Moyenne";
+       for my $l (0.. $#somme) {
+           next if((grep {$_ == $l} @ign) > 0);
+           print FILE "; ".sprintf("%.0f",4.*$somme[$l]/$nombre_eleves)/4;
+       }
+       print FILE "\n";
+       print FILE "Min";
+       for my $l (0.. $#min) {
+           next if((grep {$_ == $l} @ign) > 0);
+           print FILE "; $min[$l]";
+       }
+       print FILE "\n";
+       print FILE "Max";
+       for my $l (0.. $#max) {
+           next if((grep {$_ == $l} @ign) > 0);
+           print FILE "; $max[$l]";
+       }
+       #print FILE "Moyenne & \\multicolumn{",scalar(@{ $tablequestion[$interro] })+$table[$interro][0],"}{c||}{ }";
+       #my $moyenne = sprintf("%.0f",4.*$somme/$nombre_eleves)/4;
+       #print FILE " & $moyenne\\\\\n";
+       print FILE "\n";
+       print FILE "\n\n\n";
+    }
+    close FILE;
+}
+
+if(-e $fichier) {
+    &charger();
+}
+
+sub choisir_interro() {
+    while(1) {
+       my $i = 1;
+       my $var;
+       my $message = '';
+       foreach $var ( @interros ) {
+           $message .= $i++.') '.$var."\n";
+       }
+       print $message;
+       $var = <STDIN>;
+       chop($var);
+       if(/\D/ || $var < 1 || $var > $i) {
+           print "Mauvaise entrée\n";
+           next;
+       }
+       $interro_courante = $var-1;
+       last;
+    }
+}
+
+sub editer_eleve() {
+    my $eleve;
+    while(1) {
+       open COL, "| column";
+       my $i = 1;
+       my @eleves = sort sort_alpha keys(%corr_nom);
+       foreach my $eleve_l (@eleves) {
+           my $eleve_lm = $eleve_l;
+           $eleve_lm =~ s/\n/ /;
+           print COL $i++.") ".$eleve_lm."\n";
+       }
+       print COL $i.") Annuler\n";
+       close COL;
+       my $var = <STDIN>;
+       chop($var);
+       if(/\D/ || $var < 1 || $var > $i) {
+           print "Mauvaise entrée\n";
+           next;
+       }
+       elsif( $var == $i ) {
+           return;
+       }
+       $eleve = $eleves[$var-1];
+       last;
+    }
+    my $notes_c = ${$corr_nom{$eleve}}[$interro_courante];
+    if($notes_c == "Absent") {
+       print "Absent à ".$interros[$interro_courante]."\n";
+    }
+    &entrer_notes($interro_courante,$eleve);
+}
+
+sub quitter() {
+    exit 0;
+}
+
+my @actions = ("Ajouter une interro", "Ajouter un élève");
+my @actions_f = (\&ajout_interro,
+                \&ajout_eleve,
+                \&choisir_interro,
+                \&editer_eleve,
+                \&definir_exos,
+                \&entrer_bareme,
+                \&entrer_notes,
+                \&sauver,
+                \&export_latex,
+                \&export_csv,
+                \&quitter,
+    );
+while(1) {
+    if(scalar(@interros)>0) {
+       $actions[2] = "Choisir une interro";
+       $actions[3] = "Éditer les notes d'un élève";
+       $actions[4] = "Définir les exercices de l'interro";
+       $actions[5] = "Définir le barême de l'interro";
+       $actions[6] = "Entrer les notes de l'interro";
+       $actions[7] = "Sauvegarder";
+       $actions[8] = "Exporter en LaTeX";
+       $actions[9] = "Exporter en CSV";
+    }
+    
+
+    my $action;
+    while(1) {
+       my $i = 1;
+       my $var;
+       my @vart = ( @actions, 'Quitter' );
+       my $message = 'Interro sélectionnée : '.$interros[$interro_courante]."\n";
+       foreach $var ( @vart ) {
+           $message .= $i++.') '.$var."\n";
+       }
+       print $message;
+       $var = <STDIN>;
+       chop($var);
+       if(/\D/ || $var < 1 || $var > $i) {
+           print "Mauvaise entrée\n";
+           next;
+       }
+       $action = $actions_f[$var-1];
+       last;
+    }
+    &{$action}($interro_courante);
+}
+
+#&export_latex();
diff --git a/mails_iprof b/mails_iprof
new file mode 100755 (executable)
index 0000000..04f2603
--- /dev/null
@@ -0,0 +1,53 @@
+#!/usr/bin/env sh
+# The MIT License (MIT)
+# 
+# Copyright (c) 2011-2015 Ismaël Bouya http://www.normalesup.org/~bouya/
+# 
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+# 
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+if [ "$*" = "" ]; then
+  echo "`basename $0` academie login password"
+  echo "où academie est remplacé dans:"
+  echo "https://bv.ac-academie.fr/iprof/ServletIprof"
+  exit 1
+fi
+
+iPROF="https://bv.ac-$1.fr/iprof/ServletIprof"
+login="$2"
+mdp="$3"
+
+numu=`curl $iPROF 2>/dev/null | grep numu| sed -e "s/.*value='\(.*\)'.*/\1/"`
+
+session=`curl -d 'codeTraitement=Authentification&typeConnexion=ENS&codeProfil=E&numu='$numu'&login='$login'&motDePasse='$mdp $iPROF 2>/dev/null | grep "value='CourrierE'" | sed -e "s/.*action='\/iprof\/ServletIprof\;\([^']*\)'.*/\1/"`
+
+curl -d 'codeTraitement=CourrierE' $iPROF';'$session 2>/dev/null 1>&2
+
+M=`mktemp`
+
+curl -d 'codeThemeEnCours=tous&codeTraitement=CourrierE&numu='$numu'&messageID=&action=&typeDossier=recu&dossierEnCours=ca' $iPROF';'$session 2>/dev/null | grep "document.f_message.messageID.value" | sed -e "s/.*messageID.value='<\([^>]*\)>'.*texteSouligne\">\([^<]*\)<.*texte\"[^>]*>\([^<]*\)<.*/\1 \3/g" >> $M
+
+Nouveau=`wc -l $M | cut -d" " -f1`
+Ancien=`wc -l $HOME/.iprof | cut -d" " -f1`
+
+if [ "x"$Nouveau != "x"$Ancien ];then
+  echo "Du nouveau sur I-prof"
+  rm $HOME/.iprof
+  cp $M $HOME/.iprof
+fi
+rm -f $M
diff --git a/mutt_check_attachment b/mutt_check_attachment
new file mode 100755 (executable)
index 0000000..f99112f
--- /dev/null
@@ -0,0 +1,75 @@
+#!/bin/bash
+
+## Original script adapted from source: http://wiki.mutt.org/?ConfigTricks/CheckAttach
+##
+## Adapted by Ismaël Bouya (http://www.normalesup.org/~bouya/) to make it so
+## that retrying to send the email shortly after will work
+##
+## Edit muttrc to have this line:
+## set sendmail = "/usr/local/bin/mutt_check_attachment_before_send.sh /usr/lib/sendmail -oem -oi"
+##
+
+
+## Attachment keywords that the message body will be searched for:
+KEYWORDS='attach|joint|voici|voil'
+
+## Check that sendmail or other program is supplied as first argument.
+if [ ! -x "$1" ]; then
+    echo "Usage: $0 </path/to/mailprog> <args> ..."
+    echo "e.g.: $0 /usr/sbin/sendmail -oem -oi"
+    exit 2
+fi
+
+## Save msg in file to re-use it for multiple tests.
+TMPFILE=`mktemp -t mutt_checkattach.XXXXXX` || exit 2
+cat > "$TMPFILE"
+
+## Define test for multipart message.
+function multipart {
+#    grep -q '^Content-Type: multipart' "$TMPFILE"
+    grep -q '^Content-Disposition: attachment' "$TMPFILE"
+}
+
+## Define test for keyword search.
+function word-attach {
+    grep -v '^>' "$TMPFILE" | grep -E -i -q "$KEYWORDS"
+}
+
+## Header override.
+function header-override {
+    grep -i -E "^X-attached: *none *$" "$TMPFILE"
+}
+
+function ask {
+       terminal=`tty`
+       dialog --yesno "Envoyer malgré la pièce jointe manquante ?" 5 30 < $terminal > $terminal
+       }
+
+#Verifie qu'on a essayé de l'envoyer y'a moins d'une minute
+function file_last {
+    if [ ! -e $HOME/.mutt_attach ]; then
+       return 0
+       fi
+    valeur=`echo \`date +%s\`-\`stat -c %Y $HOME/.mutt_attach\`'<60' | bc`
+    return $valeur
+}
+## FINAL DECISION:
+if multipart || ! word-attach || header-override || ! file_last ; then
+    "$@" < "$TMPFILE"
+    EXIT_STATUS=$?
+    if [ ! -s $HOME/.mutt_attach ]; then
+       rm -f $HOME/.mutt_attach
+       fi
+else
+    echo "No file was attached but a search of the message text suggests there should be one.  Add a header \"X-attached: none\" to override this check if no attachment is intended."
+    echo "You can also send the email again in the next minute."
+    EXIT_STATUS=1
+    touch $HOME/.mutt_attach
+fi
+
+## Delete the temporary file.
+rm -f "$TMPFILE"
+
+## That's all folks.
+exit $EXIT_STATUS
+
diff --git a/parse_bibtex_html b/parse_bibtex_html
new file mode 100755 (executable)
index 0000000..5e54729
--- /dev/null
@@ -0,0 +1,172 @@
+#!/usr/bin/env perl
+# The MIT License (MIT)
+# 
+# Copyright (c) 2011-2015 Ismaël Bouya http://www.normalesup.org/~bouya/
+# 
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+# 
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+
+use BibTeX::Parser;
+use IO::File;
+use utf8;
+use strict;
+use open ':utf8';
+
+sub parse_config_file {
+    my ($config_line, $Name, $Value, $Config);
+    (my $File, $Config) = @_;
+    if (!open (CONFIG, "$File")) {
+        print "ERROR: Config file not found : $File";
+        exit(0);
+    }
+    my $multiline = 0;
+
+    while (<CONFIG>) {
+        $config_line=$_;
+        chop ($config_line);
+        $config_line =~ s/^\s*//;
+        $config_line =~ s/\s*$//;
+        if ( ($config_line !~ /^#/) && ($config_line ne "") ){
+            if ($multiline) {
+              $$Config{$Name} =~ s/\\$//;
+              $$Config{$Name} .= $config_line;
+            } else {
+              ($Name, $Value) = split (/\s*=\s*/, $config_line);
+              $Value =~ s/^~/$ENV{"HOME"}/;
+              $$Config{$Name} = $Value;
+            }
+            $multiline = ($$Config{$Name} =~ /\\$/);
+        }
+    }
+    close(CONFIG);
+}
+
+my %Config;
+&parse_config_file ($ENV{"HOME"}."/.parse_bibtex_html.rc", \%Config);
+
+my $biblio = $Config{"biblio"};
+my $entete = $Config{"entete"};
+my $avant  = $Config{"avant"};
+my $milieu = $Config{"milieu"};
+my $apres  = $Config{"apres"};
+my $html   = $Config{"html"};
+
+my $dossier    = $Config{"dossier"};
+my $dossierweb = $Config{"dossier_web"};
+
+# http://webdesign.about.com/library/bl_htmlcodes.htm
+sub echap {
+    my $t = shift or return;
+    $t =~ s/&/&amp;/g;
+    $t =~ s/</&lt;/g;
+    $t =~ s/>/&gt;/g;
+
+    $t =~ s/--/&mdash;/g;
+
+    $t =~ s/{?\\'a}?/&aacute;/g;
+    $t =~ s/{?\\`a}?/&agrave;/g;
+    $t =~ s/{?\\"a}?/&auml;/g;
+
+    $t =~ s/{?\\r A}?/&Aring;/g;
+
+    $t =~ s/{?\\'e}?/&eacute;/g;
+    $t =~ s/{?\\`e}?/&egrave;/g;
+    $t =~ s/{?\\'E}?/&Eacute;/g;
+    $t =~ s/{?\\"e}?/&euml;/g;
+
+    $t =~ s/{?\\\^i}?/&icirc;/g;
+    $t =~ s/{?\\"i}?/&iuml;/g;
+
+    $t =~ s/{?\\"o}?/&ouml;/g;
+    $t =~ s/{?\\"o}?/&ouml;/g;
+    $t =~ s/{?\\=o}?/&#333;/g;
+    $t =~ s/{?\\o}?/&oslash;/g;
+
+    $t =~ s/{?\\"u}?/&uuml;/g;
+    $t =~ s/{?\\'u}?/&uacute;/g;
+
+    $t =~ s/{?\\~n}?/&ntilde;/g;
+
+    $t =~ s/{?\\c{?c}?}? ?/&ccedil;/g;
+    $t =~ s/{?\\'{?c}?}? ?/&#263;/g;
+
+    $t =~ s/{?\\v{? ?s}?}? ?/&#353;/g;
+
+    $t =~ s/{?\^({[^}]+}|.)}?/<sup>$1<\/sup>/g;
+    $t =~ s/{(.*)}/$1/g;
+    return $t;
+}
+
+open F, ">".$milieu;
+opendir(DIR, $dossier);
+my @FILES  = readdir(DIR); 
+my $fh     = IO::File->new($biblio);
+my $parser = BibTeX::Parser->new($fh);
+print F "\t<ul>\n";
+my %liste = ();
+
+while (my $entry = $parser->next ) {
+       if ($entry->parse_ok) {
+               my $type    = $entry->type;
+               my $title   = $entry->field("title");
+               my $key = $entry->key;
+               my @authors = $entry->author;
+#              my @editors = $entry->editor;
+               my $auth = "";
+               my @authors_sort = ();
+               foreach my $author (@authors) {
+                       $auth .= (($author->first)?$author->first. " ":"") .(($author->von)?$author->von." ":"") . (($author->last)?$author->last:"") . ", ";
+                       push(@authors_sort,$author->last);
+                       }
+               @authors_sort = sort {lc $a cmp lc $b} @authors_sort;
+               my $cle_sort = shift(@authors_sort);
+               $auth = substr $auth, 0 , -2;
+               my $suffix = '(\.|_)';
+               my @match = grep(/^$key$suffix/,@FILES);
+               my $i = 1;
+               my $chaine = "\t\t<li>";
+               $auth = echap $auth;
+               $title = echap $title;
+               if($auth =~ m/\\/ || $title =~ m/\\/) {
+                       warn "Unparsed item : $auth, $title";
+               }
+               $chaine .= "<span class='biblio_titre'>".$title."</span><br />".$auth."<br />\n";
+               @match = sort {lc $a cmp lc $b} @match;
+               foreach my $item (@match) {
+                       $chaine .= "\t\t\t<a href='".$dossierweb.$item."'>fichier ".$i++."</a> \n";
+                       }
+               $chaine .="\t\t\t<a id='".$key."' href='#".$key."' class='bibtex'>BibTeX</a>\n";
+               my $raw = $entry->raw_bibtex;
+               $raw =~ s/&/&amp;/g;
+               $chaine .= "\t\t\t<pre class='bibtex'>".$raw."</pre>\n";
+               $chaine .= "\t\t\t</li>\n";
+               $liste{$cle_sort." ".$key} = $chaine;
+       } else {
+               warn "Error parsing file: " . $entry->error;
+               }
+       }
+
+foreach my $key (sort keys %liste) {
+       print F $liste{$key};
+}
+
+print F "\t\t</ul>";
+close F;
+
+exec "cat $entete $avant $milieu $apres 1> $html" or die "$!\n";
diff --git a/remove_attachements b/remove_attachements
new file mode 100755 (executable)
index 0000000..b5243ab
--- /dev/null
@@ -0,0 +1,149 @@
+#!/usr/bin/env perl
+# Inspired by Aaron . Ciuffo (at gmail)
+
+# The MIT License (MIT)
+# 
+# Copyright (c) 2011-2015 Ismaël Bouya http://www.normalesup.org/~bouya/
+# 
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+# 
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+
+use strict;
+
+use Email::MIME;
+use DateTime;
+use Digest::MD5 qw(md5_hex);
+
+use vars qw(
+  $filter_attachments_file
+  $email $email_parsed
+  @email_parts
+  @new_email_parts
+  $mail_was_modified
+  @removed_files
+);
+
+@removed_files = ();
+@new_email_parts = ();
+$mail_was_modified = 0;
+my @mailr = ();
+my $premiere = 1;
+my $premiere_ligne;
+foreach( <STDIN> ) {
+    my $ligne = $_;
+    if($ligne =~ m/^From/ && $premiere) {
+       $premiere_ligne = $ligne;
+       next;
+    }
+    $premiere = 0;
+    if($ligne =~ m/^Content-Disposition: attachment; filename/) {
+       my $fichier = $ligne;
+       chomp($fichier);
+       if($ligne =~ m/^Content-Disposition: attachment; filename\*/) {
+           $fichier =~ s/^.*filename\*.*''([^\s]*)\s?.*$/\1/;
+           $fichier =~ s/%2E/./g;
+           $fichier =~ s/%20/_/g;
+           $fichier =~ s/%//g;
+           $ligne =~ s/filename\*.*''([^ \n\r\t]*)/filename="$fichier"/;
+       }
+       else {
+           $fichier =~ s/^.*filename="?(.*[^"])"?.*$/\1/;
+           $fichier =~ s/ /_/g;
+           $fichier =~ s/[^-a-zA-Z0-9_.]/_/g;
+           $ligne =~ s/filename=.*$/filename="$fichier"/;
+       }
+    }
+    push(@mailr,$ligne);
+}
+$email = join( '',@mailr );
+
+$filter_attachments_file = $ENV{HOME}."/.attachements/".DateTime->now(time_zone => 'local')->strftime('%Y%m%d_%H%M%S')."_".substr(md5_hex($email),0,5)."/" ;
+
+$email_parsed = Email::MIME->new( $email );
+if($email_parsed->content_type =~m[^multipart/encrypted]) {
+    print STDOUT $premiere_ligne;
+    print STDOUT $email_parsed->as_string;
+    exit;
+}
+
+my @parts = $email_parsed->parts;
+my $extension = "text/";
+$email_parsed->walk_parts(sub {
+    my ($part) = @_;
+    if ($part->content_type =~m[text/plain]i){
+       $extension = "text/plain";
+       return;
+    }
+});
+
+sub parse_parts {
+  my ($part) = @_;
+  if($part->content_type =~ m[$extension]i or $part->content_type =~ m[application/pgp-signature]i or !$part->content_type) {
+    push( @new_email_parts, $part);
+  }
+  elsif ($part->content_type =~ m[multipart/mixed]i) {
+    foreach( $part->subparts ) {
+      parse_parts($_);
+    }
+  }
+  else {
+       if(length($part->body) == 0) {
+               return;
+       }
+       if(!$mail_was_modified) {
+           mkdir $filter_attachments_file;
+           $mail_was_modified = 1;
+           push( @removed_files, "keepdir://".$filter_attachments_file);
+       }
+       my $fichier = $part->filename(1);
+       $fichier =~ s/ /\\ /g;
+       push( @removed_files, "file://".$filter_attachments_file.$fichier." ".$part->content_type );
+       open(my $out, '>:raw', $filter_attachments_file.$part->filename(1));
+       print $out $part->body;
+       close($out);
+  }
+}
+foreach( $email_parsed->subparts ) {
+  parse_parts($_);
+}
+
+if ($mail_was_modified)
+{
+   my $remove_string = "The following attachments were removed:";
+   $remove_string = $remove_string."\n".$_ foreach (@removed_files);
+   $remove_string = $email_parsed->debug_structure."\n".$remove_string;
+   push (@new_email_parts, Email::MIME->create(
+   attributes => {
+       content_type => "text/plain",
+       disposition => "attachment",
+       charset => "US-ASCII",
+       filename => "removed_attachments.txt"
+            },
+            body => $remove_string,
+        ) );
+   $email_parsed->parts_set( \@new_email_parts );
+   $email_parsed->content_type_set( 'multipart/mixed' );
+   $email = $email_parsed->as_string;   
+
+}
+
+print STDOUT $premiere_ligne;
+print STDOUT $email;
+
+
diff --git a/unicode_chars b/unicode_chars
new file mode 100755 (executable)
index 0000000..25f4522
--- /dev/null
@@ -0,0 +1,45 @@
+#!/usr/bin/env python3
+# The MIT License (MIT)
+# 
+# Copyright (c) 2011-2015 Ismaël Bouya http://www.normalesup.org/~bouya/
+# 
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+# 
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+import sys
+import unicodedata
+
+string = sys.stdin.readline().strip()
+for char in string:
+  print("U+%04x" % ord(char), end="")
+  if (ord(char) < 31):
+    print()
+  else:
+    print(" " + char + " ", end="")
+    try:
+      print(unicodedata.name(char), "["+unicodedata.category(char)+"]")
+      decomposition = unicodedata.decomposition(char).split(" ")
+      if len(decomposition) > 1:
+        for subchar in decomposition:
+          try:
+            unicode_char = chr(int(subchar, 16))
+            print("           U+%s" % subchar, unicodedata.name(unicode_char))
+          except ValueError:
+            print("           " + subchar)
+    except:
+      pass