The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl -w

#use strict;
use warnings;
use Config::General qw(ParseConfig SaveConfig);
use Sys::Hostname;
use English qw( -no_match_vars );
use Module::Load;
use File::Temp qw(tempfile);

=head1 NAME

psConfigureDaemon - Ask a series of questions to generate a configuration file.

=head1 DESCRIPTION

Ask questions based on a service to generate a configuration file.

=cut

my $was_installed = 0;
my $DEFAULT_FILE;
my $confdir;

if ($was_installed) {
    $confdir = "XXX_CONFDIR_XXX";
}
else {
    $confdir = "."
}

$DEFAULT_FILE = $confdir . "/daemon.conf";

print " -- perfSONAR-PS Daemon Configuration --\n";
print " - [press enter for the default choice] -\n\n";

my $file = shift;

if ( not $file ) {
    $file = &ask( "What file should I write the configuration to? ", $DEFAULT_FILE, undef, '.+' );
}

my $tmp;
my $default_hostname = hostname();
my $hostname;

my %config = ();
if ( -f $file ) {
    %config = ParseConfig($file);
}

# make sure all the endpoints start with a "/".
if ( defined $config{"port"} ) {
    foreach my $port ( keys %{ $config{"port"} } ) {
        if ( defined $config{"port"}->{$port}->{"endpoint"} ) {
            foreach my $endpoint ( keys %{ $config{"port"}->{$port}->{"endpoint"} } ) {
                my $new_endpoint = $endpoint;

                if ( $endpoint =~ /^[^\/]/mx ) {
                    $new_endpoint = "/" . $endpoint;
                }

                if ( $endpoint ne $new_endpoint ) {
                    $config{"port"}->{$port}->{"endpoint"}->{$new_endpoint} = $config{"port"}->{$port}->{"endpoint"}->{$endpoint};
                    delete( $config{"port"}->{$port}->{"endpoint"}->{$endpoint} );
                }
            }
        }
    }
}

