403Webshell
Server IP : 103.119.228.120  /  Your IP : 18.117.172.189
Web Server : Apache
System : Linux v8.techscape8.com 3.10.0-1160.119.1.el7.tuxcare.els2.x86_64 #1 SMP Mon Jul 15 12:09:18 UTC 2024 x86_64
User : nobody ( 99)
PHP Version : 5.6.40
Disable Function : shell_exec,symlink,system,exec,proc_get_status,proc_nice,proc_terminate,define_syslog_variables,syslog,openlog,closelog,escapeshellcmd,passthru,ocinum cols,ini_alter,leak,listen,chgrp,apache_note,apache_setenv,debugger_on,debugger_off,ftp_exec,dl,dll,myshellexec,proc_open,socket_bind,proc_close,escapeshellarg,parse_ini_filepopen,fpassthru,exec,passthru,escapeshellarg,escapeshellcmd,proc_close,proc_open,ini_alter,popen,show_source,proc_nice,proc_terminate,proc_get_status,proc_close,pfsockopen,leak,apache_child_terminate,posix_kill,posix_mkfifo,posix_setpgid,posix_setsid,posix_setuid,dl,symlink,shell_exec,system,dl,passthru,escapeshellarg,escapeshellcmd,myshellexec,c99_buff_prepare,c99_sess_put,fpassthru,getdisfunc,fx29exec,fx29exec2,is_windows,disp_freespace,fx29sh_getupdate,fx29_buff_prepare,fx29_sess_put,fx29shexit,fx29fsearch,fx29ftpbrutecheck,fx29sh_tools,fx29sh_about,milw0rm,imagez,sh_name,myshellexec,checkproxyhost,dosyayicek,c99_buff_prepare,c99_sess_put,c99getsource,c99sh_getupdate,c99fsearch,c99shexit,view_perms,posix_getpwuid,posix_getgrgid,posix_kill,parse_perms,parsesort,view_perms_color,set_encoder_input,ls_setcheckboxall,ls_reverse_all,rsg_read,rsg_glob,selfURL,dispsecinfo,unix2DosTime,addFile,system,get_users,view_size,DirFiles,DirFilesWide,DirPrintHTMLHeaders,GetFilesTotal,GetTitles,GetTimeTotal,GetMatchesCount,GetFileMatchesCount,GetResultFiles,fs_copy_dir,fs_copy_obj,fs_move_dir,fs_move_obj,fs_rmdir,SearchText,getmicrotime
MySQL : ON |  cURL : ON |  WGET : ON |  Perl : ON |  Python : ON |  Sudo : ON |  Pkexec : ON
Directory :  /usr/local/ssl/local/ssl/local/ssl/local/share/man/man3/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /usr/local/ssl/local/ssl/local/ssl/local/share/man/man3/Net::IP::Match::Regexp.3pm
.\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28)
.\"
.\" Standard preamble:
.\" ========================================================================
.de Sp \" Vertical space (when we can't use .PP)
.if t .sp .5v
.if n .sp
..
.de Vb \" Begin verbatim text
.ft CW
.nf
.ne \\$1
..
.de Ve \" End verbatim text
.ft R
.fi
..
.\" Set up some character translations and predefined strings.  \*(-- will
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
.\" double quote, and \*(R" will give a right double quote.  \*(C+ will
.\" give a nicer C++.  Capital omega is used to do unbreakable dashes and
.\" therefore won't be available.  \*(C` and \*(C' expand to `' in nroff,
.\" nothing in troff, for use with C<>.
.tr \(*W-
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
.ie n \{\
.    ds -- \(*W-
.    ds PI pi
.    if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
.    if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\"  diablo 12 pitch
.    ds L" ""
.    ds R" ""
.    ds C` ""
.    ds C' ""
'br\}
.el\{\
.    ds -- \|\(em\|
.    ds PI \(*p
.    ds L" ``
.    ds R" ''
.    ds C`
.    ds C'
'br\}
.\"
.\" Escape single quotes in literal strings from groff's Unicode transform.
.ie \n(.g .ds Aq \(aq
.el       .ds Aq '
.\"
.\" If the F register is turned on, we'll generate index entries on stderr for
.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
.\" entries marked with X<> in POD.  Of course, you'll have to process the
.\" output yourself in some meaningful fashion.
.\"
.\" Avoid warning from groff about undefined register 'F'.
.de IX
..
.nr rF 0
.if \n(.g .if rF .nr rF 1
.if (\n(rF:(\n(.g==0)) \{
.    if \nF \{
.        de IX
.        tm Index:\\$1\t\\n%\t"\\$2"
..
.        if !\nF==2 \{
.            nr % 0
.            nr F 2
.        \}
.    \}
.\}
.rr rF
.\"
.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
.\" Fear.  Run.  Save yourself.  No user-serviceable parts.
.    \" fudge factors for nroff and troff
.if n \{\
.    ds #H 0
.    ds #V .8m
.    ds #F .3m
.    ds #[ \f1
.    ds #] \fP
.\}
.if t \{\
.    ds #H ((1u-(\\\\n(.fu%2u))*.13m)
.    ds #V .6m
.    ds #F 0
.    ds #[ \&
.    ds #] \&
.\}
.    \" simple accents for nroff and troff
.if n \{\
.    ds ' \&
.    ds ` \&
.    ds ^ \&
.    ds , \&
.    ds ~ ~
.    ds /
.\}
.if t \{\
.    ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
.    ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
.    ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
.    ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
.    ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
.    ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
.\}
.    \" troff and (daisy-wheel) nroff accents
.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
.ds ae a\h'-(\w'a'u*4/10)'e
.ds Ae A\h'-(\w'A'u*4/10)'E
.    \" corrections for vroff
.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
.    \" for low resolution devices (crt and lpr)
.if \n(.H>23 .if \n(.V>19 \
\{\
.    ds : e
.    ds 8 ss
.    ds o a
.    ds d- d\h'-1'\(ga
.    ds D- D\h'-1'\(hy
.    ds th \o'bp'
.    ds Th \o'LP'
.    ds ae ae
.    ds Ae AE
.\}
.rm #[ #] #H #V #F C
.\" ========================================================================
.\"
.IX Title "Net::IP::Match::Regexp 3"
.TH Net::IP::Match::Regexp 3 "2016-08-24" "perl v5.16.3" "User Contributed Perl Documentation"
.\" For nroff, turn off justification.  Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
.nh
.SH "NAME"
Net::IP::Match::Regexp \- Efficiently match IP addresses against ranges
.SH "LICENSE"
.IX Header "LICENSE"
Copyright 2005\-2006 Clotho Advanced Media, Inc., <cpan@clotho.com>
.PP
Copyright 2007\-2008 Chris Dolan, <cdolan@cpan.org>
.PP
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
.SH "SYNOPSIS"
.IX Header "SYNOPSIS"
.Vb 1
\&    use Net::IP::Match::Regexp qw( create_iprange_regexp match_ip );
\&    
\&    my $regexp = create_iprange_regexp(
\&       qw( 10.0.0.0/8 87.134.66.128 87.134.87.0/24 145.97.0.0/16 )
\&    );
\&    if (match_ip(\*(Aq209.249.163.62\*(Aq, $regexp)) {
\&       ...
\&    }
.Ve
.SH "DESCRIPTION"
.IX Header "DESCRIPTION"
This module allows you to check an \s-1IP\s0 address against one or more \s-1IP\s0
ranges.  It employs Perl's highly optimized regular expression engine
to do the hard work, so it is very fast.  It is optimized for speed by
doing the match against a regexp which implicitly checks the broadest
\&\s-1IP\s0 ranges first.  An advantage is that the regexp can be computed and
stored in advance (in source code, in a database table, etc) and
reused, saving much time if the \s-1IP\s0 ranges don't change too often.  The
match can optionally report a value (e.g. a network name) instead of
just a boolean, which makes module useful for mapping \s-1IP\s0 ranges to
names or codes or anything else.
.SH "LIMITATIONS"
.IX Header "LIMITATIONS"
This module does not yet support IPv6 addresses, although that feature
should not be hard to implement as long as the regexps start with a 4
vs. 6 flag.  Patches welcome.  :\-)
.PP
This module only accepts \s-1IP\s0 ranges in \f(CW\*(C`a.b.c.d/x\*(C'\fR (aka \s-1CIDR\s0)
notation.  To work around that limitation, I recommend
Net::CIDR::Lite to conveniently convert collections of \s-1IP\s0 address
ranges into \s-1CIDR\s0 format.
.PP
This module makes no effort to validate the \s-1IP\s0 addresses or ranges
passed as arguments.  If you pass address ranges like
\&\f(CW\*(C`1000.0.0.0/300\*(C'\fR, you will probably get weird regexps out.
.SH "FUNCTIONS"
.IX Header "FUNCTIONS"
.ie n .IP "create_iprange_regexp($iprange | $hashref | $arrayref, ...)" 4
.el .IP "create_iprange_regexp($iprange | \f(CW$hashref\fR | \f(CW$arrayref\fR, ...)" 4
.IX Item "create_iprange_regexp($iprange | $hashref | $arrayref, ...)"
This function digests \s-1IP\s0 ranges into a regular expression that can
subsequently be used to efficiently test single \s-1IP\s0 addresses.  It
returns a regular expression string that can be passed to \fImatch_ip()\fR.
.Sp
The simple way to use this is to pass a list of \s-1IP\s0 ranges as
\&\f(CW\*(C`aaa.bbb.ccc.ddd/n\*(C'\fR.  When used this way, the return value of the
\&\fImatch_ip()\fR function will be simply \f(CW1\fR or \f(CW\*(C`undef\*(C'\fR.
.Sp
The more complex way is to pass a hash reference of \s-1IP\s0 range => return
value pairs.  When used this way, the return value of the \fImatch_ip()\fR
function will be the specified return value or \f(CW\*(C`undef\*(C'\fR for no match.
.Sp
For example:
.Sp
.Vb 2
\&    my $re1 = create_iprange_regexp(\*(Aq209.249.163.0/25\*(Aq, \*(Aq127.0.0.1/32\*(Aq);
\&    print match_ip(\*(Aq209.249.163.62\*(Aq, $re1); # prints \*(Aq1\*(Aq
\&    
\&    my $re2 = create_iprange_regexp({\*(Aq209.249.163.0/25\*(Aq => \*(Aqclotho.com\*(Aq,
\&                                     \*(Aq127.0.0.1/32\*(Aq => \*(Aqlocalhost\*(Aq});
\&    print match_ip(\*(Aq209.249.163.62\*(Aq, $re2); # prints \*(Aqclotho.com\*(Aq
.Ve
.Sp
Be aware that the value string will be wrapped in single quotes in the
regexp.  Therefore, you must double-escape any single quotes in that
value.  For example:
.Sp
.Vb 1
\&    create_iprange_regexp({\*(Aq208.201.239.36/31\*(Aq => \*(AqO\e\e\*(AqReilly publishing\*(Aq});
.Ve
.Sp
Note that the scalar and hash styles can be mixed (a rarely used
feature).  These two examples are equivalent:
.Sp
.Vb 4
\&    create_iprange_regexp(\*(Aq127.0.0.1/32\*(Aq,
\&                          {\*(Aq209.249.163.0/25\*(Aq => \*(Aqclotho.com\*(Aq},
\&                          \*(Aq10.0.0.0/8\*(Aq,
\&                          {\*(Aq192.168.0.0/16\*(Aq => \*(AqLAN\*(Aq});
\&    
\&    create_iprange_regexp({\*(Aq127.0.0.1/32\*(Aq => 1,
\&                           \*(Aq209.249.163.0/25\*(Aq => \*(Aqclotho.com\*(Aq,
\&                           \*(Aq10.0.0.0/8\*(Aq => 1,
\&                           \*(Aq192.168.0.0/16\*(Aq => \*(AqLAN\*(Aq});
.Ve
.Sp
If any of the \s-1IP\s0 ranges are overlapping, the broadest one is used.  If
they are equivalent, then the first one passed is used.  If you have
some data that might be ambiguous, you pass an arrayref instead of a
hashref, but it's better to clean up your data instead!  For example:
.Sp
.Vb 2
\&    my $re = create_iprange_regexp([\*(Aq1.1.1.0/31\*(Aq => \*(Aqzero\*(Aq, \*(Aq1.1.1.1/31\*(Aq => \*(Aqone\*(Aq]);
\&    print match_ip(\*(Aq1.1.1.1\*(Aq, $re));   # prints \*(Aqzero\*(Aq, since both match
.Ve
.Sp
\&\s-1WARNING:\s0 This function does no checking for validity of \s-1IP\s0 ranges.  It
happily accepts \f(CW\*(C`1000.0.0.0/\-38\*(C'\fR and makes a garbage regexp.
Hopefully a future version will validate the ranges, perhaps via
Net::CIDR or Net::IP.
.ie n .IP "create_iprange_regexp_depthfirst($iprange | $hashref | $arrayref, ...)" 4
.el .IP "create_iprange_regexp_depthfirst($iprange | \f(CW$hashref\fR | \f(CW$arrayref\fR, ...)" 4
.IX Item "create_iprange_regexp_depthfirst($iprange | $hashref | $arrayref, ...)"
Returns a regexp in matches the most specific \s-1IP\s0 range instead of the
broadest range.  Example:
.Sp
.Vb 3
\&    my $re = create_iprange_regexp_depthfirst({\*(Aq192.168.0.0/16\*(Aq => \*(AqLAN\*(Aq,
\&                                               \*(Aq192.168.0.1\*(Aq => \*(Aqrouter\*(Aq});
\&    match_ip(\*(Aq192.168.0.1\*(Aq, $re);
.Ve
.Sp
returns 'router' instead of '\s-1LAN\s0'.
.ie n .IP "match_ip($ipaddr, $regexp)" 4
.el .IP "match_ip($ipaddr, \f(CW$regexp\fR)" 4
.IX Item "match_ip($ipaddr, $regexp)"
Given a single \s-1IP\s0 address as a string of the form \f(CW\*(C`aaa.bbb.ccc.ddd\*(C'\fR
and a regular expression string (typically the output of
\&\fIcreate_iprange_regexp()\fR), this function returns a specified value
(typically \f(CW1\fR) if the \s-1IP\s0 is in one of the ranges, or \f(CW\*(C`undef\*(C'\fR if no
ranges match.
.Sp
See \fIcreate_ipranges_regexp()\fR for more details about the return value
of this function.
.Sp
\&\s-1WARNING:\s0 This function does no checking for validity of the \s-1IP\s0 address.
.SH "SEE ALSO"
.IX Header "SEE ALSO"
There are several other \s-1CPAN\s0 modules that perform a similar function.
This one is comparable to or faster than the other ones that I've
found and tried.  Here is a synopsis of those others:
.SS "Net::IP::Match"
.IX Subsection "Net::IP::Match"
Optimized for speed by taking a \*(L"source filter\*(R" approach.  That is, it
modifies your source code at run time, kind of like a C preprocessor.
A huge limitation is that the \s-1IP\s0 ranges must be hard-coded into your
program.
.SS "Net::IP::Match::XS"
.IX Subsection "Net::IP::Match::XS"
(Also released as Net::IP::CMatch)
.PP
Optimized for speed by doing the match in C instead of in Perl.  This
module loses efficiency, however, because the \s-1IP\s0 ranges must be
re-parsed every invocation.
.SS "Net::IP::Resolver"
.IX Subsection "Net::IP::Resolver"
Uses Net::IP::Match::XS to implement a range-to-name map.
.SH "PERFORMANCE"
.IX Header "PERFORMANCE"
I ran a series of test on a Mac G5 with Perl 5.8.6 to compare this
module to Net::IP::Match::XS.  The tests are intended to be a
realistic net filter case: 100,000 random \s-1IP\s0 addresses tested against
a number of semi-random \s-1IP\s0 ranges.  Times are in seconds.
.PP
.Vb 5
\&    Networks: 1, IPs: 100000
\&    Test name              | Setup time | Run time | Total time 
\&    \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-
\&    Net::IP::Match::XS     |    0.000   |  0.415   |    0.415   
\&    Net::IP::Match::Regexp |    0.001   |  1.141   |    1.141   
\&    
\&    Networks: 10, IPs: 100000
\&    Test name              | Setup time | Run time | Total time 
\&    \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-
\&    Net::IP::Match::XS     |    0.000   |  0.613   |    0.613   
\&    Net::IP::Match::Regexp |    0.003   |  1.312   |    1.316   
\&    
\&    Networks: 100, IPs: 100000
\&    Test name              | Setup time | Run time | Total time 
\&    \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-
\&    Net::IP::Match::XS     |    0.000   |  2.621   |    2.622   
\&    Net::IP::Match::Regexp |    0.024   |  1.381   |    1.405   
\&    
\&    Networks: 1000, IPs: 100000
\&    Test name              | Setup time | Run time | Total time 
\&    \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-
\&    Net::IP::Match::XS     |    0.003   | 20.910   |   20.912   
\&    Net::IP::Match::Regexp |    0.203   |  1.514   |    1.717
.Ve
.PP
This test indicates that ::Regexp is faster than ::XS when you have
more than about 50 \s-1IP\s0 ranges to test.  The relative run time does not
vary significantly with the number of singe \s-1IP\s0 to match, but with a
small number of \s-1IP\s0 addresses to match, the setup time begins to
dominate, so ::Regexp loses in that scenario.
.PP
To reproduce the above benchmarks, run the following command in the
distribution directory:
.PP
.Vb 1
\&   perl benchmark/speedtest.pl \-s \-n 1,10,100,1000 \-i 100000
.Ve
.SH "IMPLEMENTATION"
.IX Header "IMPLEMENTATION"
The speed of this module comes from the short-circuit nature of
regular expressions.  The setup function turns all of the \s-1IP\s0 ranges
into binary strings, and mixes them into a regexp with \f(CW\*(C`|\*(C'\fR choices
between ones and zeros.  This regexp can then be passed to the match
function.  When an unambiguous match is found, the regexp sets a
variable (via the regexp \f(CW$LAST_REGEXP_CODE_RESULT\fR, aka $^R, feature)
and terminates.  That variable becomes the return value for the match,
typically a true value.
.PP
Here's an example of the regexp for a single range, that of the
Clotho.com subnet:
.PP
.Vb 2
\&    print create_iprange_regexp(\*(Aq209.249.163.0/25\*(Aq)\*(Aq
\&    # ^41101000111111001101000110(?{\*(Aq1\*(Aq})
.Ve
.PP
If we add another range, say a \s-1NAT LAN,\s0 we get:
.PP
.Vb 2
\&    print create_iprange_regexp(\*(Aq209.249.163.0/25\*(Aq, \*(Aq192.168.0.0/16\*(Aq)\*(Aq
\&    # ^4110(?>0000010101000(?{\*(Aq1\*(Aq})|1000111111001101000110(?{\*(Aq1\*(Aq}))
.Ve
.PP
Note that for a 192.168.x.x address, the regexp checks at most the
first 16 bits (1100000010101000) whereas for a 209.249.163.x address,
it goes out to 25 bits (1101000111111001101000110).  The cool part is
that for an \s-1IP\s0 address that starts in the lower half (say 127.0.0.1)
only needs to check the first bit (0) to see that the regexp won't
match.
.PP
If mapped return values are specified for the ranges, they get embedded
into the regexp like so:
.PP
.Vb 3
\&    print create_iprange_regexp({\*(Aq209.249.163.0/25\*(Aq => \*(Aqclotho.com\*(Aq,
\&                                 \*(Aq192.168.0.0/16\*(Aq => \*(Aqlocalhost\*(Aq})\*(Aq
\&    # ^4110(?>0000010101000(?{\*(Aqlocalhost\*(Aq})|1000111111001101000110(?{\*(Aqclotho.com\*(Aq}))
.Ve
.PP
This could be implemented in C to be even faster.  In C, it would
probably be better to use a binary tree instead of a regexp.  However,
a goal of this module is to create a serializable representation of
the range data, and the regexp is perfect for that.  So, I'll
probably never do a C version.
.SH "COMPATIBILITY"
.IX Header "COMPATIBILITY"
Because this module relies on the \f(CW\*(C`(?{ code })\*(C'\fR feature of regexps,
it won't work on old Perl versions.  I've successfully tested this
module on Perl 5.6.0, 5.8.1 and 5.8.6.  In theory, the code regexp
feature should work in 5.005, but I've used \f(CW\*(C`our\*(C'\fR and the like, so it
won't work there.  I don't have a 5.005 to test anyway...
.PP
Update from Oct 2008: I no longer keep a 5.6.0 around, so I rely on
cpantesters.org to tell me when this breaks for older Perls.
.SH "CODING"
.IX Header "CODING"
This module has 100% code coverage in its regression tests, as
reported by Devel::Cover via \f(CW\*(C`perl Build testcover\*(C'\fR.
.PP
This module passes Perl Best Practices guidelines, as enforced by
Perl::Critic v1.093.
.SH "AUTHOR"
.IX Header "AUTHOR"
Chris Dolan
.PP
I originally developed this module at Clotho Advanced Media Inc.  Now
I maintain it in my spare time.
.SH "ACKNOWLEDGMENTS"
.IX Header "ACKNOWLEDGMENTS"
TeachingBooks.net inspired and subsidized development of the original
version of this module.
.PP
Chris Snyder contributed a valuable and well-written bug report about
handling missing mask values.
.PP
Michael Aronsen of cohaesio.com suggested the depth-first matching
feature.

Youez - 2016 - github.com/yon3zu
LinuXploit