NAME

ZConf - A configuration system allowing for either file or LDAP backed storage.

VERSION

Version 6.1.0

SYNOPSIS

    use ZConf;

	#creates a new instance
    my $zconf = ZConf->new;
    
    my @configs

METHODS

new

my $zconf=ZConf->(\%args);

This initiates the ZConf object. If it can't be initiated, $zconf->error will be set. This error should be assumed to be permanent.

When it is run for the first time, it creates a filesystem only config file.

args hash

file

The default is xdf_config_home."/zconf.zml", which is generally '~/.config/zconf.zml'.

This is incompatible with the sys option.

    my $zconf=ZConf->new();
    if($zconf->error){
		warn('error: '.$zconf->{error}."\n".$zconf->errorString);
    }

chooseSet

This chooses what set should be used using the associated chooser string for the config in question.

This method does fail safely. If a improper configuration is returned by chooser string, it uses the value the default set.

It takes one arguement, which is the configuration it is for.

If the chooser errors, is blank, or is just a newline, the default is returned.

	my $set=$zconf->chooseSet("foo/bar");
    if($zconf->error){
		warn('error: '.$zconf->{error}."\n".$zconf->errorString);
    }

configExists

This method is used for checking if a config exists or not.

It takes one option, which is the configuration to check for.

The returned value is a perl boolean value.

    $zconf->configExists("foo/bar")
	if($zconf->error){
		print 'error: '.$zconf->error."\n".$zconf->errorString."\n";
	}

configNameCheck

This checks if the name of a config is legit or not. See the section CONFIG NAME for more info on config naming.

	my ($error, $errorString) = $zconf->configNameCheck($config);
	if($error){
		warn("ZConf configExists:".$error.": ".$errorString);
		$self->{error}=$error;
		$self->{errorString}=$errorString;
        $self->warn;
		return undef;
	};

createConfig

This method is used for creating a new config.

One arguement is needed and that is the config name.

The returned value is a perl boolean.

    $zconf->createConfig("foo/bar")
	if($zconf->error){
		print 'error: '.$zconf->{error}."\n".$zconf->errorString."\n";
	};

defaultSetExists

This checks to if the default set for a config exists. It takes one arguement, which is the name of the config. The returned value is a Perl boolean.

    my $returned=$zconf->defaultSetExists('someConfig');
    if($zconf->error){
		warn('error: '.$zconf->{error}."\n".$zconf->errorString);
    }
    if($returned){
        print "It exists.\n";
    }

delConfig

This removes a config. Any sub configs will need to removes first. If any are present, this method will error.

    #removes 'foo/bar'
    $zconf->delConfig('foo/bar');
    if(defined($zconf->error)){
		warn('error: '.$zconf->{error}."\n".$zconf->errorString);
    }

delSet

This deletes a specified set.

Two arguements are required. The first one is the name of the config and the and the second is the name of the set.

    $zconf->delSetFile("foo/bar", "someset");
    if($zconf->error){
		warn('error: '.$zconf->{error}."\n".$zconf->errorString);
    }

dumpToZML

This dumps a loaded config to a ZML object.

One arguement is required and it is the name of the loaded config.

    my $zml=$foo->dumpToZML($config);
	if($zconf->error){
		warn('error: '.$zconf->{error}."\n".$zconf->errorString);
	}

getAutoupdate

This gets if a config should be automatically updated or not.

One arguement is required and it is the config. If this is undefined or a matching one is not found, the global is used.

The return value is a boolean.

#fetches the global
my $autoupdate=$zconf->getAutoupdate();

#fetches it for 'some/config'
my $autoupdate=$zconf->getAutoupdate('some/config');

getAvailableSets

This gets the available sets for a config.

The only arguement is the name of the configuration in question.

my @sets = $zconf->getAvailableSets("foo/bar");
if($zconf->error){
	warn('error: '.$zconf->error.":".$zconf->errorString);
}

getDefault

This gets the default set currently being used if one is not choosen.

