From 3aae246cf7f4af7ae49da09e5ed0c180f31f0c12 Mon Sep 17 00:00:00 2001
From: fextracker <fextracker@treefish.org>
Date: Tue, 20 Sep 2016 04:00:06 +0200
Subject: [PATCH] Original release 20160919 2016-09-19: dop: do not show return
 value of &lt;&lt;perl-code;>> in dynamic html 2016-09-19: file if this code
 ends with a ";" 2016-09-07: new fex.ph config variable $purge 2016-09-01:
 dop: removed (forgotten) CGI::Carp 2016-08-29: fexsend,fexget: update
 function aborts if new version is not newer 2016-08-03: added timeout to
 error output, fixes hanging fup 2016-08-03: fexsend: fixed bug dangling
 symlinks raise an error in archive mode 2016-07-21: fexsrv: map http client
 headers HTTP-HOST HTTP-VERSION PROXY* to 2016-07-21: HTTP_X_HOST
 HTTP_X_VERSION HTTP_X_PROXY* 2016-07-11: added missing fex.png fexit.png to
 distribution 2016-05-31: fur: fixed bug no external user registration
 possible

---
 bin/ezz                             | 1074 +++++++++++++++++++++++++--
 bin/fbm                             |    2 +-
 bin/fex_cleanup                     |   11 +-
 bin/fexget                          |   17 +-
 bin/fexsend                         |   37 +-
 bin/fexsrv                          |   22 +-
 bin/fpg                             |   42 +-
 bin/l                               |   96 ++-
 bin/logwatch                        |    7 +-
 bin/sexsend                         |    2 +-
 bin/zz                              | 1067 +++++++++++++++++++++++++-
 cgi-bin/fac                         |    7 +-
 cgi-bin/fup                         |   10 +-
 cgi-bin/fur                         |    3 +-
 doc/Changes                         |   11 +
 doc/SSL                             |   46 +-
 doc/concept                         |   42 +-
 doc/new                             |    7 +-
 doc/version                         |    2 +-
 htdocs/FAQ/admin.faq                |    2 +-
 htdocs/FAQ/admin.html               |    5 +-
 htdocs/FAQ/all.html                 |    5 +-
 htdocs/FAQ/faq.pl                   |    2 +
 htdocs/FAQ/local.html               |    5 +-
 htdocs/FAQ/meta.faq                 |    2 +-
 htdocs/FAQ/meta.html                |    5 +-
 htdocs/FAQ/misc.html                |    5 +-
 htdocs/FAQ/user.html                |    5 +-
 htdocs/FAQ/xx.html                  |   15 +
 htdocs/FAQ/xx.pl                    |    6 +
 htdocs/FAQ/zz.pl                    |    1 +
 htdocs/download/fexget              |   17 +-
 htdocs/download/fexsend             |   37 +-
 htdocs/download/sexsend             |    2 +-
 htdocs/fex.png                      |  Bin 0 -> 7188 bytes
 htdocs/fexit.html                   |    5 +-
 htdocs/fexit.png                    |  Bin 0 -> 23729 bytes
 htdocs/version                      |    2 +-
 install                             |   13 +-
 lib/dop                             |   14 +-
 lib/fex.ph                          |   11 +
 lib/fex.pp                          |   10 +
 locale/czech/htdocs/FAQ/FAQ.html    |    5 +-
 locale/french/htdocs/FAQ/FAQ.html   |    5 +-
 locale/galician/htdocs/FAQ/FAQ.html |    5 +-
 locale/german/htdocs/FAQ/FAQ.html   |    5 +-
 locale/italian/htdocs/FAQ/FAQ.html  |    5 +-
 locale/spanish/htdocs/FAQ/FAQ.html  |    5 +-
 locale/translations                 |    2 +-
 49 files changed, 2469 insertions(+), 237 deletions(-)
 create mode 100644 htdocs/FAQ/xx.html
 create mode 100755 htdocs/FAQ/xx.pl
 create mode 100644 htdocs/FAQ/zz.pl
 create mode 100644 htdocs/fex.png
 create mode 100644 htdocs/fexit.png

diff --git a/bin/ezz b/bin/ezz
index 523dc8c..39dc91e 100755
--- a/bin/ezz
+++ b/bin/ezz
@@ -1,56 +1,1042 @@
-#!/bin/sh
+#!/usr/bin/perl -w
+#
+# vv : visual versioning
+# zz : generic shell clip board
+# ezz : clip board editor
+#
+# http://fex.rus.uni-stuttgart.de/fstools/vv.html
+# http://fex.rus.uni-stuttgart.de/fstools/zz.html
+#
+# by Ulli Horlacher <framstag@rus.uni-stuttgart.de>
+#
+# Perl Artistic Licence
+#
+# vv is a script to handle file versions:
+# list, view, recover, diff, purge, migrate, save, delete
+#
+# vv is an extension to emacs idea of backup~ files
+#
+# File versions are stored in local subdirectory .versions/
+#
+# To use vv with jed, install to your jed library path:
+#
+#   http://fex.rus.uni-stuttgart.de/sw/share/jedlib/vv.sl
+#
+# To use vv with vim, add to your .vimrc:
+#
+#   autocmd BufWritePre  * execute '! vv -s ' . shellescape(@%)
+#   autocmd BufWritePost * execute '! vv -b ' . shellescape(@%)
+#
+# To use vv with emacs, add to your .emacs:
+#
+#   (add-hook 'before-save-hook (lambda () (shell-command (
+#    concat "vv -s " (shell-quote-argument (buffer-file-name))))))
+#   (add-hook 'after-save-hook  (lambda () (shell-command (
+#    concat "vv -b " (shell-quote-argument (buffer-file-name))))))
+#   (setq make-backup-files nil)
+#
+# To use vv with ANY editor, first set:
+#
+#   export EDITOR=your_favourite_editor
+#   alias ve='vv -e'
+#
+# and then edit your file with:
+#
+#   ve file
+#
+# $HOME/.vvrc is the config file for vv
 
-ZZ=${ZZ:-$HOME/.zz}
+# 2013-04-15 initial version
+# 2013-04-16 added options -m and -v
+# 2013-04-18 added option -s
+# 2013-04-22 realfilename() fixes symlink problematics
+# 2013-04-22 use rsync instead of cp
+# 2013-04-23 added option -I
+# 2013-04-23 renamed from jedv to vv
+# 2013-04-24 added options -e -0
+# 2013-05-09 added option -R
+# 2013-05-22 modified option -d to double argument
+# 2013-05-22 added vvrc with $exclude and @diff
+# 2013-07-05 fixed bug potential endless loop in rotate()
+# 2014-04-16 added change-file-test for opt_s (needs .versions/$file)
+# 2014-04-18 added option -b : save backup
+# 2014-05-02 fixed bug wrong file ownership when using as root
+# 2014-06-18 options -r -d -v : parameter is optional, default is 1
+# 2014-06-18 fixed (stupid!) bug option -s does only sometimes saving
+# 2014-06-20 options -d -v : argument is optional, default is last file
+# 2014-07-22 fixed bug no (new) backup version 0 on option -r
+# 2014-11-14 added option -D : delete last saved version
+# 2014-11-14 make .versions/ mode 777 if parent directory is world writable
+# 2015-03-19 allow write access by root even if file and .versions/ have different owners
+# 2015-03-20 better error formating for jed
+# 2015-06-02 added option -r . to restore last saved backup
+# 2016-03-07 added options -M -L
+# 2016-03-08 renamed option -I to -H
+# 2016-05-02 added -A option to preserve ACLs with rsync
+# 2016-06-07 option -v : use PAGER=cat if STDOUT is not a tty
+# 2016-06-08 added zz, ezz and installer vvzz
+# 2016-07-06 avoid empty $ZZ versioning
+# 2016-09-12 added option -q quiet mode
 
-usage() {
-  exec cat<<EOD
-ezz is the edit helper program for the generic zz clip board program.
-The clip board is \$ZZ (default: \$HOME/.zz). Options and modes are:
+use Getopt::Std;
+use File::Basename;
+use Digest::MD5 'md5_hex';
+use Cwd 'abs_path';
 
-"ezz"                  edit \$ZZ
-"... | ezz"            write STDIN from pipe to \$ZZ and call editor
-"... | ezz +"          add STDIN from pipe to \$ZZ and call editor
-"ezz 'perl-script'"    run perl-script on \$ZZ
-"ezz - 'perl-script'"  run perl-script on \$ZZ and write result to STDOUT
-"ezz filter [args]"    run filter [with args] on \$ZZ
-"ezz - filter [args]"  run filter [with args] on \$ZZ and write result to STDOUT
-"ezz -r"               restore \$ZZ from last ezz operation (\$ZZ~)
+$prg = abs_path($0);
+$0 =~ s:.*/::;
+
+$ZZ = $ENV{ZZ} || "$ENV{HOME}/.zz";
+
+&install if $0 eq 'vvzz';
+&zz      if $0 eq 'zz';
+&ezz     if $0 eq 'ezz';
+
+# vv
+$usage = <<EOD;
+usage: $0 [-l] [file]
+       $0 -r . file
+       $0 -r version-number file [new-file]
+       $0 -d version-number[:version-number] file
+       $0 -v version-number file
+       $0 -s file
+       $0 -D file
+       $0 -e file
+       $0 -M file|.
+       $0 -L file|.
+       $0 -m [-R]
+       $0 -p
+       $0 -q
+       $0 -H
+options: -l   list available versions
+         -v   view version
+         -r   recover file (. is last saved backup)
+         -d   show diff
+         -s   save file to new version
+         -D   delete last saved version
+         -e   edit file with \$EDITOR (with versioning)
+         -p   purge orphaned versions (without current file)
+         -q   quiet mode
+         -m   migrate backup files to version files (-R all recursive)
+         -M   migrate to more versions (upto 100)
+         -L   migrate to less versions (upto 10)
+         -H   show more information
+examples: $0 project.pl
+          $0 -d 2 project.pl
+          $0 -r 2 project.pl project_2.pl
+EOD
+
+$vvrc = $ENV{HOME} . '/.vvrc';
+
+$opt_l = 1;
+$opt_h = $opt_p = $opt_m = $opt_s = $opt_0 = $opt_e = $opt_H = $opt_b = 0;
+$opt_q = $opt_D = $opt_R = 0;
+$opt_r = $opt_d = $opt_v = $opt_M = $opt_L = '';
+${'opt_+'} = 0;
+getopts('hHls0bepqmRDrdv+M:L:') or die $usage;
+
+if ($opt_h) {
+  print $usage;
+  exit;
+}
+
+if ($opt_H) {
+  open $prg,$prg or die "$0: $prg - $!\n";
+  $_ = <$prg>;
+  $_ = <$prg>;
+  while (<$prg>) {
+    last if /^\s*$/ or /^#\s*\d\d\d\d-\d\d-\d\d/;
+    print;
+  }
+  exit;
+}
+
+if ($opt_r) {
+  die "usage: $0 -r version-number file\n" unless @ARGV;
+  if ($ARGV[0] =~ /^(\d\d?|\.)$/) { $opt_r = shift }
+  else                            { $opt_r = 1 }
+  die "usage: $0 -r version-number file\n" if scalar @ARGV != 1;
+}
+
+if ($opt_d) {
+  if (@ARGV and $ARGV[0] =~ /^\d\d?(:\d\d?)?$/) { $opt_d = shift }
+  else                                          { $opt_d = 1 }
+  &check_ARGV;
+  die "usage: $0 -d version-number file\n" unless @ARGV;
+}
+
+if ($opt_v) {
+  if (@ARGV and $ARGV[0] =~ /^\d\d?$/) { $opt_v = shift }
+  else                                 { $opt_v = 1 }
+  &check_ARGV;
+  die "usage: $0 -v version-number file\n" unless @ARGV;
+}
+
+if ($0 eq 've' or $opt_e) {
+  $a = pop @ARGV or die $usage;
+  $opt_e = 1;
+} else {
+  $a = shift @ARGV;
+  die $usage if not $opt_r and @ARGV;
+}
+
+unless (-e $vvrc) {
+  open $vvrc,'>',$vvrc or die "$0: cannot write $vvrc - $!\n";
+  print {$vvrc} q{
+$exclude = q(
+  \.tmp$
+  ^mutt-.+-\d+
+  ^#.*#$
+);
+
+@diff = qw'diff -u';
+
+};
+  close $vvrc;
+}
+
+require $vvrc;
+
+if ($a) {
+
+  $file = realfilename($a);
+  $ofile = "$file~";
+  $bfile = basename($file);
+  $dir = dirname($file);
+  $vdir = "$dir/.versions";
+  $vfile = "$vdir/$bfile";
+  $vfile0 = "$vfile~0~";
+  $vfile1 = "$vfile~1~";
+  $vfile01 = "$vfile~01~";
+
+  # change eugid if root and version directory belongs user
+  my @s = stat($vdir);
+  if ($> == 0 and (not @s or $s[4])) {
+    if (my @s = stat($a)) {
+      $) = $s[5];
+      $> = $s[4];
+    }
+  }
+
+  if ($opt_r ne '.' and not ($opt_M or $opt_L)) {
+    if (not -e $file and -s $vfile) {
+      warn "$0: $a does not exist any more\n";
+      print "found $vfile - recover it? ";
+      $_ = <STDIN>;
+      copy($vfile,$file,'.') if /^y/i;
+      exit 0;
+    }
+    die "$0: $a does not exist\n" unless -e $file;
+    die "$0: $a is not a regular file\n" if -l $file or not -f $file;
+  }
+} else {
+  $file = '*';
+  $vdir = ".versions";
+}
+
+if ($opt_M) {
+  if (-d $opt_M and not -l $opt_M) {
+    my $vvv = "$opt_M/.versions";
+    mkdir $vvv;
+    die "$0: cannot mkdir $vvv - $!\n" unless -d $vvv;
+    opendir $vvv,$vvv or die "$0: cannot opendir $vvv - $!\n";
+    while (my $v = readdir($vvv)) {
+      mv100("$opt_M/$1") if -f "$vvv/$v" and $v =~ /(.+)~1~$/;
+    }
+    close $vvv;
+    $vvv .= "/.versions";
+    unless (-d $vvv) {
+      mkdir $vvv or die "$0: cannot mkdir $vvv - $!\n";
+    }
+    $vvv .= "/n";
+    unlink $vvv;
+    symlink 100,$vvv or die "$0: cannot create $vvv - $!\n";
+  } else {
+    die "usage: $0 -M file\n" if @ARGV or $opt_r;
+    mv100($opt_M);
+  }
+  exit;
+}
+
+if ($opt_L) {
+  if (-d $opt_L and not -l $opt_L) {
+    my $vvv = "$opt_L/.versions";
+    mkdir $vvv;
+    die "$0: cannot mkdir $vvv - $!\n" unless -d $vvv;
+    opendir $vvv,$vvv or die "$0: cannot opendir $vvv - $!\n";
+    while (my $v = readdir($vvv)) {
+      mv10("$opt_L/$1") if -f "$vvv/$v" and $v =~ /(.+)~01~$/;
+    }
+    closedir $vvv;
+    $vvv .= "/.versions";
+    unless (-d $vvv) {
+      mkdir $vvv or die "$0: cannot mkdir $vvv - $!\n";
+    }
+    $vvv .= "/n";
+    unlink $vvv;
+    symlink 10,$vvv or die "$0: cannot create $vvv - $!\n";
+  } else {
+    die "usage: $0 -L file\n" if @ARGV or $opt_r;
+    mv10($opt_L);
+  }
+  exit;
+}
+
+if ($opt_e) {
+  die $usage unless $a;
+  $editor = $ENV{EDITOR} or die "$0: environment variable EDITOR not set\n";
+  system(qw'vv -s',$file) if -f $file; # save current version
+  system($editor,@ARGV,$file); exit $? if $?;
+  unlink $ofile;                       # delete new file~ created by editor
+  system(qw'vv -0',$file);             # post rotating
+  system(qw'vv -b',$file);             # save backup
+  exit;
+}
+
+if ($opt_v) {
+  die "$0: no such file $bfile\n" unless $bfile;
+  if (-f "$vfile~0$opt_v~") { $vfile .= "~0$opt_v~" }
+  else                      { $vfile .= "~$opt_v~" }
+  if (-f $vfile) {
+    if (-t STDOUT) {
+      if (($ENV{EDITOR}||$0) =~ /jed/) {
+        $ENV{JEDINIT} = "SAVE_STATE=0";
+        exec 'jed',$vfile,qw'-tmp -f set_readonly(1)';
+      } elsif ($ENV{PAGER}) {
+        exec $ENV{PAGER},$vfile;
+      } else {
+        exec 'view',$vfile;
+      }
+    } else {
+      exec 'cat',$vfile;
+    }
+  } else {
+    die "$0: no $vfile\n";
+  }
+  exit;
+}
+
+if ($opt_p) {
+  opendir $vdir,$vdir or die "$0: no $vdir\n";
+  while ($vfile = readdir($vdir)) {
+    next unless -f "$vdir/$vfile";
+    $bfile = $vfile;
+    $bfile =~ s/~\d\d?~$//;
+    if (not -f $bfile or -l $bfile) {
+      unlink "$vdir/$vfile";
+      $purge{$bfile}++;
+    }
+  }
+  if (@purge = keys %purge) {
+    foreach $p (@purge) {
+      printf "%2d %s~ purged\n",$purge{$p},$p;
+    }
+  }
+  exit;
+}
+
+if ($opt_m) {
+  migrate('.');
+  exit;
+}
+
+if (length($opt_r)) {
+  die "$0: no such file $bfile\n" unless $bfile;
+  if ($opt_r eq '.') {
+    die "$0: no $vfile\n" unless -f $vfile;
+    copy($vfile,$file,$opt_r);
+  } else {
+    if ($opt_r =~ /^\d$/ and -f "$vfile~0$opt_r~") {
+      $vfile .= "~0$opt_r~"
+    } else {
+      $vfile .= "~$opt_r~"
+    }
+    die "$0: no version $opt_r for $file\n" unless -f $vfile;
+    if ($nfile = shift @ARGV) {
+      copy($vfile,$nfile);
+    } else {
+      copy($file,$vfile0) if mtime($file) > mtime($vfile0);
+      copy($vfile,$file);
+    }
+  }
+  exit;
+}
+
+if (length($opt_d)) {
+  die "$0: no such file $bfile\n" unless $bfile;
+  @diff = qw'diff -u' unless @diff;
+  if ($opt_d =~ /^(\d\d?):(\d\d?)$/) {
+    if (-f "$vdir/$bfile~0$1~" and -f "$vdir/$bfile~0$2~") {
+      exec @diff,"$vdir/$bfile~0$2~","$vdir/$bfile~0$1~"
+    } else {
+      exec @diff,"$vdir/$bfile~$2~","$vdir/$bfile~$1~"
+    }
+  } else {
+    if (-f "$vdir/$bfile~0$opt_d~") {
+      exec @diff,"$vdir/$bfile~0$opt_d~",$file;
+    } else {
+      exec @diff,"$vdir/$bfile~$opt_d~",$file;
+    }
+  }
+  exit $!;
+}
+
+if ($opt_s) {
+  die $usage unless $file;
+  if ($exclude) {
+    $exclude =~ s/^\s+//;
+    $exclude =~ s/\s+$//;
+    $exclude =~ s/\s+/|/g;
+    if ($bfile =~ /$exclude/) {
+      warn "\r\n$0: ignoring $bfile\n";
+      exit;
+    }
+  }
+  unless (-d $vdir) {
+    mkdir $vdir or die "$0: cannot mkdir $vdir - $!\n";
+  }
+  chmod 0777,$vdir if (stat $dir)[2] & 00002;
+
+  # migrate old file~ to versions
+  if (-f $ofile and not -l $ofile and -r $ofile) {
+    $vfn = rotate($vfile);
+    rename($ofile,$vfn);
+  }
+
+  # rotate and save if file has changed
+  if (-f $vfile1) {
+    if (md5f($vfile1) ne md5f($file)) {
+      $vfn = rotate($vfile);
+      copy($file,$vfn);
+    }
+    exit;
+  }
+  # rotate and save if file has changed
+  if (-f $vfile01) {
+    if (md5f($vfile01) ne md5f($file)) {
+      $vfn = rotate($vfile);
+      copy($file,$vfn);
+    }
+    exit;
+  }
+  # save new file
+  if ((readlink("$vdir/.versions/n")||10) == 100) {
+    copy($file,$vfile01);
+  } else {
+    copy($file,$vfile1);
+  }
+  exit;
+}
+
+# backup version
+if ($opt_b) {
+  die $usage unless $file;
+  unless (-d $vdir) {
+    mkdir $vdir or die "\r\n$0: cannot mkdir $vdir - $!\n";
+  }
+  copy($file,$vfile);
+  if ($ENV{VIMRUNTIME}) {
+    print "\n";
+  } else {
+    warn "$file --> $vfile\n" unless $opt_q;
+  }
+  exit;
+}
+
+# special post rotating from -e
+if ($opt_0) {
+  my @sb = stat $file or die "$0: $file - $!\n";
+  if (-f $vfile1) {
+    while (my @sv = stat $vfile1) {
+      # no version change?
+      if ($sb[7] == $sv[7] and $sb[9] == $sv[9]) {
+        # rotate back
+        rb10($vfile);
+      } else {
+        last;
+      }
+    }
+  }
+  if (-f $vfile01) {
+    while (my @sv = stat $vfile01) {
+      # no version change?
+      if ($sb[7] == $sv[7] and $sb[9] == $sv[9]) {
+        # rotate back
+        rb10($vfile);
+      } else {
+        last;
+      }
+    }
+  }
+  exit;
+}
+
+# delete last version, roll back
+if ($opt_D) {
+  die "usage: $0 -D file\n" unless $vfile1 or $vfile01;
+  stat $file or die "$0: $file - $!\n";
+  # 0 version?
+  if (-f $vfile0) {
+    unlink $vfile0;
+  } else {
+    # rotate back
+    rb10($vfile) if -f $vfile1;
+    rb100($vfile) if -f $vfile01;
+  }
+  exec $0,'-l',$file;
+  exit;
+}
+
+# default!
+if ($opt_l) {
+  `stty -a` =~ /columns (\d+)/;
+  $tw = ($1 || 80)-36;
+  if (opendir $vdir,$vdir) {
+    while ($vfile = readdir($vdir)) {
+      if (-f "$vdir/$vfile") {
+        if ($bfile) {
+          if ($vfile =~ /^\Q$bfile\E~(\d\d?)~$/) {
+            push @{$v{$file}},$1;
+          }
+        } else {
+          if ($vfile =~ /^(.+)~(\d\d?)~$/) {
+            push @{$v{$1}},$2;
+          } else {
+            push @{$v{$vfile}},0;
+          }
+        }
+      }
+    }
+    closedir $vdir;
+    $ct = '';
+    foreach $file (sort keys %v) {
+      if (not -f $file or -l $file) {
+        warn "$0: orphaned $file~\n";
+        next;
+      }
+      @v = sort @{$v{$file}};
+      if ($bfile) {
+        @stat = stat $file or die "$0: $file - $!\n";
+        print "version bytes        date time";
+        if (${'opt_+'}) {
+          print "     content";
+          $ct = content($file);
+          $ct =~ s/(.{$tw}).+/$1*/;
+        }
+        print "\n";
+        if (length($v[0]) == 1) { $lf = "%s  %10s  %s %s\n" }
+        else                    { $lf = "%2s %10s  %s %s\n" }
+        printf $lf,'.',size($stat[7]),isodate($stat[9]),$ct;
+        foreach $v (@v) {
+          $vfile = "$vdir/$bfile~$v~";
+          @stat = stat $vfile or next;
+          if (${'opt_+'}) {
+            $ct = content($vfile);
+            $ct =~ s/(.{$tw}).+/$1*/;
+          }
+          printf $lf,int($v),size($stat[7]),isodate($stat[9]),$ct;
+        }
+      } else {
+        my $n = scalar(@v);
+        $n-- if $v[0] == 0; # do not count zero version
+        printf "%d %s\n",$n,$file;
+      }
+    }
+  }
+  exit;
+}
+
+
+sub size {
+  my $s = shift;
+  if    ($s > 9999999999) { $s = int($s/2**30).'G' }
+  elsif ($s > 9999999)    { $s = int($s/2**20).'M' }
+  elsif ($s > 9999)       { $s = int($s/2**10).'k' }
+  return $s;
+}
+
+
+sub content {
+  my $file = shift;
+  my $ct;
+  local $_;
+
+  chomp ($ct = `file $file`);
+  $ct =~ s/.*?: //;
+  $ct =~ s/,.*//;
+
+  if ($ct =~ /text/ and open $file,$file) {
+    read $file,$_,1024;
+    close $file;
+    s/[\x00-\x20]+/ /g;
+    s/^ //;
+    s/ $//;
+    $ct = '"'.$_.'"';
+  }
+
+  return $ct;
+}
+
+
+sub isodate {
+  my @d = localtime shift;
+  return sprintf('%d-%02d-%02d %02d:%02d:%02d',
+                 $d[5]+1900,$d[4]+1,$d[3],$d[2],$d[1],$d[0]);
+}
+
+sub rotate {
+  my $vf = shift; # version base file
+  my $vf1 = "$vf~1~";
+  my $vf01 = "$vf~01~";
+  my ($vfi,$vfn);
+
+  if (-f $vf1) {
+    for (my $i = 8; $i >= 0; $i--) {
+      $vfi = sprintf("%s~%d~",$vf,$i);
+      $vfn = sprintf("%s~%d~",$vf,$i+1);
+      if (-e $vfi) {
+        rename $vfi,$vfn or die "$0: $vfi --> $vfn : $!\n";
+      }
+    }
+    # was there a version 0?
+    if (-e $vf1) {
+      my $bf = $vf;
+      $bf =~ s:/\.versions/:/:;
+      my @sb = stat $bf;
+      my @sv = stat $vf1;
+      # version change? (other size or mtime)
+      if (@sb and @sv and $sb[7] == $sv[7] and $sb[9] == $sv[9]) {
+        # same version
+        unlink $vf1;
+      } else {
+        # other version
+        rotate($vf);
+      }
+    }
+    return "$vf~1~";
+  } elsif (-f $vf01) {
+    for (my $i = 98; $i >= 0; $i--) {
+      $vfi = sprintf("%s~%02d~",$vf,$i);
+      $vfn = sprintf("%s~%02d~",$vf,$i+1);
+      if (-e $vfi) {
+        rename $vfi,$vfn or die "$0: $vfi --> $vfn : $!\n";
+      }
+    }
+    # was there a version 0?
+    if (-e $vf01) {
+      my $bf = $vf;
+      $bf =~ s:/\.versions/:/:;
+      my @sb = stat $bf;
+      my @sv = stat $vf01;
+      # version change? (other size or mtime)
+      if (@sb and @sv and $sb[7] == $sv[7] and $sb[9] == $sv[9]) {
+        # same version
+        unlink $vf01;
+      } else {
+        # other version
+        rotate($vf);
+      }
+    }
+    return "$vf~01~";
+  }
+
+  return "$vf~1~";
+}
+
+sub copy {
+  my ($from,$to,$restore) = @_;
+
+  unless ($restore) {
+    if (-l $file or not -f $file) {
+      die "$0: $file is not a regular file\n";
+    }
+  }
+
+  if (open $to,'>>',$to) {
+    close $to;
+    if (system(qw'rsync -aA',$from,$to) == 0) {
+      if ($ENV{VIMRUNTIME}) {
+        print "\n";
+      } else {
+        warn "$from --> $to\n" unless $opt_q;
+      }
+    } else {
+      exit $?;
+    }
+  } else {
+    die "\r\n$0: cannot write $to - $!\n";
+  }
+}
+
+sub realfilename {
+  my $file = shift;
+
+  return $file unless -e $file;
+
+  if (-l $file) {
+    my $link = readlink($file);
+    if ($link !~ /^\// and $file =~ m:(.*/).:) {
+      $link = $1 . $link;
+    }
+    return realfilename($link);
+  } else {
+    return $file;
+  }
+}
+
+sub migrate {
+  my $dir = shift;
+  my $vdir = "$dir/.versions";
+  my $dfile;
+
+  opendir $dir,$dir or die "$0: cannot read directory $dir - $!\n";
+  while ($file = readdir($dir)) {
+    $dfile = "$dir/$file";
+    next if -l $dfile or $file eq '.' or $file eq '..';
+    if (-d $dfile and $opt_R and $file ne '.versions') {
+      migrate($dfile);
+    } elsif (-f $dfile and $file =~ /~$/) {
+      if (-d $vdir) {
+        for ($i = 8; $i > 0; $i--) {
+          $n = $i+1;
+          rename "$vdir/$file$i~","$vdir/$file$n~";
+        }
+      } else {
+        mkdir $vdir or die "$0: cannot mkdir $vdir - $!\n";
+      }
+      $nfile = sprintf("%s/%s1~",$vdir,$file);
+      rename $dfile,$nfile or die "$0: cannot move $dfile to $nfile - $!\n";
+      warn "$dfile --> $nfile\n" unless $opt_q;
+    }
+  }
+  closedir $dir;
+}
+
+sub mtime {
+  my @s = stat shift;
+  return @s ? $s[9] : 0;
+}
+
+sub md5f {
+  my $file = shift;
+  my $md5 = 0;
+  local $/;
+
+  if (open $file,$file) {
+    $md5 = md5_hex(<$file>);
+    close $file;
+  }
+  return $md5;
+}
+
+
+# if ARGV is empty use last saved file as default file argument
+sub check_ARGV {
+  local $_;
+  local *V;
+
+  if (not @ARGV) {
+    if (-d '.versions' and open V,'ls -at .versions|') {
+      while (<V>) {
+        chomp;
+        if (-f) {
+          close V;
+          s/~\d+~$//;
+          @ARGV = ($_);
+          return;
+        }
+      }
+    }
+  }
+
+}
+
+
+sub mv10 {
+  my $file = shift;
+  my $vfile = dirname($file).'/.versions/'.basename($file);
+
+  die "$0: $file has no extended versions\n" unless -f "$vfile~01~";
+  for (my $i=1; $i<10; $i++) {
+    my $vfile1 = "$vfile~$i~";
+    my $vfile2 = "$vfile~0$i~";
+    if (-f $vfile2) {
+      warn "$vfile2 --> $vfile1\n" unless $opt_q;
+      rename $vfile2,$vfile1 or die "$0: $!\n";
+    }
+  }
+  for (my $i=10; $i<100; $i++) {
+    unlink "$vfile~$i~";
+  }
+}
+
+sub mv100 {
+  my $file = shift;
+  my $vfile = dirname($file).'/.versions/'.basename($file);
+
+  die "$0: $file has already extended versions\n" if -f "$vfile~01~";
+  die "$0: $file has no versions\n" unless -f "$vfile~1~";
+  for (my $i=1; $i<10; $i++) {
+    my $vfile1 = "$vfile~$i~";
+    my $vfile2 = "$vfile~0$i~";
+    if (-f $vfile1) {
+      warn "$vfile1 --> $vfile2\n" unless $opt_q;
+      rename $vfile1,$vfile2 or die "$0: $!\n";
+    }
+  }
+}
+
+
+# rotate back
+sub rb10 {
+  my $vfile = shift;
+
+  for (my $i = 1; $i <= 8; $i++) {
+    my $vfi = sprintf("%s~%d~",$vfile,$i);
+    my $vfn = sprintf("%s~%d~",$vfile,$i+1);
+    if (-f $vfn) {
+      rename $vfn,$vfi;
+    } else {
+      unlink $vfi if $i == 1;
+      last;
+    }
+  }
+}
+
+
+# rotate back
+sub rb100 {
+  my $vfile = shift;
+
+  for (my $i = 1; $i <= 98; $i++) {
+    my $vfi = sprintf("%s~%02d~",$vfile,$i);
+    my $vfn = sprintf("%s~%02d~",$vfile,$i+1);
+    if (-f $vfn) {
+      rename $vfn,$vfi;
+    } else {
+      unlink $vfi if $i == 1;
+      last;
+    }
+  }
+}
+
+
+
+sub pathsearch {
+  my $prg = shift;
+
+  foreach my $dir (split(':',$ENV{PATH})) {
+    return "$dir/$prg" if -x "$dir/$prg";
+  }
+}
+
+
+# zz is the generic clip board program
+#
+# to use zz with vim, write to your .vimrc:
+#
+# noremap <silent> zz> :w !zz<CR><CR>
+# noremap <silent> zz< :r !zz --<CR>
+sub zz {
+  my $bs = 2**16;
+  my $wm = '>';
+  my ($file,$tee,$x);
+
+  if ("@ARGV" =~ /^(-h|--help)$/) {
+    print <<'EOD';
+zz is the generic clip board program. It can hold any data, ASCII or binary.
+The clip board itself is $ZZ (default: $HOME/.zz).
+See also the clip board editor "ezz".
+Limitation: zz does not work across accounts or hosts! Use xx instead.
+
+Options and modes are:
+
+  "zz"              show content of $ZZ
+  "zz file(s)"      copy file(s) content into $ZZ
+  "zz -"            write STDIN (keyboard, mouse buffer) to $ZZ
+  "zz +"            add STDIN (keyboard, mouse buffer) to $ZZ
+  "... | zz"        write STDIN from pipe to $ZZ
+  "... | zz +"      add STDIN from pipe to $ZZ
+  "... | zz -"      write STDIN from pipe to $ZZ and STDOUT
+  "zz | ..."        write $ZZ to pipe
+  "... | zz | ..."  save pipe data to $ZZ (like tee)
+  "zz --"           write $ZZ to STDOUT
+  "zz -v"           show clip board versions (history)
+  "zz -1"           write $ZZ version 1 to STDOUT
+  "zz -9"           write $ZZ version 9 to STDOUT
+
+Examples:
+
+  zz *.txt
+  ls -l | zz
+  zz | wc -l
+  (within vi)   :w !zz
+  (within vi)   :r !zz
+  (within mutt) |zz
+EOD
+    exit;
+  }
+
+  if ("@ARGV" eq '-v') {
+    exec qw'vv -+l',$ZZ;
+  }
+
+  if ("@ARGV" =~ /^-(\d)$/) {
+    exec "vv -v $1 '$ZZ' | cat";
+  }
+
+  # read mode
+  if (-t STDIN and not @ARGV or "@ARGV" eq '--') {
+    exec 'cat',$ZZ;
+  }
+
+  # write mode
+  system "vv -s '$ZZ' >/dev/null 2>&1" if -s $ZZ;
+
+  if (@ARGV and $ARGV[0] eq '+') {
+    shift @ARGV;
+    $wm = '>>';
+  }
+
+  if ("@ARGV" eq '-') {
+    @ARGV = ();
+    $tee = 1 unless -t STDIN;
+  }
+
+ $tee = 1 unless @ARGV or -t STDIN or -t STDOUT;
+ $bs = 2**12 if $tee;
+
+  open $ZZ,$wm,$ZZ or die "$0: cannot write $ZZ - $!\n";
+
+  if (@ARGV) {
+    while ($file = shift @ARGV) {
+      if (-f $file) {
+        if (open $file,$file) {
+          while (read($file,$x,$bs)) {
+            my $s = syswrite $ZZ,$x;
+            defined($s) or die "$0: cannot write to $ZZ - $!\n";
+          }
+          close $file;
+        } else {
+          warn "$0: cannot read $file - $!\n";
+        }
+      } elsif (-e $file) {
+        warn "$0: $file is not a regular file\n";
+      } else {
+        warn "$0: $file does not exist\n";
+      }
+    }
+    close $ZZ;
+    $ZZ1 = $ZZ.'~1~';
+    $ZZ1 =~ s:(.*)/(.*):$1/.versions/$2:;
+    if (-e $ZZ and not -s $ZZ and -s $ZZ1 ) {
+      system qw'rsync -aA',$ZZ1,$ZZ;
+    }
+  } else {
+    while (read(STDIN,$x,$bs)) {
+      syswrite $ZZ,$x;
+      syswrite STDOUT,$x if $tee;
+    }
+  }
+
+  exit;
+}
+
+
+sub ezz {
+  my $bs = 2**16;
+  my $wm = '>';
+  my $editor = $ENV{EDITOR} || 'vi';
+  my ($out,$file,$x);
+
+  $ENV{JEDINIT} = "SAVE_STATE=0";
+
+  if ("@ARGV" =~ /^(-h|--help)$/) {
+    print <<'EOD';
+ezz is the edit helper for the zz clip board program.
+The clip board itself is $ZZ (default: $HOME/.zz).
+
+Options and modes are:
+
+  "ezz"                    edit $ZZ with $EDITOR
+  "... | ezz"              write STDIN from pipe to $ZZ and call $EDITOR
+  "... | ezz +"            add STDIN from pipe to $ZZ and call $EDITOR
+  "ezz 'perl commands'"    execute perl commands on $ZZ
+  "ezz - 'perl commands'"  execute perl commands on $ZZ and show result
+  "ezz filter [args]"      run filter [with args] on $ZZ
+  "ezz - filter [args]"    run filter [with args] on $ZZ and show result
 
 Examples:
 
   ls -l | ezz
-  ezz "s/ /_/g"
+  ezz 's/ /_/g'
   ezz head -3
   ezz - head -3
-
-Limitation: zz does not work across different accounts!
 EOD
+    exit;
+  }
+
+  system "vv -s '$ZZ' >/dev/null 2>&1" if -s $ZZ;
+
+  unless (-t STDIN) {
+    if ("@ARGV" eq '+') {
+      @ARGV = ();
+      $wm = '>>';
+    }
+    open $ZZ,$wm,$ZZ or die "$0: cannot write $ZZ - $!\n";
+    syswrite $ZZ,$x while read(STDIN,$x,$bs);
+    close $ZZ;
+  }
+
+  if (@ARGV) {
+    $out = shift @ARGV if $ARGV[0] eq '-';
+    $cmd = shift @ARGV or exec 'cat',$ZZ;
+    rename $ZZ,"$ZZ~" or die "$0: cannot move $ZZ to $ZZ~ - $!\n";
+    $cmd = quotemeta $cmd;
+    @ARGV = map { quotemeta } @ARGV;
+    if (pathsearch($cmd)) {
+      system "$cmd @ARGV <'$ZZ~'>'$ZZ'";
+    } else {
+      system "perl -pe $cmd @ARGV <'$ZZ~'>'$ZZ'";
+    }
+    if ($? == 0) { unlink "$ZZ~" }
+    else         { rename "$ZZ~",$ZZ }
+    exec 'cat',$ZZ if $out;
+  } else {
+    exec $editor,$ZZ;
+  }
+  exit;
 }
 
-JEDINIT="SAVE_STATE=0"; export JEDINIT
-
-if [ ! -t 0 ]; then
-  if [ x"$1"x = x+x ]; then
-    shift
-    cat >>$ZZ
-  else
-    cat >$ZZ
-  fi
-fi
-
-test -z "$1" && exec ${EDITOR:-vi} $ZZ
-
-case "X$*" in
-  X-h) usage;;
-  X-r) exec mv $ZZ~ $ZZ;;
-esac
-
-OUT="$1"
-test "X$OUT" = X- && shift
-test -z "$1" && exec cat $ZZ
-mv $ZZ $ZZ~
-case `type "$1" 2>&1` in
-  *not\ found) perl -pe "$@" <$ZZ~>$ZZ || mv $ZZ~ $ZZ;;
-            *) "$@"          <$ZZ~>$ZZ || mv $ZZ~ $ZZ;;
-esac
-test "X$OUT" = X- && exec cat $ZZ
+
+sub install {
+  my ($dir);
+  local $| = 1;
+
+  print "Installation directory: ";
+  $dir = <STDIN>||'';
+  chomp $dir;
+  $dir =~ s:/+$::;
+  $dir ||= '.';
+  if ($dir eq '.') {
+    unlink qw'zz ezz vv';
+    link $prg,'zz'   or die "$0: cannot create zz - $!\n";
+    link $prg,'ezz'  or die "$0: cannot create ezz - $!\n";
+    rename $prg,'vv' or die "$0: cannot create vv - $!\n";
+  } else {
+    die "$0: $dir does not exist\n"     unless -e $dir;
+    die "$0: $dir is not a directory\n" unless -d $dir;
+    die "$0: $dir is not writable\n"    unless -w $dir;
+    chdir $dir or die "$0: cannot cd $dir - $!\n";
+    unlink qw'zz ezz vv';
+    system qw'rsync -a',$prg,'vv';
+    exit $? if $?;
+    link 'vv','zz'  or die "$0: cannot create $dir/zz - $!\n";
+    link 'vv','ezz' or die "$0: cannot create $dir/ezz - $!\n";
+  }
+  print "Installation completed. See:\n";
+  print "\t$dir/vv -h\n";
+  print "\t$dir/zz -h\n";
+  print "\t$dir/ezz -h\n";
+  exit;
+}
diff --git a/bin/fbm b/bin/fbm
index 1d9c10d..e6d81aa 100755
--- a/bin/fbm
+++ b/bin/fbm
@@ -20,7 +20,7 @@ use constant M => 2**20;
 
 our ($SH,$windoof,$sigpipe,$useragent);
 our ($FEXSERVER);
-our $version = 20160328;
+our $version = 20160919;
 
 # server defaults
 my $server = 'fex.rus.uni-stuttgart.de';
diff --git a/bin/fex_cleanup b/bin/fex_cleanup
index 1d87dcf..1f38d6b 100755
--- a/bin/fex_cleanup
+++ b/bin/fex_cleanup
@@ -41,7 +41,8 @@ our ($FEXHOME);
 our ($spooldir,@logdir,$docdir);
 our ($akeydir,$ukeydir,$dkeydir,$skeydir,$gkeydir,$xkeydir,$lockdir);
 our ($durl,$debug,$autodelete,$hostname,$admin,$admin_pw,$bcc);
-$keep_default = 5;
+our $keep_default = 5;
+our $purge = $keep_default*3;
 
 # load common code, local config : $HOME/lib/fex.ph
 require "$FEXLIB/fex.pp" or die "$0: cannot load $FEXLIB/fex.pp - $!\n";