while (1) {
    my $input;

    print "1) Add/Edit endpoint\n";
    print "2) Enable/Disable port/endpoint\n";
    print "3) Set global values\n";
    print "4) Save configuration\n";
    print "5) Exit\n";
    $input = &ask( "? ", q{}, undef, '[12345]' );

    if ( $input == 5 ) {
        exit(0);
    }
    elsif ( $input == 4 ) {
        if ( -f $file ) {
            system("mv $file $file~");
        }

        SaveConfig_mine( $file, \%config );
        print "\n";
        print "Saved config to $file\n";
        print "\n";
    }
    elsif ( $input == 3 ) {
        $config{"max_worker_processes"}     = &ask( "Enter the maximum number of children processes (0 means infinite) ",                   "0",                                                          $config{"max_worker_processes"},     '^\d+$' );
        $config{"max_worker_lifetime"}      = &ask( "Enter number of seconds a child can process before it is stopped (0 means infinite) ", "0",                                                          $config{"max_worker_lifetime"},      '^\d+$' );
        $config{"disable_echo"}             = &ask( "Disable echo by default (0 for yes, 1 for now) ",                                      0,                                                            $config{"disable_echo"},             '^[01]$' );
        $config{"ls_instance"}              = &ask( "The LS for MAs to register with ",                                                     "http://packrat.internet2.edu:8005/perfSONAR_PS/services/LS", $config{"ls_instance"},              '(^http|^$)' );
        $config{"ls_registration_interval"} = &ask( "Interval between when LS registrations occur [in minutes] ",                           60,                                                           $config{"ls_registration_interval"}, '^\d+$' );
        $config{"reaper_interval"}          = &ask( "Interval between when children are repeaed [in seconds] ",                             20,                                                           $config{"reaper_interval"},          '^\d+$' );
        $config{"pid_dir"}                  = &ask( "Enter pid dir location ",                                                              "/var/run",                                                   $config{"pid_dir"},                  q{} );
        $config{"pid_file"}                 = &ask( "Enter pid filename ",                                                                  "ps.pid",                                                     $config{"pid_file"},                 q{} );
    }
    elsif ( $input == 2 ) {
        my @elements = ();
        my %status   = ();

        foreach my $port ( sort keys %{ $config{"port"} } ) {
            next if ( !defined $config{"port"}->{$port}->{"endpoint"} );
            push @elements, $port;

            if ( defined $config{"port"}->{$port}->{"disabled"} and $config{"port"}->{$port}->{"disabled"} == 1 ) {
                $status{$port} = 1;
            }
        }

        foreach my $port ( sort keys %{ $config{"port"} } ) {
            next if ( !defined $config{"port"}->{$port}->{"endpoint"} );
            foreach my $endpoint ( sort keys %{ $config{"port"}->{$port}->{"endpoint"} } ) {
                push @elements, "$port$endpoint";
                if ( defined $config{"port"}->{$port}->{"endpoint"}->{$endpoint}->{"disabled"}
                    and $config{"port"}->{$port}->{"endpoint"}->{$endpoint}->{"disabled"} == 1 )
                {
                    $status{"$port$endpoint"} = 1;
                }
            }
        }

        if ( $#elements > -1 ) {
            print "\n";
            print "Select element to enable/disable: \n";
            my $len = $#elements;
            for my $i ( 0 .. $len ) {
                print " $i) $elements[$i] ";
                print " *" if ( defined $status{ $elements[$i] } );
                print "\n";
            }
            print "\n";
            print " * element is disabled\n";
            print "\n";

            do {
                $input = &ask( "Select a number from the above ", q{}, undef, '^\d+$' );
            } while ( $input > $#elements );

            my $new_status;

            if ( defined $status{ $elements[$input] } ) {
                $new_status = 0;
            }
            else {
                $new_status = 1;
            }

            print "\n";
            if ($new_status) {
                print "Disabling";
            }
            else {
                print "Enabling";
            }

            if ( $elements[$input] =~ /^(\d+)(\/.*)$/mx ) {
                print " endpoint " . $elements[$input] . "\n";
                $config{"port"}->{$1}->{"endpoint"}->{$2}->{"disabled"} = $new_status;
            }
            elsif ( $elements[$input] =~ /^(\d+)$/mx ) {
                print " port " . $elements[$input] . "\n";
                $config{"port"}->{$1}->{"disabled"} = $new_status;
            }
            print "\n";
        }
    }
    elsif ( $input == 1 ) {
        my @endpoints = ();
        foreach my $port ( sort keys %{ $config{"port"} } ) {
            next if ( !defined $config{"port"}->{$port}->{"endpoint"} );
            foreach my $endpoint ( sort keys %{ $config{"port"}->{$port}->{"endpoint"} } ) {
                push @endpoints, "$port$endpoint";
            }
        }

        if ( $#endpoints > -1 ) {
            print "\n";
            print "Existing Endpoints: \n";
            my $len = $#endpoints;
            for my $i ( 0 .. $len ) {
                print " $i) $endpoints[$i]\n";
            }
            print "\n";
        }

        do {
            $input = &ask( "Enter endpoint in form 'port/endpoint_path' (e.g. 8080/perfSONAR_PS/services/SERVICE_NAME) or select from a number from the above ", q{}, undef, '^(\d+[\/].*|\d+)$' );
            if ( $input =~ /^\d+$/mx ) {
                $input = $endpoints[$input];
            }
        } while ( !( $input =~ /\d+[\/].*/mx ) );

        my ( $port, $endpoint );
        if ( $input =~ /(\d+)([\/].*)/mx ) {
            $port     = $1;
            $endpoint = $2;
        }

        if ( !defined $config{"port"} ) {
            my %hash = ();
            $config{"port"} = \%hash;
        }

        if ( !defined $config{"port"}->{$port} ) {
            my %hash = ();
            $config{"port"}->{$port} = \%hash;
            $config{"port"}->{$port}->{"endpoint"} = ();
        }

        if ( !defined $config{"port"}->{$port}->{"endpoint"}->{$endpoint} ) {
            $config{"port"}->{$port}->{"endpoint"}->{$endpoint} = ();
        }

        my $valid_module = 0;
        my $module       = $config{"port"}->{$port}->{"endpoint"}->{$endpoint}->{"module"};
        if ( defined $module ) {
            if ( $module eq "perfSONAR_PS::Services::MA::SNMP" ) {
                $module = "snmp";
            }
            elsif ( $module eq "perfSONAR_PS::Services::MA::Status" ) {
                $module = "status";
            }
            elsif ( $module eq "perfSONAR_PS::Services::MA::CircuitStatus" ) {
                $module = "circuitstatus";
            }
            elsif ( $module eq "perfSONAR_PS::Services::MA::Topology" ) {
                $module = "topology";
            }
            elsif ( $module eq "perfSONAR_PS::Services::LS::LS" ) {
                $module = "ls";
            }
            elsif ( $module eq "perfSONAR_PS::Services::MA::perfSONARBOUY" ) {
                $module = "perfsonarbuoy";
            }
            elsif ( $module eq "perfSONAR_PS::Services::MA::PingER" ) {
                $module = "pingerma";
            }
            elsif ( $module eq "perfSONAR_PS::Services::MP::PingER" ) {
                $module = "pingermp";
            }
        }

        my %opts;
        do {
            $module = &ask( "Enter endpoint module [snmp,ls,perfsonarbuoy,pingerma,pingermp,status,circuitstatus,topology] ", q{}, $module, q{} );
            $module = lc($module);

            if ( $module eq "snmp" or $module eq "status" or $module eq "ls" or $module eq "circuitstatus" or $module eq "topology"
                   or $module eq "perfsonarbuoy" or $module eq "pingerma" or $module eq "pingermp") {
                $valid_module = 1;
            }
        } while ( $valid_module == 0 );

        if ( !defined $hostname ) {
            $hostname = &ask( "Enter the external host or IP for this machine ", $hostname, $default_hostname, '.+' );
        }

        my $accesspoint = &ask( "Enter the accesspoint for this service ", "http://$hostname:$port$endpoint", undef, '^http' );

        if ( $module eq "snmp" ) {
            $config{"port"}->{$port}->{"endpoint"}->{$endpoint}->{"module"} = "perfSONAR_PS::Services::MA::SNMP";
            config_snmp_ma( $config{"port"}->{$port}->{"endpoint"}->{$endpoint}, $accesspoint, \%config );
        }
        elsif ( $module eq "status" ) {
            $config{"port"}->{$port}->{"endpoint"}->{$endpoint}->{"module"} = "perfSONAR_PS::Services::MA::Status";
            config_status_ma( $config{"port"}->{$port}->{"endpoint"}->{$endpoint}, $accesspoint, \%config );
        }
        elsif ( $module eq "circuitstatus" ) {
            $config{"port"}->{$port}->{"endpoint"}->{$endpoint}->{"module"} = "perfSONAR_PS::Services::MA::CircuitStatus";
            config_circuitstatus_ma( $config{"port"}->{$port}->{"endpoint"}->{$endpoint}, $accesspoint, \%config );
        }
        elsif ( $module eq "topology" ) {
            $config{"port"}->{$port}->{"endpoint"}->{$endpoint}->{"module"} = "perfSONAR_PS::Services::MA::Topology";
            config_topology_ma( $config{"port"}->{$port}->{"endpoint"}->{$endpoint}, $accesspoint, \%config );
        }
        elsif ( $module eq "ls" ) {
            $config{"port"}->{$port}->{"endpoint"}->{$endpoint}->{"module"} = "perfSONAR_PS::Services::LS::LS";
            config_ls( $config{"port"}->{$port}->{"endpoint"}->{$endpoint}, $accesspoint, \%config );
        }
        elsif ( $module eq "perfsonarbuoy" ) {
            $config{"port"}->{$port}->{"endpoint"}->{$endpoint}->{"module"} = "perfSONAR_PS::Services::MA::perfSONARBOUY";
            config_perfsonarbuoy_ma( $config{"port"}->{$port}->{"endpoint"}->{$endpoint}, $accesspoint, \%config );
        }
        elsif ($module eq "pingerma") {
            $config{"port"}->{$port}->{"endpoint"}->{$endpoint}->{"module"} = "perfSONAR_PS::Services::MA::PingER";
            $config{"port"}->{$port}->{"endpoint"}->{$endpoint}->{"service_type"} = "MA";
            config_pinger($config{"port"}->{$port}->{"endpoint"}->{$endpoint}, $accesspoint, \%config, "pingerma");
        }
        elsif ($module eq "pingermp") {
            $config{"port"}->{$port}->{"endpoint"}->{$endpoint}->{"module"} = "perfSONAR_PS::Services::MP::PingER";
            $config{"port"}->{$port}->{"endpoint"}->{$endpoint}->{"service_type"} = "MP";
            config_pinger($config{"port"}->{$port}->{"endpoint"}->{$endpoint}, $accesspoint, \%config, "pingermp");
        }
    }
}

sub config_ls {
    my ( $config, $accesspoint, $def_config ) = @_;

    if ( !defined $config->{"ls"} ) {
        $config->{"ls"} = ();
    }

    $config->{"ls"}->{"ls_ttl"}           = &ask( "Enter default TTL for registered data [in minutes] ",                                   "60",                $config->{"ls"}->{"ls_ttl"},           '\d+' );
    $config->{"ls"}->{"metadata_db_name"} = &ask( "Enter the directory of the XML database ",                                              $confdir . "/xmldb", $config->{"ls"}->{"metadata_db_name"}, '^\/' );
    $config->{"ls"}->{"metadata_db_file"} = &ask( "Enter the name of the container inside of the XML database ",                           "store.dbxml",       $config->{"ls"}->{"metadata_db_file"}, '.+' );
    $config->{"ls"}->{"reaper_interval"}  = &ask( "Should the LS periodically remove old registration information (0 for no, 1 for yes) ", "0",                 $config->{"ls"}->{"reaper_interval"},  '^[01]$' );
    if ( $config->{"ls"}->{"reaper_interval"} ) {
        $config->{"ls"}->{"reaper_interval"} = &ask( "Enter the time between LS removal [in minutes] ", "30", "30", '^\d+$' );
    }

    $config->{"ls"}->{"service_name"} = &ask( "Enter a name for this service ", "Lookup Service", $config->{"ls"}->{"service_name"}, '.+' );

    $config->{"ls"}->{"service_type"} = &ask( "Enter the service type ", "MA", $config->{"ls"}->{"service_type"}, '.+' );

    $config->{"ls"}->{"service_description"} = &ask( "Enter a service description ", "Lookup Service", $config->{"ls"}->{"service_description"}, '.+' );

    $config->{"ls"}->{"service_accesspoint"} = &ask( "Enter the service's URI ", $accesspoint, $config->{"ls"}->{"service_accesspoint"}, '^http:\/\/' );

    return;
}

sub config_perfsonarbuoy_ma {
    my ( $config, $accesspoint, $def_config ) = @_;

    my $amiconfdir = $confdir;

    $config->{"perfsonarbuoy"}->{"owmesh"} = &ask( "Enter the directory *LOCATION* of the 'owmesh.conf' file: ", $amiconfdir, $config->{"perfsonarbuoy"}->{"owmesh"}, '.+' );
    $amiconfdir = $config->{"perfsonarbuoy"}->{"owmesh"};

    $config->{"perfsonarbuoy"}->{"metadata_db_type"} = &ask( "Enter the database type to read from (file or xmldb) ", "file", $config->{"perfsonarbuoy"}->{"metadata_db_type"}, '(file|xmldb)' );

    if ( $config->{"perfsonarbuoy"}->{"metadata_db_type"} eq "file" ) {
        delete $config->{"perfsonarbuoy"}->{"metadata_db_file"} if $config->{"perfsonarbuoy"}->{"metadata_db_file"} and $config->{"perfsonarbuoy"}->{"metadata_db_file"} =~ m/dbxml$/mx;
        $config->{"perfsonarbuoy"}->{"metadata_db_file"} = &ask( "Enter the filename of the XML file ", $amiconfdir . "/store.xml", $config->{"perfsonarbuoy"}->{"metadata_db_file"}, '\.xml$' );
    }
    elsif ( $config->{"perfsonarbuoy"}->{"metadata_db_type"} eq "xmldb" ) {
        $config->{"perfsonarbuoy"}->{"metadata_db_name"} = &ask( "Enter the directory of the XML database ", $amiconfdir . "/xmldb", $config->{"perfsonarbuoy"}->{"metadata_db_name"}, '.+' );
        delete $config->{"perfsonarbuoy"}->{"metadata_db_file"} if $config->{"perfsonarbuoy"}->{"metadata_db_file"} and $config->{"perfsonarbuoy"}->{"metadata_db_file"} =~ m/\.xml$/mx;
        $config->{"perfsonarbuoy"}->{"metadata_db_file"} = &ask( "Enter the name of the container inside of the XML database ", "store.dbxml", $config->{"perfsonarbuoy"}->{"metadata_db_file"}, '.+' );
    }

    $config->{"perfsonarbuoy"}->{"enable_registration"} = &ask( "Will this service register with an LS (0 for no, 1 for yes)", "0", $config->{"perfsonarbuoy"}->{"enable_registration"}, '^[01]$' );

    if ( $config->{"perfsonarbuoy"}->{"enable_registration"} eq "1" ) {
        my $registration_interval = $def_config->{"ls_registration_interval"};
        $registration_interval = $config->{"perfsonarbuoy"}->{"ls_registration_interval"} if ( defined $config->{"perfsonarbuoy"}->{"ls_registration_interval"} );
        $config->{"perfsonarbuoy"}->{"ls_registration_interval"} = &ask( "Interval between when LS registrations occur [in minutes] ", "30", $registration_interval, '^\d+$' );

        my $ls_instance = $def_config->{"ls_instance"};
        $ls_instance = $config->{"perfsonarbuoy"}->{"ls_instance"} if ( defined $config->{"perfsonarbuoy"}->{"ls_instance"} );
        $config->{"perfsonarbuoy"}->{"ls_instance"} = &ask( "URL of an LS to register with ", q{}, $ls_instance, '^http:\/\/' );
    }

    $config->{"perfsonarbuoy"}->{"service_name"} = &ask( "Enter a name for this service ", "perfSONARBOUY MA", $config->{"perfsonarbuoy"}->{"service_name"}, '.+' );

    $config->{"perfsonarbuoy"}->{"service_type"} = &ask( "Enter the service type ", "MA", $config->{"perfsonarbuoy"}->{"service_type"}, '.+' );

    $config->{"perfsonarbuoy"}->{"service_description"} = &ask( "Enter a service description ", "perfSONARBOUY MA", $config->{"perfsonarbuoy"}->{"service_description"}, '.+' );

    $config->{"perfsonarbuoy"}->{"service_accesspoint"} = &ask( "Enter the service's URI ", $accesspoint, $config->{"perfsonarbuoy"}->{"service_accesspoint"}, '^http:\/\/' );

    return;
}

sub config_snmp_ma {
    my ( $config, $accesspoint, $def_config ) = @_;

    my $rrdtool = q{};
    if ( open( RRDTOOL, "which rrdtool |" ) ) {
        $rrdtool = <RRDTOOL>;
        $rrdtool =~ s/rrdtool:\s+//mx;
        $rrdtool =~ s/\n//gmx;
        unless ( close(RRDTOOL) ) {
            return -1;
        }
    }

    unless ($rrdtool) {
        return -1;
    }

    $config->{"snmp"}->{"rrdtool"} = &ask( "Enter the location of the RRD binary ", $rrdtool, $config->{"snmp"}->{"rrdtool"}, '.+' );

    $config->{"snmp"}->{"default_resolution"} = &ask( "Enter the default resolution of RRD queries ", "300", $config->{"snmp"}->{"default_resolution"}, '^\d+$' );

    $config->{"snmp"}->{"metadata_db_type"} = &ask( "Enter the database type to read from (file or xmldb) ", "file", $config->{"snmp"}->{"metadata_db_type"}, '(file|xmldb)' );

    my $makeStore = &ask( "Automatically generate a 'test' metadata database (0 for no, 1 for yes) ", "0", "0", '^[01]$' );
    if ( $makeStore ) {
        eval { 
#            load RRDp; 
            use RRDp; 
            $RRDp::error_mode = 'catch';
            RRDp::start $config->{"snmp"}->{"rrdtool"};
            my $cmd .= "create ".$confdir."/localhost.rrd --start N --step 1 ";
            $cmd .= "DS:ifinoctets:COUNTER:10:U:U ";
            $cmd .= "DS:ifoutoctets:COUNTER:10:U:U ";
            $cmd .= "DS:ifinerrors:COUNTER:10:U:U ";
            $cmd .= "DS:ifouterrors:COUNTER:10:U:U ";
            $cmd .= "DS:ifindiscards:COUNTER:10:U:U ";
            $cmd .= "DS:ifoutdiscards:COUNTER:10:U:U ";
            $cmd .= "RRA:AVERAGE:0.5:1:241920 ";
            $cmd .= "RRA:AVERAGE:0.5:2:120960 ";
            $cmd .= "RRA:AVERAGE:0.5:6:40320 ";
            $cmd .= "RRA:AVERAGE:0.5:12:20160 ";
            $cmd .= "RRA:AVERAGE:0.5:24:10080 "; 
            $cmd .= "RRA:AVERAGE:0.5:36:6720 ";
            $cmd .= "RRA:AVERAGE:0.5:48:5040 ";
            $cmd .= "RRA:AVERAGE:0.5:60:4032 ";
            $cmd .= "RRA:AVERAGE:0.5:120:2016";
            RRDp::cmd $cmd;
            my $answer = RRDp::read;
        };
        if ($EVAL_ERROR) {
            return -1;
        }

        my($fileHandle, $fileName) = tempfile();
        $makeStore = $fileName;
        print $fileHandle "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
        print $fileHandle "<nmwg:store  xmlns:nmwg=\"http://ggf.org/ns/nmwg/base/2.0/\"\n";
        print $fileHandle "             xmlns:netutil=\"http://ggf.org/ns/nmwg/characteristic/utilization/2.0/\"\n";
        print $fileHandle "             xmlns:neterr=\"http://ggf.org/ns/nmwg/characteristic/errors/2.0/\"\n";
        print $fileHandle "             xmlns:netdisc=\"http://ggf.org/ns/nmwg/characteristic/discards/2.0/\"\n";
        print $fileHandle "             xmlns:nmwgt=\"http://ggf.org/ns/nmwg/topology/2.0/\"\n";
        print $fileHandle "             xmlns:snmp=\"http://ggf.org/ns/nmwg/tools/snmp/2.0/\"\n";
        print $fileHandle "             xmlns:nmtm=\"http://ggf.org/ns/nmwg/time/2.0/\">\n\n";
        foreach my $et (("netutil", "neterr", "netdisc")) {
            foreach my $dir (("in", "out")) {
                print $fileHandle "  <nmwg:metadata xmlns:nmwg=\"http://ggf.org/ns/nmwg/base/2.0/\" id=\"m-".$dir."-".$et."-1\">\n";
                if($et eq "netutil") {
                    print $fileHandle "    <netutil:subject xmlns:netutil=\"http://ggf.org/ns/nmwg/characteristic/utilization/2.0/\" id=\"s-".$dir."-".$et."-1\">\n";
                }
                elsif($et eq "neterr") {
                    print $fileHandle "    <neterr:subject xmlns:neterr=\"http://ggf.org/ns/nmwg/characteristic/errors/2.0/\" id=\"s-".$dir."-".$et."-1\">\n";
                }
                elsif($et eq "netdisc") {
                    print $fileHandle "    <netdisc:subject xmlns:netdisc=\"http://ggf.org/ns/nmwg/characteristic/discards/2.0/\" id=\"s-".$dir."-".$et."-1\">\n";
                }
                print $fileHandle "      <nmwgt:interface xmlns:nmwgt=\"http://ggf.org/ns/nmwg/topology/2.0/\">\n";
                print $fileHandle "        <nmwgt:ifAddress type=\"ipv4\">127.0.0.1</nmwgt:ifAddress>\n";
                print $fileHandle "        <nmwgt:hostName>localhost</nmwgt:hostName>\n";
                print $fileHandle "        <nmwgt:ifName>eth0</nmwgt:ifName>\n";
                print $fileHandle "        <nmwgt:ifIndex>2</nmwgt:ifIndex>\n";
                print $fileHandle "        <nmwgt:direction>".$dir."</nmwgt:direction>\n";
                print $fileHandle "        <nmwgt:capacity>1000000000</nmwgt:capacity>\n";
                print $fileHandle "      </nmwgt:interface>\n";
                if($et eq "netutil") {
                    print $fileHandle "    </netutil:subject>\n";
                    print $fileHandle "    <nmwg:eventType>http://ggf.org/ns/nmwg/characteristic/utilization/2.0</nmwg:eventType>\n";
                }
                elsif($et eq "neterr") {
                    print $fileHandle "    </neterr:subject>\n";
                    print $fileHandle "    <nmwg:eventType>http://ggf.org/ns/nmwg/characteristic/errors/2.0</nmwg:eventType>\n";
                }      
                elsif($et eq "netdisc") {
                    print $fileHandle "    </netdisc:subject>\n";
                    print $fileHandle "    <nmwg:eventType>http://ggf.org/ns/nmwg/characteristic/discards/2.0</nmwg:eventType>\n";
                }     
                print $fileHandle "    <nmwg:eventType>http://ggf.org/ns/nmwg/tools/snmp/2.0</nmwg:eventType>\n";
                print $fileHandle "  </nmwg:metadata>\n\n";
 
                print $fileHandle "  <nmwg:data xmlns:nmwg=\"http://ggf.org/ns/nmwg/base/2.0/\" id=\"d-".$dir."-".$et."-1\" metadataIdRef=\"m-".$dir."-".$et."-1\">\n";
                print $fileHandle "    <nmwg:key id=\"k-".$dir."-".$et."-1\">\n";
                print $fileHandle "      <nmwg:parameters id=\"pk-".$dir."-".$et."-1\">\n";
                print $fileHandle "        <nmwg:parameter name=\"eventType\">http://ggf.org/ns/nmwg/tools/snmp/2.0</nmwg:parameter>\n";
                if($et eq "netutil") {
                    print $fileHandle "        <nmwg:parameter name=\"eventType\">http://ggf.org/ns/nmwg/characteristic/utilization/2.0</nmwg:parameter>\n";             
                }
                elsif($et eq "neterr") {
                    print $fileHandle "        <nmwg:parameter name=\"eventType\">http://ggf.org/ns/nmwg/characteristic/errors/2.0</nmwg:parameter>\n";             
                }     
                elsif($et eq "netdisc") {
                    print $fileHandle "        <nmwg:parameter name=\"eventType\">http://ggf.org/ns/nmwg/characteristic/discards/2.0</nmwg:parameter>\n";             
                }    
                print $fileHandle "        <nmwg:parameter name=\"type\">rrd</nmwg:parameter>\n";
                print $fileHandle "        <nmwg:parameter name=\"file\">".$confdir."/localhost.rrd</nmwg:parameter>\n";
                if($et eq "netutil") {        
                    print $fileHandle "        <nmwg:parameter name=\"valueUnits\">Bps</nmwg:parameter>\n";
                    print $fileHandle "        <nmwg:parameter name=\"dataSource\">if".$dir."octets</nmwg:parameter>\n";
                }
                elsif($et eq "neterr") {
                    print $fileHandle "        <nmwg:parameter name=\"valueUnits\">Eps</nmwg:parameter>\n";
                    print $fileHandle "        <nmwg:parameter name=\"dataSource\">if".$dir."errors</nmwg:parameter>\n";
                }                
                elsif($et eq "netdisc") {
                    print $fileHandle "        <nmwg:parameter name=\"valueUnits\">Dps</nmwg:parameter>\n";
                    print $fileHandle "        <nmwg:parameter name=\"dataSource\">if".$dir."discards</nmwg:parameter>\n";
                }   
                print $fileHandle "      </nmwg:parameters>\n";
                print $fileHandle "    </nmwg:key>\n";
                print $fileHandle "  </nmwg:data>\n\n";
            }
        }
        print $fileHandle "</nmwg:store>\n";
        close($fileHandle);
    }

    if ( $config->{"snmp"}->{"metadata_db_type"} eq "file" ) {
        delete $config->{"snmp"}->{"metadata_db_file"} if $config->{"snmp"}->{"metadata_db_file"} and $config->{"snmp"}->{"metadata_db_file"} =~ m/dbxml$/mx;
        $config->{"snmp"}->{"metadata_db_file"} = &ask( "Enter the filename of the XML file ", $confdir . "/store.xml", $config->{"snmp"}->{"metadata_db_file"}, '\.xml$' );
        if ( $makeStore ) {
            if ( -f $config->{"snmp"}->{"metadata_db_file"} ) {
                system("mv " . $config->{"snmp"}->{"metadata_db_file"} . " " . $config->{"snmp"}->{"metadata_db_file"} . "~");
            }
            system( "mv " . $makeStore . " " . $config->{"snmp"}->{"metadata_db_file"});
        }
        delete $config->{"snmp"}->{"db_autoload"}               if $config->{"snmp"}->{"db_autoload"};
        delete $config->{"snmp"}->{"autoload_metadata_db_file"} if $config->{"snmp"}->{"autoload_metadata_db_file"};
        delete $config->{"snmp"}->{"metadata_db_name"}          if $config->{"snmp"}->{"metadata_db_name"};
    }
    elsif ( $config->{"snmp"}->{"metadata_db_type"} eq "xmldb" ) {
        $config->{"snmp"}->{"metadata_db_name"} = &ask( "Enter the directory of the XML database ", $confdir . "/xmldb", $config->{"snmp"}->{"metadata_db_name"}, '.+' );
        delete $config->{"snmp"}->{"metadata_db_file"} if $config->{"snmp"}->{"metadata_db_file"} and $config->{"snmp"}->{"metadata_db_file"} =~ m/\.xml$/mx;
        $config->{"snmp"}->{"metadata_db_file"} = &ask( "Enter the name of the container inside of the XML database ", "store.dbxml", $config->{"snmp"}->{"metadata_db_file"}, '.+' );

        if ( $makeStore ) {
            $config->{"snmp"}->{"db_autoload"} = 1;
            $config->{"snmp"}->{"autoload_metadata_db_file"} = &ask( "Enter the filename of the base XML file to load ", $confdir . "/store.xml", $config->{"snmp"}->{"autoload_metadata_db_file"}, '\.xml$' );
            if ( -f $config->{"snmp"}->{"autoload_metadata_db_file"} ) {
                system("mv " . $config->{"snmp"}->{"autoload_metadata_db_file"} . " " . $config->{"snmp"}->{"autoload_metadata_db_file"} . "~");
            }
            system( "mv " . $makeStore . " " . $config->{"snmp"}->{"metadata_db_file"});
        }
        else {
            $config->{"snmp"}->{"db_autoload"} = &ask( "Would you like to auto-load the database [non-destructive] ? (0 for no, 1 for yes) ", "1", $config->{"snmp"}->{"db_autoload"}, '^[01]$' );
            if ( $config->{"snmp"}->{"db_autoload"} eq "1" ) {
                $config->{"snmp"}->{"autoload_metadata_db_file"} = &ask( "Enter the filename of the base XML file to load ", $confdir . "/store.xml", $config->{"snmp"}->{"autoload_metadata_db_file"}, '\.xml$' );            
            }
        }
    }

    $config->{"snmp"}->{"enable_registration"} = &ask( "Will this service register with an LS (0 for no, 1 for yes) ", "0", $config->{"snmp"}->{"enable_registration"}, '^[01]$' );

    if ( $config->{"snmp"}->{"enable_registration"} eq "1" ) {
        my $registration_interval = $def_config->{"ls_registration_interval"};
        $registration_interval = $config->{"snmp"}->{"ls_registration_interval"} if ( defined $config->{"snmp"}->{"ls_registration_interval"} );
        $config->{"snmp"}->{"ls_registration_interval"} = &ask( "Interval between when LS registrations occur [in minutes] ", "30", $registration_interval, '^\d+$' );

        my $ls_instance = $def_config->{"ls_instance"};
        $ls_instance = $config->{"snmp"}->{"ls_instance"} if ( defined $config->{"snmp"}->{"ls_instance"} );
        $config->{"snmp"}->{"ls_instance"} = &ask( "URL of an LS to register with ", q{}, $ls_instance, '^http:\/\/' );
    }

    $config->{"snmp"}->{"service_name"} = &ask( "Enter a name for this service ", "SNMP MA", $config->{"snmp"}->{"service_name"}, '.+' );

    $config->{"snmp"}->{"service_type"} = &ask( "Enter the service type ", "MA", $config->{"snmp"}->{"service_type"}, '.+' );

    $config->{"snmp"}->{"service_description"} = &ask( "Enter a service description ", "SNMP MA", $config->{"snmp"}->{"service_description"}, '.+' );

    $config->{"snmp"}->{"service_accesspoint"} = &ask( "Enter the service's URI ", $accesspoint, $config->{"snmp"}->{"service_accesspoint"}, '^http:\/\/' );

    return;
}

sub config_pinger($$$$) {
	my ($config, $accesspoint, $def_config, $modulename) = @_;
	my $moduletype = ($modulename =~ /ma$/ ? "MA" : "MP");

	$config->{$modulename}->{"db_type"} = &ask("Enter the database type to read from (sqlite,mysql) ", "mysql", $config->{$modulename}->{"db_type"}, '^(sqlite|mysql)$');

	if ($config->{$modulename}->{"db_type"} eq "sqlite") {
		$config->{$modulename}->{"db_file"} = &ask("Enter the filename of the SQLite database ", "pinger.db", $config->{$modulename}->{"db_file"}, '.+');
	} elsif ($config->{$modulename}->{"db_type"} eq "mysql") {
		$config->{$modulename}->{"db_name"} = &ask("Enter the name of the MySQL database ", "", $config->{$modulename}->{"db_name"}, '.+');
		$config->{$modulename}->{"db_host"} = &ask("Enter the host for the MySQL database ", "localhost", $config->{$modulename}->{"db_host"}, '.+');
		$tmp = &ask("Enter the port for the MySQL database (leave blank for the default) ", "", $config->{$modulename}->{"db_port"}, '^\d*$');
		$config->{$modulename}->{"db_port"} = $tmp if ($tmp ne "");
		$tmp = &ask("Enter the username for the MySQL database (leave blank for none) ", "", $config->{$modulename}->{"db_username"}, '');
		$config->{$modulename}->{"db_username"} = $tmp if ($tmp ne "");
		$tmp  = &ask("Enter the password for the MySQL database (leave blank for none) ", "", $config->{$modulename}->{"db_password"}, '');
		$config->{$modulename}->{"db_password"} = $tmp if ($tmp ne "");
	}

	if($modulename eq "pingermp") {
		$config->{$modulename}->{"configuration_file"} = &ask("Name of XML configuration file for landmarks and schedules ", "/etc/perfsonar/pinger-landmarks.xml", $config->{$modulename}->{"configuration_file"}, '.+');
	}
	
	if($modulename eq "pingerma") {
	  $config->{$modulename}->{"query_size_limit"} = &ask("Enter the limit on query size ", "100000", $config->{$modulename}->{"query_size_limit"}, '^\d*$');
  }

	$config->{$modulename}->{"enable_registration"} = &ask("Will this service register with an LS (0,1) ", "0", $config->{$modulename}->{"enable_registration"}, '^[01]$');

	if($config->{$modulename}->{"enable_registration"} eq "1") {
		my $registration_interval = $def_config->{"ls_registration_interval"};
		$registration_interval = $config->{$modulename}->{"ls_registration_interval"} if (defined $config->{$modulename}->{"ls_registration_interval"});
		$config->{$modulename}->{"ls_registration_interval"} = &ask("Enter the number of minutes between LS registrations ", "30", $registration_interval, '^\d+$');

		$config->{$modulename}->{"service_name"} = &ask("Enter a name for this service ", "PingER $moduletype", $config->{$modulename}->{"service_name"}, '.+');

#		$config->{$modulename}->{"service_type"} = &ask("Enter the service type ", $moduletype, $config->{$modulename}->{"service_type"}, '.+');

		$config->{$modulename}->{"service_description"} = &ask("Enter a service description ", "PingER $moduletype", $config->{$modulename}->{"service_description"}, '.+');

		$config->{$modulename}->{"service_accesspoint"} = &ask("Enter the service's URI ", $accesspoint, $config->{$modulename}->{"service_accesspoint"}, '^http:\/\/');
	}
}

sub config_status_ma {
    my ( $config, $accesspoint, $def_config ) = @_;

    $config->{"status"}->{"read_only"} = &ask( "Is this service read-only  (0 for no, 1 for yes) ", "0", $config->{"status"}->{"read_only"}, '^[01]$' );

    $config->{"status"}->{"db_type"} = &ask( "Enter the database type to read from ", "sqlite|mysql", $config->{"status"}->{"db_type"}, '(sqlite|mysql)' );

    if ( $config->{"status"}->{"db_type"} eq "sqlite" ) {
        $config->{"status"}->{"db_file"} = &ask( "Enter the filename of the SQLite database ", "status.db", $config->{"status"}->{"db_file"}, '.+' );
        $tmp = &ask( "Enter the table in the database to use ", "link_status", $config->{"status"}->{"db_table"}, '.+' );
        $config->{"status"}->{"db_table"} = $tmp if ($tmp);
    }
    elsif ( $config->{"status"}->{"db_type"} eq "mysql" ) {
        $config->{"status"}->{"db_name"} = &ask( "Enter the name of the MySQL database ",                               q{},         $config->{"status"}->{"db_name"}, '.+' );
        $config->{"status"}->{"db_host"} = &ask( "Enter the host for the MySQL database ",                              "localhost", $config->{"status"}->{"db_host"}, '.+' );
        $tmp                             = &ask( "Enter the port for the MySQL database (leave blank for the default)", q{},         $config->{"status"}->{"db_port"}, '^\d*$' );
        $config->{"status"}->{"db_port"} = $tmp if ($tmp);
        $tmp = &ask( "Enter the username for the MySQL database (leave blank for none) ", q{}, $config->{"status"}->{"db_username"}, q{} );
        $config->{"status"}->{"db_username"} = $tmp if ($tmp);
        $tmp = &ask( "Enter the password for the MySQL database (leave blank for none) ", q{}, $config->{"status"}->{"db_password"}, q{} );
        $config->{"status"}->{"db_password"} = $tmp if ($tmp);
        $tmp = &ask( "Enter the table in the database to use (leave blank for the default) ", "link_status", $config->{"status"}->{"db_table"}, q{} );
        $config->{"status"}->{"db_table"} = $tmp if ($tmp);
    }

    $config->{"status"}->{"enable_registration"} = &ask( "Will this service register with an LS (0 for no, 1 for yes) ", "0", $config->{"status"}->{"enable_registration"}, '^[01]$' );

    if ( $config->{"status"}->{"enable_registration"} eq "1" ) {
        my $registration_interval = $def_config->{"ls_registration_interval"};
        $registration_interval = $config->{"status"}->{"ls_registration_interval"} if ( defined $config->{"status"}->{"ls_registration_interval"} );
        $config->{"status"}->{"ls_registration_interval"} = &ask( "Interval between when LS registrations occur [in minutes] ", "30", $registration_interval, '^\d+$' );

        my $ls_instance = $def_config->{"ls_instance"};
        $ls_instance = $config->{"status"}->{"ls_instance"} if ( defined $config->{"status"}->{"ls_instance"} );
        $config->{"status"}->{"ls_instance"} = &ask( "URL of an LS to register with ", q{}, $ls_instance, '^http:\/\/' );

        $config->{"status"}->{"service_name"} = &ask( "Enter a name for this service ", "Link Status MA", $config->{"status"}->{"service_name"}, '.+' );

        $config->{"status"}->{"service_type"} = &ask( "Enter the service type ", "MA", $config->{"status"}->{"service_type"}, '.+' );

        $config->{"status"}->{"service_description"} = &ask( "Enter a service description ", "Link Status MA", $config->{"status"}->{"service_description"}, '.+' );

        $config->{"status"}->{"service_accesspoint"} = &ask( "Enter the service's URI ", $accesspoint, $config->{"status"}->{"service_accesspoint"}, '^http:\/\/' );
    }
    return;
}

sub config_circuitstatus_ma {
    my ( $config, $accesspoint, $def_config ) = @_;

    $config->{"circuitstatus"}->{"circuits_file_type"} = "file";

    $config->{"circuitstatus"}->{"circuits_file"} = &ask( "Enter the file to get link information from ", q{}, $config->{"circuitstatus"}->{"circuits_file"}, '.+' );

    $config->{"circuitstatus"}->{"status_ma_type"} = &ask( "Enter the MA to get status information from ", "sqlite|mysql", $config->{"circuitstatus"}->{"status_ma_type"}, '(sqlite|mysql|ma|ls)' );

    if ( $config->{"circuitstatus"}->{"status_ma_type"} eq "ma" ) {
        $config->{"circuitstatus"}->{"status_ma_uri"} = &ask( "Enter the URI of the Status MA ", q{}, $config->{"circuitstatus"}->{"status_ma_uri"}, '^http' );
    }
    elsif ( $config->{"circuitstatus"}->{"status_ma_type"} eq "ls" ) {
        my $ls = $def_config->{"ls_instance"};
        $ls = $config->{"circuitstatus"}->{"ls_instance"} if ( defined $config->{"circuitstatus"}->{"ls_instance"} );
        $config->{"circuitstatus"}->{"ls_instance"} = &ask( "Enter the URI of the LS to get MA information from ", q{}, $ls, '^http' );
    }
    elsif ( $config->{"circuitstatus"}->{"status_ma_type"} eq "sqlite" ) {
        $config->{"circuitstatus"}->{"status_ma_name"}  = &ask( "Enter the filename of the SQLite database ", q{},           $config->{"status"}->{"status_ma_name"},  '.+' );
        $config->{"circuitstatus"}->{"status_ma_table"} = &ask( "Enter the table in the database to use ",    "link_status", $config->{"status"}->{"status_ma_table"}, '.+' );
    }
    elsif ( $config->{"circuitstatus"}->{"status_ma_type"} eq "mysql" ) {
        $config->{"status"}->{"status_ma_name"} = &ask( "Enter the name of the MySQL database ",                               q{},         $config->{"status"}->{"status_ma_name"}, '.+' );
        $config->{"status"}->{"status_ma_host"} = &ask( "Enter the host for the MySQL database ",                              "localhost", $config->{"status"}->{"status_ma_host"}, '.+' );
        $tmp                                    = &ask( "Enter the port for the MySQL database (leave blank for the default)", q{},         $config->{"status"}->{"status_ma_port"}, '^\d*$' );
        $config->{"status"}->{"status_ma_port"} = $tmp if ($tmp);
        $tmp = &ask( "Enter the username for the MySQL database (leave blank for none) ", q{}, $config->{"status"}->{"status_ma_username"}, q{} );
        $config->{"status"}->{"status_ma_username"} = $tmp if ($tmp);
        $tmp = &ask( "Enter the password for the MySQL database (leave blank for none) ", q{}, $config->{"status"}->{"status_ma_password"}, q{} );
        $config->{"status"}->{"status_ma_password"} = $tmp if ($tmp);
        $config->{"circuitstatus"}->{"status_ma_table"} = &ask( "Enter the table in the database to use ", "link_status", $config->{"status"}->{"status_ma_table"}, '.+' );
    }

    $config->{"circuitstatus"}->{"topology_ma_type"} = &ask( "Enter the MA to get Topology information from ", "sqlite|mysql", $config->{"circuitstatus"}->{"topology_ma_type"}, '(xml|ma|none)' );

    $config->{"circuitstatus"}->{"topology_ma_type"} = lc( $config->{"circuitstatus"}->{"topology_ma_type"} );

    if ( $config->{"circuitstatus"}->{"topology_ma_type"} eq "xml" ) {
        $config->{"topology"}->{"topology_ma_name"} = &ask( "Enter the directory of the XML database ", q{}, $config->{"topology"}->{"topology_ma_name"}, '.+' );
        $config->{"topology"}->{"topology_ma_file"} = &ask( "Enter the filename of the XML database ",  q{}, $config->{"topology"}->{"topology_ma_file"}, '.+' );
    }
    elsif ( $config->{"circuitstatus"}->{"topology_ma_type"} eq "ma" ) {
        $config->{"circuitstatus"}->{"topology_ma_uri"} = &ask( "Enter the URI of the Status MA ", q{}, $config->{"circuitstatus"}->{"topology_ma_uri"}, '^http' );
    }

    $config->{"circuitstatus"}->{"cache_length"} = &ask( "Enter length of time to cache 'current' results ", q{}, $config->{"circuitstatus"}->{"cache_length"}, '^\d+$' );
    if ( $config->{"circuitstatus"}->{"cache_length"} > 0 ) {
        $config->{"circuitstatus"}->{"cache_file"} = &ask( "Enter file to cache 'current' results in ", q{}, $config->{"circuitstatus"}->{"cache_file"}, '.+' );
    }

    $config->{"circuitstatus"}->{"max_recent_age"} = &ask( "Enter age in seconds at which a result is considered stale ", q{}, $config->{"circuitstatus"}->{"max_recent_age"}, '^\d+$' );
    return;
}

sub config_topology_ma {
    my ( $config, $accesspoint, $def_config ) = @_;

    $config->{"topology"}->{"db_type"} = "xml";

    $config->{"topology"}->{"read_only"} = &ask( "Is this service read-only (0 for no, 1 for yes) ", "1", $config->{"topology"}->{"read_only"}, '^[01]$' );

    $config->{"topology"}->{"db_environment"} = &ask( "Enter the directory of the XML database ", q{}, $config->{"topology"}->{"db_environment"}, '.+' );

    $config->{"topology"}->{"db_file"} = &ask( "Enter the filename of the XML database ", q{}, $config->{"topology"}->{"db_file"}, '.+' );

    $config->{"topology"}->{"enable_registration"} = &ask( "Will this service register with an LS (0 for no, 1 for yes) ", "0", $config->{"topology"}->{"enable_registration"}, '^[01]$' );

    if ( $config->{"topology"}->{"enable_registration"} eq "1" ) {
        my $registration_interval = $def_config->{"ls_registration_interval"};
        $registration_interval = $config->{"topology"}->{"ls_registration_interval"} if ( defined $config->{"topology"}->{"ls_registration_interval"} );
        $config->{"topology"}->{"ls_registration_interval"} = &ask( "Interval between when LS registrations occur [in minutes] ", "30", $registration_interval, '^\d+$' );

        my $ls_instance = $def_config->{"ls_instance"};
        $ls_instance = $config->{"topology"}->{"ls_instance"} if ( defined $config->{"topology"}->{"ls_instance"} );
        $config->{"topology"}->{"ls_instance"} = &ask( "URL of an LS to register with ", q{}, $ls_instance, '^http:\/\/' );

        $config->{"topology"}->{"service_name"} = &ask( "Enter a name for this service ", "Topology MA", $config->{"topology"}->{"service_name"}, '.+' );

        $config->{"topology"}->{"service_type"} = &ask( "Enter the service type ", "MA", $config->{"topology"}->{"service_type"}, '.+' );

        $config->{"topology"}->{"service_description"} = &ask( "Enter a service description ", "Topology MA", $config->{"topology"}->{"service_description"}, '.+' );

        $config->{"topology"}->{"service_accesspoint"} = &ask( "Enter the service's URI ", $accesspoint, $config->{"topology"}->{"service_accesspoint"}, '^http:\/\/' );
    }
    return;
}

sub ask {
    my ( $prompt, $value, $prev_value, $regex ) = @_;

    my $result;
    do {
        print $prompt;
        if ( defined $prev_value ) {
            print "[", $prev_value, "]";
        }
        elsif ( defined $value ) {
            print "[", $value, "]";
        }
        print ": ";
        local $| = 1;
        local $_ = <STDIN>;
        chomp;
        if ( defined $_ and $_ ne q{} ) {
            $result = $_;
        }
        elsif ( defined $prev_value ) {
            $result = $prev_value;
        }
        elsif ( defined $value ) {
            $result = $value;
        }
        else {
            $result = q{};
        }
    } while ( $regex and ( not $result =~ /$regex/mx ) );

    return $result;
}

sub SaveConfig_mine {
    my ( $file, $hash ) = @_;

    my $fh;

    if ( open( $fh, ">", $file ) ) {
        printValue( $fh, q{}, $hash, -4 );
        if ( close($fh) ) {
            return 0;
        }
    }
    return -1;
}

sub printSpaces {
    my ( $fh, $count ) = @_;
    while ( $count > 0 ) {
        print $fh " ";
        $count--;
    }
    return;
}

sub printScalar {
    my ( $fileHandle, $name, $value, $depth ) = @_;

    printSpaces( $fileHandle, $depth );
    if ( $value =~ /\n/mx ) {
        my @lines = split( $value, '\n' );
        print $fileHandle "$name     <<EOF\n";
        foreach my $line (@lines) {
            printSpaces( $fileHandle, $depth );
            print $fileHandle $line . "\n";
        }
        printSpaces( $fileHandle, $depth );
        print $fileHandle "EOF\n";
    }
    else {
        print $fileHandle "$name     " . $value . "\n";
    }
    return;
}

sub printValue {
    my ( $fileHandle, $name, $value, $depth ) = @_;

    if ( ref $value eq "" ) {
        printScalar( $fileHandle, $name, $value, $depth );

        return;
    }
    elsif ( ref $value eq "ARRAY" ) {
        foreach my $elm ( @{$value} ) {
            printValue( $fileHandle, $name, $elm, $depth );
        }

        return;
    }
    elsif ( ref $value eq "HASH" ) {
        if ( $name eq "endpoint" or $name eq "port" ) {
            foreach my $elm ( sort keys %{$value} ) {
                printSpaces( $fileHandle, $depth );
                print $fileHandle "<$name $elm>\n";
                printValue( $fileHandle, q{}, $value->{$elm}, $depth + 4 );
                printSpaces( $fileHandle, $depth );
                print $fileHandle "</$name>\n";
            }
        }
        else {
            if ($name) {
                printSpaces( $fileHandle, $depth );
                print $fileHandle "<$name>\n";
            }
            foreach my $elm ( sort keys %{$value} ) {
                printValue( $fileHandle, $elm, $value->{$elm}, $depth + 4 );
            }
            if ($name) {
                printSpaces( $fileHandle, $depth );
                print $fileHandle "</$name>\n";
            }
        }

        return;
    }
}

__END__
	
=head1 SEE ALSO

L<Config::General>, L<Sys::Hostname>, L<Data::Dumper>

To join the 'perfSONAR-PS' mailing list, please visit:

  https://mail.internet2.edu/wws/info/i2-perfsonar

The perfSONAR-PS subversion repository is located at:

  https://svn.internet2.edu/svn/perfSONAR-PS

Questions and comments can be directed to the author, or the mailing list.
Bugs, feature requests, and improvements can be directed here:

https://bugs.internet2.edu/jira/browse/PSPS

=head1 VERSION

$Id$

=head1 AUTHOR

Jason Zurawski, zurawski@internet2.edu
Aaron Brown, aaron@internet2.edu

=head1 LICENSE

You should have received a copy of the Internet2 Intellectual Property Framework
along with this software.  If not, see
<http://www.internet2.edu/membership/ip.html>

=head1 COPYRIGHT

Copyright (c) 2004-2008, Internet2 and the University of Delaware

All rights reserved.

=cut