my $defaultSet = $zml->getDefault();

getComments

This gets a list of variables that have comments.

my @keys = $zconf->getComments("foo/bar")
if($zconf->error){
	print 'error: '.$zconf->error."\n".$zconf->errorString."\n";
}

getConfigRevision

This fetches the revision for the speified config.

    my $revision=$zconf->getConfigRevision('some/config');
    if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
    }

getCtime

This fetches the mtime for a variable.

Two arguements are required. The first is the config and the second is the variable.

The returned value is UNIX time value for when it was last changed. If it is undef, it means the variable has not been changed since ZConf 2.0.0 came out.

    my $time=$zconf->getMtime('some/config', 'some/var');
    if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
    }
    if(defined($time)){
        print "variable modified at".$time." seconds past 1970-01-01.\n";
    }else{
        print "variable not modifined since ZConf 2.0.0 came out.\n";
    }

getKeys

This gets gets the keys for a loaded config.

my @keys = $zconf->getKeys("foo/bar")
if($zconf->error){
	warn('error: '.$zconf->error.":".$zconf->errorString);
}

getLoadedConfigRevision

This gets the revision of the specified config, if it is loaded.

    my $rev=$zconf->getLoadedConfigRevision;
    if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
    }

getLoadedConfigs

This gets gets the keys for a loaded config.

my @configs = $zconf->getLoadedConfigs("foo/bar")
if($zconf->error){
	warn('error: '.$zconf->error.":".$zconf->errorString);
}

getMetas

This gets a list of variables that have meta variables.

my @keys = $zconf->getComments("foo/bar")
if($zconf->error){
	warn('error: '.$zconf->error.":".$zconf->errorString);
}

getMtime

This fetches the mtime for a variable.

Two arguements are required. The first is the config and the second is the variable.

The returned value is UNIX time value for when it was last changed. If it is undef, it means the variable has not been changed since ZConf 2.0.0 came out.

    my $time=$zconf->getMtime('some/config', 'some/var');
    if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
    }
    if(defined($time)){
        print "variable modified at".$time." seconds past 1970-01-01.\n";
    }else{
        print "variable not modifined since ZConf 2.0.0 came out.\n";
    }

getOverrideChooser

This will get the current override chooser for a config.

If no chooser is specified for the loaded config

One arguement is required it is the name of the config.

This method is basically a wrapper around regexMetaGet.

    my $orchooser=$zconf->getOverrideChooser($config);
    if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
    }

getSet

This gets the set for a loaded config.

my $set = $zconf->getSet("foo/bar")
if($zconf->error){
	warn('error: '.$zconf->error.":".$zconf->errorString);
}

getSubConfigs

This gets any sub configs for a config. "" can be used to get a list of configs under the root.

One arguement is accepted and that is the config to look under.

    #lets assume 'foo/bar' exists, this would return
    my @subConfigs=$zconf->getSubConfigs("foo");
    if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
    }

getComment

This requires three arguments.

The first is the name of the config.

The second is the variable.

The third is the comment name.

If the comment does not exist, undef is returned. It is also possible it errored, but a non-existant variable is not considered a error.

my $value=$zconf->getVar($someConfig, $someVariable, $someComment);
if($zconf->error){
    warn('error: '.$zconf->error.":".$zconf->errorString);
}
if(!defined($value)){
    print "'.$someVariable.' and/or '".$someComment."' does not exist\n";
}

getMeta

This requires three arguments.

The first is the name of the config.

The second is the variable.

The third is the meta name.

If the comment does not exist, undef is returned. It is also possible it errored, but a non-existant variable is not considered a error.

my $value=$zconf->getVar($someConfig, $someVariable, $someMeta);
if($zconf->error){
    warn('error: '.$zconf->error.":".$zconf->errorString);
}
if(!defined($value)){
    print "'.$someVariable.' and/or '".$someMeta."' does not exist\n";
}

getVar

This reqyures two arguments.

The first is the name of the config.

The second is the variable.

If the variable does not exist, undef is returned. It is also possible it errored, but a non-existant variable is not considered a error.

my $value=$zconf->getVar($someConfig, $someVariable);
if($zconf->error){
    warn('error: '.$zconf->error.":".$zconf->errorString);
}
if(!defined($value)){
    print "'.$someVariable.' does not exist\n";
}

initBackend

This initializes a backend.

One arguement is required and it is the backend name.

    my $backend=$zconf->initBackend('file');
    if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
    }else{
        if($backend->error){
		warn('backend error: '.$backend->error.":".$backend->errorString);
        }
    }

isLoadedConfigLocked

This returns if the loaded config is locked or not.

Only one arguement is taken and that is the name of the config.

    my $returned=$zconf->isLoadedConfigLocked('some/config');
    if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
    }

isConfigLoaded

This checks if a config or not.

One argument is taken and that is if a config is loaded or not.

    $zconf->isConfigLoaded($config);
    if( $zconf->error ){
		warn('error: '.$zconf->error.":".$zconf->errorString);
    }

isConfigLocked

This checks if a config is locked or not.

One arguement is required and it is the name of the config.

The returned value is a boolean value.

    my $locked=$zconf->isConfigLocked('some/config');
    if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
    }
    if($locked){
        print "The config is locked\n";
    }

LDAPconnect

This generates a Net::LDAP object based on the LDAP backend.

    my $ldap=$zconf->LDAPconnect();
    if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
    }

override

This runs the overrides for a config.

This overrides various variables in the config by running the chooser stored in '#!zconf=override/chooser'. If it fails, the profile 'default' is used.

Once a profile name has been picked, everything under '#!zconf=override/profiles/<profile>/' has /^override\/profiles\/<profile>\// removed and it is set as a regular variable.

One arguement is taken and it is a hash.

If a value of undef is returned, but no error is set, no '#!zconf=override/chooser' is not defined.

This method does not invoke the method updateIfNeeded.

args hash

config

This is the config to operate on.

profile

If this is not specified, the chooser stored in the meta is '#!zconf=override/chooser'.

read

This reads a config. The only accepted option is the config name.

It takes one arguement, which is a hash.

hash args

config

The config to load.

override

This specifies if override should be ran not.

If this is not specified, it defaults to 1, true.

set

The set for that config to load.

    $zconf->read({config=>"foo/bar"})
	if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
	}

readChooser

This reads the chooser for a config. If no chooser is defined "" is returned.

The name of the config is the only required arguement.

my $chooser = $zconf->readChooser("foo/bar")
if($zconf->error){
	warn('error: '.$zconf->error.":".$zconf->errorString);
}

regexCommentDel

This searches through the comments for variables in a loaded config for any that match the supplied regex and removes them.

One arguement is taken and it is a hash.

A hash of hash containing copies of the deleted variables are returned.

args hash

config

This is the config search.

varRegex

The variable to search for matching comment names.

commentRegex

The regex use for matching comment names.

    my %deleted=$zconf->regexCommentDel({
                                         config=>"foo/bar",
                                         varRegex=>"^some/var$",
                                         commentRegex=>"^monkey\/";
                                        });
	if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
	}

regexCommentGet

This searches through the comments for variables in a loaded config for any that match the supplied regex and returns them.

One arguement is taken and it is a hash.

A hash of hash containing copies of the deleted variables are returned.

args hash

config

This is the config search.

varRegex

The variable to search for matching comment names.

commentRegex

The regex use for matching comment names.

    my %deleted=$zconf->regexCommentGet({
                                         config=>"foo/bar",
                                         varRegex=>"^some/var$",
                                         commentRegex=>"^monkey\/";
                                        });
	if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
	}

regexMetaDel

This searches through the meta variables in a loaded config for any that match the supplied regex and removes them.

One arguement is taken and it is a hash.

A hash of hash containing copies of the deleted variables are returned.

args hash

config

