Initial mod_perl-2.0 port.
authorshort <>
Sun, 21 Aug 2005 07:27:55 +0000 (07:27 +0000)
committershort <>
Sun, 21 Aug 2005 07:27:55 +0000 (07:27 +0000)
Hash/Makefile.am [new file with mode: 0644]
Hash/Sub.pm [new file with mode: 0644]
Hash/Sub/Makefile.am [new file with mode: 0644]
Hash/Sub/Readonly.pm [new file with mode: 0644]
Makefile.am
ModPerlPm.pm [new file with mode: 0644]
Project.pm [deleted file]

diff --git a/Hash/Makefile.am b/Hash/Makefile.am
new file mode 100644 (file)
index 0000000..7e550dd
--- /dev/null
@@ -0,0 +1,26 @@
+# $Id$
+# automake source for the Makefile of My/Hash/ subdir
+# Copyright (C) 2005 Jan Kratochvil <project-www.jankratochvil.net@jankratochvil.net>
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; exactly version 2 of June 1991 is required
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+include $(top_srcdir)/Makefile-head.am
+
+SUBDIRS= \
+               Sub
+
+EXTRA_DIST+= \
+               Sub.pm
+
diff --git a/Hash/Sub.pm b/Hash/Sub.pm
new file mode 100644 (file)
index 0000000..9fa5fd7
--- /dev/null
@@ -0,0 +1,40 @@
+# $Id$
+# Hash tied to optionally dynamically generate its values
+# Copyright (C) 2005 Jan Kratochvil <project-www.jankratochvil.net@jankratochvil.net>
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; exactly version 2 of June 1991 is required
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+package My::Hash::Sub;
+our $VERSION=do { my @r=(q$Revision$=~/\d+/g); sprintf "%d.".("%03d"x$#r),@r; };
+our $CVS_ID=q$Id$;
+use strict;
+use warnings;
+require Tie::Hash;     # for Tie::StdHash
+our @ISA=qw(Tie::StdHash);
+use Carp qw(cluck confess);
+
+
+sub FETCH($$)
+{
+my($this,$key)=@_;
+
+       my $val=$this->SUPER::FETCH($key);
+       return $val if $key=~/_sub$/;   # force
+       return $val if !defined $val;   # 1-item array is intentional.
+       return $val if "CODE" ne ref $val;
+       return &{$val}($this,$key);
+}
+
+1;
diff --git a/Hash/Sub/Makefile.am b/Hash/Sub/Makefile.am
new file mode 100644 (file)
index 0000000..3ea0c64
--- /dev/null
@@ -0,0 +1,23 @@
+# $Id$
+# automake source for the Makefile of My/Hash/Readonly/ subdir
+# Copyright (C) 2005 Jan Kratochvil <project-www.jankratochvil.net@jankratochvil.net>
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; exactly version 2 of June 1991 is required
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+include $(top_srcdir)/Makefile-head.am
+
+EXTRA_DIST+= \
+               Readonly.pm
+
diff --git a/Hash/Sub/Readonly.pm b/Hash/Sub/Readonly.pm
new file mode 100644 (file)
index 0000000..ad829a9
--- /dev/null
@@ -0,0 +1,46 @@
+# $Id$
+# Hash tied to optionally dynamically generate its values and being locked/readonly
+# Copyright (C) 2005 Jan Kratochvil <project-www.jankratochvil.net@jankratochvil.net>
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; exactly version 2 of June 1991 is required
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+package My::Hash::Sub::Readonly;
+our $VERSION=do { my @r=(q$Revision$=~/\d+/g); sprintf "%d.".("%03d"x$#r),@r; };
+our $CVS_ID=q$Id$;
+use strict;
+use warnings;
+
+use My::Web;   # for &Wrequire
+use Carp qw(cluck confess);
+
+Wrequire 'My::Hash::Sub';
+our @ISA=qw(My::Hash::Sub);
+
+
+# Implementation reason: &Hash::Util::lock_hash does not work for tied hashes!
+
+
+sub TIEHASH($@)
+{
+my($class,@list)=@_;
+
+       return bless {@list},$class;
+}
+
+sub STORE  { confess "READ-ONLY requirement violation"; }
+sub DELETE { confess "READ-ONLY requirement violation"; }
+sub CLEAR  { confess "READ-ONLY requirement violation"; }
+
+1;
index 841a425..63b0901 100644 (file)
@@ -1,6 +1,6 @@
 # $Id$
-# automake source for the Makefile of project/ subdir
-# Copyright (C) 2003 Jan Kratochvil <project-www.jankratochvil.net@jankratochvil.net>
+# automake source for the Makefile of My::Web "My/" subdir
+# Copyright (C) 2003-2005 Jan Kratochvil <project-www.jankratochvil.net@jankratochvil.net>
 # 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 
 include $(top_srcdir)/Makefile-head.am
 
+SUBDIRS= \
+               Hash
+
 EXTRA_DIST+= \
-               Project.pm \
                Web.pm \
+               ModPerlPm.pm \
                arrow-left.png \
                arrow-right.png \
                arrow-up.png
+
diff --git a/ModPerlPm.pm b/ModPerlPm.pm
new file mode 100644 (file)
index 0000000..7d7bf89
--- /dev/null
@@ -0,0 +1,65 @@
+# $Id$
+# Handle the set of ".pm" files for mod_perl
+# Copyright (C) 2005 Jan Kratochvil <project-www.jankratochvil.net@jankratochvil.net>
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; exactly version 2 of June 1991 is required
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+package My::ModPerlPm;
+require 5.6.0; # at least 'use warnings;' but we need some 5.6.0+ modules anyway
+our $VERSION=do { my @r=(q$Revision$=~/\d+/g); sprintf "%d.".("%03d"x$#r),@r; };
+our $CVS_ID=q$Id$;
+use strict;
+use warnings;
+
+use Carp qw(cluck confess);
+
+use Exporter;
+our @EXPORT=qw();
+our @ISA=qw(Exporter);
+
+
+# $args{"sub"}=sub { $_[0]->{"module"...}; };
+sub list($%)
+{
+my($self,%args)=@_;
+
+       my $filename="make -s MODPERL_PM-print|";
+       local *F;
+       open F,$filename or confess "$filename: $!";
+       local $_;
+       my @r;
+       while (<F>) {
+               next if !s/^MODPERL_PM:([^:]+)://;
+               my $subdir=$1;
+               for (split) {
+                       my %r;
+                       $r{"url"}=$subdir."/".$_;
+                       $r{"url"}=~s{^[.](/.*[.]pm)$}{$1} or confess "Invalid project: subdir=$subdir base=$_";
+                       $r{"module"}=$r{"url"};
+                       $r{"module"}=~s{^/}{} or confess "Relative module: ".$r{"module"};
+                       $r{"file"}=$r{"module"};
+                       $r{"module"}=~s{/}{::}g;
+                       $r{"module"}=~s{[.]pm$}{} or confess;
+                       -r $r{"file"} or do { warn "FIXME: Non-existing file \"".$r{"file"}."\" for URL: ".$r{"url"}; next; };
+                       do { &{$_}(\%r) if $_; } for $args{"sub"};
+                       push @r,\%r;
+                       }
+               }
+       close F or confess "$filename: $!";
+       cluck "No modules?" if !@r;
+       return @r;
+}
+
+1;
diff --git a/Project.pm b/Project.pm
deleted file mode 100644 (file)
index bbcee8a..0000000
+++ /dev/null
@@ -1,353 +0,0 @@
-# $Id$
-# Common functions for HTML/XHTML output generation
-# Copyright (C) 2003 Jan Kratochvil <project-www.jankratochvil.net@jankratochvil.net>
-# 
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; exactly version 2 of June 1991 is required
-# 
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-
-package My::Project;
-require 5.6.0; # at least 'use warnings;' but we need some 5.6.0+ modules anyway
-our $VERSION=do { my @r=(q$Revision$=~/\d+/g); sprintf "%d.".("%03d"x$#r),@r; };
-our $CVS_ID=q$Id$;
-use strict;
-use warnings;
-
-use My::Web;
-require CGI;
-
-use Exporter;
-our @EXPORT=qw();
-our @ISA=qw(My::Web Exporter);
-
-
-sub ENTRIES     { return top_dir_disk()."/project/CVS/Entries"; }
-sub ENTRIES_LOG { return top_dir_disk()."/project/CVS/Entries.Log"; }
-
-
-sub print_project
-{
-my($class,$ListItem,%args)=@_;
-
-       print "<h1>".$W->{"title"}."</h1>\n";
-       do { print $_ if $_; } for ($args{"project_text_after_title"});
-       print $ListItem->{"description"};
-       print "<hr />\n";
-       print $args{"before_project_data"} || "";
-       return if $args{"no_project_data"};
-       my @table=(
-               {"key"=>"summary","text"=>"Summary"},
-               {"key"=>"license","text"=>"License","format"=>sub ($) {
-                               my %known=(
-                                               "PD"=>"Public Domain",
-                                               "GPL"=>a_href("http://www.gnu.org/licenses/gpl.html","GNU General Public License"),
-                                               "LGPL"=>a_href("http://www.gnu.org/licenses/lgpl.html","GNU Lesser General Public License"),
-                                               "com"=>"Commercial"
-                                               );
-                               return $known{$_[0]};
-                               }},
-               {"key"=>"maintenance","text"=>"State","format"=>sub ($) {
-                               my %known=(
-                                               "active"=>"Ready to use. Project is now actively developed.",
-                                               "ready"=>"Ready to use. Maintained.",
-                                               "dead"=>"Dead code, no longer supported.",
-                                               "merge"=>"Functions belong to existing other project.",
-                                               "obsolete"=>"Obsoleted.",
-                                               "update"=>"Package needs updating to recent software.",
-                                               "accepted"=>"This patch got already integrated by the original package maintainer.",
-                                               "pending"=>"Patch is ready to be applied to the mainstream.",
-                                               "ignored"=>"Patch was ignored. It is not applied in the mainstream.",
-                                               ""=>"",
-                                               );
-                               my @r;
-                               for ($known{($_[0]=~/^([^-]*)-?/)[0] || ""}) {
-                                       push @r,$_ if $_;
-                                       push @r," $'" if $';
-                                       }
-                               return join(" ",@r);
-                               }},
-               {"key"=>"aminet","text"=>a_href('http://www.aminet.net/','Aminet'),"format"=>sub ($) {
-                               return join(" ",
-                                               a_href('http://www.aminet.net/'.$_[0].".lha",$_[0].".lha"),
-                                               "(".a_href('http://www.aminet.net/'.$_[0].".readme","readme").")");
-                               }},
-               {"key"=>qr(^download\b),"text"=>sub ($) {
-                                               $_[0]=~s/^download//;
-                                               $_[0]=~s/^-/ /;
-                                               return "Download".$_[0];
-                                               },
-                               "format"=>sub ($) {
-                                               return a_href($_[0],CGI::escapeHTML(File::Basename::basename($_[0])),"size"=>2);
-                                               }},
-               {"key"=>qr(^link\b),"text"=>sub ($) {
-                                               $_[0]=~s/^link-//;
-                                               return $_[0];
-                                               },
-                               "format"=>sub ($) {
-                                               return($_[0]=~/^<a\b/ ? $_[0] : a_href($_[0],CGI::escapeHTML($_[0])));
-                                               }},
-               {"key"=>qr(^cvs\b),"text"=>sub ($) {
-                                               $_[0]=~s/^cvs//;
-                                               $_[0]=~s/^-/ /;
-                                               return "CVS".$_[0];
-                                               },
-                               "format"=>sub ($$) {
-                                               my($val,$key)=@_;
-                                               $key=~s/^cvs//;
-                                               $key=~s/^-/ /;
-                                               my $branch="";
-                                               $branch=$1 if $val=~s/:(.*)//;
-                                               return join("<br />\n\t\t",
-                                                               CGI::escapeHTML("cvs -d ".$W->{"pserver"}.":".$W->{"pserver_path"}." -z3"
-                                                                               ." checkout".(!$branch ? "" : " -r $branch -kk")
-                                                                               .($val!~m#/# ? "" : " -d ".File::Basename::basename($val))
-                                                                               ." $val"),
-                                                               join(" | \n\t\t",
-                                                                               map({ a_href($_->[1],$_->[0]); }
-                                                                                               ["ViewCVS CVS repository",$W->{"project_viewcvs"}.$val."/".(!$branch ? "" : '?only_with_tag='.$branch)],
-                                                                                               ["Download CVS snapshot" ,
-                                                                                                               $W->{"project_viewcvs"}.$val."/".File::Basename::basename($val).".tar.gz?tarball=1"
-                                                                                                                               .(!$branch ? "" : '&only_with_tag='.$branch)],
-                                                                                               ["CVS ChangeLog"         ,"/project/ChangeLog.txt.pl?cvs=$val"])));
-                                               }},
-               {"key"=>"ownership","text"=>"Ownership"},
-               {"key"=>"sponsorship","text"=>"Sponsorship"},
-               {"key"=>"language","text"=>"Programming language","format"=>sub ($) {
-                               return a_href("http://java.sun.com/",CGI::escapeHTML($_[0]))
-                                               if $_[0]=~/^Java\b/;
-                               return a_href("http://www.php.net/",CGI::escapeHTML($_[0]))
-                                               if $_[0]=~/^PHP\b/;
-                               return undef();
-                               }},
-               );
-
-sub tableit_func
-{
-my($tableit,$val,$key,$ListItem)=@_;
-
-       delete $ListItem->{$key};
-       my $r="";
-       $r.="<tr>";
-               if ($tableit->{"text"}) {
-                       $r.="<td>";
-                               $r.=(!ref $_ ? $_ : &{$_}($key)) for ($tableit->{"text"});
-                       $r.="</td>";
-                       }
-               if ($tableit->{"format"}) {
-                       do { $val=$_ if defined $_; } for (&{$tableit->{"format"}}($val,$key));
-                       }
-               return join("",map("<tr><td>".$_->[0]."</td><td>".$_->[1]."</td></tr>\n",@$val))
-                               if ref $val;
-               $r.="<td>$val</td>";
-       $r.="</tr>\n";
-}
-
-       print '<table border="0" class="print_project">'."\n";
-               for my $tableit (@table) {
-                       if (!ref $tableit->{"key"}) {
-                               print tableit_func($tableit,$ListItem->{$tableit->{"key"}},$tableit->{"key"},$ListItem)
-                                               if $ListItem->{$tableit->{"key"}};
-                               }
-                       else {
-                               for my $key (@{$ListItem->{"keys_array"}}) {
-                                       my $keyregex=$tableit->{"key"};
-                                       next if $key!~/$keyregex/;
-                                       print tableit_func($tableit,$ListItem->{$key},$key,$ListItem);
-                                       }
-                               }
-                       }
-       print "</table>\n";
-       print vskip;
-}
-
-sub project_arr_to_hash (@)
-{
-my(@arr)=@_;
-
-       return (
-                       @arr,
-                       "keys_array"=>[ My::Web::arr_keys(@arr) ],
-                       );
-}
-
-sub title ($$)
-{
-my($class,$hashref)=@_;
-
-       return $hashref->{"name"}.": ".$hashref->{"summary"},
-}
-
-# $args{"ListItem"}=\%...;
-sub init_project ($%)
-{
-my($class,%args)=@_;
-
-       my $ListItem={ project_arr_to_hash(@{$args{"ListItem"}}) };
-       my $W=$class->init(
-                       "title"=>$class->title($ListItem),
-                       map(("rel_$_"=>top_dir('/project/Rel.pl?rel='.$_.'&project='.($args{"__PACKAGE__"}=~/^.*::([^:]+)::[^:]+$/)[0])),
-                                       qw(prev next)),
-                       "rel_up"=>top_dir('/project/'),
-#                      "rel_start"=>top_dir(), # TODO:homepage
-                       %args,
-                       # FIXME: "head_css" no longer exists in My::Web branch "apache2"
-                       "head_css"=>($args{"head_css"} || "")."
-table.print_project td { vertical-align: top; }
-",
-                       "WebConfig::heading_novskip"=>1,
-                       );
-       $class->heading();
-       print $class->platforms($ListItem->{"platform"});
-       $class->print_project({ %$ListItem },%args);
-       return $W;
-}
-
-sub one_item_list_read($$)
-{
-my($class,$name)=@_;
-
-       Wrequire "project::${name}::ListItem";
-       my $item=eval('\@project::'.$name.'::ListItem::ListItem');
-       do { warn "Broken project/$name/ListItem.pm"; next; } if !defined $item;
-       return @$item;
-}
-
-sub item_hash_read ()
-{
-# FIXME: $class
-       my %dirs;
-       for my $ENTRIES (ENTRIES(),ENTRIES_LOG()) {
-               local *E;
-               next if !open E,$ENTRIES;
-               while (<E>) {
-                       chomp;
-                       do { $dirs{$1}=1; next; } if m#^(?:A )?D/([^/]*)/#;
-                       next if m#^/([^/]*)/# ;
-                       next if /^D$/;
-                       warn "File $ENTRIES contains invalid line \"$_\": $!";
-                       }
-               close E;
-               }
-
-       my %item;
-       for my $dir (keys(%dirs)) {
-               Wrequire "project::${dir}::ListItem";
-               my $item=eval('\@project::'.$dir.'::ListItem::ListItem');
-               do { warn "Broken project/$dir/ListItem.pm"; next; } if !defined $item;
-               $item{$dir}={ My::Project::project_arr_to_hash(My::Project->one_item_list_read($dir)) };
-               }
-       return %item;
-}
-
-our @platforms=(
-               "unixuser"=>"UNIX",
-               "unixdevel"=>"UNIX-devel",
-               "web"=>"Web",
-               "amiga"=>"Amiga",
-               "w32"=>"MS-Windows",
-               "dos"=>"MS-DOS",
-               "patch"=>"Patches",
-               );
-
-sub views ($$)
-{
-my($class,$view_selected)=@_;
-
-       my $view=sub ($$)
-               {
-               my($current,$href,$content)=@_;
-
-                       return a_href($href,$content) if $current ne $view_selected;
-                       return "<b>".$content."</b> (current)";
-               };
-
-       return <<"HERE";
-<h1>Project List of @{[ a_href 'http://www.jankratochvil.net/','Jan Kratochvil' ]}</h1>
-
-<ul>
-       <li>@{[ &{$view}('Detailed'     ,'/project/','Detailed project listing per platform') ]}</li>
-       <li>@{[ &{$view}('BriefPlatform','/project/List.html.pl?platform=platform',
-                       'Brief project listing per platform') ]}</li>
-       <li>@{[ &{$view}('BriefUnified' ,'/project/List.html.pl',
-                       'Unified brief project listing') ]}</li>
-</ul>
-@{[ vskip "1ex" ]}
-HERE
-}
-
-sub platforms ($;$%)
-{
-my($class,$platform_selected,%args)=@_;
-
-       my $r="";
-       $r.='<table border="0" align="center"><tr>'."\n";
-               $r.='<td>';
-                       $r.='<table border="1" align="center"'  # align="left"
-                                       .' style="border-collapse: collapse; border-style: solid; border-width: 1px;">'."\n";
-                               $r.='<tr>'."\n";
-                                       $r.='<td style="padding: 5px; font-weight: bold;">'."\n";
-                                               $r.='Projects';
-                                       $r.='</td>'."\n";
-                               $r.='</tr>'."\n";
-                       $r.='</table>';
-               $r.='</td>';
-               $r.='<td>';
-                       $r.='<table border="1" align="center" style="border-collapse: collapse; border-style: solid;">'."\n";
-                               $r.='<tr>'."\n";
-                                       my @platforms=@platforms;
-                                       while (@platforms) {
-                                               my $platform_sym =shift @platforms;
-                                               my $platform_name=shift @platforms;
-                                               my $chosen=($platform_selected && $platform_selected eq $platform_sym);
-                                               $r.='<td style="padding: 5px;">';
-                                                       $r.=a_href((!$platform_selected ? "" : "/project/").'#'.$platform_sym,$platform_name,
-                                                                       "attr"=>($chosen
-                                                                                       ? 'style="text-decoration: underline; font-weight: bold;"'
-                                                                                       : 'style="text-decoration: inherit; /* revoke underline */"'));
-                                               $r.="</td>\n";
-                                               }
-                               $r.='</tr>'."\n";
-                       $r.='</table>'."\n";
-               $r.='</td>'."\n";
-       $r.='</tr></table>'."\n";
-       if (!$args{"novskip"}) {
-               $r.="<hr />\n";
-               $r.=My::Web::vskip "6ex";
-               }
-       $r;
-}
-
-sub section ($$)
-{
-my($class,$name)=@_;
-
-       my %item=( $class->one_item_list_read($name) );
-       my $title=$class->title(\%item);
-       my $r="";
-
-       print $class->platforms($item{"platform"},"novskip"=>1);
-
-       $r.='<table border="0" align="center"><tr>'."\n";
-               $r.='<td>';
-                       $r.='<table border="1" align="center" style="border-collapse: collapse; border-style: solid;">'."\n";
-                               $r.='<tr><td style="font-size: larger;">'."\n";
-                                       $r.=a_href "/project/$name/",$title;
-                               $r.='</td></tr>'."\n";
-                       $r.='</table>'."\n";
-               $r.='</td>'."\n";
-       $r.='</tr></table>'."\n";
-       $r.=vskip "1ex";
-       $r;
-}
-
-1;