@@ -418,8 +419,9 @@ exit;
 sub cleanup {
   my ($to,$from,$file) = @_;
   my ($data,$download,$notify,$mtime,$warn,$dir,$filename,$dkey,$delay);
-  my $comment = '';
   my $keep = $keep_default;
+  my $purge = $::purge || 3*$keep;
+  my $comment = '';
   my $kf = "$to/$from/$file/keep";
   my $ef = "$to/$from/$file/error";
   local $_;
@@ -440,8 +442,9 @@ sub cleanup {
         logdel($file,"$file deleted");
       }
     } elsif ($mtime = lmtime("$file/error")) {
-      if ($today > 3*$keep*DS+$mtime) {
-        verbose("rmrf $file (today=$today mtime_error=$mtime keep=$keep)");
+      $purge = $1*$keep if $purge =~ /(\d+).*keep/;
+      if ($today > $purge*DS+$mtime) {
+        verbose("rmrf $file (today=$today mtime_error=$mtime keep=$keep purge=$purge)");
         logdel($file,"$file deleted");
       }
     } else {
diff --git a/bin/fexget b/bin/fexget
index b0616a1..3ac605f 100755
--- a/bin/fexget
+++ b/bin/fexget
@@ -13,6 +13,7 @@ use strict qw'vars subs';
 use Config;
 use POSIX;
 use Encode;
+use Cwd 'abs_path';
 use Getopt::Std;
 use File::Basename;
 use Socket;
@@ -30,7 +31,7 @@ our $SH;
 our ($fexhome,$idf,$tmpdir,$windoof,$useragent);
 our ($xv,%autoview);
 our $bs = 2**16; # blocksize for tcp-reading and writing file
-our $version = 20160328;
+our $version = 20160919;
 our $CTYPE = 'ISO-8859-1';
 our $fexsend = $ENV{FEXSEND} || 'fexsend';
 our $DEBUG = $ENV{DEBUG};
@@ -89,6 +90,7 @@ usage: $0 [-v] [-m limit] [-s filename] [-o] [-k] [-X] [-P proxy:port] F*EX-URL(
    or: $0 [-v] -a
    or: $0 -l [-i tag]
    or: $0 -H
+   or: $0 -V
 options: -v verbose mode
          -m limit kB/s
          -s save to filename (-s- means: write to STDOUT/pipe)
@@ -102,6 +104,7 @@ options: -v verbose mode
          -i tag alternate server/account, see: $fexsend -h
          -P use Proxy for connection to the F*EX server
          -H show hints and examples
+         -V show version and ask for upgrade
 argument: F*EX-URL may be file number (see: $0 -l)
 EOD
 
@@ -167,10 +170,15 @@ if ($opt_V) {
     $_ = <STDIN>||'';
     if (/^y/i) {
       my $new = `wget -nv -O- http://fex.belwue.de/download/fexget`;
-      if ($new !~ /upgrade fexget/) {
+      my $newversion = $1 if $new =~ /version = (\d+)/;
+      if ($new !~ /upgrade fexget/ or not $newversion) {
         die "$0: bad update\n";
       }
-      system qw'cp -a',$_0,$_0.'_old';
+      if ($newversion <= $version) {
+        die "$0: no newer version\n";
+      }
+      $_0 = abs_path($_0);
+      system qw'rsync -a',$_0,$_0.'_old';
       exit $? if $?;
       open $_0,'>',$_0 or die "$0: cannot write $_0. - $!\n";
       print {$_0} $new;
@@ -178,6 +186,7 @@ if ($opt_V) {
       exec $_0,qw'-V .';
     }
   }
+  exit;
   exit if "@ARGV" eq '.';
 }
 
@@ -328,7 +337,7 @@ URL: foreach my $url (@ARGV) {
       ($file) = grep { $_ = $1 if /^X-File:\s+(.+)/ } @r;
       $file = $url unless $file;
       $file =~ s:.*/::;
-      printf "%s deleted\n",urldecode($file);
+      printf "%s deleted\n",locale(decode_utf8(urldecode($file)));
     } else {
       s:HTTP/[\d\. ]+::;
       die "$0: server response: $_";
diff --git a/bin/fexsend b/bin/fexsend
index f47bed4..fae77e9 100755
--- a/bin/fexsend
+++ b/bin/fexsend
@@ -17,10 +17,10 @@ use IO::Handle;
 use IO::Socket::INET;
 use Getopt::Std;
 use File::Basename;
-use Cwd qw'abs_path';
+use Cwd 'abs_path';
 use Fcntl qw':flock :mode';
-use Digest::MD5 qw'md5_hex';  # encrypted ID / SID
-use Time::HiRes qw'time';
+use Digest::MD5 'md5_hex';  # encrypted ID / SID
+use Time::HiRes 'time';
 # use Smart::Comments;
 use constant k => 2**10;
 use constant M => 2**20;
@@ -37,7 +37,7 @@ our ($tpid,$frecipient);
 our ($FEXID,$FEXXX,$HOME);
 our (%alias);
 our $chunksize = 0;
-our $version = 20160328;
+our $version = 20160919;
 our $_0 = $0;
 our $DEBUG = $ENV{DEBUG};
 
@@ -248,6 +248,14 @@ Partner program xx is an internet clipboard. See: xx -h
 
 Partner program fexget is for downloading. See: fexget -h
 
+fexsend stores the login data (server, user and auth-ID) in the file
+$HOME/.fex/id
+The format of this file is ([data] is optional):
+
+server-URL[!proxy[:port[:chunk-size]]
+e-mail-address
+auth-ID
+
 For temporary usage of a HTTP proxy use:
   $0 -P your_proxy:port:chunksize_in_MB file recipient
 Example:
@@ -361,10 +369,15 @@ if ($xx) {
       $_ = <STDIN>||'';
       if (/^y/i) {
         my $new = `wget -nv -O- http://fex.belwue.de/download/fexsend`;
-        if ($new !~ /upgrade fexsend/) {
+        my $newversion = $1 if $new =~ /version = (\d+)/;
+        if ($new !~ /upgrade fexsend/ or not $newversion) {
           die "$0: bad update\n";
         }
-        system qw'cp -aL',$_0,$_0.'_old';
+        if ($newversion <= $version) {
+          die "$0: no newer version\n";
+        }
+        $_0 = abs_path($_0);
+        system qw'rsync -a',$_0,$_0.'_old';
         exit $? if $?;
         open $_0,'>',$_0 or die "$0: cannot write $_0. - $!\n";
         print {$_0} $new;
@@ -372,6 +385,7 @@ if ($xx) {
         exec $_0,qw'-V .';
       }
     }
+    exit;
     exit if "@ARGV" eq '.';
   }
 
@@ -3206,9 +3220,10 @@ sub query_sid {
   $sid = $id;
 
   if ($port eq 443 or $proxy) {
+    return if $opt_d;
     return if $features;    # early return if we know enough
-    $req = "OPTIONS /FEX HTTP/1.1";
-    $req = "HEAD /index.html HTTP/1.1";
+    $req = "OPTIONS /FEX HTTP/1.1"; # does not work with (some) proxies
+    $req = "GET /SID HTTP/1.1";     # needed as FEATURES query
   } else {
     $req = "GET /SID HTTP/1.1";
   }
@@ -3469,7 +3484,8 @@ sub readahead {
 
 sub fileid {
   my $file = shift;
-  my @s = stat($file);
+  my $dirmode = shift;
+  my @s = $dirmode ? lstat($file) : stat($file);
 
   if (@s) {
     return md5_hex($file.$s[0].$s[1].$s[7].$s[9]);
@@ -3528,6 +3544,9 @@ sub fmd {
           next if $file eq '..';
           if ($file eq '.') {
             $fmd .= fileid($dir);
+          } elsif (-l "$dir/$file") {
+            # hack for dangling symlinks: do not raise an error
+            $fmd .= fileid("$dir/$file",'dirmode');
           } else {
             $fmd .= fmd("$dir/$file");
           }
diff --git a/bin/fexsrv b/bin/fexsrv
index 8bef7fc..2843167 100755
--- a/bin/fexsrv
+++ b/bin/fexsrv
@@ -15,6 +15,7 @@ BEGIN {
   # stunnel workaround
   $SIG{CHLD} = "DEFAULT";
   $ENV{PERLINIT} = q{
+    $ENV{LC_ALL} = 'en_US.UTF-8';
     unshift @INC,(getpwuid($<))[7].'/perl';
     # web error handler
     $SIG{__DIE__} = $SIG{__WARN__} = sub {
@@ -92,7 +93,7 @@ foreach my $lib (
 # import from fex.pp
 our ($hostname,$debug,$timeout,$max_error,$max_error_handler);
 our ($spooldir,@logdir,$docdir,$xkeydir,$akeydir,$lockdir);
-our ($force_https,$default_locale,$bs,$MB,$adlm);
+our ($force_https,$default_locale,$bs,$MB,$adlm,@forbidden_user_agents);
 our (@locales);
 
 # load common code (local config: $FEXHOME/lib/fex.ph)
@@ -144,7 +145,7 @@ else {
   if ($ssl_ra) {
     $ENV{PROTO} = 'https';
     $ENV{REMOTE_ADDR} = $ra = $ssl_ra;
-    if ($ssl_ra =~ /\w:\w/) {
+    if ($ssl_ra =~ /[\w:]:\w/) {
       # ($rh) = `host $ssl_ra 2>/dev/null` =~ /name pointer (.+)\.$/;
       $^W = 0; eval 'use Socket6'; $^W = 1;
       http_error(503) if $@;
@@ -368,6 +369,8 @@ REQUEST: while (*STDIN) {
     if ($uri =~ /\\|%5c/i) { badchar("\\") }
   }
 
+  my $fua = join('|',@forbidden_user_agents);
+
   while ($_ = shift @header) {
 
     # header inquisition!
@@ -381,12 +384,8 @@ REQUEST: while (*STDIN) {
       exit;
     }
 
-    if ($header =~ /\nRange:/ and /^User-Agent: (FDM)/) {
-      disconnect($1,"499 Download Manager $1 Not Supported",30);
-    }
-
-    if (/^User-Agent: (Java\/[\d\.]+)/) {
-      disconnect($1,"499 User-Agent $1 Not Supported",30);
+    if ($fua and /^User-Agent: ($fua)/) {
+      disconnect($1,"499 User Agent $1 Not Supported",30);
     }
 
     if (/^Range:.*,/) {
@@ -436,7 +435,7 @@ REQUEST: while (*STDIN) {
     }
 
     # HTTP header ==> environment variables
-    if (/^([\w\-]+):\s*(.+)/s) {
+    if (/^([\w\-_]+):\s*(.+)/s) {
       $http_var = $1;
       $http_val = $2;
       $http_var =~ s/-/_/g;
@@ -448,7 +447,10 @@ REQUEST: while (*STDIN) {
       } else {
         $http_val =~ s/\s+/ /g;
         if ($http_var =~ /^HTTP_(HOST|VERSION)$/) {
-          $http_var = 'X-'.$http_var;
+          $http_var = 'HTTP_X_'.$1;
+        } elsif ($http_var =~ /^PROXY/) {
+          # http://cert.at/warnings/all/20160718.html
+          $http_var = 'HTTP_X_'.$http_var;
         } elsif ($http_var !~ /^CONTENT_/) {
           $http_var = 'HTTP_'.$http_var;
         }
diff --git a/bin/fpg b/bin/fpg
index 5f2f751..7e616bd 100755
--- a/bin/fpg
+++ b/bin/fpg
@@ -2,7 +2,7 @@
 #
 # Programname:			fpg - Frams' Perl grep
 # Author: 			framstag@rus.uni-stuttgart.de
-# Copyright:			GPL
+# Licence:			Perl Artistic
 #
 # History:
 #   2003-02-27 Framstag		initial version
@@ -18,13 +18,16 @@
 #                               -n ==> -S, new -n option
 #   2008-10-14 Framstag		added option -M
 #   2008-11-23 Framstag		added option -~
+#   2016-06-12 Framstag		option -o respects (match)
 
 use Getopt::Std;
 use Term::ReadLine;
 use locale;
 
-sub usage {
-  die <<EOD
+$0 =~ s:.*/::;
+$| = 1;
+
+$usage  = <<EOD;
 usage: $0 [options] 'EXP' [file...]
    or: $0 [options] -Q file...
 options: -r        recursively scan through directories
@@ -35,7 +38,7 @@ options: -r        recursively scan through directories
 	 -l        list filenames only
 	 -L        list filenames only that do NOT match
 	 -p        show paragraphs, not lines (multiline record separator)
-	 -o        show only matched strings, not whole lines
+	 -o        show only matched strings (in parenthesis), not whole lines
 	 -M        mail-mode: search and show complete mails from mbox files
 	 -c        print (count) only number of matches (NOT LINES!)
 	 -F        EXP is a string, not a Perl regular expression
@@ -53,10 +56,7 @@ EOD
 #examples: $0 -r 'from.*STDIN' *
 #          $0 -e 'length>30 and not /\\w/' script
 #See "perldoc perlre" for help on regular expressions.
-}
 
-$0 =~ s:.*/::;
-$| = 1;
 
 $maxlen = 0;
 
@@ -67,10 +67,15 @@ $opt_S = 4;
 $opt_x = $opt_X = '';
 $opt_R = "\n";
 
-usage() if !getopts('hirvlLFMopscQen~S:R:C:x:X:') or $opt_h and not @ARGV;
+getopts('hirvlLFMopscQen~S:R:C:x:X:') or die $usage;
+
+if ($opt_h) {
+  print $usage;
+  exit;
+}
 
 unless ($opt_Q) {
-  $exp = shift or usage();
+  $exp = shift or die $usage;
 }
 
 if ($opt_C and ($opt_l or $opt_L or $opt_s or $opt_v or $opt_p or $opt_M)) {
@@ -129,7 +134,7 @@ sub scan {
   } else {
     $exp =~ s/([\@\$\%\^\&\*\(\)\+\[\]\{\}\\\|\.\?])/\\$1/g if $opt_F;
     $exp = '(?i)'.$exp if $opt_i;
-    $exp = '(?s)'.$exp if $opt_p or $opt_R;
+    $exp = '(?s)'.$exp if $opt_p or $opt_R ne "\n";
     #? $exp =~ s/\.\*\*/[.\n]*/g;
   }
 
@@ -277,12 +282,19 @@ sub grepf {
           else	      { $n++ while /$exp/omg }
         } else {
           if ($opt_o) {
-            my $m = '';
-            while (s/($exp)//) {
-              $n++;
-              $m .= "$1\n";
+            if ($exp =~ /\([^?]+\)/) {
+              if (/$exp/) {
+                $n++;
+                $_ = "$1\n";
+              }
+            } else {
+              my $m = '';
+              while (s/($exp)//) {
+                $n++;
+                $m .= "$1\n";
+              }
+              $_ = $m;
             }
-            $_ = $m;
           } elsif ($opt_Q) {
             $n += s/($exp)/$B$1$N/mg;
           } else {
diff --git a/bin/l b/bin/l
index affd4a2..203e310 100755
--- a/bin/l
+++ b/bin/l
@@ -13,7 +13,7 @@ use Getopt::Std;
 # the name of the game
 $0 =~ s:.*/::;
 
-$ENV{LC_CTYPE} = 'C';
+$ENV{LC_ALL} = 'C';
 
 # unshift @ARGV,split /\s+/,$ENV{'l_opt'} if $ENV{'l_opt'};
 
@@ -32,9 +32,20 @@ $opt_l = 1                            if $0 eq 'll';
 $opt_l = $opt_i = $opt_a = $opt_S = 1 if $0 eq 'lll';
 &examples if $opt_E;
 if ($0 eq 'lf' or $0 eq 'llf') {
-  $opt_F ||= shift or usage(1);
-  $opt_R ||= scalar(@ARGV) || ($opt_F eq '.');
-  $opt_l ||= $0 eq 'llf';
+  $opt_l = $0 eq 'llf';
+  if (scalar(@ARGV) == 0) {
+    die usage(1);
+  } elsif (scalar(@ARGV) == 1) {
+    $opt_F = shift;
+    $opt_R = $opt_F if $opt_F eq '.';
+  } elsif (-d $ARGV[-1]) {
+    $opt_R = pop(@ARGV);
+    $opt_F = join('|',@ARGV);
+  } else {
+    $opt_F = join('|',@ARGV);
+  }
+  @ARGV = ();
+  @ARGV = ($opt_R) if -d $opt_R;
 }
 
 $postsort = $opt_t||$opt_s;
@@ -138,6 +149,8 @@ sub collect {
   my @files = @_;
   my $f;
 
+  getacl(@files) if $opt_l and not $opt_n;
+
   # loop over all argument files/directories
   foreach $f (@files) {
 
@@ -175,8 +188,8 @@ sub collect {
       $f =~ s:/$:: if $opt_d;
 
       # on trailing / list subdirs, too
-      if ($f =~ m:/$:) { &list(&getfiles($f)) }
-      elsif ($f eq '') { &list('/') }
+      if ($f =~ m:/$:) { list(getfiles($f)) }
+      elsif ($f eq '') { list('/') }
       else {
         if ($opt_L) {
           unless (-e $f) {
@@ -262,6 +275,8 @@ sub list {
 	    elsif ($i eq 'a') { $line .= sprintf '%10s %10s %10s ',
 	                                 $dates{'a'},$dates{'m'},$dates{'c'} }
 	  } else {
+            # $mode =~ s/(....)(...)/sprintf($1.uc($2))/e if $ACL{$file};
+            substr($mode,4,3) = uc(substr($mode,4,3)) if $ACL{$file};
 	    if    ($i eq 'm') { $line .= $mode.' ' }
 	    elsif ($i eq 'u') { $line .= sprintf '%-8s ',  $uid }
 	    elsif ($i eq 'g') { $line .= sprintf '%-8s ',  $gid }
@@ -283,15 +298,22 @@ sub list {
       } else {
 
 	if ($opt_n) {
-          if ($opt_l) { $line .= sprintf "%06o %6d %6d $z%15s %10d ",
-	                                 $mode,$uid,$gid,$size,$date }
-          else        { $line .= sprintf "%06o $z%15s %10d ",
-	                                 $mode,$size,$date }
+          if ($opt_l) {
+            $line .= sprintf "%06o %6d %6d $z%15s %10d ",
+	                     $mode,$uid,$gid,$size,$date;
+          } else {
+            $line .= sprintf "%06o $z%15s %10d ",$mode,$size,$date;
+          }
 	} else {
-          if ($opt_l) { $line .= sprintf "%s %-8s %-8s $z%19s %s ",
-	                                 $mode,$uid,$gid,$size,$date }
-          else        { $line .= sprintf "%s $z%19s %s ",
-	                                 $mode,$size,substr($date,0,-3) }
+          if ($opt_l) {
+            # $mode .= $ACL{$file} ? '+' : ' ';
+            # $mode =~ s/(....)(...)/sprintf($1.uc($2))/e if $ACL{$file};
+            substr($mode,4,3) = uc(substr($mode,4,3)) if $ACL{$file};
+            $line .= sprintf "%s %-8s %-8s $z%19s %s ",
+                             $mode,$uid,$gid,$size,$date;
+          } else {
+            $line .= sprintf "%s $z%19s %s ",$mode,$size,substr($date,0,-3);
+          }
         }
 
 	if ($opt_i)   { $line .= sprintf '%3s %10s ',$links,$inode }
@@ -375,13 +397,14 @@ sub info {
         substr($mode,8,1) =~ tr/-x/Tt/ if -k _;
         $mode = $type.$mode;
       } else {
-        # with short list display only effektive file access modes
+        # with short list display only effective file access modes
+        use filetest 'access'; # respect ACLs ==> cannot use pseudofile _
         $mode = $type
-	        . (-r _ ? 'R' : '-')
-                . (-w _ ? 'W' : '-')
-                . (-x _ ? 'X' : '-');
-        substr($mode,2,1) =~ tr/-x/Ss/ if -u _ or -g _;
-        substr($mode,3,1) =~ tr/-x/Tt/ if -k _;
+	        . (-r $file ? 'R' : '-')
+                . (-w $file ? 'W' : '-')
+                . (-x $file ? 'X' : '-');
+        substr($mode,2,1) =~ tr/-x/Ss/ if -u $file or -g $file;
+        substr($mode,3,1) =~ tr/-x/Tt/ if -k $file;
       }
     }
 
@@ -425,6 +448,25 @@ sub info {
   return ($linkname,$inode,$links,$size,$mode,$uid,$gid,$date,%dates);
 }
 
+# get ACLs
+#
+# INPUT: filenames
+#
+# GLOBAL: @ACL
+sub getacl {
+  my @files;
+
+  $getfacl ||= pathsearch('getfacl') or return;
+  # warn "### @_\n";
+  foreach my $file (@_) { push @files,$file if -e $file }
+  if (@files and open my $acl,'-|',$getfacl,'-ps',@files) {
+    while (<$acl>) {
+      $ACL{$1} = $1 if /^# file: (.+)/;
+    }
+    close $acl;
+  }
+}
+
 
 # reformat integer into 3-digit doted format
 # (when non-numerical mode is set)
@@ -482,6 +524,7 @@ sub getfiles {
     warn "$0: cannot read $dir : $!\n";
   }
 
+  getacl(@dirs,@files) if $opt_l and not $opt_n;
   return (@dirs,@files);
 }
 
@@ -497,6 +540,15 @@ sub nodes {
 }
 
 
+sub pathsearch {
+  my $prg = shift;
+
+  foreach my $dir (split(':',$ENV{PATH})) {
+    return "$dir/$prg" if -x "$dir/$prg";
+  }
+}
+
+
 # reformat timetick to ISO date string
 #
 # INPUT: timetick
@@ -552,7 +604,7 @@ sub usage {
     print OUT "usage: $0 $opts [-F regexp] [file...]\n";
   }
   $opts =~ s/R//;
-  print OUT "usage: lf $opts regexp [directory...]\n";
+  print OUT "usage: lf $opts regexp [regexp...] [directory]\n";
   print OUT <<EOD;
 options: -l  long list (implicit if called 'll')
          -a  list also .* files
@@ -566,7 +618,7 @@ options: -l  long list (implicit if called 'll')
          -n  numerical output
          -r  reverse list
          -z  squeeze size field (slows down output)
-         -L  derefernce symbolic links
+         -L  show absolute real path (dereference symbolic links)
          -R  recursive into subdirs
          -x  do not cross filesystem boundaries with -R
          -F  find files matching case insensitive regexp
diff --git a/bin/logwatch b/bin/logwatch
index fdc2f25..3aafafb 100755
--- a/bin/logwatch
+++ b/bin/logwatch
@@ -120,7 +120,11 @@ for (;;) {
     }
     $post = /\nPOST\s/;
     if (/^\n*(CONNECT|CONTINUE).*\s\[([\d_]+)\]/i) { $pid = $2 }
-    if (/\n(POST|GET)\s+\/(\w+)/i)                 { $cgi = $2 }
+    if (/\n(POST|GET)\s+(\S+)/i) {
+      $cgi = $2;
+      $cgi =~ s:.*/::;
+      $cgi =~ s:\?.*::;
+    }
     if (/Content-Length: (\d+)/i) {
       $d = $1;
       while ($d =~ s/(\d)(\d\d\d\b)/$1,$2/) {};
@@ -180,6 +184,7 @@ sub read_debug_log {
       binmode($log,":utf8");
       while (<$log>) {
         s/\r//;
+        s/[^\x09\x20-\xFF]/_/g;
         if (/^Content-Disposition:.*name="FILE".*filename="(.+)"/i) {
           print "  FILE=\"$1\"\n";
         } elsif (/^Content-Disposition:.*name="(\w+)"/i) {
diff --git a/bin/sexsend b/bin/sexsend
index 9a7d48b..8b9e1d1 100755
--- a/bin/sexsend
+++ b/bin/sexsend
@@ -19,7 +19,7 @@ use constant M => 2**20;
 
 eval 'use Net::INET6Glue::INET_is_INET6';
 
-our $version = 20160328;
+our $version = 20160919;
 our $DEBUG = $ENV{DEBUG};
 
 my %SSL = (SSL_version => 'TLSv1');
diff --git a/bin/zz b/bin/zz
index 0317412..39dc91e 100755
--- a/bin/zz
+++ b/bin/zz
@@ -1,55 +1,1042 @@
-#!/bin/sh
+#!/usr/bin/perl -w
+#
+# vv : visual versioning
+# zz : generic shell clip board
+# ezz : clip board editor
+#
+# http://fex.rus.uni-stuttgart.de/fstools/vv.html
+# http://fex.rus.uni-stuttgart.de/fstools/zz.html
+#
+# by Ulli Horlacher <framstag@rus.uni-stuttgart.de>
+#
+# Perl Artistic Licence
+#
+# vv is a script to handle file versions:
+# list, view, recover, diff, purge, migrate, save, delete
+#
+# vv is an extension to emacs idea of backup~ files
+#
+# File versions are stored in local subdirectory .versions/
+#
+# To use vv with jed, install to your jed library path:
+#
+#   http://fex.rus.uni-stuttgart.de/sw/share/jedlib/vv.sl
+#
+# To use vv with vim, add to your .vimrc:
+#
+#   autocmd BufWritePre  * execute '! vv -s ' . shellescape(@%)
+#   autocmd BufWritePost * execute '! vv -b ' . shellescape(@%)
+#
+# To use vv with emacs, add to your .emacs:
+#
+#   (add-hook 'before-save-hook (lambda () (shell-command (
+#    concat "vv -s " (shell-quote-argument (buffer-file-name))))))
+#   (add-hook 'after-save-hook  (lambda () (shell-command (
+#    concat "vv -b " (shell-quote-argument (buffer-file-name))))))
+#   (setq make-backup-files nil)
+#
+# To use vv with ANY editor, first set:
+#
+#   export EDITOR=your_favourite_editor
+#   alias ve='vv -e'
+#
+# and then edit your file with:
+#
+#   ve file
+#
+# $HOME/.vvrc is the config file for vv
+
+# 2013-04-15 initial version
+# 2013-04-16 added options -m and -v
+# 2013-04-18 added option -s
+# 2013-04-22 realfilename() fixes symlink problematics
+# 2013-04-22 use rsync instead of cp
+# 2013-04-23 added option -I
+# 2013-04-23 renamed from jedv to vv
+# 2013-04-24 added options -e -0
+# 2013-05-09 added option -R
+# 2013-05-22 modified option -d to double argument
+# 2013-05-22 added vvrc with $exclude and @diff
+# 2013-07-05 fixed bug potential endless loop in rotate()
+# 2014-04-16 added change-file-test for opt_s (needs .versions/$file)
+# 2014-04-18 added option -b : save backup
+# 2014-05-02 fixed bug wrong file ownership when using as root
+# 2014-06-18 options -r -d -v : parameter is optional, default is 1
+# 2014-06-18 fixed (stupid!) bug option -s does only sometimes saving
+# 2014-06-20 options -d -v : argument is optional, default is last file
+# 2014-07-22 fixed bug no (new) backup version 0 on option -r
+# 2014-11-14 added option -D : delete last saved version
+# 2014-11-14 make .versions/ mode 777 if parent directory is world writable
+# 2015-03-19 allow write access by root even if file and .versions/ have different owners
+# 2015-03-20 better error formating for jed
+# 2015-06-02 added option -r . to restore last saved backup
+# 2016-03-07 added options -M -L
+# 2016-03-08 renamed option -I to -H
+# 2016-05-02 added -A option to preserve ACLs with rsync
+# 2016-06-07 option -v : use PAGER=cat if STDOUT is not a tty
+# 2016-06-08 added zz, ezz and installer vvzz
+# 2016-07-06 avoid empty $ZZ versioning
+# 2016-09-12 added option -q quiet mode
+
+use Getopt::Std;
+use File::Basename;
+use Digest::MD5 'md5_hex';
+use Cwd 'abs_path';
+
+$prg = abs_path($0);
+$0 =~ s:.*/::;
+
+$ZZ = $ENV{ZZ} || "$ENV{HOME}/.zz";
+
+&install if $0 eq 'vvzz';
+&zz      if $0 eq 'zz';
+&ezz     if $0 eq 'ezz';
+
+# vv
+$usage = <<EOD;
+usage: $0 [-l] [file]
+       $0 -r . file
+       $0 -r version-number file [new-file]
+       $0 -d version-number[:version-number] file
+       $0 -v version-number file
+       $0 -s file
+       $0 -D file
+       $0 -e file
+       $0 -M file|.
+       $0 -L file|.
+       $0 -m [-R]
+       $0 -p
+       $0 -q
+       $0 -H
+options: -l   list available versions
+         -v   view version
+         -r   recover file (. is last saved backup)
+         -d   show diff
+         -s   save file to new version
+         -D   delete last saved version
+         -e   edit file with \$EDITOR (with versioning)
+         -p   purge orphaned versions (without current file)
+         -q   quiet mode
+         -m   migrate backup files to version files (-R all recursive)
+         -M   migrate to more versions (upto 100)
+         -L   migrate to less versions (upto 10)
+         -H   show more information
+examples: $0 project.pl
+          $0 -d 2 project.pl
+          $0 -r 2 project.pl project_2.pl
+EOD
+
+$vvrc = $ENV{HOME} . '/.vvrc';
+
+$opt_l = 1;
+$opt_h = $opt_p = $opt_m = $opt_s = $opt_0 = $opt_e = $opt_H = $opt_b = 0;
+$opt_q = $opt_D = $opt_R = 0;
+$opt_r = $opt_d = $opt_v = $opt_M = $opt_L = '';
+${'opt_+'} = 0;
+getopts('hHls0bepqmRDrdv+M:L:') or die $usage;
+
+if ($opt_h) {
+  print $usage;
+  exit;
+}
+
+if ($opt_H) {
+  open $prg,$prg or die "$0: $prg - $!\n";
+  $_ = <$prg>;
+  $_ = <$prg>;
+  while (<$prg>) {
+    last if /^\s*$/ or /^#\s*\d\d\d\d-\d\d-\d\d/;
+    print;
+  }
+  exit;
+}
+
+if ($opt_r) {
+  die "usage: $0 -r version-number file\n" unless @ARGV;
+  if ($ARGV[0] =~ /^(\d\d?|\.)$/) { $opt_r = shift }
+  else                            { $opt_r = 1 }
+  die "usage: $0 -r version-number file\n" if scalar @ARGV != 1;
+}
+
+if ($opt_d) {
+  if (@ARGV and $ARGV[0] =~ /^\d\d?(:\d\d?)?$/) { $opt_d = shift }
+  else                                          { $opt_d = 1 }
+  &check_ARGV;
+  die "usage: $0 -d version-number file\n" unless @ARGV;
+}
+
+if ($opt_v) {
+  if (@ARGV and $ARGV[0] =~ /^\d\d?$/) { $opt_v = shift }
+  else                                 { $opt_v = 1 }
+  &check_ARGV;
+  die "usage: $0 -v version-number file\n" unless @ARGV;
+}
+
+if ($0 eq 've' or $opt_e) {
+  $a = pop @ARGV or die $usage;
+  $opt_e = 1;
+} else {
+  $a = shift @ARGV;
+  die $usage if not $opt_r and @ARGV;
+}
+
+unless (-e $vvrc) {
+  open $vvrc,'>',$vvrc or die "$0: cannot write $vvrc - $!\n";
+  print {$vvrc} q{
+$exclude = q(
+  \.tmp$
+  ^mutt-.+-\d+
+  ^#.*#$
+);
+
+@diff = qw'diff -u';
+
+};
+  close $vvrc;
+}
+
+require $vvrc;
+
+if ($a) {
+
+  $file = realfilename($a);
+  $ofile = "$file~";
+  $bfile = basename($file);
+  $dir = dirname($file);
+  $vdir = "$dir/.versions";
+  $vfile = "$vdir/$bfile";
+  $vfile0 = "$vfile~0~";
+  $vfile1 = "$vfile~1~";
+  $vfile01 = "$vfile~01~";
+
+  # change eugid if root and version directory belongs user
+  my @s = stat($vdir);
+  if ($> == 0 and (not @s or $s[4])) {
+    if (my @s = stat($a)) {
+      $) = $s[5];
+      $> = $s[4];
+    }
+  }
+
+  if ($opt_r ne '.' and not ($opt_M or $opt_L)) {
+    if (not -e $file and -s $vfile) {
+      warn "$0: $a does not exist any more\n";
+      print "found $vfile - recover it? ";
+      $_ = <STDIN>;
+      copy($vfile,$file,'.') if /^y/i;
+      exit 0;
+    }
+    die "$0: $a does not exist\n" unless -e $file;
+    die "$0: $a is not a regular file\n" if -l $file or not -f $file;
+  }
+} else {
+  $file = '*';
+  $vdir = ".versions";
+}
+
+if ($opt_M) {
+  if (-d $opt_M and not -l $opt_M) {
+    my $vvv = "$opt_M/.versions";
+    mkdir $vvv;
+    die "$0: cannot mkdir $vvv - $!\n" unless -d $vvv;
+    opendir $vvv,$vvv or die "$0: cannot opendir $vvv - $!\n";
+    while (my $v = readdir($vvv)) {
+      mv100("$opt_M/$1") if -f "$vvv/$v" and $v =~ /(.+)~1~$/;
+    }
+    close $vvv;
+    $vvv .= "/.versions";
+    unless (-d $vvv) {
+      mkdir $vvv or die "$0: cannot mkdir $vvv - $!\n";
+    }
+    $vvv .= "/n";
+    unlink $vvv;
+    symlink 100,$vvv or die "$0: cannot create $vvv - $!\n";
+  } else {
+    die "usage: $0 -M file\n" if @ARGV or $opt_r;
+    mv100($opt_M);
+  }
+  exit;
+}
+
+if ($opt_L) {
+  if (-d $opt_L and not -l $opt_L) {
+    my $vvv = "$opt_L/.versions";
+    mkdir $vvv;
+    die "$0: cannot mkdir $vvv - $!\n" unless -d $vvv;
+    opendir $vvv,$vvv or die "$0: cannot opendir $vvv - $!\n";
+    while (my $v = readdir($vvv)) {
+      mv10("$opt_L/$1") if -f "$vvv/$v" and $v =~ /(.+)~01~$/;
+    }
+    closedir $vvv;
+    $vvv .= "/.versions";
+    unless (-d $vvv) {
+      mkdir $vvv or die "$0: cannot mkdir $vvv - $!\n";
+    }
+    $vvv .= "/n";
+    unlink $vvv;
+    symlink 10,$vvv or die "$0: cannot create $vvv - $!\n";
+  } else {
+    die "usage: $0 -L file\n" if @ARGV or $opt_r;
+    mv10($opt_L);
+  }
+  exit;
+}
+
+if ($opt_e) {
+  die $usage unless $a;
+  $editor = $ENV{EDITOR} or die "$0: environment variable EDITOR not set\n";
+  system(qw'vv -s',$file) if -f $file; # save current version
+  system($editor,@ARGV,$file); exit $? if $?;
+  unlink $ofile;                       # delete new file~ created by editor
+  system(qw'vv -0',$file);             # post rotating
+  system(qw'vv -b',$file);             # save backup
+  exit;
+}
+
+if ($opt_v) {
+  die "$0: no such file $bfile\n" unless $bfile;
+  if (-f "$vfile~0$opt_v~") { $vfile .= "~0$opt_v~" }
+  else                      { $vfile .= "~$opt_v~" }
+  if (-f $vfile) {
+    if (-t STDOUT) {
+      if (($ENV{EDITOR}||$0) =~ /jed/) {
+        $ENV{JEDINIT} = "SAVE_STATE=0";
+        exec 'jed',$vfile,qw'-tmp -f set_readonly(1)';
+      } elsif ($ENV{PAGER}) {
+        exec $ENV{PAGER},$vfile;
+      } else {
+        exec 'view',$vfile;
+      }
+    } else {
+      exec 'cat',$vfile;
+    }
+  } else {
+    die "$0: no $vfile\n";
+  }
+  exit;
+}
+
+if ($opt_p) {
+  opendir $vdir,$vdir or die "$0: no $vdir\n";
+  while ($vfile = readdir($vdir)) {
+    next unless -f "$vdir/$vfile";
+    $bfile = $vfile;
+    $bfile =~ s/~\d\d?~$//;
+    if (not -f $bfile or -l $bfile) {
+      unlink "$vdir/$vfile";
+      $purge{$bfile}++;
+    }
+  }
+  if (@purge = keys %purge) {
+    foreach $p (@purge) {
+      printf "%2d %s~ purged\n",$purge{$p},$p;
+    }
+  }
+  exit;
+}
+
+if ($opt_m) {
+  migrate('.');
+  exit;
+}
+
+if (length($opt_r)) {
+  die "$0: no such file $bfile\n" unless $bfile;
+  if ($opt_r eq '.') {
+    die "$0: no $vfile\n" unless -f $vfile;
+    copy($vfile,$file,$opt_r);
+  } else {
+    if ($opt_r =~ /^\d$/ and -f "$vfile~0$opt_r~") {
+      $vfile .= "~0$opt_r~"
+    } else {
+      $vfile .= "~$opt_r~"
+    }
+    die "$0: no version $opt_r for $file\n" unless -f $vfile;
+    if ($nfile = shift @ARGV) {
+      copy($vfile,$nfile);
+    } else {
+      copy($file,$vfile0) if mtime($file) > mtime($vfile0);
+      copy($vfile,$file);
+    }
+  }
+  exit;
+}
+
+if (length($opt_d)) {
+  die "$0: no such file $bfile\n" unless $bfile;
+  @diff = qw'diff -u' unless @diff;
+  if ($opt_d =~ /^(\d\d?):(\d\d?)$/) {
+    if (-f "$vdir/$bfile~0$1~" and -f "$vdir/$bfile~0$2~") {
+      exec @diff,"$vdir/$bfile~0$2~","$vdir/$bfile~0$1~"
+    } else {
+      exec @diff,"$vdir/$bfile~$2~","$vdir/$bfile~$1~"
+    }
+  } else {
+    if (-f "$vdir/$bfile~0$opt_d~") {
+      exec @diff,"$vdir/$bfile~0$opt_d~",$file;
+    } else {
+      exec @diff,"$vdir/$bfile~$opt_d~",$file;
+    }
+  }
+  exit $!;
+}
+
+if ($opt_s) {
+  die $usage unless $file;
+  if ($exclude) {
+    $exclude =~ s/^\s+//;
+    $exclude =~ s/\s+$//;
+    $exclude =~ s/\s+/|/g;
+    if ($bfile =~ /$exclude/) {
+      warn "\r\n$0: ignoring $bfile\n";
+      exit;
+    }
+  }
+  unless (-d $vdir) {
+    mkdir $vdir or die "$0: cannot mkdir $vdir - $!\n";
+  }
+  chmod 0777,$vdir if (stat $dir)[2] & 00002;
+
+  # migrate old file~ to versions
+  if (-f $ofile and not -l $ofile and -r $ofile) {
+    $vfn = rotate($vfile);
+    rename($ofile,$vfn);
+  }
+
+  # rotate and save if file has changed
+  if (-f $vfile1) {
+    if (md5f($vfile1) ne md5f($file)) {
+      $vfn = rotate($vfile);
+      copy($file,$vfn);
+    }
+    exit;
+  }
+  # rotate and save if file has changed
+  if (-f $vfile01) {
+    if (md5f($vfile01) ne md5f($file)) {
+      $vfn = rotate($vfile);
+      copy($file,$vfn);
+    }
+    exit;
+  }
+  # save new file
+  if ((readlink("$vdir/.versions/n")||10) == 100) {
+    copy($file,$vfile01);
+  } else {
+    copy($file,$vfile1);
+  }
+  exit;
+}
+
+# backup version
+if ($opt_b) {
+  die $usage unless $file;
+  unless (-d $vdir) {
+    mkdir $vdir or die "\r\n$0: cannot mkdir $vdir - $!\n";
+  }
+  copy($file,$vfile);
+  if ($ENV{VIMRUNTIME}) {
+    print "\n";
+  } else {
+    warn "$file --> $vfile\n" unless $opt_q;
+  }
+  exit;
+}
+
+# special post rotating from -e
+if ($opt_0) {
+  my @sb = stat $file or die "$0: $file - $!\n";
+  if (-f $vfile1) {
+    while (my @sv = stat $vfile1) {
+      # no version change?
+      if ($sb[7] == $sv[7] and $sb[9] == $sv[9]) {
+        # rotate back
+        rb10($vfile);
+      } else {
+        last;
+      }
+    }
+  }
+  if (-f $vfile01) {
+    while (my @sv = stat $vfile01) {
+      # no version change?
+      if ($sb[7] == $sv[7] and $sb[9] == $sv[9]) {
+        # rotate back
+        rb10($vfile);
+      } else {
+        last;
+      }
+    }
+  }
+  exit;
+}
+
+# delete last version, roll back
+if ($opt_D) {
+  die "usage: $0 -D file\n" unless $vfile1 or $vfile01;
+  stat $file or die "$0: $file - $!\n";
+  # 0 version?
+  if (-f $vfile0) {
+    unlink $vfile0;
+  } else {
+    # rotate back
+    rb10($vfile) if -f $vfile1;
+    rb100($vfile) if -f $vfile01;
+  }
+  exec $0,'-l',$file;
+  exit;
+}
+
+# default!
+if ($opt_l) {
+  `stty -a` =~ /columns (\d+)/;
+  $tw = ($1 || 80)-36;
+  if (opendir $vdir,$vdir) {
+    while ($vfile = readdir($vdir)) {
+      if (-f "$vdir/$vfile") {
+        if ($bfile) {
+          if ($vfile =~ /^\Q$bfile\E~(\d\d?)~$/) {
+            push @{$v{$file}},$1;
+          }
+        } else {
+          if ($vfile =~ /^(.+)~(\d\d?)~$/) {
+            push @{$v{$1}},$2;
+          } else {
+            push @{$v{$vfile}},0;
+          }
+        }
+      }
+    }
+    closedir $vdir;
+    $ct = '';
+    foreach $file (sort keys %v) {
+      if (not -f $file or -l $file) {
+        warn "$0: orphaned $file~\n";
+        next;
+      }
+      @v = sort @{$v{$file}};
+      if ($bfile) {
+        @stat = stat $file or die "$0: $file - $!\n";
+        print "version bytes        date time";
+        if (${'opt_+'}) {
+          print "     content";
+          $ct = content($file);
+          $ct =~ s/(.{$tw}).+/$1*/;
+        }
+        print "\n";
+        if (length($v[0]) == 1) { $lf = "%s  %10s  %s %s\n" }
+        else                    { $lf = "%2s %10s  %s %s\n" }
+        printf $lf,'.',size($stat[7]),isodate($stat[9]),$ct;
+        foreach $v (@v) {
+          $vfile = "$vdir/$bfile~$v~";
+          @stat = stat $vfile or next;
+          if (${'opt_+'}) {
+            $ct = content($vfile);
+            $ct =~ s/(.{$tw}).+/$1*/;
+          }
+          printf $lf,int($v),size($stat[7]),isodate($stat[9]),$ct;
+        }
+      } else {
+        my $n = scalar(@v);
+        $n-- if $v[0] == 0; # do not count zero version
+        printf "%d %s\n",$n,$file;
+      }
+    }
+  }
+  exit;
+}
+
+
+sub size {
+  my $s = shift;
+  if    ($s > 9999999999) { $s = int($s/2**30).'G' }
+  elsif ($s > 9999999)    { $s = int($s/2**20).'M' }
+  elsif ($s > 9999)       { $s = int($s/2**10).'k' }
+  return $s;
+}
+
+
+sub content {
+  my $file = shift;
+  my $ct;
+  local $_;
+
+  chomp ($ct = `file $file`);
+  $ct =~ s/.*?: //;
+  $ct =~ s/,.*//;
+
+  if ($ct =~ /text/ and open $file,$file) {
+    read $file,$_,1024;
+    close $file;
+    s/[\x00-\x20]+/ /g;
+    s/^ //;
+    s/ $//;
+    $ct = '"'.$_.'"';
+  }
+
+  return $ct;
+}
 
+
+sub isodate {
+  my @d = localtime shift;
+  return sprintf('%d-%02d-%02d %02d:%02d:%02d',
+                 $d[5]+1900,$d[4]+1,$d[3],$d[2],$d[1],$d[0]);
+}
+
+sub rotate {
+  my $vf = shift; # version base file
+  my $vf1 = "$vf~1~";
+  my $vf01 = "$vf~01~";
+  my ($vfi,$vfn);
+
+  if (-f $vf1) {
+    for (my $i = 8; $i >= 0; $i--) {
+      $vfi = sprintf("%s~%d~",$vf,$i);
+      $vfn = sprintf("%s~%d~",$vf,$i+1);
+      if (-e $vfi) {
+        rename $vfi,$vfn or die "$0: $vfi --> $vfn : $!\n";
+      }
+    }
+    # was there a version 0?
+    if (-e $vf1) {
+      my $bf = $vf;
+      $bf =~ s:/\.versions/:/:;
+      my @sb = stat $bf;
+      my @sv = stat $vf1;
+      # version change? (other size or mtime)
+      if (@sb and @sv and $sb[7] == $sv[7] and $sb[9] == $sv[9]) {
+        # same version
+        unlink $vf1;
+      } else {
+        # other version
+        rotate($vf);
+      }
+    }
+    return "$vf~1~";
+  } elsif (-f $vf01) {
+    for (my $i = 98; $i >= 0; $i--) {
+      $vfi = sprintf("%s~%02d~",$vf,$i);
+      $vfn = sprintf("%s~%02d~",$vf,$i+1);
+      if (-e $vfi) {
+        rename $vfi,$vfn or die "$0: $vfi --> $vfn : $!\n";
+      }
+    }
+    # was there a version 0?
+    if (-e $vf01) {
+      my $bf = $vf;
+      $bf =~ s:/\.versions/:/:;
+      my @sb = stat $bf;
+      my @sv = stat $vf01;
+      # version change? (other size or mtime)
+      if (@sb and @sv and $sb[7] == $sv[7] and $sb[9] == $sv[9]) {
+        # same version
+        unlink $vf01;
+      } else {
+        # other version
+        rotate($vf);
+      }
+    }
+    return "$vf~01~";
+  }
+
+  return "$vf~1~";
+}
+
+sub copy {
+  my ($from,$to,$restore) = @_;
+
+  unless ($restore) {
+    if (-l $file or not -f $file) {
+      die "$0: $file is not a regular file\n";
+    }
+  }
+
+  if (open $to,'>>',$to) {
+    close $to;
+    if (system(qw'rsync -aA',$from,$to) == 0) {
+      if ($ENV{VIMRUNTIME}) {
+        print "\n";
+      } else {
+        warn "$from --> $to\n" unless $opt_q;
+      }
+    } else {
+      exit $?;
+    }
+  } else {
+    die "\r\n$0: cannot write $to - $!\n";
+  }
+}
+
+sub realfilename {
+  my $file = shift;
+
+  return $file unless -e $file;
+
+  if (-l $file) {
+    my $link = readlink($file);
+    if ($link !~ /^\// and $file =~ m:(.*/).:) {
+      $link = $1 . $link;
+    }
+    return realfilename($link);
+  } else {
+    return $file;
+  }
+}
+
+sub migrate {
+  my $dir = shift;
+  my $vdir = "$dir/.versions";
+  my $dfile;
+
+  opendir $dir,$dir or die "$0: cannot read directory $dir - $!\n";
+  while ($file = readdir($dir)) {
+    $dfile = "$dir/$file";
+    next if -l $dfile or $file eq '.' or $file eq '..';
+    if (-d $dfile and $opt_R and $file ne '.versions') {
+      migrate($dfile);
+    } elsif (-f $dfile and $file =~ /~$/) {
+      if (-d $vdir) {
+        for ($i = 8; $i > 0; $i--) {
+          $n = $i+1;
+          rename "$vdir/$file$i~","$vdir/$file$n~";
+        }
+      } else {
+        mkdir $vdir or die "$0: cannot mkdir $vdir - $!\n";
+      }
+      $nfile = sprintf("%s/%s1~",$vdir,$file);
+      rename $dfile,$nfile or die "$0: cannot move $dfile to $nfile - $!\n";
+      warn "$dfile --> $nfile\n" unless $opt_q;
+    }
+  }
+  closedir $dir;
+}
+
+sub mtime {
+  my @s = stat shift;
+  return @s ? $s[9] : 0;
+}
+
+sub md5f {
+  my $file = shift;
+  my $md5 = 0;
+  local $/;
+
+  if (open $file,$file) {
+    $md5 = md5_hex(<$file>);
+    close $file;
+  }
+  return $md5;
+}
+
+
+# if ARGV is empty use last saved file as default file argument
+sub check_ARGV {
+  local $_;
+  local *V;
+
+  if (not @ARGV) {
+    if (-d '.versions' and open V,'ls -at .versions|') {
+      while (<V>) {
+        chomp;
+        if (-f) {
+          close V;
+          s/~\d+~$//;
+          @ARGV = ($_);
+          return;
+        }
+      }
+    }
+  }
+
+}
+
+
+sub mv10 {
+  my $file = shift;
+  my $vfile = dirname($file).'/.versions/'.basename($file);
+
+  die "$0: $file has no extended versions\n" unless -f "$vfile~01~";
+  for (my $i=1; $i<10; $i++) {
+    my $vfile1 = "$vfile~$i~";
+    my $vfile2 = "$vfile~0$i~";
+    if (-f $vfile2) {
+      warn "$vfile2 --> $vfile1\n" unless $opt_q;
+      rename $vfile2,$vfile1 or die "$0: $!\n";
+    }
+  }
+  for (my $i=10; $i<100; $i++) {
+    unlink "$vfile~$i~";
+  }
+}
+
+sub mv100 {
+  my $file = shift;
+  my $vfile = dirname($file).'/.versions/'.basename($file);
+
+  die "$0: $file has already extended versions\n" if -f "$vfile~01~";
+  die "$0: $file has no versions\n" unless -f "$vfile~1~";
+  for (my $i=1; $i<10; $i++) {
+    my $vfile1 = "$vfile~$i~";
+    my $vfile2 = "$vfile~0$i~";
+    if (-f $vfile1) {
+      warn "$vfile1 --> $vfile2\n" unless $opt_q;
+      rename $vfile1,$vfile2 or die "$0: $!\n";
+    }
+  }
+}
+
+
+# rotate back
+sub rb10 {
+  my $vfile = shift;
+
+  for (my $i = 1; $i <= 8; $i++) {
+    my $vfi = sprintf("%s~%d~",$vfile,$i);
+    my $vfn = sprintf("%s~%d~",$vfile,$i+1);
+    if (-f $vfn) {
+      rename $vfn,$vfi;
+    } else {
+      unlink $vfi if $i == 1;
+      last;
+    }
+  }
+}
+
+
+# rotate back
+sub rb100 {
+  my $vfile = shift;
+
+  for (my $i = 1; $i <= 98; $i++) {
+    my $vfi = sprintf("%s~%02d~",$vfile,$i);
+    my $vfn = sprintf("%s~%02d~",$vfile,$i+1);
+    if (-f $vfn) {
+      rename $vfn,$vfi;
+    } else {
+      unlink $vfi if $i == 1;
+      last;
+    }
+  }
+}
+
+
+
+sub pathsearch {
+  my $prg = shift;
+
+  foreach my $dir (split(':',$ENV{PATH})) {
+    return "$dir/$prg" if -x "$dir/$prg";
+  }
+}
+
+
+# zz is the generic clip board program
+#
 # to use zz with vim, write to your .vimrc:
 #
 # noremap <silent> zz> :w !zz<CR><CR>
-# noremap <silent> zz< :r !zz<CR>
+# noremap <silent> zz< :r !zz --<CR>
+sub zz {
+  my $bs = 2**16;
+  my $wm = '>';
+  my ($file,$tee,$x);
 
-ZZ=${ZZ:-$HOME/.zz}
+  if ("@ARGV" =~ /^(-h|--help)$/) {
+    print <<'EOD';
+zz is the generic clip board program. It can hold any data, ASCII or binary.
+The clip board itself is $ZZ (default: $HOME/.zz).
+See also the clip board editor "ezz".
+Limitation: zz does not work across accounts or hosts! Use xx instead.
 
-if [ "$*" = -h -o "$*" = --help ]; then
-  exec cat<<EOD
-zz is the generic clip board program. See also the edit helper program ezz.
-The clip board is \$ZZ (default: \$HOME/.zz). Options and modes are:
+Options and modes are:
 
-"zz"            write \$ZZ to STDOUT
-"zz file(s)"    copy file(s) into \$ZZ
-"zz -"          write STDIN (keyboard, mouse buffer) to \$ZZ
-"zz +"          add STDIN (keyboard, mouse buffer) to \$ZZ
-"... | zz"      write STDIN from pipe to \$ZZ
-"... | zz +"    add STDIN from pipe to \$ZZ
-"zz | ..."      write \$ZZ to pipe
-"zz .."         write previous \$ZZ to STDOUT
+  "zz"              show content of $ZZ
+  "zz file(s)"      copy file(s) content into $ZZ
+  "zz -"            write STDIN (keyboard, mouse buffer) to $ZZ
+  "zz +"            add STDIN (keyboard, mouse buffer) to $ZZ
+  "... | zz"        write STDIN from pipe to $ZZ
+  "... | zz +"      add STDIN from pipe to $ZZ
+  "... | zz -"      write STDIN from pipe to $ZZ and STDOUT
+  "zz | ..."        write $ZZ to pipe
+  "... | zz | ..."  save pipe data to $ZZ (like tee)
+  "zz --"           write $ZZ to STDOUT
+  "zz -v"           show clip board versions (history)
+  "zz -1"           write $ZZ version 1 to STDOUT
+  "zz -9"           write $ZZ version 9 to STDOUT
 
 Examples:
 
   zz *.txt
   ls -l | zz
   zz | wc -l
-  (within mutt:) |zz
-  (within tin:)  |azz
-  (within vi:)   :w !zz
-  (within vi:)   :r !zz
+  (within vi)   :w !zz
+  (within vi)   :r !zz
+  (within mutt) |zz
+EOD
+    exit;
+  }
+
+  if ("@ARGV" eq '-v') {
+    exec qw'vv -+l',$ZZ;
+  }
+
+  if ("@ARGV" =~ /^-(\d)$/) {
+    exec "vv -v $1 '$ZZ' | cat";
+  }
+
+  # read mode
+  if (-t STDIN and not @ARGV or "@ARGV" eq '--') {
+    exec 'cat',$ZZ;
+  }
+
+  # write mode
+  system "vv -s '$ZZ' >/dev/null 2>&1" if -s $ZZ;
+
+  if (@ARGV and $ARGV[0] eq '+') {
+    shift @ARGV;
+    $wm = '>>';
+  }
+
+  if ("@ARGV" eq '-') {
+    @ARGV = ();
+    $tee = 1 unless -t STDIN;
+  }
+
+ $tee = 1 unless @ARGV or -t STDIN or -t STDOUT;
+ $bs = 2**12 if $tee;
+
+  open $ZZ,$wm,$ZZ or die "$0: cannot write $ZZ - $!\n";
+
+  if (@ARGV) {
+    while ($file = shift @ARGV) {
+      if (-f $file) {
+        if (open $file,$file) {
+          while (read($file,$x,$bs)) {
+            my $s = syswrite $ZZ,$x;
+            defined($s) or die "$0: cannot write to $ZZ - $!\n";
+          }
+          close $file;
+        } else {
+          warn "$0: cannot read $file - $!\n";
+        }
+      } elsif (-e $file) {
+        warn "$0: $file is not a regular file\n";
+      } else {
+        warn "$0: $file does not exist\n";
+      }
+    }
+    close $ZZ;
+    $ZZ1 = $ZZ.'~1~';
+    $ZZ1 =~ s:(.*)/(.*):$1/.versions/$2:;
+    if (-e $ZZ and not -s $ZZ and -s $ZZ1 ) {
+      system qw'rsync -aA',$ZZ1,$ZZ;
+    }
+  } else {
+    while (read(STDIN,$x,$bs)) {
+      syswrite $ZZ,$x;
+      syswrite STDOUT,$x if $tee;
+    }
+  }
 
-Limitation: zz does not work across different accounts or hosts! Use xx instead.
+  exit;
+}
+
+
+sub ezz {
+  my $bs = 2**16;
+  my $wm = '>';
+  my $editor = $ENV{EDITOR} || 'vi';
+  my ($out,$file,$x);
+
+  $ENV{JEDINIT} = "SAVE_STATE=0";
+
+  if ("@ARGV" =~ /^(-h|--help)$/) {
+    print <<'EOD';
+ezz is the edit helper for the zz clip board program.
+The clip board itself is $ZZ (default: $HOME/.zz).
+
+Options and modes are:
+
+  "ezz"                    edit $ZZ with $EDITOR
+  "... | ezz"              write STDIN from pipe to $ZZ and call $EDITOR
+  "... | ezz +"            add STDIN from pipe to $ZZ and call $EDITOR
+  "ezz 'perl commands'"    execute perl commands on $ZZ
+  "ezz - 'perl commands'"  execute perl commands on $ZZ and show result
+  "ezz filter [args]"      run filter [with args] on $ZZ
+  "ezz - filter [args]"    run filter [with args] on $ZZ and show result
+
+Examples:
+
+  ls -l | ezz
+  ezz 's/ /_/g'
+  ezz head -3
+  ezz - head -3
 EOD
-fi
-
-if [ "$1" = + ]; then
-  shift
-  exec cat -- "$@" >>$ZZ
-fi
-
-if [ -t 0 ]; then
-    if [ -z "$1" ]; then
-        exec cat -- $ZZ
-    elif [ "$1" = .. ]; then
-        exec cat -- $ZZ~
-    else
-        test -f $ZZ && mv $ZZ $ZZ~
-        exec cat -- "$@" >$ZZ
-    fi
-else
-    test -f $ZZ && mv $ZZ $ZZ~
-    exec cat >$ZZ
-fi
+    exit;
+  }
+
+  system "vv -s '$ZZ' >/dev/null 2>&1" if -s $ZZ;
+
+  unless (-t STDIN) {
+    if ("@ARGV" eq '+') {
+      @ARGV = ();
+      $wm = '>>';
+    }
+    open $ZZ,$wm,$ZZ or die "$0: cannot write $ZZ - $!\n";
+    syswrite $ZZ,$x while read(STDIN,$x,$bs);
+    close $ZZ;
+  }
+
+  if (@ARGV) {
+    $out = shift @ARGV if $ARGV[0] eq '-';
+    $cmd = shift @ARGV or exec 'cat',$ZZ;
+    rename $ZZ,"$ZZ~" or die "$0: cannot move $ZZ to $ZZ~ - $!\n";
+    $cmd = quotemeta $cmd;
+    @ARGV = map { quotemeta } @ARGV;
+    if (pathsearch($cmd)) {
+      system "$cmd @ARGV <'$ZZ~'>'$ZZ'";
+    } else {
+      system "perl -pe $cmd @ARGV <'$ZZ~'>'$ZZ'";
+    }
+    if ($? == 0) { unlink "$ZZ~" }
+    else         { rename "$ZZ~",$ZZ }
+    exec 'cat',$ZZ if $out;
+  } else {
+    exec $editor,$ZZ;
+  }
+  exit;
+}
+
+
+sub install {
+  my ($dir);
+  local $| = 1;
+
+  print "Installation directory: ";
+  $dir = <STDIN>||'';
+  chomp $dir;
+  $dir =~ s:/+$::;
+  $dir ||= '.';
+  if ($dir eq '.') {
+    unlink qw'zz ezz vv';
+    link $prg,'zz'   or die "$0: cannot create zz - $!\n";
+    link $prg,'ezz'  or die "$0: cannot create ezz - $!\n";
+    rename $prg,'vv' or die "$0: cannot create vv - $!\n";
+  } else {
+    die "$0: $dir does not exist\n"     unless -e $dir;
+    die "$0: $dir is not a directory\n" unless -d $dir;
+    die "$0: $dir is not writable\n"    unless -w $dir;
+    chdir $dir or die "$0: cannot cd $dir - $!\n";
+    unlink qw'zz ezz vv';
+    system qw'rsync -a',$prg,'vv';
+    exit $? if $?;
+    link 'vv','zz'  or die "$0: cannot create $dir/zz - $!\n";
+    link 'vv','ezz' or die "$0: cannot create $dir/ezz - $!\n";
+  }
+  print "Installation completed. See:\n";
+  print "\t$dir/vv -h\n";
+  print "\t$dir/zz -h\n";
+  print "\t$dir/ezz -h\n";
+  exit;
+}
diff --git a/cgi-bin/fac b/cgi-bin/fac
index 262975d..a6a0012 100755
--- a/cgi-bin/fac
+++ b/cgi-bin/fac
@@ -205,13 +205,13 @@ if (defined $PARAM{"createUser"}) {
   if ($PARAM{"editUser"} =~ /^#.*/) {
     &editRestrictionsForm;
   } else {
+    $user = normalize_user($PARAM{"editUser"});
     if (defined $PARAM{"delete file"}) {
-      $user = normalize_user($PARAM{"editUser"});
       unlink "$user/\@ALLOWED_RECIPIENTS";
       print "upload restrictions for $user have been deleted\n";
       &end_html;
     } else {
-      editUser($PARAM{"editUser"});
+      editUser($user);
     }
   }
 } elsif ($PARAM{"contentBox"} and $PARAM{"ar"}) {
@@ -564,8 +564,9 @@ sub saveFile {
       &end_html;
     }
   } else {
-    system qw'cp -a',$ar,"$ar~";
+    system 'mv',$ar,"$ar~";
   }
+  $rf =~ s/^\s+$//;
   open $ar,'>',$ar or http_die("cannot write $ar - $!");
   print {$ar} $rf;
   close $ar or http_die("cannot write $ar - $!");;
diff --git a/cgi-bin/fup b/cgi-bin/fup
index 2a799ac..9ba0ef2 100755
--- a/cgi-bin/fup
+++ b/cgi-bin/fup
@@ -1613,7 +1613,10 @@ sub parse_request {
 
     &check_space($cl) if $cl > 0;
 
-    $SIG{ALRM} = sub { die "TIMEOUT\n" };
+    $SIG{ALRM} = sub {
+      $SIG{__DIE__} = 'DEFAULT';
+      die "TIMEOUT\n";
+    };
     alarm($timeout);
     binmode(STDIN,':raw');
 
@@ -1942,7 +1945,10 @@ sub showstatus {
     exit;
   }
 
-  $SIG{ALRM} = sub { die "TIMEOUT in showstatus: no (more) data received\n" };
+  $SIG{ALRM} = sub {
+    $SIG{__DIE__} = 'DEFAULT';
+    die "TIMEOUT in showstatus: no (more) data received\n";
+  };
   alarm($timeout*2);
 
   $t0 = $t1 = time;
diff --git a/cgi-bin/fur b/cgi-bin/fur
index bca85af..0ab7be9 100755
--- a/cgi-bin/fur
+++ b/cgi-bin/fur
@@ -48,7 +48,8 @@ unless (@local_domains or @local_rdomains) {
 }
 
 unless (@local_hosts and ipin($ra,@local_hosts) or
-        @local_rhosts and ipin($ra,@local_rhosts)) {
+        @local_rdomains and @local_rhosts and
+        (not @registration_hosts or ipin($ra,@registration_hosts))) {
   html_error($error,
     "Registrations from your host ($ra) are not allowed.",
     "Contact $ENV{SERVER_ADMIN} for details."
diff --git a/doc/Changes b/doc/Changes
index cdc834f..2457b74 100644
--- a/doc/Changes
+++ b/doc/Changes
@@ -1,3 +1,14 @@
+2016-09-19 dop: do not show return value of <<perl-code;>> in dynamic html
+                file if this code ends with a ";"
+2016-09-07 new fex.ph config variable $purge
+2016-09-01 dop: removed (forgotten) CGI::Carp
+2016-08-29 fexsend,fexget: update function aborts if new version is not newer
+2016-08-03 added timeout to error output, fixes hanging fup
+2016-08-03 fexsend: fixed bug dangling symlinks raise an error in archive mode
+2016-07-21 fexsrv: map http client headers HTTP-HOST HTTP-VERSION PROXY* to
+                   HTTP_X_HOST HTTP_X_VERSION HTTP_X_PROXY*
+2016-07-11 added missing fex.png fexit.png to distribution
+2016-05-31 fur: fixed bug no external user registration possible
 2016-03-11 fuc: added MIME headers to notification e-mail
 2016-03-08 fexsend: added support for recipient:options
 2016-03-07 fexsend,fexget: added update function to option -V
diff --git a/doc/SSL b/doc/SSL
index 6eb73bf..90e01ef 100644
--- a/doc/SSL
+++ b/doc/SSL
@@ -2,14 +2,27 @@
 
 # execute this as root!
 
-# Redhat : stunnel-4 does not work! you need to install stunnel-5
-# Debian : stunnel-5.06 does not work! you need to install stunnel-5.18
+# Redhat+CentOS : stunnel does not work! you need to install stunnel-4
+#
+# Debian+Ubuntu : stunnel-5 does not work! you need to install stunnel-4
+#
+# apt-get install gcc make libssl-dev
+# yum install gcc make openssl-devel
+# cd /tmp
+# wget ftp://ftp.nluug.nl/pub/networking/stunnel/archive/4.x/stunnel-4.57.tar.gz
+# tar xvzf stunnel-4.57.tar.gz
+# cd stunnel-4.57
+# ./configure --prefix /opt/stunnel-4.57
+# make
+# make install
+# ln -s /opt/stunnel-4.57/bin/stunnel /usr/local/bin/stunnel4
 
 mkdir /home/fex/etc
 cd /home/fex/etc/
 
-openssl req -new -x509 -days 9999 -nodes -out stunnel.pem -keyout stunnel.pem
+# create self-signed certificate
 # see http://www.infodrom.org/Debian/tips/stunnel.html
+openssl req -new -x509 -days 9999 -nodes -out stunnel.pem -keyout stunnel.pem
 dd if=/dev/urandom count=2 | openssl dhparam -rand - 1024 >> stunnel.pem
 openssl x509 -text -in stunnel.pem
 chmod 600 stunnel.pem
@@ -19,23 +32,26 @@ debug = warning
 output = /home/fex/spool/stunnel.log
 cert = /home/fex/etc/stunnel.pem
 sslVersion = all
+fips = no
 TIMEOUTclose = 1
-exec = perl
-execargs = perl -T /home/fex/bin/fexsrv stunnel
+exec = /home/fex/bin/fexsrv
+execargs = fexsrv stunnel
 EOD
 
-case $(lsb_release -a 2>/dev/null) in
-  *CentOS*) echo 'fips = no' >>stunnel.conf;;
-esac
+## https://www.stunnel.org/pipermail/stunnel-users/2013-October/004414.html
+#case $(lsb_release -a 2>/dev/null) in
+#  *CentOS*) echo 'fips = no' >>stunnel.conf;;
+#esac
 
 chown -R fex .
 
 stunnel=$(which stunnel4)
 if [ -z "$stunnel" ]; then
-  echo "no stunnel found" >&2
-else
+  echo "no stunnel4 found" >&2
+  exit
+fi
 
-  cat <<EOD>/etc/xinetd.d/fexs
+cat <<EOD>/etc/xinetd.d/fexs
 # default: on
 # description: fex web server with SSL
 # note: only possible on port 443!
@@ -56,11 +72,9 @@ service fexs
 }
 EOD
 
-  /etc/init.d/xinetd restart
-  echo 'To enforce https, add to fex.ph:'
-  echo '$force_https = 1;'
-
-fi
+/etc/init.d/xinetd restart
+echo 'To enforce https, add to fex.ph:'
+echo '$force_https = 1;'
 
 # Hint: on some systems stunnel works not well with xinetd
 #       you can also run stunnel without xinetd, in server daemon mode
diff --git a/doc/concept b/doc/concept
index fde9902..6203c43 100644
--- a/doc/concept
+++ b/doc/concept
@@ -51,7 +51,7 @@ program "fac" (F*EX admin control) or http://YOURFEXSERVER/fac
 
 Alternativly the users can register theirselves with http://YOURFEXSERVER/fur
 (F*EX user registration), if the admin allows them to do so. This is done by
-setting the variables @local_domains and @local_hosts in FEXHOME/lib/fex.ph
+setting the variables @local_domains and @local_hosts in $FEXHOME/lib/fex.ph
 Example:
 
 	@local_hosts = qw(127.0.0.1 10.10.100.0-10.10.255.255);
@@ -146,7 +146,7 @@ and more than once (until expiration date).
 If you want "delay autodelete" to be the default behaviour for all users
 and each transfer then set
 	$autodelete = 'DELAY'; # or 'NO' for no autodelete
-in FEXHOME/lib/fex.ph
+in $FEXHOME/lib/fex.ph
 
 In addition, you can add to the "Recipient(s)" field of the fup CGI:
 ":autodelete=delay" or ":autodelete=no" or ":keep=x" (where x is the number
@@ -193,18 +193,18 @@ The administrator can also forbid a user to fex to any recipient address,
 but the allowed ones with: fac -r USER
 
 
-By standard installation the base directory FEXHOME is the same as the
-login HOME of user fex, but you can move it if you want. FEXHOME is
+By standard installation the base directory $FEXHOME is the same as the
+login HOME of user fex, but you can move it if you want. $FEXHOME is
 determined by the full path of fexsrv as configured in
-/etc/xinetd.d/fex . Change this when you move FEXHOME!
+/etc/xinetd.d/fex . Change this when you move $FEXHOME!
 
 You can also add (name based) virtual hosts with fac.
 
-Do not give write permission to any other user to any file in FEXHOME or
+Do not give write permission to any other user to any file in $FEXHOME or
 below!
 
 
-FEXHOME contains:
+$FEXHOME contains:
 
 	spool/				spool directory and user data
         htdocs/				directory for generic download files
@@ -273,7 +273,7 @@ A registered full F*EX user is identified by the file $spooldir/$from/@
 Only if this file contains his auth-ID this user is able to send files to
 others. Otherwise he is just an unpriviledged recipient.
 
-You can customize the upload CGI fup by editing FEXHOME/lib/fup.pl
+You can customize the upload CGI fup by editing $FEXHOME/lib/fup.pl
 
 Additional directories in spool:
 
@@ -362,13 +362,13 @@ For streaming receiving you can use "fexget -s-" or "wget -O-".
 
 
 fexsrv also can do generic document output (via dop) like a normal web
-server. For this, your files must be under FEXHOME/htdocs and they must
-not have the same name as the CGIs under FEXHOME/cgi-bin, because the CGIs
+server. For this, your files must be under $FEXHOME/htdocs and they must
+not have the same name as the CGIs under $FEXHOME/cgi-bin, because the CGIs
 have priority.
 
 For security reasons, documents to be delivered by dop:
 - the file must be readable by group or world
-- the file must be in FEXHOME/htdocs or a directory specified by @doc_dirs
+- the file must be in $FEXHOME/htdocs or a directory specified by @doc_dirs
 - the filename must not start with a "."
 - the filename must not contain a "@"
 - the filename must not end with "~"
@@ -387,15 +387,23 @@ fexsrv.
 
 *.html files may contain $VARIABLES$ which will be substituted with the
 value of the corresponding environment variable. See example
-$SERVER_ADMIN$ in FEXHOME/htdocs/index.html
+$SERVER_ADMIN$ in $FEXHOME/htdocs/index.html
 
 *.html files may contain <<perl-code>> (even multiline) which will be
-evaluated and its output will be placed in. Same goes for <<<perl-code>>>
-but without output catching.
-See example FEXHOME/htdocs/dynamic.html
-This perl-code must not contain '>>' strings itself!
+evaluated. The output from print and printf statements will be placed
+in. If the perl-code does not end with a ";" then its return value is also
+added to the output.
+
+Same goes for <<<perl-code>>> but without output catching.
+
+This perl-code must not contain ">>" strings itself!
+
+See example $FEXHOME/htdocs/dynamic.html
+
+To chainload external perl-code do not use "require" but "do" statement.
 Pay attention: do not place security relevant data inside << >> because it
-will be delivered to the client if the URL ends with '!'! See example:
+will be delivered to the client if the URL ends with a "!" character, see
+example:
 http://fex.rus.uni-stuttgart.de/index.html
 http://fex.rus.uni-stuttgart.de/index.html!
 
diff --git a/doc/new b/doc/new
index badf322..bcd8be8 100644
--- a/doc/new
+++ b/doc/new
@@ -2,11 +2,6 @@ New release on http://fex.belwue.de/fex.html
 
 Important changes:
 
-- recipient address can have attached :options (keep,autodelete,locale)
-
-- added config variable @extra_header with default HTTP security headers,
-  see: https://securityheaders.io/?q=http%3A%2F%2Ffex.belwue.de
-
-- dynamic HTML runs in own Perl namespace (DOP)
+- new fex.ph config variable $purge
 
 - fixed various bugs
diff --git a/doc/version b/doc/version
index 7b735e5..d9e31cb 100644
--- a/doc/version
+++ b/doc/version
@@ -1 +1 @@
-fex-20160328
+fex-20160919
diff --git a/htdocs/FAQ/admin.faq b/htdocs/FAQ/admin.faq
index 61691fc..1f7c404 100644
--- a/htdocs/FAQ/admin.faq
+++ b/htdocs/FAQ/admin.faq
@@ -2,7 +2,7 @@ Q: I cannot install a web server like fexsrv, because I have no root permissions
 A: F*EX is hard bound to fexsrv for several reasons (performance, file size limit, session concept, etc) and cannot be run as CGI under apache. But you might have a look at
 
    * https://github.com/FileZ/FileZ
-   * http://freshmeat.net/projects/eventh/
+   * https://github.com/jlmeeker/evh2
    * http://www.schaarwaechter.de/sp/projekte/dateiaustausch.html (German only!)
 
    which implement a file exchange as pure CGIs, but with a 2 GB file size limit, which F*EX does not have.
diff --git a/htdocs/FAQ/admin.html b/htdocs/FAQ/admin.html
index a096645..9585c69 100644
--- a/htdocs/FAQ/admin.html
+++ b/htdocs/FAQ/admin.html
@@ -2,11 +2,14 @@
 <head><title>F*EX FAQ</title></head>
 <body>
 
+## << do "./xx.pl" or print $! >>
+## << $_ = `pwd` >>
+
 ## <pre>
 ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
 ## </pre>
 
-<< require "./faq.pl" or print $! >>
+<< do "./faq.pl" or print $! >>
 
 </body>
 </html>
diff --git a/htdocs/FAQ/all.html b/htdocs/FAQ/all.html
index a096645..9585c69 100644
--- a/htdocs/FAQ/all.html
+++ b/htdocs/FAQ/all.html
@@ -2,11 +2,14 @@
 <head><title>F*EX FAQ</title></head>
 <body>
 
+## << do "./xx.pl" or print $! >>
+## << $_ = `pwd` >>
+
 ## <pre>
 ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
 ## </pre>
 
-<< require "./faq.pl" or print $! >>
+<< do "./faq.pl" or print $! >>
 
 </body>
 </html>
diff --git a/htdocs/FAQ/faq.pl b/htdocs/FAQ/faq.pl
index 3a2fcff..0e484b9 100644
--- a/htdocs/FAQ/faq.pl
+++ b/htdocs/FAQ/faq.pl
@@ -140,3 +140,5 @@ sub anchor {
   s/_+$//;
   return $_;
 }
+
+' ';
diff --git a/htdocs/FAQ/local.html b/htdocs/FAQ/local.html
index a096645..9585c69 100644
--- a/htdocs/FAQ/local.html
+++ b/htdocs/FAQ/local.html
@@ -2,11 +2,14 @@
 <head><title>F*EX FAQ</title></head>
 <body>
 
+## << do "./xx.pl" or print $! >>
+## << $_ = `pwd` >>
+
 ## <pre>
 ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
 ## </pre>
 
-<< require "./faq.pl" or print $! >>
+<< do "./faq.pl" or print $! >>
 
 </body>
 </html>
diff --git a/htdocs/FAQ/meta.faq b/htdocs/FAQ/meta.faq
index f910621..09fe46f 100644
--- a/htdocs/FAQ/meta.faq
+++ b/htdocs/FAQ/meta.faq
@@ -70,7 +70,7 @@ A: For example:
    * European Commission Institute for Energy and Transport http://fex.jrc.nl
    * High Performance Computing Center Stuttgart http://fex.hlrs.de
    * Swiss National Supercomputing Centre http://fex.cscs.ch
-   * Centre National de la Recherche Scientifique (French National Center for Scientific Research) http://bigfiles.cnrs-gif.fr
+   * Centre National de la Recherche Scientifique http://bigfiles.cnrs-gif.fr
    * Institut Pasteur http://dl.pasteur.fr
    * Justus Liebig University http://fex.hrz.uni-giessen.de
    * Fiat Chrysler https://fex.fiatitem.com/
diff --git a/htdocs/FAQ/meta.html b/htdocs/FAQ/meta.html
index a096645..9585c69 100644
--- a/htdocs/FAQ/meta.html
+++ b/htdocs/FAQ/meta.html
@@ -2,11 +2,14 @@
 <head><title>F*EX FAQ</title></head>
 <body>
 
+## << do "./xx.pl" or print $! >>
+## << $_ = `pwd` >>
+
 ## <pre>
 ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
 ## </pre>
 
-<< require "./faq.pl" or print $! >>
+<< do "./faq.pl" or print $! >>
 
 </body>
 </html>
diff --git a/htdocs/FAQ/misc.html b/htdocs/FAQ/misc.html
index a096645..9585c69 100644
--- a/htdocs/FAQ/misc.html
+++ b/htdocs/FAQ/misc.html
@@ -2,11 +2,14 @@
 <head><title>F*EX FAQ</title></head>
 <body>
 
+## << do "./xx.pl" or print $! >>
+## << $_ = `pwd` >>
+
 ## <pre>
 ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
 ## </pre>
 
-<< require "./faq.pl" or print $! >>
+<< do "./faq.pl" or print $! >>
 
 </body>
 </html>
diff --git a/htdocs/FAQ/user.html b/htdocs/FAQ/user.html
index a096645..9585c69 100644
--- a/htdocs/FAQ/user.html
+++ b/htdocs/FAQ/user.html
@@ -2,11 +2,14 @@
 <head><title>F*EX FAQ</title></head>
 <body>
 
+## << do "./xx.pl" or print $! >>
+## << $_ = `pwd` >>
+
 ## <pre>
 ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
 ## </pre>
 
-<< require "./faq.pl" or print $! >>
+<< do "./faq.pl" or print $! >>
 
 </body>
 </html>
diff --git a/htdocs/FAQ/xx.html b/htdocs/FAQ/xx.html
new file mode 100644
index 0000000..3c8eb43
--- /dev/null
+++ b/htdocs/FAQ/xx.html
@@ -0,0 +1,15 @@
+<html>
+<head><title>F*EX FAQ</title></head>
+<body>
+
+## << do "./xx.pl" or print $! >>
+## << $_ = `pwd` >>
+
+## <pre>
+## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
+## </pre>
+
+<< require "./xx.pl"; >>
+
+</body>
+</html>
diff --git a/htdocs/FAQ/xx.pl b/htdocs/FAQ/xx.pl
new file mode 100755
index 0000000..68e45b4
--- /dev/null
+++ b/htdocs/FAQ/xx.pl
@@ -0,0 +1,6 @@
+package FAQ;
+
+print "abc\n";
+printf "1 2 3\n";
+print "___\n";
+1;
diff --git a/htdocs/FAQ/zz.pl b/htdocs/FAQ/zz.pl
new file mode 100644
index 0000000..0f57817
--- /dev/null
+++ b/htdocs/FAQ/zz.pl
@@ -0,0 +1 @@
+0;
diff --git a/htdocs/download/fexget b/htdocs/download/fexget
index b0616a1..3ac605f 100755
--- a/htdocs/download/fexget
+++ b/htdocs/download/fexget
@@ -13,6 +13,7 @@ use strict qw'vars subs';
 use Config;
 use POSIX;
 use Encode;
+use Cwd 'abs_path';
 use Getopt::Std;
 use File::Basename;
 use Socket;
@@ -30,7 +31,7 @@ our $SH;
 our ($fexhome,$idf,$tmpdir,$windoof,$useragent);
 our ($xv,%autoview);
 our $bs = 2**16; # blocksize for tcp-reading and writing file
-our $version = 20160328;
+our $version = 20160919;
 our $CTYPE = 'ISO-8859-1';
 our $fexsend = $ENV{FEXSEND} || 'fexsend';
 our $DEBUG = $ENV{DEBUG};
@@ -89,6 +90,7 @@ usage: $0 [-v] [-m limit] [-s filename] [-o] [-k] [-X] [-P proxy:port] F*EX-URL(
    or: $0 [-v] -a
    or: $0 -l [-i tag]
    or: $0 -H
+   or: $0 -V
 options: -v verbose mode
          -m limit kB/s
          -s save to filename (-s- means: write to STDOUT/pipe)
@@ -102,6 +104,7 @@ options: -v verbose mode
          -i tag alternate server/account, see: $fexsend -h
          -P use Proxy for connection to the F*EX server
          -H show hints and examples
+         -V show version and ask for upgrade
 argument: F*EX-URL may be file number (see: $0 -l)
 EOD
 
@@ -167,10 +170,15 @@ if ($opt_V) {
     $_ = <STDIN>||'';
     if (/^y/i) {
       my $new = `wget -nv -O- http://fex.belwue.de/download/fexget`;
-      if ($new !~ /upgrade fexget/) {
+      my $newversion = $1 if $new =~ /version = (\d+)/;
+      if ($new !~ /upgrade fexget/ or not $newversion) {
         die "$0: bad update\n";
       }
-      system qw'cp -a',$_0,$_0.'_old';
+      if ($newversion <= $version) {
+        die "$0: no newer version\n";
+      }
+      $_0 = abs_path($_0);
+      system qw'rsync -a',$_0,$_0.'_old';
       exit $? if $?;
       open $_0,'>',$_0 or die "$0: cannot write $_0. - $!\n";
       print {$_0} $new;
@@ -178,6 +186,7 @@ if ($opt_V) {
       exec $_0,qw'-V .';
     }
   }
+  exit;
   exit if "@ARGV" eq '.';
 }
 
@@ -328,7 +337,7 @@ URL: foreach my $url (@ARGV) {
       ($file) = grep { $_ = $1 if /^X-File:\s+(.+)/ } @r;
       $file = $url unless $file;
       $file =~ s:.*/::;
-      printf "%s deleted\n",urldecode($file);
+      printf "%s deleted\n",locale(decode_utf8(urldecode($file)));
     } else {
       s:HTTP/[\d\. ]+::;
       die "$0: server response: $_";
diff --git a/htdocs/download/fexsend b/htdocs/download/fexsend
index f47bed4..fae77e9 100755
--- a/htdocs/download/fexsend
+++ b/htdocs/download/fexsend
@@ -17,10 +17,10 @@ use IO::Handle;
 use IO::Socket::INET;
 use Getopt::Std;
 use File::Basename;
-use Cwd qw'abs_path';
+use Cwd 'abs_path';
 use Fcntl qw':flock :mode';
-use Digest::MD5 qw'md5_hex';  # encrypted ID / SID
-use Time::HiRes qw'time';
+use Digest::MD5 'md5_hex';  # encrypted ID / SID
+use Time::HiRes 'time';
 # use Smart::Comments;
 use constant k => 2**10;
 use constant M => 2**20;
@@ -37,7 +37,7 @@ our ($tpid,$frecipient);
 our ($FEXID,$FEXXX,$HOME);
 our (%alias);
 our $chunksize = 0;
-our $version = 20160328;
+our $version = 20160919;
 our $_0 = $0;
 our $DEBUG = $ENV{DEBUG};
 
@@ -248,6 +248,14 @@ Partner program xx is an internet clipboard. See: xx -h
 
 Partner program fexget is for downloading. See: fexget -h
 
+fexsend stores the login data (server, user and auth-ID) in the file
+$HOME/.fex/id
+The format of this file is ([data] is optional):
+
+server-URL[!proxy[:port[:chunk-size]]
+e-mail-address
+auth-ID
+
 For temporary usage of a HTTP proxy use:
   $0 -P your_proxy:port:chunksize_in_MB file recipient
 Example:
@@ -361,10 +369,15 @@ if ($xx) {
       $_ = <STDIN>||'';
       if (/^y/i) {
         my $new = `wget -nv -O- http://fex.belwue.de/download/fexsend`;
-        if ($new !~ /upgrade fexsend/) {
+        my $newversion = $1 if $new =~ /version = (\d+)/;
+        if ($new !~ /upgrade fexsend/ or not $newversion) {
           die "$0: bad update\n";
         }
-        system qw'cp -aL',$_0,$_0.'_old';
+        if ($newversion <= $version) {
+          die "$0: no newer version\n";
+        }
+        $_0 = abs_path($_0);
+        system qw'rsync -a',$_0,$_0.'_old';
         exit $? if $?;
         open $_0,'>',$_0 or die "$0: cannot write $_0. - $!\n";
         print {$_0} $new;
@@ -372,6 +385,7 @@ if ($xx) {
         exec $_0,qw'-V .';
       }
     }
+    exit;
     exit if "@ARGV" eq '.';
   }
 
@@ -3206,9 +3220,10 @@ sub query_sid {
   $sid = $id;
 
   if ($port eq 443 or $proxy) {
+    return if $opt_d;
     return if $features;    # early return if we know enough
-    $req = "OPTIONS /FEX HTTP/1.1";
-    $req = "HEAD /index.html HTTP/1.1";
+    $req = "OPTIONS /FEX HTTP/1.1"; # does not work with (some) proxies
+    $req = "GET /SID HTTP/1.1";     # needed as FEATURES query
   } else {
     $req = "GET /SID HTTP/1.1";
   }
@@ -3469,7 +3484,8 @@ sub readahead {
 
 sub fileid {
   my $file = shift;
-  my @s = stat($file);
+  my $dirmode = shift;
+  my @s = $dirmode ? lstat($file) : stat($file);
 
   if (@s) {
     return md5_hex($file.$s[0].$s[1].$s[7].$s[9]);
@@ -3528,6 +3544,9 @@ sub fmd {
           next if $file eq '..';
           if ($file eq '.') {
             $fmd .= fileid($dir);
+          } elsif (-l "$dir/$file") {
+            # hack for dangling symlinks: do not raise an error
+            $fmd .= fileid("$dir/$file",'dirmode');
           } else {
             $fmd .= fmd("$dir/$file");
           }
diff --git a/htdocs/download/sexsend b/htdocs/download/sexsend
index 9a7d48b..8b9e1d1 100755
--- a/htdocs/download/sexsend
+++ b/htdocs/download/sexsend
@@ -19,7 +19,7 @@ use constant M => 2**20;
 
 eval 'use Net::INET6Glue::INET_is_INET6';
 
-our $version = 20160328;
+our $version = 20160919;
 our $DEBUG = $ENV{DEBUG};
 
 my %SSL = (SSL_version => 'TLSv1');
diff --git a/htdocs/fex.png b/htdocs/fex.png
new file mode 100644
index 0000000000000000000000000000000000000000..a9ac834648e9db5528199a83d72581c8655dd63c
GIT binary patch
literal 7188
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
WFkxnCW7$gp0000<MNUMnLSTXfmf9u&

literal 0
HcmV?d00001

diff --git a/htdocs/fexit.html b/htdocs/fexit.html
index ce281d3..f825d30 100644
--- a/htdocs/fexit.html
+++ b/htdocs/fexit.html
@@ -35,8 +35,9 @@ You can also drag files or directories to the fexit icon with the Windows
 explorer.
 <p>
 With <a href="$FEXIT$">fexit</a> you also have access to the
-<a href="/usecases/xx.html">F*EX internet clipboard</a> to exchange files
-between your Windows or UNIX accounts.
+<a href="http://fex.rus.uni-stuttgart.de/usecases/xx.html">
+F*EX internet clipboard</a>
+to exchange files between your Windows or UNIX accounts.
 <p>
 <a href="$FEXIT$"><img src='fexit.png'></a>
 <p>
diff --git a/htdocs/fexit.png b/htdocs/fexit.png
new file mode 100644
index 0000000000000000000000000000000000000000..585afaef4e136087bee6834d380b070b4bb7236b
GIT binary patch
literal 23729
zcmXtg1yEc~6D>i4CAbD#_QTyJI9Uj;!2<+`;O=a2cL)~T-Q5Z9?y$JK!vg!r|K6**
zRa<xJ%;}k)p6R|b(;KR!@bx3wCp0)XxR26OAQd<`_!>C4cP1$CZzaitf7af95Y5Eo
z#o*woqtTxYklx-uIZ0?bsoI)4xf(c_z-g)j)J+^5Eo^N7oGk2Y2BsE9OR{iq061xo
z*f+O7C+V)gs3ewPnI#!3twLuT934^^$fO~5J5Egej5zqxG6c$^%6c`3@7RC&mI1@A
za@t;de}R&U0AgY}c?dVVZN2t(C#P}?*U(&Xje*0I^riGQsE^=M#?ev9QEG-y$L%*9
z0ocZQuN=9Y+zHqaXlR<F$@SJsxDUJmSmH2h9G-{(p$b0vjpBDSKtmptE(tc|KQY+<
z5C`UEC|Ke|BrE~3DB_?yeWgGgKS0I%WPI#c6}%yMzm<O=B6YrjUjSfSTyj9nD5^Jr
zK^<39tV{bH9W*vHk)I8|=jp>g7~2Q7_V<2>#|YF?QUo%k?@BTAuyVxv>9fi>l=2c>
zh^o*+>p>R@zIPN@*tOVX|Ee5V1;j|=qI8R+QA%SC{gR4NqRIyt;^60^mc{={1mYhd
zkl6?!^F&>>;sDU!@V^Xx#q>O5t9YVFNl_-o#05|R<EW&LD1!^2zY-1AYW)Dl`I>?D
z_8XW2Ki=8Cd#f?|=!Sq&28a=V-y5d}$ipiOVWeutxyK496UX?1VaZTtuW6(<GyF?!
z41>Fh<KK|Okws6=VCCV7qY<MJqtFMIq0mcUp=eQJgunxVXbiD5C|~gB`N|wL)#_7A
z?uxZLOVrdfciD{9!uzSj@%|C~MHDmU5>vt!lTdFlR>JP4!~T|65+aI9j8cIz#E}(t
z2Cz#NoqJNNuWYzMsK4>Ag8ADWBA3kDuD-V#pgNL9{YOId9)&V6#ur6$NG9pz6RuNa
zY_8;pa&9w+Oi37uq_jF-Rm}*o`xnIIzpow3aeZ_5km3%Qg7c*x63p$#!5QK|j&g%X
zXC8|BRkYlsOmPM(Azm>Qg17)fX}^>Z#?jG|{^2IHp4W~eX!sK(U0>(w3{2kceR43I
zqA&Dv@mE+L<eLzglr3E--s**|b=bgA8R1m(StqP^<T!&JT_Jzm)U->BmLLCjikdyL
z^40g0D?G#%PCFrAlgM6k>v6Qv$aF#en3+4PXGO^jU@HK)4|=+4qXYiOBv6bx;!Fm9
zM&*6IXo-+Q*g)3Mb)4Q;FgNg9NO#$?hjg?AqGAO6cfbDfv;u3oXwL`T%w(>4?czhU
z+Ugp5o>n4Knzrch<2bHS^K?B$(UhxkvBcH6)s8WfSc*ID6|9F^VI8o&N?p6DanIBH
z(G#Rb!DlpV`nj%^v|7De;4AO7fxP~2o^QJ!lVJ2S8}>(otj!reyGhaS;|*XXP28pp
z-puQ}H1s5@?&z|P>P-TsX<1h)u4!t$@F^#-lU3}nt9i2*!(QM@noQE~_NVP4smtM;
zQa<N}OHR`Q%etBO1FxoKDRYxXlQ?VvG!&!a3^chepoTu@?z4se+HgaiMrH2oWtmj;
zgR6KJ1JPTz+I7+O7tz<KX{5f!uiy6Q9riedGy~nO;-q%ytW)wdzR`nn;KZ?NGejuX
za%7)3tmi$>#*iw<wQj)Z>#RlJU|XM~i?QMdqEl+khgQzLE}p;y)VRZ~MHkn3mum)K
z=Q~KI`+5F;C>>TojBn^5J`flOiVKlKs!m7ckSasWf~16nNVOQzpoNA6a1@55h!<3s
zR*(nPFF6vzHj8;f&GV!0o;TND&R_n*1kP7$X>Ds-S-ktybMX8Ejm7Xe-%);0D=&G1
z_T<Z!oHIX9<Tip&{la-xP47K3UNzbohTA?uy;hKQ-0Eq!qFZ5t`{wY<Sd_8$rgBhE
z*?F%hnvfUMmx~1ay28cY2z2<(3M$~9ltB#lor-?nC{<26T?l;qC(d{(gVXjOIbA4z
zWuj3koF-M2#)d~<Hqk`ol#OwEjU}V1Ch={Px^7B(@-mCiqP89w!c-yYktKPIdBt)x
zDq#TtlP?lN=MtV%(KNm9%u&z8aC(GP{Ble-1ME6MKxm6W*dYRx#t4XGb&@fE)4?~{
zNkbWO!sSqYTR(+Qm8?Z#U|Q3!3ER5$;KAdN)&cOigl`Ap^*px)`lu~#yJZ0k#r*JU
z8=}KB7vmUot#Df4JWPCQIz2WS!kmXr1$gGzaHm!lNSj5LDqs0R-?J`+XUcIpzYCU=
zQ7)GOWvj#aiK}Q6(*fzFEVLx?aFD3NARM8!3_d5?=GwSyvZW+ab3JTSHRVtI;ljz+
zqn*Mvr)T=DzgV81OzK{Fa;B;CW=knj&$YtB9P#Zm(Mx45Ws|(BHXue{HC)y$I}5md
z=Un#aan*@YO8MibxsS(-O;WS?Y`&e0^7(;W;uq@60yzU>KZYM7MClp|z1!=+OM}Gf
zsxPOyy!^el>b%8j(pNAxPdul*kRfp=TfCR+6-4wIYUdhajAI0k=5Hbw9JBAKhR&t3
zluxP3RI4M5mL(f^QL1*0iXUKC0Mk(p;Hs>oukGrDnRHBIu){-6j=ShXt?Ylyxi#=*
z(M{^o3C<bJ!AUEUKHTZ>O|h;jsw`R>ZHeL>Te~G|#{CFG+raZ@tLZI%H@&HnypTR?
zDAC*J>#eLjU;4|4@vH`)TA7+a=P9+}PfB8@;xwOo^_x{Dl-%CqDrYg*IidYZ_yLT2
z%AMRK-Pzwm41gBd#w^|AV%4(Yh`Ddpe=5}mcAKqhR*mREy^nPuM`^J0ie1_fnWUl!
z9PzjWaYWKo)G(Q1r9%r8*(4^9)5F>hr=yu#LcDotQ|{_`()s8-4Fw!=B5>?A9{+i)
zu$0$Kq%-Nx0Mn9v%)BT2HH%^7c2SD_&Q6i-2|xJ^nPVFt14j@0b_vj|qcc>^I4)6*
z^6a(E=iOdY*rkdi^TR>oE+icCQ!ym34semit!zQZkfIM}p>61yry0x!_MKoPoNcLy
zvvV>M^cqtsKT*E>f}S9D-J9s!zo@Vl<%&HNfTLW&w^5|i9g1+3C#p?aWjUau;fp0+
z?TIRxfsmFPQ;<TFhmYLgY`f!!C(e#ti$@h;hoS7~?}ucW-Q_2ZmaRiJO)yl91&ROJ
z=WG3y16#RhcKYX-b97S+PD-XxaCPU?7v^sUMJ4sx^+zd+lpzPN0%vY}p|tUk^ntHD
z=}Wcy8Px!>dbXV-6}8g2CurWsSs(ZnUU7V&1Rhpk@AT6L#8CbAhst0G$8Xn_L|U?@
zv)~y@<92xC)(?L;lt5vpS~L>hO6R`G++a=3*fKqA(HH7Hmop~mSd{;mB~l}%HU{*F
zBH?4J-yrtIBy3gn*O!#2NtDC3kx6f$wChYoQCzX{U8wK|H(7Y%;92BYP?anb)%#p3
zYnAp0$BBd)M0X#*(FA_RSVP)(?xrjFqx#~h?VTOUX6GCx@w}!hE9cAnsC>#qkS`m%
zyO<sqAKjU-HI&j4G#*BON<$o&8dwwSFqFdZ9E&vBgP%kxf<3h4v!#y8`4Vn@&={HC
z<2zCR>JKG>juP?6tU7MA-866gIw_r3q?s$<7^m)iC(#^p{E9ceZ;^4Q+2{u_?5@xe
ztM(r8to%e7P&51`9N{HH!|DbZSK2_ICBuC3XV<#vY++X2L7hWL{R5?8jyCg2rFv+N
z%pec+&UTAY%Im}5DuSRecZ>Spe9%!`#n&TnMZOn?;Ld}!%Mvv<QBZDk=Wu<A_VU2^
zCTmF9J^)aX;)}#Y|D+dku-Qn^M2ac6<Ay)~`V2mQqJ)<7NYn14!i%ZXEh-=$ivYH?
zxyz{Akw9GcYaP)Pc9RRNt>4w4x9}1*Dn{)=23SYcNLE3F0c!Z_q2^l-MxTymBA*e@
zI{m0n=>xHVSOwQWtj|<9Xf9IW`w<p*FUR`oU$J_H@sMa$q`%${ym#1w?MT?+P*sSv
zVZ08C)<T=vRb{XqY!GlEmRFvUZiP64kY7SKks<?%%}#1Z88i0Ze*^^ss8PP#4QjuO
zQTaZjB3jJ06T|;OEs_q8l;I`yKa;sIAbUcC)(4BTbTrcU&YK<`2XYhdmMD~h_^S3(
zagq1%20RJMH1weiO?r*+)y#EOyN$Nwn?o48&J<EOVW9!is{2{Uq(s5+U%k<$TbY?L
za<({`Pb=FS^Cr|Jhb=c&-@6-95}f<z=O*20ygd+J3!Wfm=>#{(;?!IR=FgWG?{G+b
zgSfb~pC*p9;VJ**8nO*(&K;u_zsaa?FlnW8SLN%zwyPWnncU%7UA2F9U4Im`9GrTG
zMTZj>l891HPuyO|dZM4o!o#Wf-R8sLYm~McIz0Y7=q-XRjhQazo)7<IpPbF))p2wA
z@g*9wQ*X`XRvGECvh!GiJ`ymAERI6|pNZ0icJcKmg*4!Gb_NX_CI8UC*!K+PkO<3@
zlH^UfDCP^C2;#lu4|bib6Qho0f<CsQ2~Dc_diU>?pRK;vKLiQHVm#(*UqR7pj)QQ)
z?VK&pt`_9gPHj5z;-8eketB5j`No4Pc0~y;!SpzOTHQRZ<Vx?I>GMBuxm;u)qtMY~
z41O{P){r62pWC$QDo==OlRlL6VBpSM<CwX|uc1v7C=yxPyr7MK?nQ&=+z{=ILX4fB
z2)C<1GhHhLB%kE&czqbRploL-3p4<O$JE0YEU+qfca~;jUrB<pUDWOdbmn{v-*hP0
zXFuO^q`Ql=Q`OJ#?d4^7j4y^tnmz{&8#V5(6PPj8!RQjN(!pVewCJF+(7_m`Hdm5j
z{zHF?o1>hs@7oNG=+K}$R!~Yh3WiWw%-@owC(*#NZ-JrG>=I%U(s@fZCe8bb>)x%I
zBD2)%XJ)`<=SbzGQ;vBF6!>CpF@OXhaP~<wCINUw%t!cJe>F#ko-h8AWG5o`4^{j6
z^CG>7T4n4hb&5J%h83HSPZ-il+oEnVsqBV6zU{oHNr<a}o5}U3tI=0lMdJtF7&chO
zY{-Hn2UoUm*lB|c4v`jCiIP3@H+=e%>=^O61T68;7({l|mo$~UQA_bfTf%9$53E2P
zJ=zTGfYu5`5;?7{Uq$Ox{$BgOQ0G<y<THlNTaDyiej1FLw-2luZ%iWltQW5qq#_~Q
zUKb^U+4HVms`6YQJ6`PI9X(d;Z=`y*62*zpa1eKXz4$W@5bX<oP_{~m_DGd?I6;b5
zIP}evwVo~Ten0LhonzZ9LP=DqX9zY}gecyTjmIS?Og5}~aOQA$o(Q?)F*<Kh4!|y2
zY!6~`qoKnDxC~IaGnJQ@ojr<{=J#)(oim|W@kmQX=%i)hrtO3(kzZ;>3<EV|35-qo
znoiN^7uZ&I2F|^m;<E00S6-fXsu@Sye3XIW5|XKa7!?sx-}RQEC{8xaG)8m#-+JE_
zGO|9W0*+mYIRlDk`4btS1F>XIjuwBa3H3-jW32-^UO)0%S~)t3=yOIbxL<zv?}=2b
z0|(4~0J1R2d66A_q?OU~;GJGX4^>l;LpAnRJ^U%tXK$iDDx+NVO<t*pFD8e8fnEv?
zC%aU)uV6<UTYCPBgVW20ScWcuKj{V=o%A>f9rn<xjl_*C?F4a5kp=Y5LWMNOoA7a~
zi)*L-u4RZ%c&|$pRRKB1^@K`7jx<>~aFNeO;fB77SF!sLlQ+ZTZsi*GbTWea5g^re
zy`}nc&cal*JjE!N+V(03ej>qsbE*(8&+e6LLZQo5#s(SS(~}%UcRXv`UPs7@ou@&4
zCv1%{)BC=h7xHk8@GcfB?;a4>>znthNxTFog;Ij0mV@-6O>UrECRf8r3u|hcAEtLP
zOyc7mIDfGa@>4F1o{BgQ1%GaJ5P^o>rzZzYh=Kdf<r^X6G%TS6t9FTNX*e~9s^;PH
z-3abfai^zkWo8?6)~uho%y~%<69_C0#!CkGOJlV?Z+m05{|Yr<AOT-SrWYW#XzvNT
zJdFy7-1YLWC~^{Zy8X35zUBstxX8cQuV=C>KhCe6HG7297yJy{oW;hSc^2{ZPSSC0
zhaQa;QUN_h=qAuuydLrtAwC-uEGzbg3?g?{loRLeR`<CFVFMjCr*$C242b7rM(66~
zy~v_d7^>I)1TFY(7Sd|213sQ8v=$nhn72Kv&BUKN(J6%SLSAeA7v`o6O+wCkOYk9o
zYF)1q)1vq@CffH0)pE?QU+t&vG}aZ<^t@n~I&!x*-HJn3NAk28c1yksg00t|ic6w&
zlf?#Q0zFVMg&G2!Wq)Zg(3s{A(6_pyP@>aIq5dvD?8|ce#X%=cZ}KCj-xOlkvuJk5
z#K)ca$p!0Jt7;3t-qZCKtKIkl7NpN-MXg4CYq#Q(>5tR_Z(aupXY?D=u{fZ{5nC%-
z(%8Wp%|<&f9gKzVpJK^9r~h%r8}ZFL$^^tGAD-776hYZ4^=#i{=KeHxl`j3PFTq@Q
zJ75u^Cp?1^-8iG#`pQOx22y2ztOQW52KW(ywGGD1BrDze8prLmzF(F*Dm+dHk_HK|
zc#P5DlNc4%4P@p4u^G^Ww3Hw^U1f!2Rnw~7c(@ujyhCMmKh5jdZ?aj$K>8{5-Qizh
zkC<OsI)`q<aneytAF{DrKKW_hB*jNR^qfbv?nb^8UJFG3xfzo8xxMwQTykK*mR~tq
zyq@TIT?(vK|8t^No4zY$<CT+esjs1)!hbo)C-K?2@Qb3z(LU?=n!_>|VPgAKm2ukM
zQ!UrD${-!TW2{KnSGlFj&dlU=w$Z0T>Vgxui{i}o+kBXnuyg9m7}n`?E`@iy89eUT
z`OEye4#iC$1adcY8xnFFp;Kt=^y-uA8<4SXG|SQHwY{0CMhJnWs5z~>tYJEQbaKpp
zNkPqVz7x(jYbDed_*u^_pA$|FeM-E~w0~{?TCt^D3@((b7BB;9LyIiWh2ug(_FlGg
zv@p+qtK&SfickmCb->ZX15L9v5#_=H4Joyx_C$wcq^sj(=(>B-+CF^7rSp%&g9+n2
zC_F970!G}iBrbx;nyzE70hZ!Ma-=9Zv!A7!jW8B(r~~F<=Q1Y*xE#0u)e#DMYrtZp
zWSy;{scGDFSr?7&`4=Zf8_I&@i65IiK-+iNsGJDDR!`CQks~C1Br$6m#**|sB!OgR
zwYWi2$=tq9uqK<w7&}>66r4OMDOR@r%-{OkDQB3vK8M7gUuGtnzL|MH=9~TT>CdO?
zjXLi*TMHjqbXJgxGY;DzkN(^#Gk+?3o*6g)<;UwIhACwnD$VMI8b(922{KUo*~fVs
zwzl6I%`D`7T}`4$ECDh*Z+%P=@JWz+L0Jd{60U+@2z^{nm}^DY(*v>M8(WXo3oF-u
zmN0j<=w!Oxm$Odnf{NR~Ef|`MVE0r2*&d6Q<+US4+e-@4XR-O>CHT+OXX2v+#?o>-
znhFit>B{wF4whCfcmH*Ix={A{tQBm;dn!QJq8pm8kQK+T72TSNbZt7xax-o@0ty&b
zKOTAED*7_F!2k+c*3m+??ng*ad`|2s49l{OGi^3hRo&^*&tgm|)L*%2rk$y4UYkeC
zAySL^isi;!SIQKqYlT>mV(ikG?Mu=yhF|%I7N8NpA0IGYUsU_SGdlk<zBy3S)$nu2
ziz1%BB8iJVUYav#wa83JXK@+Bv8OEC&=4oy+BQ|}gvW&J>x4)R;fhf_2Rl7}x(U#P
zP?tTlb&p_3^axxapp91Cc%r3(f-OydQqM7|ff_Ff_~^@JfumfG1q@TEC5($9{Z^zB
zYt&+Hm2`5J!>*gt%19)j?GjyZX2WjE6iLq5(tnj)%~g=r(pu~p@p><JAI#ExF!K5G
zZHRCFn`<u2v@d>j8<NoXX@P#>G39l3y?%q6GC4;k<_?6NRp+#(wR|0^&h<ZIVK0z%
zah+OZSyH1Up7q8XBeX2-*dixTDDk`LBi<)iVAwzV950Dv+xc=w&B^#3Rk-s}8xv7?
zg}mvW6?TE5Wof_^j8(TW7kuzXQGr(ME>clWyzOa5EoxWbT)@y@UIF$}4fcBN_|Fte
zVjcealM4kBv)e&0g5onX_SB*4n&-oZ)cZno*UxQ9At5dg-SPW2BG%nsXvuG2rWsQD
ztxpx#72Z$V*NU0$d+8t$?d#PT!u-l!K&xvfET8v2bDYY&`%9+4P9Eft)YKbxS=*Q<
z$#q|;zjRa98WLi9+R`}wt;6XrdGJNGe#=3NE&J3u;kxsjHfx5{!BFRapZAd!$!lqZ
zV8`<J8<`X9woi^Q+ghQ=Sx29TQ}mP&h1TuHOzq4<TkjihPoak^OA4Kpgv^jUM`QW5
zABE{6o)D3VHK*ZOB=Bnwd*R`0VEZey5wd2C6PjfEyc0{viGAwymz(g$yqP&)^I@Mg
z!|jOzL*#KZ)BF5b&S?)L$?7pOxU&lX<@DK_6&Bx-Ce-oVsbRwvN+9HMG~{aKMW=gp
ztq06uX7RqrV=h$qzK^T($9{}cK(Bhr*yFykF#QSQinV5cG=5WjoC%4v`TVxx+$6me
zA7?<Ew-6Rcou0K9ggRHWZ}zM?$35>-ZNV8n_LG&3&9_YUb7hR@v@PJ^fy0RFbM}n)
zG#=Lt#QLq;v=?*NXZ#M20}9aT6bhm9jQ=#U3D1{qaVx)1LYKx4D3b2JLjl;>*4Jw@
zifaWr=BQ&k<oFzGzqMHcat=00tz<CTweEgRWGNf^j4`cV`~|^$&z;RH%(5%?y8=9M
z2{?q1{Z5h*1PXuQhLav(pa`&u-E){zh$ers+welQ0r<<RnrWf>$*?gv_-nVadGzeC
zX1Iun$w#HI@uNfxIm+jWzW0rZ1NCKau#)Fo!s>^?nJ;60hy#^%Kd~ZYyu5us&=FBf
zs`>5qqZ$NZAc8#n46zP2Rj5MzX7~IlHUn7(qAz;LcHy_eD8xr3GTfx|@KO>nlc`2T
ziQ`r5E&q%9^q&cJN@Vl`zO|=s(^h{Pe!LqsMeWiJ2|4(1VIhP2+6XG>u~J!DZ+Ar`
z>`{6<5K`q?=T&&_uMc@BjizXufVEzxwavfIM^hqB^)xG9uplc?QBp10&>d!Qh}GR?
z@ZO$0T$Fwt)g0N|)y`2y)oa_#!Zp)_-OTZfJ2swrJw)htIFGl0u3w!t750Ta&bg1V
zrgZf^&yW>Yp<@=6&sKAsye-%3BW8;r)02l6Z%m(?W`u$XK+e#LuJ=8pl4km8<8I;A
zg=wvANy}@S8N6bFBXr-Hc5>Opg1qGS-Hz<#GFnmo@mPabz^rlZUljMcv!M5QRM04R
zQ_b1v7>Mh4@MJr4PY(8uO!BEa&xU}#7AUMfoAlploOti(XTlbjkD<%54>A!cu*Yp9
z#g&IN@ax$T2%Uoeaq;{{&$Z;?GFCCe9y&sz$kU>adHDSy>E8tCPZD(N`w8+K&r<{k
zb-s3)sZ)DwCmrjJFMwgMWHeZv*9Y{O5LkcsxyVl>;8FX|t}I2%VOw!HxzO$oC(HV)
z#@hsOpYNb0149`dc~d!@1DQJ<ck^%h1n!{Y?gDa}7hQA6!p_62`itfqQ;Z^yC)FZa
zu=W2$yoWLhSD(9nXZpN6mv%hWdz#5>Uch0arq)dHV`hl2h}5kh(Ap3?1KXgB7H_&v
zwS@>+A{Fr3rrEz*>%3h2s#RDrfI>uC?uBhn!N;hb9WEmlwYDo8%eOwxeHw)eJ+S9(
zlGfGBopfX`CmgNdjB_`(N~ZD;H#L%o@gF4doD;>4{MsaNUN{pXVve*1Nn9q2_<mSQ
z1+s-V9<d+*1@^ka5U##Ok?3vAOL9@V)YaD+_M8@W$t5c1B4qbFMPjHOKr!>NRL!h*
z1@K-xuoR$8B@H77YJOocz6sq$G8%11y<x}W-|g2@ED}kOng~i=8-R?7Z|6=&B@q;~
zCm}syR5;%#<NWGnP~dTT@l~jDl!IHR<8&=TlNOtFErwX?dS$`<Kx`bfke^J9AZ~&d
z)j~<C#aR{kSgITu2^L-+l$N4V&b{_;=*|J{+jVwLPnDHefwm&IJHb3D&0_|^0TeeP
zPvQCz*mG=Hs<iT&+1jnIQH4&UnIaEA6Ks7PZOi{cxa3#qNzSUFn~EK7C)&sTBPZZw
zpV9WtHiLaui0d)0YpNWGRoDR^m!j@U?e6&r-JA@#d`e4eEfN_r|M?{H*r(wL2~*hS
zJtv2}_IVbWg2zMRU$Zia-nZ#8HU4$gmSrvAaH-QfUhyF_od%nI?BH=-c;UGp|HnD{
zy=G?0{IV;>76RC3NdY&M*87_vpJ&H1kNT{UkI&5!sBL`yYdHG4_QQ*O;bgBf=IU8^
zblY2SsqX4cITg~=3~Pxlpx{5Pr)4$WVzu?ImbZwPAoSTwSUC)felhR)lBqSukI>n8
z9(n_Lv-H`Y#;sy<eyoB}@7J4;wdw%V9Q+2s&6%z3iFU79b<nKint_f2b<S?1;Hy$K
zq!Y3kEmxq%!@qr*DSSUpARu>9;yN|b=@aq#uqbxC^h=0fRK#JId0g;z{8UjWO4xnv
zy40;P<<@!Jb358~^2PN}L+!`KO_6X6&GY|gb)gsCwc~}H<E>^wDy(fzWVjS=!?!%+
z%jkEogS?1d4quuBs|_}DzpX}>9kvh_sV8JUo0HI*TVGZTx(W9fZ4mz_w%+kN!cYW=
zV^-4F8)Q-xRV)JWfGLj<kEYm8xSZ2CT4o(Y>_}pP3g9f-_CN<jBY(#yLfJVV-l(Ok
zGFdrMIdQm1Mu}L+qb@UK|8V?(N3Q=0my|n9GP1%clDPdD(V(&%rTsUy^bmgW3$lz<
zZ4ovqgWU~n#z&}bih_|v;eRp`GD~Ob1Ry-8Xw|imN;aS7#lR)^-i(T5rj1#Pc%`Fk
zQfhJFr~A!03GOmwA|)8XSJJzla~u7O@tn%l*98V-kU^rqGO%v#e$U_!-%Ho&`J>#q
z?7u)21W1vp4(kLJRJ21n%)Yxqq9Dr_9N1I1j{D@T1vcU1;9Z~Pn@Rd!P~BPSw~UDY
ze;0tg@yvBgjD$?A5aN7J0CHM)R-|bCoizO1T&<&dT}A66;=RX0JB8ZVVc*pPQsr5+
zZv4;2=fcR$miHX&%J0_+d(d5x&rR}af_BHYjyoU5pSn|~@>@83<8GK3b?UA<Hk#>A
zwccydu-b}9cX=Ewk3MmH;+gs0t!ZojGSRs@=$XzQn;hD4v7&>imD%RyK3&GT{%};-
zpcCxc_IiZwadK}rR113^EwTIxNv@ILl5p^jYH(CqI<2!_@3pkK96}bpJQ$fcZ}^=_
zF@>?<v%jjvsPz8M=k#k@zN7fzb(*dh3^fDR<yn$!9lS}~aes4H>d3s4s#33{_5}<V
z=$i8K8Lu{Ta?+@u-dVx-GYXwQ%|&LO)0zn#f+O+qj1L;nohC)LSe~Hf_h-8f|5Y0#
zTaEsmiqPerm^C%ZqtI~4|AN+kqlJ$BMx6R1K~Yvc?g4JQ9#6kph21t1`c%~sFqAX2
zdDP79GE6P+HPJWjx3)0kG9+dh8ozs#0YYt$jM~E9iV~-CjWskDns%jQsHp2jMB_3l
zHL<Be^Qq`Z{U+ZP2l+5_1A+8fbU37`%!$;voN9P;Aq-;FL_#jB43^JE>pdSuT8hEe
z1%n~N?6{7xjeu?98$S^9hrVR9g0sdcKLPp!y_%;14WVOnGi&Zxy4jp=-EJ3lG@7j;
zA>?$Lj*FoQ?}v)ghCjnp5A~T~o7Xc9#b(F3?T6@la$)}v8XM^2g!h>z?0F(8zQEQy
zhYuD#F|lMg%mws#oT|J`f;APq*vqZnm3Z2uHy?Lnwm;unD`K@$xX$pnQV9P|oW^jp
z|7|jCn$&JTCRv((vFHd@%oO8tuFahgfChm_^%VsNJkMLsxcZ)tj0oA%#{_r(wodZ%
zuJRt&kkPi^{QV*V6Ik9A?IZmJ?G2+d25!ah&$g0OSw5vPze~B5{9P8JX<rm#ar8Bs
z586YLncg_}ts7J(o-Yo3-H*oPzuGGAcpU7H$Fp@P;QI-Ij6d(|S>mo_0&u5NzrLO<
zSbE*#HnwxP&Vy(^AM%Q%KOSIbzVw7O>NZbNIkw8!OC49-^V^S4iRhho<f>C@-z?UP
z>~pec#`iRX+6Q2}ll!hZBZwKD1!yTD3v16?LJFQofx7eGHAqbI-2%DqSDs(DZC^)T
zXx-w`34~lOU1zx=ZFjdb(XIAtt<m54Kk4+|Rp2wbU9>2^dK~L?v@hFu3i`}1z<fp;
zMR4k2`!Czb1Et{}6W*2s=r$`?B`*b)-epZUJ8APxFBkYjAA}upe-8??-BH%3!ri%Q
zzB6IN;z&ns9{v@F1Ngf*5UC+Ys<c_<?@>#PyY;JmH$L4?fhoEuSqf$0>jv7yB|gTq
zHySLtePafC?tIt0e|xKe`S2h-qNrD|9Zs+u$}sGV*9*nI`t-P#+bS&R{LDk4#jLlI
zVjpiD=6^P&J5t%UJgj5O>dcJlxa}vUSXwHzD}H1g<8J|qef%u`J1=By87{HH-TOtc
z{WCNwbItBazER|M`MI~gkAH92uXlzvVB?|gQq|PD?bIMxkX~d~$Y4td(z(}_3BDbO
zW^sFpY^)Ug!CZmZuO`|XhJSeIT_Du@RH*lIctlIlk@kYo;kDnc+Q$gOiv%wI*q#A{
zuhAVFlUur9?_Y10(s{Ts4%d7fj(0gjLiE}U7W_N=K_KXNuk$%eobpGJeO<?kv)0sD
z;(fjAdn4KyfKW!p!CYp!N6)StsO~tjv&k#SVp;+6)a2Q5f2C0&d=1uHb6ikcvkkUb
zHcfiDY?8l!xRC=cLl<Z6I$kYQTpT{Ev@_izH+%wBTOVpSzVj53%2l0TIvNzwy*+Bn
z;7&g1Fp65~|0A^3pLDOChKF13JWEXreu>DPe=HWhe1yDOCGkU6&Xd1}h8#>%bTmy-
zP0MN*aYwgpO&4~!b+x4FKW*$cEFLFhoQ^MDPLHv=U-Tl73*IiBj;|f60D;Tf;f>^v
z273~qy1(SC6pgRU%2|&?k@`^Fv^VoUL73Oc2)zMn#W#rTYzcLE&0`E4aE!L>U47Aq
z4QqK_G1vai<l5dLGu5@*`~-RUb9u_HxU`{a=5-!G7L{9>;TWEB!sm0%skm-1e=pqZ
ztMFqc{0wqjo^gJ~4Oui?MzhqfJ*2(w^vQ=tJuQ|)b-|O3BBmWxYn_)1W9mG65Dba=
z?Uc8Dy3KVt;^?Co_{?|am>(Gt7;un_<CPJIkF=!15P-RuW&6L-`h2B@!R{dGlV0EO
z5>LP%K09wTaYaL_R3Te?u=9;clJ_=k=hND*NYm!pqa)qC&<3XLRq8W)AC|~G87{v2
zqVm_maa#Ip2l<Hly>aODJ5P`XYIfnrBQ15R(;S#M+NLR9YSRgAKgi}H>pnK*qzvo6
zhKgrp{1e4Zo&898?Rt>en#aAYZRdSv9|hG}*+U?8gYZ4CfphT@EUU%X9=7!;OE{i#
zKdZ|s1iewDaHIbnCcii0q8M-t<FL(5q@8f*ZQG`Rxz5{^zMkc~Mz4GI%z<^U`cm*K
zKxEXsw;iM?*izVtDjvrq@2ATUvE)UrQ|=4HUEOz8!2+gZZfAW|+6ko4czafK3gN?<
z%FG+6VkL!p-x`=7TLZiSBIgl(pb5{-v2z;j1)V?dqSKBFUlJl$4(LTk3WPx?QrhAk
zu=#ZxzUeGeNIjkDcRD?#Q^5L{YJX3Z^f&snZ<0}ToG&sLnEu%r{X05g!VaavJ~WB8
z4Ey`$DDfF8=D%@&`&`vYp#FBw^1U9NiqSNmZzl>5Ib9<M;~j>-Z+ubrdvaJWO3Nze
zWo@Ww{YPB;zl>fpj2z+t+^sI^v5^GwePN`pJ^ciCI7zAG?pXQs=41E+wrx)dq1%#$
zR&BzAS0q%q)K92}^)Yfhit1FkiJ}RwvjBHOnDw0>?|yp{@nMM8OrdSnltZcYBDalU
zzNc5d=l4l&8X_ScBB6%Yn7?ho7g>=SWph6#I+}Nm{59N<$(D`t?R5>n)>DENUW?HM
zc<86^RmwD)Xme?9e}8fTUj`thE?&>kdeH4?r&mOLhvF?QxJ`Gc6Lrqr+d#s8W^;Dg
zQ({MAgru2?{P8Y5U9PK^8qe(ljac8Mr}5<eEc!FoxL}SM!<eT}3jX6)i8ESU2auW-
z=QcKcQ(0o1a;W)o2UsMosI!1BSWaxRj(Bz^HL;V{&(MU*?@<#yaYaIUfQ#(om?>Hi
zniKVhKcL*ssJ{RglZxvs$_d}lOl{CoW}0ZiCVv$pY1(M==~al_beWBDlE~G(WZgR2
z=6l+fSY#^AD!1FyzREGJGBrO|Zb3>M5tAck9J(C~j2avNqV9|f(ca7-Ns?R53I`>|
zKRDj*5C(Q8)G5hI6y1N36_kFQjYUF=hB)LN#z5LSmx8~F2z`Co*R9W!S-HRScHavN
zHP1GjPm`-PBv3)=1ICDVvgG}sG(<<CS>6f^bOhIKQ>P<msMu+Eemu)F0$2yV9Hw``
zUjTb^CDipX?`!|U>-LNq-?vl^arALsafVb{Y=tAGrNg=<OM>KN)GSLfkCe`>RVAbG
z^}ZCSiZ-|7CYA(R2_k2g(DPvUPxdO$bN)U_KBSvWgj<#~ZXi*4pTLYUcuqe!i)@4b
z)$;vm>tNH3GfoE|0BY#8)peRmck+A8!yRO?&;I23AGRacrzw(5y1@vcS<4kkf1;2Z
z`kEebG+iZwVG9Bc(}q$el0(D9sNbxnQ~~%^JON`xXpMonrJ|*&IAOds&3b{3zwu3N
zaV(g`waXqg`r?OiT)yiQ?<CSIY{vX8Lq31oPEKE@PLjb6@<uKfNDayOle>P39(vIG
z@hjL$lA~L@hzfnkFHngo4=XNEr69Pk9PbeA`ycPmbUL`kd~=)%{o40<=(`VUCuLP;
z_34+5Iz;F|fn~_JJizQEU3Z_(L`19eo3g?s4t2%t8H>FqdpDNXP8_<3_^iH89E?V~
znJ8}Gv2v95`qLU_K^biq|NAmwB@Y`vl`@edbGg{YEJtfwu9{DvE`v$!RIeTt(_Y)p
zrpy1`MSM4uGhEBZ@Uq_!{AkSUe$nSk5_#~Rv<V+$)kn6)QK)$d2bBPiL)M$ZZ*&K#
zRgBYfg(>AD(Jj_{8iRS2`=c(ao-A;mByr3>nX+8<Ua2(0qxn~!g-@{l1hK8}TP5FA
zLYoRkO;+CrDqjVY?g@Io!0so&OEc(gc9aJYst#@)+XidN4=C;N9I?hKe)%{mXvH9T
zR!3R!)IR&bOq~oY1@1tjuXvVf`+A8>#pgNHtG6e*;&^HQ5!N2ZQa4Prb3dS7pK~F4
zHWrsP*Q%lk5qJBD$tiEmZ9_2)UB7Bo*Ep%&*}I%f@96&gEl}T%P{1oD(f;0pNQ{|F
zA<&#zZMcn{?ZYn)bD=Sd$pmngCMn3Qw)Y*j35#<K0rLEf!<!Wqq7LeB0y-7NB#^13
zV}z>&nCZiuf>xw`mmEnJx6oV5Kj<|2GUukth)Fm4PV11nIUhE3DtyzHHre>O0wZ`v
z=j`YLjg~d#zo}tDA#^u_L)yJMIdp8CP!bmnnEiGDM|zsgl<*r~d|8+T>_@+A?pOCg
zN&waHqp_@2K}Ty?ZiFBsiOI=IR^C{H;S%@r66gNY)YK)uY96r@mq-V#J|Bl?hrZbU
z_#sgFTZA#0G1rqLqFB0y%ptD=$CAh87|*(?r^!loS3#$!1hNf=U&`)gt0Ej+tn$yT
z<t9X_aD;PXdV8e;o$e5n2_8$aAHBYfJcbUB|GDgO&KGW&vN7PQjbIqPCYq6XH;Nhd
z`j3BaBHJrl={h!?9PW}U`(ZoupV|Gf3tirryC9OI8nH=C#8Mr{U?H*Aj}v7oDA3W^
zEGec2l7Dv0p0;rqi`c+9B&f^&!VQqevV178F5sNFbCSbt>MeigVg#2iQD|<7Wi;sh
z)z|h!2s<m+J+&)e^h5wNWDEQIPZmFop2hV3^G3~&RDLSAixEq^vtstf%;<|P??zoR
z!cKg#KiV*L+f5@98OI=yzCRURl(dWICP{)jD;{$q2brx!Pm#DNHR^PKRK#)_H!vhO
z>Nf{nFFVexjIqHbI*>f%ehe7t(RMow64f>l1wAF7`h9M}+uJ*_L+bp}&42(b72m3#
z4Z;YlyQks2{L^G2fLCL#Nno68d`^8JMA1TEWgE9{suRQdesNt=JiouTR26Qbs6T8|
zKXb|chlarg@;kSwKQ<wwj;k>O;0{)l8$=a@|18}%PXtpagF9fq;vf6NDJV<{aS_)S
z1C4ceiKo=j;pNXrgP3q`504SZw(dJ065q)Rtom}8BP$RmM~~&Jylrx<;N2~Ek2}WD
zV??ZoVrdn&o6#pvBVe3JUc_l?HTr4<m1T$M6<fnZt%m(MbUL*geIa$+vP?vc?<|vk
zEo5)V_g1AXG}e8g{L33JoYcgC&B<uvXye~+ELKgEr8zQ(2AZCeqPpo<KAY=uDf%iz
z>wBM_M{~g}y(;~~&zn|E92aD*ddxP+wPUf;ua1~ZQIeFP6Z3Vc?pY5(5$k~^%uoy~
z3G;Q#>}N4hEGA6%lLA>n%kVXrO#&ZZ`kmh=q7+f$y0p4t^PR2!K3_|wmBIX8F+=iP
zvy9w#$Sx-a=8f1g6RK4oaj+wQR9*e5U46eS`ecJ3fWiLP`p0+p`FYj;4@fff2r?qu
zDZ{^1Aj-?UoB?EL9|!&NXxJJJe)`p{Z*<&JyH1d{;xZ4axKl@831Hwv?kol#Mj?QU
zC3mUMyiiZl>=be78p$iIZ(8}X<p)#262>(9Zj3j5h@c?A1w&~Y;KEjT#?Q2Ow5Tj-
z=%GSZ|9Gv~)!=srX$2QAsnrtPaMo_#K4XI@sgmS`cm^MU2MXY&#rUHEG0D{ATe_ux
zK>u%9y-;c1T6EMGFJpWX2~UnGIgdPPkY2<08hOz^WYnV+-j>SOnFKWaD+k3{057NV
zZ>iY$lV6kdTW{$7Rcg9Y*2@bk7uWEU{d&XaNckJe<YKQzHc<UWRXb3_w8q@fxxE?4
z&&paK6Pg&vA+XN&K}JKtq29<|TTWTB{9Jr?Hh(0?1(c$4!K@G33Tfm#%4c6TO+v+t
zU$tWS2z(GX!8lZ_ff-AY9yx28QnuW{&dkryl0T}-6?%d&3>==%x||YoszniLuhvwo
zcpwnPO)%KULgCAok1}Nr2Nr(NvzF~7a8qTr-@p8YA5whgmFX_a))OL~T){G}ACJl%
z4(KP(DmLCQ=S!_N<Ui>Dml;9l?d|QjKVJTgL04B-MTU??MVC+<g%YH%4~Ys+f7`Bx
zHeGNGXZ=9#OOQpwQ2s~l7JFh>X*6PDO2_q&f{jBedW#VYd8r1F{`Lw77ev21aKAv}
zfFkzq?E@HXpI;Ks13l|sM#Ha7xpu8H>8p06lu~$6x_^Ll5Ei0}O#U~bpcHJ5B*Ed_
z*+uw}f5ce`Q>i~n%NycU-iyT$mbZ~rvi?633@Q{q0Lr{R_=Vl5pVW2Lo>}?5M9r`4
z|4E1fS^9nCUA6Q7$g^mYq|38p9M4$U#*zIY&XXgN?HFl<_<!VIQ2jQFa-%*!Z1@){
zW(wPH^`4!bz0s|LVJ`wFRsJdx0_%h;_x(KT@88-YN{bb=8OghzjKMmO=<Lh%ui-%y
z21G~2$SIycu5>Genl4v?o4dOs|BQ@`g6q5ZPg0*N*g~D2FPsS4+uIN2IL}L`oQ4z3
zHg479K(_^!ty537n;H-$7h&gGo1B=Gi7&ak7DLwvaByFwn){+d7t{6+Na98tce>~^
z%NXTy1by6Eic$_~<9@QFbL?6iycdY1tTym@S)ji5WO5vW8<~mQM}~vbR(#Bl9&tnG
z6KVdf8RAFdSxR>eWSKE1k7d2Vp8saO{K$^-7&Z6?WfP=pzOnaZnq1(hmCds;Oi{Rk
zr*#qYf@M9Z>8xj-4A^evf9FUi&|cblB6f3$EYL42;+Ua_weL^a%uOF$Pdd44-;%<^
ziRQW){yJvxZ&N@Nqe>q0eff&VyK*?MxU6~vmP-zk<F(x?v(=b>ASB>g`1DhtK-C7A
z?&SVmD4`C~{q|7Ba<;;lA-PRJrZAIEamZm0KR5JBbyMR{lvYPc8jWrSfw0J10uRF?
z?{2Kg1kHp_SMMKpWkp5B?iK#)z#>+9n8HL}geMPKq4M7il5>uayFtU-Bt0er;#5DU
zg+3tVP_dFR=-RqNjL_*{!;l}I-^P;W-<kBu+lAzb%yZ-dGoV~Do55-Qf}Z<s;!r$X
z#z>aAR_=2(l7+I8VaMMX%~nJIsS+Ufj)S>D2SP9JUow>{njPifgw-jK`{%-oH=7=L
zBWqm#St=b*a~SP$p|7u>snT1P%>Uu<>+7rQy4KAwBW$*&>kyt9@ksmXL;*4OX<<@k
z5LKiEhG9Kx@qL{>ofvG+E!HBKZo0l4T<RM@D*X`ozL|K<d|y2G@>-Li!yc{+z~*}P
zy&N^USslH!UK<Q{9*XO@hk(JCp69IEb#7;EkG37R=Kz%TjO&KxAftAaZ>xby4r}mW
z7C%pkJ^tXeuOc0<2aVt9ZE!epmHo@5GePcjBN)3TNBb-0pWSzd&`1BP6lBhOAV3?A
zKR_`r`g7V*DLG?Xgp)eh*!<79t|rOhcc&ow<#Ru?(f(>bbR&B+M7U_~9h8`t8Q7EP
zTX~<^_8h6q!Ni=0wqE<LlUV+6o)@?3dE6al3SY#@%GS;VF_O7&6;G^tJ6fJ&{hLM3
zhsVdz%V@AyFZNe9N1_t84~Z%UMeAC1Me1*2>fi1(pP%cuI31!fMu2xFFv*-Y#01D)
zjv_U@_dCGPI)xhv-PpASijW_<yXq@dmaDxo_YX4nO<9(5Y#vr`&s!iKdyDx`5}VY)
zDQ-%lN?Y5fbE+QC^Y%uk!|ArtVJ1B#D)jeN1swlC%Yg|F3%V|Pw(YkC3h5<ZUXMFp
zE$iphSAP7BrZEhAU+(_uAQ_p2^AGF)_dSVK)oH_uLNcE+n3UIM_2F`x(}>4-($Uyg
z>a4RjlICAd+^@T=gr_^#ipg{o+239pu0X2Xurf0I>yIAZw!UeHC~E(>oZxo_um?FI
zCMRwUOm@21R;t|>U*5{I9O;%qe`w$4H}WzNIS}Rl#j{RM;D20a*7COt_|FTlc_<18
zCp9BVE6%mU_M{5Hs99is*mqQfZDl7pf7qv8H0TGD`Sj3hHvW@B<n`=~p7-JEGxqCk
zB^Y{4u<CS+k12Q$ra@&y##pmCbvET{vUy7jVDvLLGWo#rug+)xHCKptZX}PkPayuy
zz}qTWZ8T7ji)t|1c;SCVPvkI2WQ_8La{|Z|&ve}Ea-^fYwji1O7GYTwW2ZrTe)lhD
z4~|H@hs{Z4W34azr7t>OS(On3kL3DK3W{G|)!&c*7UW5GHcrlC@3`bdw6zN9Y{Ps_
z>McwE@%b#mO3&nD=9o+0@CcTFX_r5Wrl3@BmhomNhWX#*p=doy$PQi-?`l(O0LtSL
z`$O=XP|};Ah?sxiE-a3>mECpS-R$|{Qbh*%J1%*5v3kv*D7g;7H&Nxh6ZRT_Pjes}
za7&=noDs0P8&TKTb=rWJ7XMZm?w6R^+t7O+WC!oDChL=0_n_ex$frq~e*a-*E~YE1
zHyH}3i~n`wAW3BZPXiz5-yF@=QEBD++#Gejldm|6>0M+emN?4P!opWQ0TJ!-qRE%c
zR<*b_ZL#xMsw%aAR>by<B@On4D$+cz!_y}xYaV2y#|=lR{}V4743Jt(LCI(ZWagB|
z;e3Ys^1t-Q&A`U3U#};x@$&7cVMBTUkZe|1pmn~0r=2L~7~=7FC~scm%}*Ny5hQ#+
zWUIs#qcVP%i~CQ@L^de4gV~(hNd8FSL8L84ra;5N|HTV#lmX=U0FHUC;hZ1*x#mko
zI7}P=*UOP)h(+(w^YHIXT9*K%vIzf2<8x3SDWeD&By%{R?TJwPzwHVJpc%he;j#pK
zaE?NNIj&^omz>7Nq!14e51fH7;Vh`mk_Mmp@bzXk8z=eoJ<K@DC?w#zLVER2o6g|;
z+lC^<Wzh0a0#E{CfV=(&RMRphF}37wXhOe#=Pf;Qc|^NkuIOsW=V5Zc<&4thac?~V
zVt_I7qadtmZ=&NTQf&oC`3f<g|5(xQ1jf1;-4QL{dUn7UkfKeLmb(a|6$gyjplIW<
znXuU5{RKxp_5a7Y%KLnJAxoI2|2<<%^{}hXuUH2&rST7)sNRmB!k;!TPI`sfre~A4
ztLK>-w$3B*#3E!0w<Q%*gS+@Yi67zh;o*M7#EK)%dnKiW#;k<`Lh=%P6MV5$(C8(U
z6!9L$?PS{3W;PG+jkZn?S?K#GiXL8$&C>U)7kpofTXq!*xjDT>(m6PantY~r5^MQ6
zW`>?6J!<Lb6vf(i6R9|T^xVXR%zRkgZ&%IvaqrUzg}ct*tooA#mc@VMQg8AQzy>*Z
z&FLt<XTl+;knaiAKIr#%cYDOqZRoeu@|`Tl+DlGPA9vNf^xgS?D|X8LG&w2^b!Z4^
zYYQq7M4FvbLvY7Hj(gK*9VR7Rt^uTXYe4J=8LFIzjQE-YVy93-6(Ukl_JC!U0NN+V
z$T%qotKLwObGLWC1<+e0sqKQ}c2bES**A(oaqT?cONh5S1|kgiBSqpZ7c-5*BORsr
zy^yO8HT@`;1f{eLr9^rl`k(uzjj`jc5C3U9>z`fS)qh1FUb3|KIxn9<i(NRyh2FEG
zJaIUiS~{`$@QeT#BqVMdE~=867#T+LXn5=h##K)$dBrS|CAeqJ=yclr<F2@NTd9%Z
zxs}+=5=ZXYG#@r{?tXy!=3i=IKd;loJ_hbf*d$1zZ)aW!0B|Cg1>@EGOJh@fo=Qeb
z%(-TMCvm3#(Bq$JrZP8ZH|b|Zxt}nliEDzifj$j4hW^v_@XW#juj|>WO#bxSq&Ar?
zArxn;4RL-#|6ho#5S;!LoL1>>GTu5x4+N$*&(9_<q*kx~ByovM(>x^CKO`q~ibR!+
z{wNtemWTxQv?hPsWf#ZdEU(^r5E6Fosda@2O5wBB(6KdU1!iTugZnRW&$ydRq;s#H
zKfGPF7nD}UzWbNICd&?4B5Ix)%TK_GJ=Z`yn#^xs7{kOulBLKD4(<XQ)Kj7V&2<WX
zn9PB06ld7jMU7_bb31kx3!Ab(!VxhX9H~lJ*uFM^8ShhisOU~8oI#^Z4dvgKN+-Aa
z|AI9vbl?SHeIK4<={QM)Yx<27A~4@(SOE8dJ^kc{9HLmB>lc(9>V!xJJKNJ6yAlJj
zM`Z_-9%S*gwyU6W-xe-yUH`{+OtzPI+K@I#CB<3hPcC7&tQo8xCNnCDo65`Gh!8YF
zu_He1=@Of4>mr?upeyZyWdnrHCG0ZP)bX5bZEH0oc(~7qV58lZw>6CI3r1+js)OW^
zxqEE`-3USoza^t%uiKZy4*{clZd>x&q-PU$jQSaES4nM^eosSC&6q*B&ZMoI>*-Os
z!t9&tt%aA4t6|kE&q5Ei1@oP&2}R;Zl`G1V(^G4yDxOaiaFhH}o1={@pR&!Z#JU|M
zO?eS1bF7K!!OcYX!?JC+R}uQ;WBJ<xoU&W%PN>^SQYCzC3p%Tf#_lpd;UQKJ^n?qF
zwyT$Ep4a72z0};S>FLJ;dOF4Rdo`uF(FgZUpAIBNg|+>LDF>P}URJ@&_B>ogh}7pw
z-(F-mOq=cXw*evi_rCy6pMXaKfR{oyc(F5#FdKan1>JK!(L)}PZ~cL_@z|q!zG_!Y
z+sK>Hl6}0Pwij|+8@<O?My*VtMaOJ%XJ<9pj1`(1g#jmO>F0o%L#}^4^L<<44c00G
zR#Q-X*+>|V-(vC>q|kYlEpFutzxhI$j&2h9!Yq3pD&yaUZ8Sx)=(e@b_gjr$1+p^)
zN(6n_uRtXA<$v6V2%cH4xMZp^7%ARJDN%&p1B6GbE`_jfo`zf~P1d57%+Mt;7fhME
zT=|v8NAl%9p8{ARz6phasenpBq~FC0)BmTGCy$5f?S96-ZzEgDzAp(8*^RPOq7V^d
zNtQy$(pa)Z$T}E|y|TqvlP$`cWh%SL7Q+`qWaoFU-uI8+=l9q9{^p;1?{m&`o^zgi
zp7WgL&I6Z@X`V<4aqCNt#<^sY&&Dj(2^E^TRj5(gzP+BS?Lq>HggWt%;q%y)=&RY)
zbABJtdiKZv(EldEWn>f5Uq<@M)yE{Fx%*_ix%m0MPj7NatMjj0pU)@xle4G4RdgP*
z(Db+MCEqbSx-3`7dwlVqM$_dN;<|#5TLWU`cbijBZDqxN9~QAB=xYzEL+pOa*Y9l}
zw>H_Ye+Y(Or&-p0XUyF?x3YSrN~Ght?ep3AfDLB3K=RC{ql~p(b&5d#tFl+<ImTJL
zxgZc138UVyNso*YM5vk$T&qkOF@?QgnTU(AbK>vT&{yTrjMXanR2}6eUOR-MQ_ht|
z-v?Y8rHp;biIl8UMKxF`D&4|uK>^PDAm8+jMfy_?(!i?zu*!=NnK-J{m3NUjBB9-K
z>#o&^_CN!-gywCYqJH0gNiuiU;4U_{vjYXze&K1;RJKMg@INso5$lSDeg4%om_{Ca
zJWG3OrEB;oie0n|cPDdbYYyDd^MWP)Jqg~PQa-CZtF_dJ2X}g2=GJ>aqxj^Q<>az3
zQDs|b1^^GTtioDztBlo6Gml-%srSnAxHg03>2LYa{G+qeBZe?lBkqAtPPfQE(L|Tp
zQR>X|RUPEjBFKQQZM=Ezjr?p+X&m0mcBAsT5A@~gkTD%3384D{Q9g$-YJ5UU@muQI
zdJ}nX0CoOt-ZOW2HbP<gk-M@tngMywQlnr0G=1%A_>Z)|Lf*Ix1K5!Ye6KpV%Vzp5
z-1N>pkXRmU^E%hVa9foqUguQpEYk;SppcMA=DJ-C(FZ-xcEb3>bFRTOcexY4lVv1;
zFuEJqD<UjqDNOnP%=uHsWa!v1;j=zcA(OVL#N(xBv@Ds(@i-^Rna~i9P;Mdsl%&mg
zOb-0No}Z8Q8uJqiB}ZW81wQm2zxmHIfOR|0sQ5voO0K5I!jU<H*a(>i**r1-E{yI{
zFetG+R74n-S<B#U^laTiuUN6;VOVo5OYog$&&c3{tXH^fJ!xZg=5-R>N5HluzXD?t
zAGKIL8o8CkXmk68BfcnGeCXC^wmrv*LoD3ooGP2X<*`pg4gSPDM3;YaZmWK$1?YoR
zU^e0<K7-MSj*0i&$0A3jsZeVtbyfpSF$H2E(Y>laY)o?0io`0^V%$+Ed4Eb8yQ-=x
zkc9w#F_C+18+^&lGvHAtkcE!U&e$C?vJ$!{1)~IbRXBb5E}wBu(vK&6+~w2WB(VJ-
z^g!GPxvo4B8F(m2Z|8uJ8yg~!_IkcypFHVbKZ+#cOcHGS`xQMC3o2Py*crl}g8m@|
z{nE}IkKxdcy+#LGErbYf136u^Sl^8E#S+ej#(}<fyaWAa0h_DWBSA-3=7PNwre23h
z>s&=hc55%jSMF-?@KgtRKn?UPGVmBPHoe_{i>g8nn`hUJc?|Ra&73LD^w;x^sIvWi
zckKA}T~@gCy~RWU5zYKd`8RnqC=cjHBreby&!HT+ryfV$W>~~`P+bhX+-B{zwwqB;
zHyT|Q0MW3%e37JP2+2F#nW+7IQ0UsH%V@*>&<IkVCu2{Pouv_!77X-B`<xxr0#clZ
zBOUq%A}_`pAxPmN;i-6etO1{5^WNhp8=X#vOlhuMT*RyQT<WvASRxIyn?>B-1M#hB
zWK7IX^_M0IOn2c@cUX#WX}zZ0%|rBT0Kqv@<dLE6QRu>?=-PUKSOul~&0fLOJL>Vp
z_^I90B^6Kk`>pOaL4BylTP%;iEMCKKy`_A+8>9v7=3F|AV$ovZN8L*2B?2>%Q*B{d
zu0L(l-JkgWD!QNTIlYHieqV?iln_CbW4@Ud$NzA)J@R?grFZU|iLIRzO?=3GY3|lK
zYybP@9p?%b?wAo(oz(6aspLW+rby4W9U`)0KW0%_^i~Wx)6sRqYcnogg!=D-@+tl%
zgzEu)H5FO66GlI~E1?LZ?t67&c>8uQNjZq!UVCT17S;2x2T&brp`;S(*sd3!J$JEs
zoC`(xmSXdXP?ZcUvBl@s+Pl*JZAwhfHR9n4Cry12ZqWQN<URzM6gwl{V@6>#2+wQC
z%`@e^nj4TM>4MtEg&Zced$j_gl_Hld%WgzUeV(?^As2ZjU|~fcow_;metUfKvV8E^
z=&sG%1NBmA%c)lXlaUwRzf^rk%}mrbQ*%#*G7Gxl@Z4$FX}Lk=!|@NE#ViF!ES?o%
zW{W)rg?Tb41`77p!cVQ3Jt2wq1XJN=!=ft(Mc<4>9=D<vAI%wD^49CwP?SsRe6g5Y
z|9Vg_|Dx>6h1|E+jNp6JhC!<ONB)nWxa>iq4hLhudYpZUZP2iedh;$hKTBAIl1@6$
z`yF99MH`P=`VXIt%6t+keG+J!K9d!Ep(ywQe3*mtJfIy9e!bm(`C8?YBNW1Id>AL%
z56rQyixu0w=Yzj*Q2~Uu+ZS(msLI`7TaXSh9L}d)EEXXdf?_)_nF}A=8ZwhX=xEEh
z*|nBuq4{2B5&4U8DMs(SGzB5b(ND7;>OvuH#IS<zaoeTZuV1jKdMXJ#F=PD4<wZtc
zp3wA+0J6Wu>-2Vy+D_<#ZE;|W5Vr1!@T5ZtFfeP#n4RlXO<5TKhxY4+WU}l_kD@f-
z@sdrq)STR0SI4&IX8m2Qtf>R8V}p05CbpJRn}3%82C|L#$=W9`gWvLJovwJ}-s6(X
zE)>Ez+d6aV_-~O{Qh=q7y-+i!(byj5Tc`g}7bdT~S$VV9ki%e*O=9D=XKHfuw5nu)
zZ<ezW?TX0pWzRo0(_4k}>C`5;@GGZKNS-hJB@Zo|<Th`3*xr60XJdHjdCWgKRBJdg
z!uGLOFAG#Pt;url@~Xn!;PE7dqQwo>$|E4AaYhmptr$_8a;tKc*?={gfIqk|P@Hd*
z^io)qWwI;b4NgR?u5)e5l)v0uU3*!<^Zthm!2q*E%wq_8)*3<0fwdSWUpO5lg~u2d
zxB8eBm-uOwSB;`gu7K|tuub}q7&Zy;rH2`ly=r3AZ=lJBx+EJ(C5Oz6|4DsYn{sKX
zZSkc6#t5x8Fsvj5g&>*3J-;;CW~rO7rHqhK%UKM)#It<LMulie?>WQ58CQhYN5mX_
zVCcmdGn4?MYyxfX{pz-^MNj2pdHU2=!+@<wZh0FmKoFE*iY9bCkY8o9bH3zgIVnQ;
zs>kTgpxR+}vnum5GvoOmE%-^a8h|;}BVRAl@q+!H|Jw8*$}9NQa_^wW2ZB=;Vm-#x
zSxMl=v~2`ioqm*HFo0|a9~nvs1@cIxv*VO&3f~jKomc}Wlk`-QwNor3rY)w3Hi$)=
zW`(V2cuyd;(-f)sRbCGNdL~^{Vn6XVaN<<l?J0i}DGIEtXml<vrVZ7{Db#b`?rLI2
zIpXL11?!BEXa1c(hhF#cU@I9P0>rHho+%ZO05yX*tWn(DMbtscy<5Jw?Ewguv_ANO
z%}RGzMhV80TQF#NEh{dsr>{HM(1h1;aJjEpAt~f>3t>Ae4|DiX9$ox<-~$lyc<)%;
zI|b>&9h;9UB2;4iOt+;g6c2_Jo7~ZP8FlNZ{idlv$&e$T-k1zR&o*km7<Wlpy(rDg
zWxFL7XHsIO;q-obF+fkKgLZ46Y_R#jq!7^WJVZk<oqoT*=$K|wDOPxBdrT+bje7;b
z&~5Zy%f}g#=j1UWvf?QJU$x{yk7k3fa5V<AjygA;fQnD+#G>UV#G17YBzm|;$ilU0
z>1{jS{Itfm*PC-c=(g6KJ}~?SB*Kw@=ETBDX#T)mGBj(-0z&qhgJ7H1sh%Hjo=s}j
z<`)5}1QH$`=6nP)kqPP{TZ}xyv5hpwWA2~FmomB%U^d;X_4WZg$9qPJDBYf*zLd^{
zZ0Fas(ysYL@{-t%cNobL7Cw`Q3-rQ7TGJMNxz(DO1Hb{$7?2JLYA0vE=e^{;fELK#
z;HjB*QhLe5-W%q>8+wVhjfz4T*q4+Oe{_@Zv*c^AEeyh!3;D?HhP;fP`e*}dzq@d#
zCEe;PmE^THJ%GtRS-_vZ{)GnX_(-!yQZ}$`(s?cRx4YX9A+d@eAAl6ZD`onwQZi6X
zdHt&}2q@bX2Q9EY>;Ap9c0qfxqxZ%jpmlMNxQJ|Yxc3wRYYus0l^mv?fG;s8CPCZl
z683bLH6<5$he=(vu!7L|0<mQTWcu-`daZ{31@b8&upOYPlLr%RHDO8p2QFGko!#2B
zDAm`z4VzU92t65>ts6+NRKzzERZ4Vv4&R=iAw$*YrvIy(w&=!2<%X0?=|<jk$S=N4
zhk6CvOxZ`sh~@SeJu{2K)l1Fh*lXZg(bm$-)qE);S~r<U*MiyNK9L%xRJ9C*I?kl$
zx@vJcM%KqZEdfkwo`cv5{HIeC=gKc9vvh`s2W!&K1$&E+zYvTg(j-#*WmyaHu4gRM
zA^M-4%zaT*Nom-Nn0CreZWYn8wVMXFvCfTCX$4n8ewvu!^mbo_;!UOa$Wf{1b8ls5
z19V=1c{>VJF}r$;a?9R(-h-3(lZwqE9ZR16qBnW(vjNOP>||V1C3*9C7W%@VQqG`<
zk4z#1b|2tJS3U)^Fa69$Cs_MuCn?>qb^7B@0Kp*z#E}PJ7`x&?1L5`rBx;+yfOit!
zt~l}|2<S<7BW*f9l@fo^;T8{o%HS;69TsYMum2w?X5{N>=OSX{5^*M-;O8Qb?|eZp
ziy=1a_ZhUtY_X1-DBlN&hkvf(d9rM%+rhd&OD$(sT;sqib=bcRYjn<B3w1=_VI<rt
zB2VPWDG^yIzF(~pFzZzTXsd|KKZy23ocQW@m-(x5_?ej*i_|YYDZhG?6S-X3b!?T+
z53mDhw4Bsvs<vUR@QLJFKW&(pqcR`OYi@tg$<B1@d`6pX^f39-L=hf-e@{c-Tp0gn
z+IN4eL6+4=na)WG5H7`DV<s$&&y~D{BEyFN_~HlVDu!KmN85Gs#YfZughL&7_W?l`
zlM?*AdvBskr*otkaH^W=Abn~{LpI@Tc7z3hj}?8)&V2^7v5iO`$WIq-ct-&kA40>?
zqs_nvrm&HbE{i!-QgL{#UcV?mr()t$ppiq~s!>GC;6Yt><d*yFP<I&fUU@HQh+U)v
z8ey25RvvEF`4O^9JPaz9Kr63NpQGl78z)Oexr)QDwg#M?5+c<#D|peNQ@1r+P(0_Q
zL;x%qjmTp|vgb<N_)O))%(_ffwqDtalW`wqU+a~Y@jn7fMah;<t%9iCEa@|Jue2`X
z2;pqv;w6IEy=@sebWR!K6+j2s?u<$%ABd-Xlv*449WWn5J#>f05l<6|r=#>db_Yg-
z_gu^a07S?D(lOLCE!%vx)@?#W5)Yxj`}iP)O?8GXh_FXaaD0`%J#QBCE99B3-D71G
z!gz{#@wP8&3+%b*S`FjFaqWl3P)WVFB`1v1i+N|GbZzY}k|*^E+6E;IoCB-DqCHg`
z@NPFW7@y_cj66=%#%2L;4rwvmtI8}(x|;J){>xT6qly^-w?pM40{I)5y-@Q|$`+zA
zEZw0NP+CYHpVf~T2q_r5()n4b*V!=%e?@%V#HD0wj3w7bfwNu}hnquDg%?mCg~ZN%
zeJL+(wQm44BM}j^iZDJi?=~#R0BK2AwO#3jt!1!S0HH8my~Z3_HLHeg1c9H>&;Z)r
z1VN65+OGzfFO#XjK|`mneQsV}0Lx^$Ljb>-RG!LTWCJN#ooRrSEd(OS@dv0q)BG_7
zAGSC`<d`X_vcYAmaS>dSFE*{ac_oWLU>u!Qoru=E2Mi3$n&9(D+>vnv_Cn}cKrHK8
zBuOkes{Q1fi)zWeiTcPgqRnuvHy)TL2pykPGCBFLfYOn{$vMsfdY}nunAS)g3sUJO
ztp+cUNQ4!e9V4i#ZO$6iydOC=b1>Wu(60t~MiV+=qJT47s!RunNCY(*Wd@;{Q$)KK
z%ZjRb+yK=8$$TA{iiwW|h{Bm%6Y$k^xrct*7wAD7nr9@5(`Epf`AG`uGBA(-vPowZ
z9zbi)j8_}vKL^U!n7?lIwMWIj<ci0mmOr=z?At8T;WL53WFEMTS^q36P;fvzReYL6
zY5YOa?BdZtCI(ok5Fdte{N2W2x^iI-wm;`v01bzb+5?i?2U>k^OypcA>9cOJD8k=U
z7NSL2{=$j~qbqqR`2j2q1D6I^yJbPdu^ZN#?^1|uLrsusnyiky-T`X-9NtqKElH4H
zEzZ5M-wO&nB0n!hOw|nilt<^jGdU_{cmp-q|Mc`{f-eB9lEhU>60P66B8Eya?z#3~
ze}DFqlzL+lCj|gym?o+{G@D*x8u#KO74-r4AVq~aS=1z-hY}3@HQsS7kCC(*sL5r|
zSx7NsFg`5k^~F9^OBH7Oy!i8i1wsOlOr>D5djzn73>`We3u|Y*q-K7hvCvs<@P`6>
zqoFJC#r?vf*ExWii_$08X%Y<qM2{};gr;_Emm$3cj&j&$0dDsHpI7wXzuf<}XB*XZ
zdDioPHJjpZaZFGEPRc;~_ddeRmh*p+jtkOPru%y^DI!d^7jo9~u0`p)e>X-yK>QcF
z`M<{ak5qo4m&EB}{}XWH?YhOb*fco7+dkH1ICw>3UP&T9fp>SGmTpKPWx?AtW_@4&
zf8mjESc6RvZA(i?6sUzVbFSUi5Cqs3=QtDtUjHM0{(DJoM>d^}=90k+eDI?iB~g@e
z%SeRwY@ySshw+X*opi@PKMf96LG-3@$~hV4svUR2Od`$-muXTRGC_N@Q3=W`r9j2H
z0z0CA-lJhwU!ok_#b&*ii9Bz@=J2<0d4nU;o@2&;J|0(WGznZrZTxJ?sXJsY=vD(q
zcw`O1KrT2QMMPb^?sc-iM5$SIa<IyH4`%uaP4xgd4o*^DKp5{(rpEKz`qX@XCfqJb
zG5a*|U|4hfAb-cO*9O0G!moUILn&Q#*@%hqOiefx1m%IVIruUHcyG1+yUDSagexNo
z+3Y3}GYAg6e7CSaLu*X@4pgX_+{zOx?h3YI(}WDtu;OA#dxB)t!x|zT`9j~z>!+&C
zi$HcX0u+wNhU0Ck2P~|mtw!#P+?wJx#f;Q&<OF-S*Iiq$8=VPMw31Z+4ZTO(25CRI
zKuruJ+q=1NSu2G5W!kp-?vIXx&DRdJ(Q#L+<hb9}R`Kf?b>(EVwyK?OR1Wg!?puxR
zLp2Iy($@6f)13%zGIh2k@JA&b<2Y2smscy9bqoXu4*Yz&y8QMhJsRCeM>~`Hi_PiK
zWl>@>8E-OTp@h#d?+c7df=M?K3#79<Pd%4HEdCMAmqCv1qRqYsFFiqDRgPi!`iQPU
z<|R{l6XP(Nw*_uG73EkknXxGakKqj?`%Q8^2s*FN*KkYk*C3iup)CD&!;YjTnro@p
zJLF~GnvvPGk01BfH_DI~`Nf2+%9bgsT-6v&6@lFeDa;p-!^O|txyUF;OaIYTft+%M
zAI12PV4OUZjO-^-5CV0Kr(S`Ie!CjDSi5$96yH*{6G0(A7q~WM_N70k_RdI2`;7oc
zuekRuTpRbsrdl4W4%i~EM<dConRrR=u2Nkwhs4Ll8#{gYeX@?8WFPd*+5U<4K8<=G
za`I{(_p?C7-79YMBNqTT**;#I4yas9$>imVjDV7I=>E{xvbn2q^C7M*CkGuoKk;2+
zc9ci@zOvt+#qXy<cjrG0ue;9rk}XX+a1KQ5tQZX1v}`vWKUo40U4!2#`DR|e$*;qw
zTu86cyuVpK!ky-k!??6>SDCx99k|QrccQX4Ur(uidewa=oKgMR?#Eq|gD2VEUzK(T
zfj`mx9;{QJM(+ZIY$k_#QYLh3_}`>{ldXL%JYq=vA%agm$@7V7%u45z9b4U9_d8_#
z)rw!;_4~6itx9lv{8edbs`Z=+did#t%Jb`)=UgoymSkjCWHWR#T_8~EvQ`rDE3&l@
z5!H1`jDNDevm4+o*QIuygjBE^Z%#JL$^b6v3n64Q8lU0u-zf5Tn4aB+n?{G_^TrEy
z!BOAktG8cIG|@0~jbAC+ko2>NO;sDai9rZ1vMptMdo(j?L7-IdH_TSy;c%l*7`U$B
zxqKRyZ*3$!OhsL$z5LveXf~s?53d9J#wDX3_?jd~k%J76SYs~>Yle!h$ZE%b>mECj
zQj2D~iR2BZG73+#>&ox(68}+iH>Q7F-?QkOvX(o_wOxyf$R7ssij7o=^fj)`Vt6$|
zq4yx%-axCcl!B&=3}(tlAx9y>r%MH)q1NyDs8{#8e8EluPGLW6GU*qj1h8x1HeAod
zDtW-HAs}=MHfO4j6fJ!YEea02tav*d2`pktA3Y--%AX`q8c_~weFf0@g6QcO!z;Ax
G!u|)#w{eF6

literal 0
HcmV?d00001

diff --git a/htdocs/version b/htdocs/version
index 7b735e5..d9e31cb 100644
--- a/htdocs/version
+++ b/htdocs/version
@@ -1 +1 @@
-fex-20160328
+fex-20160919
diff --git a/install b/install
index 7019bee..c300815 100755
--- a/install
+++ b/install
@@ -163,6 +163,12 @@ if ($FEXHOME !~ /fex/) {
   exit unless /^y/i;
 }
 
+# old bug fix
+if (-d "$FEXHOME/htdocs/locale") {
+  chmod 0755,"$FEXHOME/htdocs/locale";
+  chmod 0755,grep { -d $_ } glob("$FEXHOME/locale/*/htdocs");
+}
+
 print "Installing:\n";
 
 $pecl = "$FEXHOME/perl/Encode/ConfigLocal.pm";
@@ -175,7 +181,7 @@ unless (-f $pecl) {
     "1;\n";
   close $pecl;
   print $pecl,"\n";
-  chownr('fex:root',"$FEXHOME/perl");
+  chownr('fex:0',"$FEXHOME/perl");
 }
 
 @save = (
@@ -388,7 +394,7 @@ unless (-f $xinetd) {
     system qw'crontab -u fex fex.cron';
   }
 
-  chownr('fex:root',$FEXHOME,"$FEXHOME/spool/.","$FEXHOME/htdocs/.");
+  chownr('fex:0',$FEXHOME,"$FEXHOME/spool/.","$FEXHOME/htdocs/.");
   chmodr('go-r',"$FEXHOME/lib","$FEXHOME/cgi-bin","$FEXHOME/spool/.");
 
   print "\n";
@@ -406,9 +412,6 @@ unless (-f $xinetd) {
         "< $FEXHOME/doc/newfeatures\n";
 }
 
-chmod 0755,"$FEXHOME/htdocs/locale";
-chmod 0755,glob("$FEXHOME/locale/*/htdocs");
-  
 if (@local_rdomains and not @local_rhosts) {
   print "\nWARNING:\n";
   print "In $fph you have \@local_rdomains but not \@local_rhosts!\n";
diff --git a/lib/dop b/lib/dop
index dc92d70..4a6ece0 100755
--- a/lib/dop
+++ b/lib/dop
@@ -8,11 +8,11 @@
 #
 
 use File::Basename;
-use CGI::Carp	qw(fatalsToBrowser);
 use Fcntl 	qw(:flock :seek :mode);
 use POSIX	qw(strftime locale_h);
 use Cwd 	qw(getcwd abs_path);
 use utf8;
+# use CGI::Carp	qw(fatalsToBrowser);
 
 # import from fex.pp
 our ($bs,$tmpdir,@doc_dirs);
@@ -126,10 +126,16 @@ sub http_output {
     foreach (@files) {
       if (/^\// or /\.\.\//) {
         # absolute path or relative path with parent directory is not allowed
+        errorlog("$streamfile: $_ is not allowed for streaming");
+        http_error(403);
+      }
+      unless (-e $_) {
+        errorlog("$streamfile: $_ does not exist");
         http_error(403);
       }
       if (@s = stat($_) and not($s[2] & S_IRGRP) or not -r $_) {
         # file must be readable by user and group
+        errorlog("$streamfile: $_ is not readable by user and group");
         http_error(403);
       }
     }
@@ -238,8 +244,10 @@ sub http_output {
         } else {
           # eval code with output substitution
           local $__ = '';
+          local $^W = 0;
           tie *STDOUT => "Buffer",\$__;
-          $__ .= eval('package DOP;' . $pc);
+          my $r .= eval('package DOP;' . $pc);
+          $__ .= $r if $pc !~ /;\s*$/;
           untie *STDOUT;
           last if $timeout;
           $dynamic = $htmldoc =~ s/<<(.+?)>>/$__/s;
@@ -603,7 +611,7 @@ sub out {
   return '';
 }
 
-# tie STDOUT to buffer variable (redefining print)
+# tie STDOUT to buffer variable (redefining print and printf)
 package Buffer;
 
 sub TIEHANDLE {
diff --git a/lib/fex.ph b/lib/fex.ph
index c69943d..d1596e2 100644
--- a/lib/fex.ph
+++ b/lib/fex.ph
@@ -85,6 +85,10 @@ $keep_max = 99;
 ##	NO      ==> keep until expiration date (see $keep)
 $autodelete = 'YES';
 
+## purge: purge files after that number of days after their deletion
+##        (purge deletes file meta-information)
+$purge = '3*$keep';
+
 ## if the file has been already downloaded then subsequentials
 ## downloads are only allowed from the same client (uses cookies)
 ## to prevent unwanted file sharing
@@ -137,6 +141,13 @@ $mail_authid = 'YES';
 ## optional: forbidden ip addresses for CGIs
 # @forbidden_hosts = qw(64.124.0.0-64.125.255.255);
 
+# forbidden user agents (sucking "download manager", etc)
+@forbidden_user_agents = qw(
+  FDM
+  Download.Master
+  Java/[\d\.]+
+);
+
 ## optional: restrict upload to these IP ranges
 # @upload_hosts = qw(127.0.0.1 ::1 10.10.100.0-10.10.200.255 129.69.1.129);
 
diff --git a/lib/fex.pp b/lib/fex.pp
index 8bfddbf..177baba 100644
--- a/lib/fex.pp
+++ b/lib/fex.pp
@@ -62,6 +62,7 @@ $fop_auth = 0;
 $mail_authid = 'yes';
 $force_https = 0;
 $debug = 0;
+@forbidden_user_agents = ('FDM');
 
 # https://securityheaders.io/
 # https://scotthelme.co.uk/hardening-your-http-response-headers/
@@ -124,6 +125,7 @@ http_die("cannot determine the server hostname") unless $hostname;
 
 $ENV{PROTO} = 'http' unless $ENV{PROTO};
 $keep = $keep_default ||= $keep || 5;
+$purge ||= 3*$keep;
 $fra = $ENV{REMOTE_ADDR} || '';
 $sid = $ENV{SID} || '';
 
@@ -320,6 +322,8 @@ sub html_header {
   my $header = 'header.html';
   my $head;
 
+  binmode(STDOUT,':utf8'); # for text/html !
+
   # http://www.w3.org/TR/html401/struct/global.html
   # http://www.w3.org/International/O-charset
   $head = qqq(qq(
@@ -370,6 +374,12 @@ sub html_error {
 
   errorlog($msg);
 
+  $SIG{ALRM} = sub {
+    $SIG{__DIE__} = 'DEFAULT';
+    die "TIMEOUT\n";
+  };
+  alarm($timeout);
+
   # cannot send standard HTTP Status-Code 400, because stupid
   # Internet Explorer then refuses to display HTML body!
   http_header("666 Bad Request - $msg");
diff --git a/locale/czech/htdocs/FAQ/FAQ.html b/locale/czech/htdocs/FAQ/FAQ.html
index a096645..9585c69 100644
--- a/locale/czech/htdocs/FAQ/FAQ.html
+++ b/locale/czech/htdocs/FAQ/FAQ.html
@@ -2,11 +2,14 @@
 <head><title>F*EX FAQ</title></head>
 <body>
 
+## << do "./xx.pl" or print $! >>
+## << $_ = `pwd` >>
+
 ## <pre>
 ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
 ## </pre>
 
-<< require "./faq.pl" or print $! >>
+<< do "./faq.pl" or print $! >>
 
 </body>
 </html>
diff --git a/locale/french/htdocs/FAQ/FAQ.html b/locale/french/htdocs/FAQ/FAQ.html
index a096645..9585c69 100644
--- a/locale/french/htdocs/FAQ/FAQ.html
+++ b/locale/french/htdocs/FAQ/FAQ.html
@@ -2,11 +2,14 @@
 <head><title>F*EX FAQ</title></head>
 <body>
 
+## << do "./xx.pl" or print $! >>
+## << $_ = `pwd` >>
+
 ## <pre>
 ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
 ## </pre>
 
-<< require "./faq.pl" or print $! >>
+<< do "./faq.pl" or print $! >>
 
 </body>
 </html>
diff --git a/locale/galician/htdocs/FAQ/FAQ.html b/locale/galician/htdocs/FAQ/FAQ.html
index a096645..9585c69 100644
--- a/locale/galician/htdocs/FAQ/FAQ.html
+++ b/locale/galician/htdocs/FAQ/FAQ.html
@@ -2,11 +2,14 @@
 <head><title>F*EX FAQ</title></head>
 <body>
 
+## << do "./xx.pl" or print $! >>
+## << $_ = `pwd` >>
+
 ## <pre>
 ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
 ## </pre>
 
-<< require "./faq.pl" or print $! >>
+<< do "./faq.pl" or print $! >>
 
 </body>
 </html>
diff --git a/locale/german/htdocs/FAQ/FAQ.html b/locale/german/htdocs/FAQ/FAQ.html
index a096645..9585c69 100644
--- a/locale/german/htdocs/FAQ/FAQ.html
+++ b/locale/german/htdocs/FAQ/FAQ.html
@@ -2,11 +2,14 @@
 <head><title>F*EX FAQ</title></head>
 <body>
 
+## << do "./xx.pl" or print $! >>
+## << $_ = `pwd` >>
+
 ## <pre>
 ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
 ## </pre>
 
-<< require "./faq.pl" or print $! >>
+<< do "./faq.pl" or print $! >>
 
 </body>
 </html>
diff --git a/locale/italian/htdocs/FAQ/FAQ.html b/locale/italian/htdocs/FAQ/FAQ.html
index a096645..9585c69 100644
--- a/locale/italian/htdocs/FAQ/FAQ.html
+++ b/locale/italian/htdocs/FAQ/FAQ.html
@@ -2,11 +2,14 @@
 <head><title>F*EX FAQ</title></head>
 <body>
 
+## << do "./xx.pl" or print $! >>
+## << $_ = `pwd` >>
+
 ## <pre>
 ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
 ## </pre>
 
-<< require "./faq.pl" or print $! >>
+<< do "./faq.pl" or print $! >>
 
 </body>
 </html>
diff --git a/locale/spanish/htdocs/FAQ/FAQ.html b/locale/spanish/htdocs/FAQ/FAQ.html
index a096645..9585c69 100644
--- a/locale/spanish/htdocs/FAQ/FAQ.html
+++ b/locale/spanish/htdocs/FAQ/FAQ.html
@@ -2,11 +2,14 @@
 <head><title>F*EX FAQ</title></head>
 <body>
 
+## << do "./xx.pl" or print $! >>
+## << $_ = `pwd` >>
+
 ## <pre>
 ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
 ## </pre>
 
-<< require "./faq.pl" or print $! >>
+<< do "./faq.pl" or print $! >>
 
 </body>
 </html>
diff --git a/locale/translations b/locale/translations
index 25f1044..e36d3ab 100644
--- a/locale/translations
+++ b/locale/translations
@@ -2729,7 +2729,7 @@ Your F*EX account has been inactive for $expire days
 Ihr F*EX Account ist seit $expire Tagen inaktiv
 Du hosch dei F*EX Konto seit $expire Tag nemme bnutzt
 Su cuenta de F*EX ha estado inactivo $expire dias
-A súa conta F*EX estivo inactiva durante $expire día
+A súa conta F*EX estivo inactiva durante $expire día
 Il tuo account F*EX è stato inattivo per $expire giorni
 Váš F*EX účet byl neaktivní $expire dnů
 Votre compte F*EX a été inactif pendant $expire days
-- 
2.39.5