This is the config search.

varRegex

The variable to search for matching comment names.

metaRegex

The regex use for matching meta variables.

    my %deleted=$zconf->regexMetaDel({
                                      config=>"foo/bar",
                                      varRegex=>"^some/var$",
                                      metaRegex=>"^monkey\/";
                                     });
	if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
	}

regexMetaGet

This searches through the meta variables in a loaded config for any that match the supplied regex and removes them.

One arguement is taken and it is a hash.

A hash of hash containing copies of the deleted variables are returned.

args hash

config

This is the config search.

varRegex

The variable to search for matching comment names.

metaRegex

The regex use for matching meta variables.

    my %deleted=$zconf->regexMetaGet({
                                      config=>"foo/bar",
                                      varRegex=>"^some/var$",
                                      metaRegex=>"^monkey\/";
                                     });
	if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
	}

regexVarDel

This searches through the variables in a loaded config for any that match the supplied regex and removes them.

Two arguements are required. The first is the config to search. The second is the regular expression to use.

#removes any variable starting with the monkey
my @deleted = $zconf->regexVarDel("foo/bar", "^monkey");
if($zconf->error){
	warn('error: '.$zconf->error.":".$zconf->errorString);
}

regexVarGet

This searches through the variables in a loaded config for any that match the supplied regex and returns them in a hash.

Two arguements are required. The first is the config to search. The second is the regular expression to use.

#returns any variable begining with monkey
my %vars = $zconf->regexVarGet("foo/bar", "^monkey");
if($zconf->error){
	warn('error: '.$zconf->error.":".$zconf->errorString);
}

regexVarSearch

This searches through the variables in a loaded config for any that match the supplied regex and returns a array of matches.

Two arguements are required. The first is the config to search. The second is the regular expression to use.

#removes any variable starting with the monkey
my @matched = $zconf->regexVarSearch("foo/bar", "^monkey")
if($zconf->error)){
	warn('error: '.$zconf->error.":".$zconf->errorString);
}

reread

This rereads the specified config file. This requires it to be already loaded.

    $zconf->reread('some/config');
    if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
    }

setAutoupdate

This sets if a value for autoupdate.

It takes two optional arguements. The first is a name for a config and second is a boolean value.

If a config name is not specified, it sets the global value for it.

#set the global auto update value to false
$zconf->setAutoupdate(undef, '0');

#sets it to true for 'some/config'
$zconf->setAutoupdate('some/config', '1');

setComment

This sets a comment variable in a loaded config.

Four arguements are required. The first is the name of the config. The second is the name of the variable. The third is the comment variable. The fourth is the value.

$zconf->setComment("foo/bar" , "somethingVar", "someComment", "eat more weazel\n\nor something"
if($zconf->error){
	warn('error: '.$zconf->error.":".$zconf->errorString);
}

setDefault

This sets the default set to use if one is not specified or choosen.

my $returned = $zconf->setDefault("something")
if($zconf->error){
	warn('error: '.$zconf->error.":".$zconf->errorString);
}

setExists

This checks if the specified set exists.

Two arguements are required. The first arguement is the name of the config. The second arguement is the name of the set. If no set is specified, the default set is used. This is done by calling 'defaultSetExists'.

    my $return=$zconf->setExists("foo/bar", "fubar");
    if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
    }else{
        if($return){
            print "It exists.\n";
        }
    }

setLockConfig

This unlocks or logs a config.

Two arguements are taken. The first is a the config name, required, and the second is if it should be locked or unlocked

    #lock 'some/config'
    $zconf->setLockConfig('some/config', 1);
    if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
    }

    #unlock 'some/config'
    $zconf->setLockConfig('some/config', 0);
    if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
    }

    #unlock 'some/config'
    $zconf->setLockConfig('some/config');
    if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
    }

setMeta

This sets a meta variable in a loaded config.

Four arguements are required. The first is the name of the config. The second is the name of the variable. The third is the meta variable. The fourth is the value.

$zconf->setMeta("foo/bar" , "somethingVar", "someComment", "eat more weazel\n\nor something"
if($zconf->{error}){
	warn('error: '.$zconf->error.":".$zconf->errorString);
}

setNameLegit

This checks if a setname is legit.

There is one required arguement, which is the set name.

The returned value is a perl boolean value.

my $set="something";
if(!$zconf->setNameLegit($set)){
	warn('error: '.$zconf->error.":".$zconf->errorString);
}

setOverrideChooser

This will set the override chooser for a config.

If no chooser is specified for the loaded config

Two arguements are required. The first is the config and th e second is the chooser string.

This method is basically a wrapper around setMeta.

    $zconf->setOverrideChooser($config, $chooser);
    if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
    }

setVar

This sets a variable in a loaded config.

Three arguements are required. The first is the name of the config. The second is the name of the variable. The third is the value.

$zconf->setVar("foo/bar" , "something", "eat more weazel\n\nor something"
if($zconf->error){
	warn('error: '.$zconf->error.":".$zconf->errorString);
}

unloadConfig

Unloads a specified configuration. The only required value is the set name. The return value is a Perl boolean value.

    zconf->unloadConfig($config);
    if( $zconf->error )
		warn('error: '.$zconf->error.":".$zconf->errorString);
    }

updatable

This checks if the loaded config on disk has a different revision ID than the saved one.

The return value is a boolean value. A value of true indicates the config has been changed on the backend.

    my $updatable=$zconf->updatable('some/config');
    if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
    }

updateIfNeeded

If a loaded config is updatable, reread it.

The returned value is a boolean value indicating if it was updated or not. A value of true indicates it was.

args hash

autocheck

This tells it to check getAutoupdate. If it returns false, it will return.

clearerror

If $zconf->{error} is set, clear it. This is primarily meant for being used internally.

config

This config to check.

This is required.

    my $updated=$zconf->updateIfNeeded({config=>'some/config'});
    if($zconf->{error}){
		warn('error: '.$zconf->error.":".$zconf->errorString);
    }
    if($updated){
        print "Updated!\n";
    }

varNameCheck

This checks if a there if the specified variable name is a legit one or not.

my ($error, $errorString) = $zconf->varNameCheck($config);
if(defined($error)){
	warn('error: '.$zconf->error.":".$zconf->errorString);
}

writeChooser

This writes a string into the chooser for a config.

There are two required arguements. The first is the config name. The second is chooser string.

No error checking is done currently on the chooser string.

Setting this to '' or "\n" will disable the chooser fuction and the default will be used when chooseSet is called.

my $returned = $zconf->writeChooser("foo/bar", $chooserString)
if($zconf->error){
	warn('error: '.$zconf->error.":".$zconf->errorString);
}

writeSetFromHash

This takes a hash and writes it to a config. It takes two arguements, both of which are hashes.

The first hash contains

The second hash is the hash to be written to the config.

args hash

config

The config to write it to.

This is required.

set

This is the set name to use.

If not defined, the one will be choosen.

revision

This is the revision string to use.

This is primarily meant for internal usage and is suggested that you don't touch this unless you really know what you are doing.

    $zconf->writeSetFromHash({config=>"foo/bar"}, \%hash);
	if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
	}

writeSetFromLoadedConfig

This method writes a loaded config to a to a set.

One arguement is required.

args hash

config

The config to write it to.

This is required.

set

This is the set name to use.

If not defined, the one will be choosen.

revision

This is the revision string to use.

This is primarily meant for internal usage and is suggested that you don't touch this unless you really know what you are doing.

    $zconf->writeSetFromLoadedConfig({config=>"foo/bar"});
	if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
	}

writeSetFromZML

This method writes a loaded config to a to a set.

One arguement is required.

args hash

config

The config to write it to.

This is required.

set

This is the set name to use.

If not defined, the one will be choosen.

zml

This is the ZML object to use.

revision

This is the revision string to use.

