Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
lemonldap-ng
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
258
Issues
258
List
Boards
Labels
Service Desk
Milestones
Merge Requests
5
Merge Requests
5
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
CI / CD
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
LemonLDAP NG
lemonldap-ng
Commits
703b3d64
Commit
703b3d64
authored
Dec 15, 2009
by
Yadd
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
New feature : convertConfig
parent
b289a536
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
232 additions
and
245 deletions
+232
-245
build/lemonldap-ng/Makefile
build/lemonldap-ng/Makefile
+1
-2
build/lemonldap-ng/debian/README.Debian
build/lemonldap-ng/debian/README.Debian
+1
-9
build/lemonldap-ng/debian/liblemonldap-ng-conf-perl.install
build/lemonldap-ng/debian/liblemonldap-ng-conf-perl.install
+1
-1
modules/lemonldap-ng-common/MANIFEST
modules/lemonldap-ng-common/MANIFEST
+2
-2
modules/lemonldap-ng-common/Makefile.PL
modules/lemonldap-ng-common/Makefile.PL
+1
-1
modules/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf.pm
modules/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf.pm
+10
-6
modules/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/DBI.pm
...s/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/DBI.pm
+1
-2
modules/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/RDBI.pm
.../lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/RDBI.pm
+144
-0
modules/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/Serializer.pm
...ldap-ng-common/lib/Lemonldap/NG/Common/Conf/Serializer.pm
+5
-2
modules/lemonldap-ng-common/scripts/convertConfig
modules/lemonldap-ng-common/scripts/convertConfig
+66
-0
modules/lemonldap-ng-common/scripts/lmConfig_File2LDIF
modules/lemonldap-ng-common/scripts/lmConfig_File2LDIF
+0
-109
modules/lemonldap-ng-common/scripts/lmConfig_File2MySQL
modules/lemonldap-ng-common/scripts/lmConfig_File2MySQL
+0
-111
No files found.
build/lemonldap-ng/Makefile
View file @
703b3d64
...
...
@@ -202,8 +202,7 @@ install_bin: install_libs install_conf_dir
@
cp
--preserve
=
mode
--remove-destination
\
${SRCPORTALDIR}
/example/scripts/purgeCentralCache
\
${SRCPORTALDIR}
/example/scripts/buildPortalWSDL
\
${SRCCOMMONDIR}
/scripts/lmConfig_File2MySQL
\
${SRCCOMMONDIR}
/scripts/lmConfig_File2LDIF
\
${SRCCOMMONDIR}
/scripts/convertConfig
\
${SRCMANAGERDIR}
/example/scripts/lmConfigEditor
\
$(RBINDIR)
chmod
+x
$(RBINDIR)
/
*
...
...
build/lemonldap-ng/debian/README.Debian
View file @
703b3d64
...
...
@@ -54,13 +54,5 @@ Modify /etc/lemonldap-ng/storage.conf to change configuration storage.
1.1 - Migrating from 'File' to 'DBI'
To use DBI mechanism to store configuration, you have to create database. An
example is given for MySQL in the file
/usr/share/doc/liblemonldap-ng-conf-perl/examples/lmConfig.mysql.
If you have a running configuration, use this to populate SQL database :
perl /usr/share/lemonldap-ng/bin/lmConfig_File2MySQL -c \
/var/lib/lemonldap-ng/conf/lmConf-<last-number>
"-c" options adds "create table" instruction.
Use the script /usr/share/lemonldap-ng/bin/convertConfig
build/lemonldap-ng/debian/liblemonldap-ng-conf-perl.install
View file @
703b3d64
...
...
@@ -3,5 +3,5 @@ debian/tmp/etc/lemonldap-ng/for_etc_hosts
debian
/
tmp
/
usr
/
share
/
perl5
/
Lemonldap
/
NG
/
Common
*
debian
/
tmp
/
usr
/
share
/
man
/
man3
/
Lemonldap
::
NG
::
Common
*
debian
/
tmp
/
usr
/
share
/
lemonldap
-
ng
/
ressources
debian
/
tmp
/
usr
/
share
/
lemonldap
-
ng
/
bin
/
lmConfig_File2MySQL
debian
/
tmp
/
usr
/
share
/
lemonldap
-
ng
/
bin
/
convertConfig
debian
/
tmp
/
var
/
lib
/
lemonldap
-
ng
/
conf
/
modules/lemonldap-ng-common/MANIFEST
View file @
703b3d64
...
...
@@ -12,6 +12,7 @@ lib/Lemonldap/NG/Common/Conf/CDBI.pm
lib/Lemonldap/NG/Common/Conf/DBI.pm
lib/Lemonldap/NG/Common/Conf/File.pm
lib/Lemonldap/NG/Common/Conf/LDAP.pm
lib/Lemonldap/NG/Common/Conf/RDBI.pm
lib/Lemonldap/NG/Common/Conf/SOAP.pm
lib/Lemonldap/NG/Common/Conf/Serializer.pm
lib/Lemonldap/NG/Common/Crypto.pm
...
...
@@ -20,8 +21,7 @@ Makefile.PL
MANIFEST
META.yml Module meta-data (added by MakeMaker)
README
scripts/lmConfig_File2LDIF
scripts/lmConfig_File2MySQL
scripts/convertConfig
lemonldap-ng.ini
t/01-Common-Conf.t
t/02-Common-Conf-File.t
...
...
modules/lemonldap-ng-common/Makefile.PL
View file @
703b3d64
...
...
@@ -34,7 +34,7 @@ WriteMakefile(
'
HTTP::Headers
'
=>
0
,
'
Config::IniFiles
'
=>
0
,
},
# e.g., Module::Name => 1.1
#EXE_FILES => [ 'scripts/
lmConfig_File2MySQL
', ],
#EXE_FILES => [ 'scripts/
convertConfig
', ],
(
$]
>=
5.005
?
## Add these new keywords supported since 5.005
...
...
modules/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf.pm
View file @
703b3d64
...
...
@@ -10,7 +10,8 @@ package Lemonldap::NG::Common::Conf;
use
strict
;
no
strict
'
refs
';
use
Lemonldap::NG::Common::Conf::
Constants
;
#inherits
use
Lemonldap::NG::Common::
Crypto
;
#link protected cipher Object "cypher" in configuration hash
use
Lemonldap::NG::Common::
Crypto
;
#link protected cipher Object "cypher" in configuration hash
use
Regexp::
Assemble
;
use
Config::
IniFiles
;
...
...
@@ -100,9 +101,10 @@ sub saveConf {
# If configuration was modified, return an error
return
CONFIG_WAS_CHANGED
if
(
$conf
->
{
cfgNum
}
!=
$self
->
lastCfg
or
$self
->
isLocked
);
if
(
not
(
$self
->
{
force
}
)
and
(
$conf
->
{
cfgNum
}
!=
$self
->
lastCfg
or
$self
->
isLocked
)
);
$self
->
lock
or
return
DATABASE_LOCKED
;
$conf
->
{
cfgNum
}
++
;
$conf
->
{
cfgNum
}
++
unless
(
$self
->
{
cfgNumFixed
}
)
;
$msg
=
"
Configuration
$conf
->{cfgNum} stored
";
return
$self
->
store
(
$conf
);
}
...
...
@@ -190,9 +192,7 @@ sub getLocalConf {
}
# Parse ini file
my
$cfg
=
Config::
IniFiles
->
new
(
-
file
=>
$file
,
);
my
$cfg
=
Config::
IniFiles
->
new
(
-
file
=>
$file
,
);
unless
(
defined
$cfg
)
{
$msg
=
"
Local config error:
"
.
@
Config::IniFiles::
errors
;
...
...
@@ -351,6 +351,10 @@ sub delete {
return
&
{
$self
->
{
type
}
.
'
::delete
'
}(
$self
,
$a
[
$#a
+
$c
]
);
}
sub
logError
{
return
&
{
$_
[
0
]
->
{
type
}
.
'
::logError
'
}(
@
_
);
}
1
;
__END__
...
...
modules/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/DBI.pm
View file @
703b3d64
...
...
@@ -91,11 +91,10 @@ sub store {
$self
->
logError
;
return
UNKNOWN_ERROR
;
}
eval
{
$self
->
dbh
->
do
("
COMMIT
");
};
unless
(
$self
->
unlock
)
{
$self
->
logError
;
return
UNKNOWN_ERROR
;
}
eval
{
$self
->
dbh
->
do
("
COMMIT
");
};
return
$fields
->
{
cfgNum
};
}
...
...
modules/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/RDBI.pm
0 → 100644
View file @
703b3d64
package
Lemonldap::NG::Common::Conf::
RDBI
;
use
strict
;
use
DBI
;
use
Lemonldap::NG::Common::Conf::
Constants
;
#inherits
use
Lemonldap::NG::Common::Conf::
Serializer
;
our
$VERSION
=
0.17
;
BEGIN
{
*
Lemonldap::NG::Common::Conf::
dbh
=
\
&dbh
;
}
sub
prereq
{
my
$self
=
shift
;
unless
(
$self
->
{
dbiChain
}
)
{
$
Lemonldap::NG::Common::Conf::
msg
=
'
"dbiChain" is required in RDBI configuration type
';
return
0
;
}
print
STDERR
__PACKAGE__
.
'
Warning: "dbiUser" parameter is not set
'
unless
(
$self
->
{
dbiUser
}
);
$self
->
{
dbiTable
}
||=
"
lmConfig
";
1
;
}
sub
available
{
my
$self
=
shift
;
my
$sth
=
$self
->
dbh
->
prepare
(
"
SELECT DISTINCT cfgNum from
"
.
$self
->
{
dbiTable
}
.
"
order by cfgNum
"
);
$sth
->
execute
();
my
@conf
;
while
(
my
@row
=
$sth
->
fetchrow_array
)
{
push
@conf
,
$row
[
0
];
}
return
@conf
;
}
sub
lastCfg
{
my
$self
=
shift
;
my
@row
=
$self
->
dbh
->
selectrow_array
(
"
SELECT max(cfgNum) from
"
.
$self
->
{
dbiTable
}
);
return
$row
[
0
];
}
sub
dbh
{
my
$self
=
shift
;
$self
->
{
dbiTable
}
||=
"
lmConfig
";
return
$self
->
{
dbh
}
if
(
$self
->
{
dbh
}
and
$self
->
{
dbh
}
->
ping
);
return
DBI
->
connect_cached
(
$self
->
{
dbiChain
},
$self
->
{
dbiUser
},
$self
->
{
dbiPassword
},
{
RaiseError
=>
1
}
);
}
sub
lock
{
my
$self
=
shift
;
my
$sth
=
$self
->
dbh
->
prepare_cached
(
q{SELECT GET_LOCK(?, 5)}
,
{},
1
);
$sth
->
execute
('
lmconfrdbi
');
my
@row
=
$sth
->
fetchrow_array
;
return
$row
[
0
]
||
0
;
}
sub
isLocked
{
my
$self
=
shift
;
my
$sth
=
$self
->
dbh
->
prepare_cached
(
q{SELECT IS_FREE_LOCK(?)}
,
{},
1
);
$sth
->
execute
('
lmconfrdbi
');
my
@row
=
$sth
->
fetchrow_array
;
return
$row
[
0
]
?
0
:
1
;
}
sub
unlock
{
my
$self
=
shift
;
my
$sth
=
$self
->
dbh
->
prepare_cached
(
q{SELECT RELEASE_LOCK(?)}
,
{},
1
);
$sth
->
execute
('
lmconfrdbi
');
my
@row
=
$sth
->
fetchrow_array
;
return
$row
[
0
]
||
0
;
}
sub
store
{
my
(
$self
,
$fields
)
=
@_
;
$self
->
{
noQuotes
}
=
1
;
$fields
=
$self
->
serialize
(
$fields
);
my
$errors
=
0
;
eval
{
$self
->
dbh
->
do
('
BEGIN
');
};
while
(
my
(
$k
,
$v
)
=
each
%$fields
)
{
unless
(
$self
->
dbh
->
do
(
"
insert into
"
.
$self
->
{
dbiTable
}
.
"
(cfgNum,field,value) values (
"
.
join
(
'
,
',
$fields
->
{
cfgNum
},
"
'
$k
'
",
"
'
$v
'
"
)
.
'
)
'
)
)
{
$self
->
logError
;
$errors
++
;
last
;
}
}
eval
{
$errors
?
$self
->
dbh
->
do
("
ROLLBACK
")
:
$self
->
dbh
->
do
("
COMMIT
");
};
unless
(
$self
->
unlock
)
{
$self
->
logError
;
}
return
$errors
?
UNKNOWN_ERROR
:
$fields
->
{
cfgNum
};
}
sub
load
{
my
(
$self
,
$cfgNum
,
$fields
)
=
@_
;
$fields
=
$fields
?
join
(
"
,
",
@$fields
)
:
'
*
';
my
$sth
=
$self
->
dbh
->
prepare
(
"
SELECT cfgNum,field,value from
"
.
$self
->
{
dbiTable
}
.
"
WHERE cfgNum=
$cfgNum
"
);
$sth
->
execute
();
my
(
$res
,
@row
);
while
(
@row
=
$sth
->
fetchrow_array
)
{
$res
->
{
$row
[
1
]
}
=
$row
[
2
];
}
unless
(
$res
)
{
$
Lemonldap::NG::Common::Conf::
msg
.=
"
No configuration
$cfgNum
found
";
return
0
;
}
$res
->
{
cfgNum
}
=
$cfgNum
;
return
$self
->
unserialize
(
$res
);
}
sub
delete
{
my
(
$self
,
$cfgNum
)
=
@_
;
$self
->
dbh
->
do
(
"
DELETE from
"
.
$self
->
{
dbiTable
}
.
"
WHERE cfgNum=
$cfgNum
"
);
}
sub
logError
{
my
$self
=
shift
;
$
Lemonldap::NG::Common::Conf::
msg
.=
"
Database error:
"
.
$self
->
dbh
->
errstr
.
"
\n
";
}
1
;
__END__
modules/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/Serializer.pm
View file @
703b3d64
...
...
@@ -17,7 +17,7 @@ sub serialize {
if
(
ref
(
$v
)
)
{
$fields
->
{
$k
}
=
Dumper
(
$v
);
$fields
->
{
$k
}
=~
s/'/'/g
;
$fields
->
{
$k
}
=
"
'
$fields
->{
$k
}'
";
$fields
->
{
$k
}
=
"
'
$fields
->{
$k
}'
"
unless
(
$self
->
{
noQuotes
}
)
;
}
elsif
(
$v
=~
/^\d+$/
)
{
$fields
->
{
$k
}
=
"
$v
";
...
...
@@ -29,7 +29,9 @@ sub serialize {
# trim
$v
=~
s/^\s*(.*?)\s*$/$1/
;
$fields
->
{
$k
}
=
"
'
$v
'
";
$v
=~
s/'/'/g
;
$v
=
"
'
$v
'
"
unless
(
$self
->
{
noQuotes
}
);
$fields
->
{
$k
}
=
$v
;
}
}
return
$fields
;
...
...
@@ -68,6 +70,7 @@ sub unserialize {
}
}
else
{
$v
=~
s/&#?39;/'/g
;
$conf
->
{
$k
}
=
$v
;
}
}
...
...
modules/lemonldap-ng-common/scripts/convertConfig
0 → 100755
View file @
703b3d64
#!/usr/bin/perl
use
strict
;
use
Getopt::
Long
;
use
Lemonldap::NG::Common::
Conf
;
my
%opts
;
my
$result
=
GetOptions
(
\
%opts
,
'
help|h
',
'
current|c=s
',
'
new|n=s
',
'
latest|l
'
);
if
(
$opts
{
help
}
or
not
(
$opts
{
current
}
and
$opts
{
new
}
)
)
{
print
STDERR
"
Usage: $0 --current=/current/lemonldap-ng.ini --new=/new/lemonldap-ng.ini
\n
";
print
STDERR
"
# other parameters:
--latest -l
convert only last configuration
";
exit
1
;
}
foreach
(
$opts
{
current
},
$opts
{
new
}
)
{
unless
(
-
e
$_
)
{
print
STDERR
"
$_
does not exist
\n
";
exit
2
;
}
unless
(
-
r
$_
)
{
print
STDERR
"
$_
is not readable
\n
";
exit
3
;
}
}
my
$old
=
Lemonldap::NG::Common::
Conf
->
new
({
confFile
=>
$opts
{
current
},
noCache
=>
1
,
});
unless
(
$old
)
{
print
STDERR
"
Failed to get current conf :
$Lemonldap
::NG::Common::Conf::msg
\n
";
exit
4
;
}
my
$new
=
Lemonldap::NG::Common::
Conf
->
new
({
confFile
=>
$opts
{
new
},
force
=>
1
,
noCache
=>
1
,
cfgNumFixed
=>
1
,
});
unless
(
$new
)
{
print
STDERR
"
Failed to create new conf object :
$Lemonldap
::NG::Common::Conf::msg
\n
";
exit
5
;
}
my
@available
;
if
(
$opts
{
lastest
}){
@available
=
$old
->
lastCfg
();
}
else
{
@available
=
$old
->
available
();
}
foreach
(
@available
)
{
my
$conf
=
$old
->
getConf
({
cfgNum
=>
$_
});
eval
{
delete
$conf
->
{
reVHosts
};
delete
$conf
->
{
cipher
};
};
unless
(
$conf
){
print
STDERR
"
\n
Failed to get conf
$_
:
$Lemonldap
::NG::Common::Conf::msg
\n
";
exit
6
;
}
print
"
Conf
$conf
->{cfgNum}:
";
my
$r
=
$new
->
saveConf
(
$conf
);
print
(
$r
?
"
stored
"
:
"
failed:
$Lemonldap
::NG::Common::Conf::msg
");
print
"
\n
";
}
modules/lemonldap-ng-common/scripts/lmConfig_File2LDIF
deleted
100755 → 0
View file @
b289a536
#!/usr/bin/perl
eval
'
exec /usr/bin/perl -S $0 ${1+"$@"}
'
if
0
;
# not running under some shell
use
Getopt::
Std
;
use
Lemonldap::NG::Common::
Conf
;
use
File::
Basename
;
use
strict
;
# Get ARGS
my
%opts
;
getopts
(
'
b:c
',
\
%opts
);
&usage
("
configuration file required
")
unless
(
$ARGV
[
0
]
);
&usage
(
qq#$ARGV[0] is not readable#
)
unless
(
-
r
$ARGV
[
0
]
);
&usage
("
configuration branch required
")
unless
(
$opts
{
b
}
);
# Internal varibales
my
$branch
=
$opts
{
b
};
my
(
$branchname
)
=
(
$branch
=~
/^ou=(.+?),/
);
my
(
$filename
,
$directories
,
$suffix
)
=
fileparse
(
$ARGV
[
0
]
);
# LDIF header
print
"
# LemonLDAP::NG configuration (converted from files)
\n
";
# Create configuration branch
if
(
$opts
{
c
})
{
print
"
dn:
$branch
objectClass: top
objectClass: organizationalUnit
ou:
$branchname
\n\n
";
}
# Create configuration entry
open
FILE
,
$ARGV
[
0
];
$/
=
"";
print
"
dn: cn=
$filename
,
$branch
objectClass: top
objectClass: applicationProcess
cn:
$filename
\n
";
while
(
<
FILE
>
)
{
my
(
$k
,
$v
)
=
split
/\n\s+/
;
chomp
$k
;
next
unless
(
$k
);
$v
=~
s/\n*$//
;
print
"
description: {
$k
}
$v
\n
";
}
print
"
\n
";
sub
usage
{
print
STDERR
shift
;
print
STDERR
"
\n
usage: $0 <options> file
Options:
-b branch : name of the configuration branch
-c : add 'create table' instruction
\n\n
";
exit
1
;
}
1
;
__END__
=head1 NAME
lmConfig_File2LDIF - Perl utility to convert Lemonldap::NG configuration file
into LDIF file.
=head1 SYNOPSIS
lmConf_File2LDIF <options> /path/to/lmConf-1
=head1 DESCRIPTION
Use this software to convert Lemonldap::NG configuration file into LDIF.
=head2 Options
=over
=item * -b : name of the configuration branch
=item * -c : create the configuration branch (organizationalUnit)
=back
=head1 SEE ALSO
Lemonldap::NG::Manager
=head1 AUTHOR
Clement Oudot, E<lt>clement@oodo.netE<gt>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2007 by Xavier Guimard
Copyright (C) 2009 by Clement Oudot
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.8 or,
at your option, any later version of Perl 5 you may have available.
=cut
modules/lemonldap-ng-common/scripts/lmConfig_File2MySQL
deleted
100755 → 0
View file @
b289a536
#!/usr/bin/perl
use
Getopt::
Std
;
use
Lemonldap::NG::Common::
Conf
;
use
strict
;
# Get ARGS
my
%opts
;
getopts
(
'
ct:
',
\
%opts
);
usage
("
configuration file required
")
unless
(
$ARGV
[
0
]
);
usage
(
qq#$ARGV[0] is not readable#
)
unless
(
-
r
$ARGV
[
0
]
);
my
$table
=
$opts
{
t
}
||
'
lmConfig
';
if
(
$opts
{
c
})
{
print
"
CREATE TABLE
$table
(
cfgNum int not null primary key,
locationRules text,
exportedHeaders text,
globalStorage text,
globalStorageOptions text,
macros text,
groups text,
portal text,
domain text,
ldapServer text,
ldapPort int,
ldapBase text,
securedCookie int,
cookieName text,
authentication text,
exportedVars text,
managerDn text,
managerPassword text,
timeout int,
whatToTrace text
\n
);
\n
";
}
my
$fields
;
open
FILE
,
$ARGV
[
0
];
$/
=
"";
while
(
<
FILE
>
)
{
my
(
$k
,
$v
)
=
split
/\n\s+/
;
chomp
$k
;
next
unless
(
$k
);
$v
=~
s/\n*$//
;
$fields
->
{
$k
}
=
$v
;
}
print
"
INSERT INTO
"
.
$table
.
"
(
\n\t
"
.
join
(
"
,
\n\t
",
keys
(
%$fields
)
)
.
"
)
\n
VALUES (
\n\t
"
.
join
(
"
,
\n\t
",
values
(
%$fields
)
)
.
"
\n
);
\n
";
close
FILE
;
sub
usage
{
print
STDERR
shift
;
print
STDERR
"
\n
usage: $0 <options> file
Options:
-t table : name of the table (default: lmConfig)
-c : add 'create table' instruction
\n
";
exit
1
;
}
1
;
__END__
=head1 NAME
lmConfig_File2MySQL - Perl utility to convert Lemonldap::NG configuration file
into MySQL SQL file.
=head1 SYNOPSIS
lmConf_File2MySQL <options> /path/to/lmConf-1
=head1 DESCRIPTION
Use this software to convert Lemonldap::NG configuration file into SQL
instructions.
=head2 Options
=over
=item * -c : add "create table" instruction
=item * -t : name of the table (lmConfig by default)
=back
=head1 SEE ALSO
Lemonldap::NG::Manager
=head1 AUTHOR
Xavier Guimard, E<lt>x.guimard@free.frE<gt>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2007 by Xavier Guimard
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.8 or,
at your option, any later version of Perl 5 you may have available.
=cut
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment