Home > Archive > LDAP > January 2006 > Net::LDAP::FilterMatch
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Net::LDAP::FilterMatch
|
|
| Hans.Klunder@bigfoot.com 2005-12-18, 7:07 pm |
| Hi,
attached is Net::LDAP::FilterMatch, a module to match Net::LDAP::Entry
objects against a Net::LDAP::Filter filter.
It can be used to filter out entries from an LDIF, but also as a simple
solution for searching while using Net::LDAP::Server.
Comments are welcome.
Kind regards,
Hans
| |
| Mike Jackson 2005-12-18, 7:07 pm |
| Hans.Klunder@bigfoot.com wrote:
> Hi,
>
> attached is Net::LDAP::FilterMatch, a module to match Net::LDAP::Entry
> objects against a Net::LDAP::Filter filter.
> It can be used to filter out entries from an LDIF, but also as a simple
> solution for searching while using Net::LDAP::Server.
>
> Comments are welcome.
>
> Kind regards,
>
> Hans
>
Cool. Where do I find Net::LDAP::Server?
Not here:
http://svn.mutatus.co.uk/wsvn/perl-...DAP/?rev=0&sc=0
--
mike
> ------------------------------------------------------------------------
>
> # ========================================
===================================
> # Net::LDAP::FilterMatch
> #
> # LDAP entry matching
> #
> # Hans Klunder <hans.klunder@bigfoot.com>
> # Copyright (c) 2005.
> #
> # See below for documentation.
> #
>
> package Net::LDAP::FilterMatch;
>
> require Exporter;
> @ISA = qw(Exporter);
> @EXPORT_OK = qw(filterMatch);
> $VERSION = '0.1';
>
>
> sub filterMatch{
> my $filter=shift;
> my $entry=shift;
>
> keys(%{$filter}); #this one is to ensure the next each works out fine
> my ($op, $args)=each(%{$filter});
>
> return (filterMatch(@{$args}[0],$entry) and filterMatch(@{$args}[1],$entry)) if ($op eq 'and');
> return (filterMatch(@{$args}[0],$entry) or filterMatch(@{$args}[1],$entry))if ($op eq 'or');
> return (not(filterMatch($args,$entry))) if ($op eq 'not');
> return ($entry->exists($args)) if ($op eq 'present');
>
> if ($op=~ / ^(equalityMatch|greaterOrEqual|lessOrEqu
al|approxMatch)/){
> my @values=$entry->get_value($args->{'attributeDesc'});
> my $type='string'; # should be derived from schema
> my $match= $type.'_'.$op;
> my $filter=$args->{'assertionValue'};
> foreach my $value(@values){
> return 1 if eval( "$match".'($filter,$value)');
> }
> return 0;
> }
> if ($op eq 'substrings'){
> my @values=$entry->get_value($args->{'type'});
> my $type='string'; # should be derived from schema
> my $match= $type.'_'.$op;
> my $regexp = join('.*', "",map { $_ } map { values %$_ } @{$args->{'substrings'}});
> $regexp =~ s/^..// if exists $args->{'substrings'}[0]{initial};
> $regexp .= '.*' unless exists $args->{'substrings'}[-1]{final};
> foreach my $value(@values){
> return 1 if eval( "$match".'($regexp,$value)' );
> }
> return 0;
> }
> }
>
> sub string_equalityMatch{
> return (@_[0] eq @_[1]);
> }
>
> sub string_greaterOrEqual{
> return (@_[0] ge @_[1]);
> }
>
> sub string_lessOrEqual{
> return (@_[0] le @_[1]);
> }
>
> sub string_approxMatch{
> return (@_[0] eq @_[1]); #this needs fixing by using String::Approx
> }
>
> sub string_substrings{
> return ($_[1]=~/$_[0]/);
> }
>
> 1;
>
> __END__
>
> =head1 NAME
>
> Net::LDAP::FilterMatch - LDAP entry matching
>
> =head1 SYNOPSIS
>
> use Net::LDAP::Entry;
> use Net::LDAP::Filter;
> use Net::LDAP::FilterMatch qw/filterMatch/;
>
> my $entry=new Net::LDAP::Entry;
> $entry->dn("cn=dummy entry");
> $entry->add (
> 'cn' => 'dummy entry',
> 'street' => [ '1 some road','nowhere' ] );
>
> my @filters=(qw/(cn=dummy*)
> (ou=*)
> (&(cn=dummy*)(street=*road))
> (&(cn=dummy*)(!(street=nowhere)))/);
>
>
> for (@filters){
> my $filter=new Net::LDAP::Filter;
> $filter->parse($_);
> print $_,' : ',filterMatch($filter,$entry) ? 'match' : 'no match' ,"\n";
> }
>
> =head1 ABSTRACT
>
> This class provides ldap entry matching functionality which can be used on its
> own or as part of a Net::LDAP::Server based LDAP server.
> Given an entry and a filter it will tell you if the filter matches the entry.
>
> =head1 SEE ALSO
>
> L<Net::LDAP::Server>
>
> =head1 COPYRIGHT
>
> This library is free software; you can redistribute it and/or modify
> it under the same terms as Perl itself.
>
> =head1 AUTHOR
>
> Hans Klunder E<lt>hans.klunder@bigfoot.comE<gt>
>
> =cut
>
>
>
>
| |
| hans.klunder@bigfoot.com 2006-01-12, 8:01 am |
| Just for the archive..
------------------------- Original message -------------------------------
Onderwerp: Re: Net::LDAP::FilterMatch
Van: "hans.klunder@bigfoot.com" <hans.klunder@bigfoot.com>
Datum: Ma, 19 december, 2005 9:26
Aan: "Mike Jackson" <mj@sci.fi>
--------------------------------------------------------------------------
Mike,
check out:
http://search.cpan.org/~aar/Net-LDA.../LDAP/Server.pm
Kind regards,
Hans
> Hans.Klunder@bigfoot.com wrote:
objects against a Net::LDAP::Filter filter.[color=darkred]
solution for searching while using Net::LDAP::Server.[color=darkred]
>
>
> Cool. Where do I find Net::LDAP::Server?
>
> Not here:
>
> http://svn.mutatus.co.uk/wsvn/perl-...DAP/?rev=0&sc=0
>
>
> --
> mike
>
>
>
# Net::LDAP::FilterMatch[color=darkred]
my ($op, $args)=each(%{$filter});[color=darkred]
$regexp .= '.*' unless exists $args->{'substrings'}[-1]{final};
foreach my $value(@values){[color=darkred]
on its[color=darkred]
entry.[color=darkred]
under the same terms as Perl itself.[color=darkred]
>
| |
| Peter Marschall 2006-01-12, 7:11 pm |
| Hi Hans,
On Sunday, 18. December 2005 21:53, Hans.Klunder@bigfoot.com wrote:
> attached is Net::LDAP::FilterMatch, a module to match Net::LDAP::Entry
> objects against a Net::LDAP::Filter filter.
> It can be used to filter out entries from an LDIF, but also as a simple
> solution for searching while using Net::LDAP::Server.
I made a few changes to the file you sent.
Fixes compared to your version:
- conjunctions (&...) and disjunctions (|...) may comprise any number of
elements.
- characters with special meaning in Perl regexes are quoted in equality
and substring filters
i.e. "(cn=Peter?)" matches "Peter?" but not "Pete" or "Peter".
- Net::LDAP::FilterMatch is now an extension of Net::LDAP::Filter
Thus loading Net::LDAP::FilterMatch after Net::LDAP::Filter
allows you to write $filter->match($entry)
- If possible greateOrEqual and lessOrEqual filters do numerical comparison.
See the attached file.
If you do not mind I'd like to include it into the perl-ldap SVN so that it
will be in the next release.
Please test if it still matches your idea how this module should behave.
Regards
Peter
--
Peter Marschall
eMail: peter@adpm.de
| |
| Hans.Klunder@bigfoot.com 2006-01-12, 7:11 pm |
| Peter,
I ran my tests and it still does what it should ;-)
Formally the LE & GE should use string comparison for CIS, but until
schema support has been build in (maybe as optional), the numeric
comparison trick will be ok.
I'm thinking about using Net::LDAP::Schema to determine the attribute
type for matching, but I haven't found the time to start at this.
Thanks for the improvements and feel free to include it in the perl-ldap
tree.
Kind regards,
Hans
Peter Marschall schreef:
> Hi Hans,
>
> On Sunday, 18. December 2005 21:53, Hans.Klunder@bigfoot.com wrote:
>
>
> I made a few changes to the file you sent.
>
> Fixes compared to your version:
> - conjunctions (&...) and disjunctions (|...) may comprise any number of
> elements.
> - characters with special meaning in Perl regexes are quoted in equality
> and substring filters
> i.e. "(cn=Peter?)" matches "Peter?" but not "Pete" or "Peter".
> - Net::LDAP::FilterMatch is now an extension of Net::LDAP::Filter
> Thus loading Net::LDAP::FilterMatch after Net::LDAP::Filter
> allows you to write $filter->match($entry)
> - If possible greateOrEqual and lessOrEqual filters do numerical comparison.
>
> See the attached file.
>
> If you do not mind I'd like to include it into the perl-ldap SVN so that it
> will be in the next release.
>
> Please test if it still matches your idea how this module should behave.
>
> Regards
> Peter
>
>
| |
| Hans.Klunder@bigfoot.com 2006-01-14, 7:01 pm |
| Peter,
I've added schema awareness. You can now do
$filter->match($entry,$schema) and it will filter based on schema,
however currently I only included caseIgnore matching.
I couldn't get the function prototyping to work with the substrings
match in combination with schema lookup while it works with
$schema=undef (I'm running Active State 5.8.7).
At the end is a small extension to Net::LDAP::Schema, which probably
does not belong here ;-)
Feedback is welcome,
Hans
Peter Marschall schreef:
> Hi Hans,
>
> On Sunday, 18. December 2005 21:53, Hans.Klunder@bigfoot.com wrote:
>
>
> I made a few changes to the file you sent.
>
> Fixes compared to your version:
> - conjunctions (&...) and disjunctions (|...) may comprise any number of
> elements.
> - characters with special meaning in Perl regexes are quoted in equality
> and substring filters
> i.e. "(cn=Peter?)" matches "Peter?" but not "Pete" or "Peter".
> - Net::LDAP::FilterMatch is now an extension of Net::LDAP::Filter
> Thus loading Net::LDAP::FilterMatch after Net::LDAP::Filter
> allows you to write $filter->match($entry)
> - If possible greateOrEqual and lessOrEqual filters do numerical comparison.
>
> See the attached file.
>
> If you do not mind I'd like to include it into the perl-ldap SVN so that it
> will be in the next release.
>
> Please test if it still matches your idea how this module should behave.
>
> Regards
> Peter
>
>
| |
| Chris Ridd 2006-01-14, 7:01 pm |
| On 14/1/06 8:00, Hans.Klunder@bigfoot.com <Hans.Klunder@bigfoot.com> wrote:
> my $schema = shift;
> my $attr = shift;
> my $matchtype = shift;
>
> my $attrtype = $schema->attribute( $attr );
> if (exists $attrtype->{$matchtype}){
> return $attrtype->{$matchtype} ;
> }
> elsif (exists $attrtype->{'sup'}){
> # the assumption is that all superiors result in the same ruleset
> return matchingruleforattribute( $schema, $attrtype->{'sup'}[0],
> $matchtype);
> }
> return undef;
> }
Cheers,
Chris
| |
| Chris Ridd 2006-01-14, 7:01 pm |
| On 14/1/06 8:00, Hans.Klunder@bigfoot.com <Hans.Klunder@bigfoot.com> wrote:
> package Net::LDAP::Schema;
>
> # given the attribute and a matchtype (e.g. equality) this will return the
> name of the rule to apply
>
> sub matchingruleforattribute($@)
> {
> my $schema = shift;
> my $attr = shift;
> my $matchtype = shift;
>
> my $attrtype = $schema->attribute( $attr );
> if (exists $attrtype->{$matchtype}){
> return $attrtype->{$matchtype} ;
> }
> elsif (exists $attrtype->{'sup'}){
> # the assumption is that all superiors result in the same ruleset
> return matchingruleforattribute( $schema, $attrtype->{'sup'}[0],
> $matchtype);
> }
> return undef;
> }
(Sorry for the previous truncated mail.) I committed a renamed version of
this bit just now - matchingrule_for_attribute.
Cheers,
Chris
| |
| Peter Marschall 2006-01-15, 7:57 am |
| Hi Hans,
On Saturday, 14. January 2006 21:00, Hans.Klunder@bigfoot.com wrote:
> I've added schema awareness. You can now do
> $filter->match($entry,$schema) and it will filter based on schema,
> however currently I only included caseIgnore matching.
> I couldn't get the function prototyping to work with the substrings
> match in combination with schema lookup while it works with
> $schema=undef (I'm running Active State 5.8.7).
I have made a few slight changes to the file and added it to the perl-ldap SVN
You may grab it from the perl-ldap SVN at
http://svn.mutatus.co.uk/wsvn/perl-ldap/trunk/
Now that we have something in public to compare to, may I asky you to
post patches instead of the full file for future updates.
BTW do you need the function call filterMatch() exported ?
I'd like to get rid of it as $filter->match() is IMHO much nicer/cleaner.
> At the end is a small extension to Net::LDAP::Schema, which probably
> does not belong here ;-)
As Chris already added it (slightly modified) to Net::LDAP::Schema
I removed that part and adapted the method calls to the Schema accordingly.
Please test if my changes were correct ;-)
Peter
--
Peter Marschall
eMail: peter@adpm.de
| |
| Hans.Klunder@bigfoot.com 2006-01-15, 7:24 pm |
| Peter,
I've created a 0.14 (see attached patch ;-)) which contains more
matching rules and some other small fixes.
However to post patches, it would be very convenient to have *readonly*
svn access.
I tried using tortoise SVN but I get a forbidden. Am I doing something
wrong ?
Using the web interface is rather cumbersome if I want to keep up with
the patches as I seem to be unable to get the files apart from
copy/paste from the webpage.
Any hints would be appreciated ;-)
I removed the "use Net::LDAP::Filter" & "use Net::LDAP::Schema" as it
does not seem to harm code execution.
The module seems to be strict, however the &$match is not allowed when
strict is active (thats why my initial version used the eval )
Regarding the approx, we could use Text::Soundex or String::Approx and
conditionally load that if present on the system, "just" a regexp would
be perfect, but I haven't come across one yet ;-)
Cheers,
Hans
Peter Marschall schreef:
> Hi Hans,
>
> On Saturday, 14. January 2006 21:00, Hans.Klunder@bigfoot.com wrote:
>
>
> I have made a few slight changes to the file and added it to the perl-ldap SVN
>
> You may grab it from the perl-ldap SVN at
> http://svn.mutatus.co.uk/wsvn/perl-ldap/trunk/
>
> Now that we have something in public to compare to, may I asky you to
> post patches instead of the full file for future updates.
>
> BTW do you need the function call filterMatch() exported ?
> I'd like to get rid of it as $filter->match() is IMHO much nicer/cleaner.
>
>
>
> As Chris already added it (slightly modified) to Net::LDAP::Schema
> I removed that part and adapted the method calls to the Schema accordingly.
>
> Please test if my changes were correct ;-)
>
> Peter
>
>
| |
| Peter Marschall 2006-01-16, 8:08 am |
| Hi Hans,
On Sunday, 15. January 2006 21:48, Hans.Klunder@bigfoot.com wrote:
> I've created a 0.14 (see attached patch ;-)) which contains more
> matching rules and some other small fixes.
>
> However to post patches, it would be very convenient to have *readonly*
> svn access.
> I tried using tortoise SVN but I get a forbidden. Am I doing something
> wrong ?
You should be able to create a local working copy of the repository using
the command "svn co http://svn.mutatus.co.uk/repos/perl-ldap/trunk/".
Using "svn diff" inside the perl-ldap directory you can generate the patch
of your changes, and using "svn update" you can update your working copy
to the latest changes from others.
(sorry, I'm a command line junkie ;-)
> I removed the "use Net::LDAP::Filter" & "use Net::LDAP::Schema" as it
> does not seem to harm code execution.
I'd like to keep then in to keep Perl happy even if the user did not specify
these two use clauses in his script.
Having them in does not hurt either ;-)
> The module seems to be strict, however the &$match is not allowed when
> strict is active (thats why my initial version used the eval )
Rest committed with a few changes (to make it a bit more readable for me ;-)))
Since the patch did not apply cleanly I had to apply a few hunks of it
manually. Please check if the result is what you wanted.
> Regarding the approx, we could use Text::Soundex or String::Approx and
> conditionally load that if present on the system, "just" a regexp would
> be perfect, but I haven't come across one yet ;-)
_cis_approxMatch() should do regexes already.
Have a try with the attached test file.
It might not be perfect (owing to interactions of the regex syntax with the
LDAP filter syntax) but better than none.
CU
Peter
--
Peter Marschall
eMail: peter@adpm.de
| |
| Hans.Klunder@bigfoot.com 2006-01-17, 7:10 pm |
| Peter,
I'm a bit too lazy for cmdline tools, however using /repos/ instead of
/wsvn/ also works for me, might be a hint in the project FAQ, creating a
diff is suddenly a breeze and so is keeping up with your versions ;-)
There's a bug in your version 0.14 which causes substring match with
schema to fail , it is fixed by the attached patch.
The regex match works, however its not very common for clients to
specify regexes (we might specify a new match for that ;-), I was
actually looking for something which matches things like
schmidt schmit schmitt etc... therefore I added a list of modules which
will be tried (String::Approx, Text::Metaphone, Text::Soundex in that
order) , if you have none it will fall back on the original regexp.
Cheers,
Hans
Peter Marschall schreef:
> Hi Hans,
>
> On Sunday, 15. January 2006 21:48, Hans.Klunder@bigfoot.com wrote:
>
>
> You should be able to create a local working copy of the repository using
> the command "svn co http://svn.mutatus.co.uk/repos/perl-ldap/trunk/".
> Using "svn diff" inside the perl-ldap directory you can generate the patch
> of your changes, and using "svn update" you can update your working copy
> to the latest changes from others.
> (sorry, I'm a command line junkie ;-)
>
>
> I'd like to keep then in to keep Perl happy even if the user did not specify
> these two use clauses in his script.
> Having them in does not hurt either ;-)
>
>
>
> Rest committed with a few changes (to make it a bit more readable for me ;-)))
>
> Since the patch did not apply cleanly I had to apply a few hunks of it
> manually. Please check if the result is what you wanted.
>
>
>
> _cis_approxMatch() should do regexes already.
> Have a try with the attached test file.
>
> It might not be perfect (owing to interactions of the regex syntax with the
> LDAP filter syntax) but better than none.
>
> CU
> Peter
>
>
| |
| Peter Marschall 2006-01-18, 7:09 pm |
| Hi,
On Tuesday, 17. January 2006 20:59, Hans.Klunder@bigfoot.com wrote:
> I'm a bit too lazy for cmdline tools, however using /repos/ instead of
> /wsvn/ also works for me, might be a hint in the project FAQ, creating a
> diff is suddenly a breeze and so is keeping up with your versions ;-)
>
> There's a bug in your version 0.14 which causes substring match with
> schema to fail , it is fixed by the attached patch.
Thanks for spotting the bug.
Whole patch committed to SVN.
You may now try "svn update" or its graphical equivalent ;-)
> The regex match works, however its not very common for clients to
> specify regexes (we might specify a new match for that ;-), I was
> actually looking for something which matches things like
> schmidt schmit schmitt etc... therefore I added a list of modules which
> will be tried (String::Approx, Text::Metaphone, Text::Soundex in that
> order) , if you have none it will fall back on the original regexp.
I guess specifying a new match is not possible.
What we might try is to convert a match a la
(sn~=Schm*dt) to a regex (i.e. add a . before the *)
but that might get very tricky with the subtleties of regexes
and LDAP filters.
So be better leave it the plain regex we have now.
I am not absolutely happy with the way how the
approx modules are selected.
I can imagine cases where I have all three installed
but want to do approx matching using metaphone.
(or even using regexes ;-)
Maybe you can use the idea we used in Authen-SASL
(get it from the same source as perl-ldap SVN ;-)
There we used the import() routine of the module to
choose the backend.
Using this idea for Net::LDAP::FilterMatch might allow
to write
use Net::DLAP::FilterMatch qw/Text::Soundex/;
to use Text::Soundex as approx matching backend.
What do you think of it ?
CU
PEter
--
Peter Marschall
eMail: peter@adpm.de
| |
| Hans.Klunder@bigfoot.com 2006-01-18, 7:09 pm |
| Peter,
sounds like a reasonable wish ( see attached patch ;-)
Allowing developers to specify their own matching module instead of the
ones we pre-cooked is a little tricky since every module uses a
different name for the match method and other peculiarities.
We could allow for:
use Net::DLAP::FilterMatch Text::Soundex=>soundex;
or
use Net::DLAP::FilterMatch qw(Text::Soundex::soundex);
But this becomes rather messy given the differences between modules, if
someone really wants something special he can always override the
_cis_approxMatch sub. What do you think ?
Cheers,
Hans
Peter Marschall wrote:
> Hi,
>
> [.....]
>
> I guess specifying a new match is not possible.
> What we might try is to convert a match a la
> (sn~=Schm*dt) to a regex (i.e. add a . before the *)
> but that might get very tricky with the subtleties of regexes
> and LDAP filters.
> So be better leave it the plain regex we have now.
>
> I am not absolutely happy with the way how the
> approx modules are selected.
> I can imagine cases where I have all three installed
> but want to do approx matching using metaphone.
> (or even using regexes ;-)
>
> Maybe you can use the idea we used in Authen-SASL
> (get it from the same source as perl-ldap SVN ;-)
>
> There we used the import() routine of the module to
> choose the backend.
>
> Using this idea for Net::LDAP::FilterMatch might allow
> to write
> use Net::DLAP::FilterMatch qw/Text::Soundex/;
> to use Text::Soundex as approx matching backend.
>
> What do you think of it ?
>
> CU
> PEter
>
>
| |
| Peter Marschall 2006-01-20, 8:00 am |
| Hi,
On Wednesday, 18. January 2006 21:30, Hans.Klunder@bigfoot.com wrote:
> sounds like a reasonable wish ( see attached patch ;-)
> Allowing developers to specify their own matching module instead of the
> ones we pre-cooked is a little tricky since every module uses a
> different name for the match method and other peculiarities.
> We could allow for:
>
> use Net::DLAP::FilterMatch Text::Soundex=>soundex;
>
> or
>
> use Net::DLAP::FilterMatch qw(Text::Soundex::soundex);
>
>
> But this becomes rather messy given the differences between modules, if
> someone really wants something special he can always override the
> _cis_approxMatch sub. What do you think ?
I am happy with the current implementation in your patch.
I do not think we need to allow any kind of approx matching module.
The three we have now should cover a broad range of applications.
Patch applied with a few changes:
- rename @Plugins (in "use vars" line) to @approxMatchers to have
one name for the beast
- reorder lines a bit: move "use vars" line before using the vars.
CU
Peter
--
Peter Marschall
eMail: peter@adpm.de
| |
| Hans.Klunder@bigfoot.com 2006-01-20, 7:16 pm |
| Peter,
Peter Marschall schreef:
> Hi,
>
> On Wednesday, 18. January 2006 21:30, Hans.Klunder@bigfoot.com wrote:
>
>
> I am happy with the current implementation in your patch.
>
> I do not think we need to allow any kind of approx matching module.
> The three we have now should cover a broad range of applications.
>
> Patch applied with a few changes:
> - rename @Plugins (in "use vars" line) to @approxMatchers to have
> one name for the beast
> - reorder lines a bit: move "use vars" line before using the vars.
>
> CU
> Peter
>
>
I appreciate your eye for detail regarding the vars, however the
reordering of the code broke the module.
The import must be in the Net::LDAP::FilterMatch section or else it will
not be called on import.
To ensure that I catch the vars errors myself (:-) I have made the
module strict again. That should cover most of these kind of typo's.
The attached patch repairs the import and also covers the strictness.
Cheers,
Hans
ps.if I find the time I'll try to make a test for this module.
| |
| Peter Marschall 2006-01-21, 3:57 am |
| Hi,
thanks for pointing that out.
Patch committed to SVN
Peter
On Friday, 20. January 2006 19:58, Hans.Klunder@bigfoot.com wrote:
> Peter,
>
> Peter Marschall schreef:
>
> I appreciate your eye for detail regarding the vars, however the
> reordering of the code broke the module.
> The import must be in the Net::LDAP::FilterMatch section or else it will
> not be called on import.
>
> To ensure that I catch the vars errors myself (:-) I have made the
> module strict again. That should cover most of these kind of typo's.
>
> The attached patch repairs the import and also covers the strictness.
>
> Cheers,
>
> Hans
> ps.if I find the time I'll try to make a test for this module.
--
Peter Marschall
eMail: peter@adpm.de
|
|
|
|
|