This is primarily meant for internal usage and is suggested that you don't touch this unless you really know what you are doing.

    $zconf->writeSetFromZML({config=>"foo/bar", zml=>$zml});
	if($zconf->error){
		warn('error: '.$zconf->error.":".$zconf->errorString);
	}

CONFIG NAME

Any configuration name is legit as long as it does not match any of the following.

undef
/./
/\/\./
/\.\.\//
/\/\//
/\.\.\//
/\/\.\./
/^\.\//
/\/$/
/^\//
/\n/

SET NAME

Any set name is legit as long as it does not match any of the following.

undef
/\//
/^\./
/^ /
/ $/
/\.\./

VARIABLE NAME

Any variable name is legit as long it does not match any of the following. This also covers comments and meta variables.

/,/
/\/\./
/\/\//
\.\.\//
/\/\.\./
/^\.\//
/\/$/	
/^\//
/\n/
/=/

ERROR HANDLING/CODES

This module uses Error::Helper for error handling. Below are the error codes returned by the error method.

1

config name contains ,

2

config name contains /.

3

config name contains //

4

config name contains ../

5

config name contains /..

6

config name contains ^./

7

config name ends in /

8

config name starts with /

9

could not sync to file

10

config name contains a \n

11

Backend errored.

12

config does not exist

13

Backend is not ZConf::backends::ldap.

14

The backend could not be found.

15

No backend specified.

16

ZML object not passed.

18

No variable name specified.

19

config key starts with a ' '

21

set not found for config

23

skilling variable as it is not a legit name

24

set is not defined

25

Config is undefined.

26

Config not loaded.

27

Set name is not a legit name.

28

ZML->parse error.

29

Could not unlink the unlink the set.

30

The sets exist for the specified config.

31

Did not find a matching set.

32

Unable to choose a set.

33

Unable to remove the config as it has sub configs.

38

Sys name matched /\//.

39

Sys name matched /\./.

40

No chooser string specified.

41

No comment specified.

42

No meta specified.

45

Config is locked.

46

LDAP entry update failed.

47

Failed to initialize the backend. It returned undef.

ERROR CHECKING

This can be done by checking $zconf->{error} to see if it is defined. If it is defined, The number it contains is the corresponding error code. A description of the error can also be found in $zconf->{errorString}, which is set to "" when there is no error.

zconf.zml

The default is 'xdf_config_home/zconf.zml', which is generally '~/.config/zconf.zml'. See perldoc ZML for more information on the file format. The keys are listed below.

For information on the keys for the backends, please see perldoc for the backend in question.

The two included are 'file' and 'ldap'. See perldoc for 'ZConf::backends::file' and 'ZConf::backends::ldap' for their key values.

zconf.zml keys

backend

This is the backend to use for storage. Current values of 'file' and 'ldap' are supported.

backendChooser

This is a Chooser string that chooses what backend should be used.

defaultChooser

This is a chooser string that chooses what the name of the default to use should be.

fileonly

This is a boolean value. If it is set to 1, only the file backend is used.

This will override 'backend'.

readfallthrough

If this is set, if any of the methods below error when trying the any backend other than 'file' , it will fall through to the file backend.

configExists
getAvailableSets
getSubConfigs
read
readChooser

UTILITIES

There are several scripts installed with this module. Please see the perldocs for the utilities listed below.

zcchooser-edit
zcchooser-get
zcchooser-run
zcchooser-set
zccreate
zcget
zcls
zcrm
zcset
zcvdel
zcvls

Backend Requirements

Coming shortly.

This will be documented more shortly.

AUTHOR

Zane C. Bowers-Hadley, <vvelox at vvelox.net>

BUGS

Please report any bugs or feature requests to bug-zconf at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=ZConf. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

perldoc ZConf

You can also look for information at:

ACKNOWLEDGEMENTS

COPYRIGHT & LICENSE

Copyright 2011 Zane C. Bowers-Hadley, all rights reserved.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.