Cleaned up ".$cleaned." stale webDAV session token(s).
");
+ &log($fh,"Cleaned up ".$cleaned." stale sockets.
");
+}
+
# ----------------------------------------------------------------------- httpd
sub check_httpd_logs {
my ($fh)=@_;
- &log($fh,'");
my ($good,$bad)=(0,0);
- foreach my $tryserver (sort(keys(%{$hostname}))) {
+ my %hostname = &Apache::lonnet::all_hostnames();
+ foreach my $tryserver (sort(keys(%hostname))) {
print(".");
my $result;
- my $answer=&reply("ping",$tryserver,$hostname);
+ my $answer=&Apache::lonnet::reply("ping",$tryserver);
if ($answer eq "$tryserver:$perlvar{'lonHostID'}") {
$result="ok";
$good++;
@@ -510,20 +646,26 @@ sub test_connections {
# ------------------------------------------------------------ Delayed messages
sub check_delayed_msg {
- my ($fh,$hostname)=@_;
+ my ($fh)=@_;
&log($fh,'
Delayed Messages
');
- print "checking buffers\n";
+ print "Checking buffers.\n";
&log($fh,'Scanning Permanent Log
');
my $unsend=0;
+ my %hostname = &Apache::lonnet::all_hostnames();
+ my $numhosts = scalar(keys(%hostname));
+
my $dfh=IO::File->new("$perlvar{'lonDaemons'}/logs/lonnet.perm.log");
while (my $line=<$dfh>) {
my ($time,$sdf,$dserv,$dcmd)=split(/:/,$line);
+ if ($numhosts) {
+ next unless ($hostname{$dserv});
+ }
if ($sdf eq 'F') {
my $local=localtime($time);
- &log($fh,"Failed: $time, $dserv, $dcmd
");
+ &log($fh,"Failed: $time, $dserv, $dcmd
");
$warnings++;
}
if ($sdf eq 'S') { $unsend--; }
@@ -531,7 +673,9 @@ sub check_delayed_msg {
}
&log($fh,"Total unsend messages: $unsend
\n");
- $warnings=$warnings+5*$unsend;
+ if ($unsend > 0) {
+ $warnings=$warnings+5*$unsend;
+ }
if ($unsend) { $simplestatus{'unsend'}=$unsend; }
&log($fh,"Outgoing Buffer
\n");
@@ -547,9 +691,24 @@ sub check_delayed_msg {
close (DFH);
# pong to all servers that have delayed messages
# this will trigger a reverse connection, which should flush the buffers
- foreach my $tryserver (keys %servers) {
- my $answer=&reply("pong",$tryserver,$hostname);
- &log($fh,"Pong to $tryserver: $answer
");
+ foreach my $tryserver (sort(keys(%servers))) {
+ if ($hostname{$tryserver} || !$numhosts) {
+ my $answer;
+ eval {
+ local $SIG{ ALRM } = sub { die "TIMEOUT" };
+ alarm(20);
+ $answer = &Apache::lonnet::reply("pong",$tryserver);
+ alarm(0);
+ };
+ if ($@ && $@ =~ m/TIMEOUT/) {
+ &log($fh,"Attempted pong to $tryserver timed out
");
+ print "Time out while contacting: $tryserver for pong.\n";
+ } else {
+ &log($fh,"Pong to $tryserver: $answer
");
+ }
+ } else {
+ &log($fh,"$tryserver has delayed messages, but is not part of the cluster -- skipping 'Pong'.
");
+ }
}
}
@@ -562,7 +721,7 @@ sub finish_logging {
my $now=time;
my $date=localtime($now);
&log($fh,"
$date ($now)\n");
- print "lon-status webpage updated\n";
+ print "lon-status webpage updated.\n";
$fh->close();
if ($errors) { $simplestatus{'errors'}=$errors; }
@@ -572,7 +731,7 @@ sub finish_logging {
}
sub log_simplestatus {
- rename ("$statusdir/newstatus.html","$statusdir/index.html");
+ rename("$statusdir/newstatus.html","$statusdir/index.html");
my $sfh=IO::File->new(">$statusdir/loncron_simple.txt");
foreach (keys %simplestatus) {
@@ -582,23 +741,394 @@ sub log_simplestatus {
$sfh->close();
}
+sub write_loncaparevs {
+ print "Retrieving LON-CAPA version information.\n";
+ my %hostname = &Apache::lonnet::all_hostnames();
+ my $output;
+ foreach my $id (sort(keys(%hostname))) {
+ if ($id ne '') {
+ my $loncaparev;
+ eval {
+ local $SIG{ ALRM } = sub { die "TIMEOUT" };
+ alarm(10);
+ $loncaparev =
+ &Apache::lonnet::get_server_loncaparev('',$id,1,'loncron');
+ alarm(0);
+ };
+ if ($@ && $@ =~ m/TIMEOUT/) {
+ print "Time out while contacting lonHost: $id for version.\n";
+ }
+ if ($loncaparev =~ /^[\w.\-]+$/) {
+ $output .= $id.':'.$loncaparev."\n";
+ }
+ }
+ }
+ if ($output) {
+ if (open(my $fh,">$perlvar{'lonTabDir'}/loncaparevs.tab")) {
+ print $fh $output;
+ close($fh);
+ &Apache::lonnet::load_loncaparevs();
+ }
+ }
+ return;
+}
+
+sub write_serverhomeIDs {
+ print "Retrieving LON-CAPA lonHostID information.\n";
+ my %name_to_host = &Apache::lonnet::all_names();
+ my $output;
+ foreach my $name (sort(keys(%name_to_host))) {
+ if ($name ne '') {
+ if (ref($name_to_host{$name}) eq 'ARRAY') {
+ my $serverhomeID;
+ eval {
+ local $SIG{ ALRM } = sub { die "TIMEOUT" };
+ alarm(10);
+ $serverhomeID =
+ &Apache::lonnet::get_server_homeID($name,1,'loncron');
+ alarm(0);
+ };
+ if ($@ && $@ =~ m/TIMEOUT/) {
+ print "Time out while contacting server: $name\n";
+ }
+ if ($serverhomeID ne '') {
+ $output .= $name.':'.$serverhomeID."\n";
+ } else {
+ $output .= $name.':'.$name_to_host{$name}->[0]."\n";
+ }
+ }
+ }
+ }
+ if ($output) {
+ if (open(my $fh,">$perlvar{'lonTabDir'}/serverhomeIDs.tab")) {
+ print $fh $output;
+ close($fh);
+ &Apache::lonnet::load_serverhomeIDs();
+ }
+ }
+ return;
+}
+
+sub write_checksums {
+ my $distro = &LONCAPA::distro();
+ if ($distro) {
+ print "Retrieving file version and checksumming.\n";
+ my $numchksums = 0;
+ my ($chksumsref,$versionsref) =
+ &LONCAPA::Checksumming::get_checksums($distro,$perlvar{'lonDaemons'},
+ $perlvar{'lonLib'},
+ $perlvar{'lonIncludes'},
+ $perlvar{'lonTabDir'});
+ if (ref($chksumsref) eq 'HASH') {
+ $numchksums = scalar(keys(%{$chksumsref}));
+ }
+ print "File version retrieved and checksumming completed for $numchksums files.\n";
+ } else {
+ print "File version retrieval and checksumming skipped - could not determine Linux distro.\n";
+ }
+ return;
+}
+
+sub clean_nosslverify {
+ my ($fh) = @_;
+ my %unlinked;
+ if (-d "$perlvar{'lonSockDir'}/nosslverify") {
+ if (opendir(my $dh,"$perlvar{'lonSockDir'}/nosslverify")) {
+ while (my $fname=readdir($dh)) {
+ next if ($fname =~ /^\.+$/);
+ if (unlink("/home/httpd/sockets/nosslverify/$fname")) {
+ &log($fh,"Unlinking $fname
");
+ $unlinked{$fname} = 1;
+ }
+ }
+ closedir($dh);
+ }
+ }
+ &log($fh,"Removed ".scalar(keys(%unlinked))." nosslverify clients
");
+ return %unlinked;
+}
+sub clean_lonc_childpids {
+ my $childpiddir = "$perlvar{'lonDocRoot'}/lon-status/loncchld";
+ if (-d $childpiddir) {
+ if (opendir(my $dh,$childpiddir)) {
+ while (my $fname=readdir($dh)) {
+ next if ($fname =~ /^\.+$/);
+ unlink("$childpiddir/$fname");
+ }
+ closedir($dh);
+ }
+ }
+}
+
+sub write_connection_config {
+ my ($isprimary,$domconf,$url,%connectssl,%changes);
+ my $primaryLibServer = &Apache::lonnet::domain($perlvar{'lonDefDomain'},'primary');
+ if ($primaryLibServer eq $perlvar{'lonHostID'}) {
+ $isprimary = 1;
+ } elsif ($primaryLibServer ne '') {
+ my $protocol = $Apache::lonnet::protocol{$primaryLibServer};
+ my $hostname = &Apache::lonnet::hostname($primaryLibServer);
+ unless ($protocol eq 'https') {
+ $protocol = 'http';
+ }
+ $url = $protocol.'://'.$hostname.'/cgi-bin/listdomconfig.pl';
+ }
+ my $domconf = &get_domain_config($perlvar{'lonDefDomain'},$primaryLibServer,$isprimary,
+ $url);
+ if (ref($domconf) eq 'HASH') {
+ if (ref($domconf->{'ssl'}) eq 'HASH') {
+ foreach my $connect ('connto','connfrom') {
+ if (ref($domconf->{'ssl'}->{$connect}) eq 'HASH') {
+ my ($sslreq,$sslnoreq,$currsetting);
+ my %contypes;
+ foreach my $type ('dom','intdom','other') {
+ $connectssl{$connect.'_'.$type} = $domconf->{'ssl'}->{$connect}->{$type};
+ }
+ }
+ }
+ }
+ if (keys(%connectssl)) {
+ my %currconf;
+ if (open(my $fh,'<',"$perlvar{'lonTabDir'}/connectionrules.tab")) {
+ while (my $line = <$fh>) {
+ chomp($line);
+ my ($name,$value) = split(/=/,$line);
+ if ($value =~ /^(?:no|yes|req)$/) {
+ if ($name =~ /^conn(to|from)_(dom|intdom|other)$/) {
+ $currconf{$name} = $value;
+ }
+ }
+ }
+ close($fh);
+ }
+ if (open(my $fh,'>',"$perlvar{'lonTabDir'}/connectionrules.tab")) {
+ my $count = 0;
+ foreach my $key (sort(keys(%connectssl))) {
+ print $fh "$key=$connectssl{$key}\n";
+ if (exists($currconf{$key})) {
+ unless ($currconf{$key} eq $connectssl{$key}) {
+ $changes{$key} = 1;
+ }
+ } else {
+ $changes{$key} = 1;
+ }
+ $count ++;
+ }
+ close($fh);
+ print "Completed writing SSL options for lonc/lond for $count items.\n";
+ }
+ } else {
+ print "Writing of SSL options skipped - no connection rules in domain configuration.\n";
+ }
+ } else {
+ print "Retrieval of SSL options for lonc/lond skipped - no configuration data available for domain.\n";
+ }
+ return %changes;
+}
+
+sub get_domain_config {
+ my ($dom,$primlibserv,$isprimary,$url) = @_;
+ my %confhash;
+ if ($isprimary) {
+ my $lonusersdir = $perlvar{'lonUsersDir'};
+ my $fname = $lonusersdir.'/'.$dom.'/configuration.db';
+ if (-e $fname) {
+ my $dbref=&LONCAPA::locking_hash_tie($fname,&GDBM_READER());
+ if (ref($dbref) eq 'HASH') {
+ foreach my $key (sort(keys(%{$dbref}))) {
+ my $value = $dbref->{$key};
+ if ($value =~ s/^__FROZEN__//) {
+ $value = thaw(&LONCAPA::unescape($value));
+ } else {
+ $value = &LONCAPA::unescape($value);
+ }
+ $confhash{$key} = $value;
+ }
+ &LONCAPA::locking_hash_untie($dbref);
+ }
+ }
+ } else {
+ if (open(PIPE,"wget --no-check-certificate '$url?primary=$primlibserv&format=raw' |")) {
+ my $config = '';
+ while () {
+ $config .= $_;
+ }
+ close(PIPE);
+ if ($config) {
+ my @pairs=split(/\&/,$config);
+ foreach my $item (@pairs) {
+ my ($key,$value)=split(/=/,$item,2);
+ my $what = &LONCAPA::unescape($key);
+ if ($value =~ s/^__FROZEN__//) {
+ $value = thaw(&LONCAPA::unescape($value));
+ } else {
+ $value = &LONCAPA::unescape($value);
+ }
+ $confhash{$what}=$value;
+ }
+ }
+ }
+ }
+ return \%confhash;
+}
+
+sub write_hosttypes {
+ my %intdom = &Apache::lonnet::all_host_intdom();
+ my %hostdom = &Apache::lonnet::all_host_domain();
+ my $dom = $hostdom{$perlvar{'lonHostID'}};
+ my $internetdom = $intdom{$perlvar{'lonHostID'}};
+ my %changes;
+ if (($dom ne '') && ($internetdom ne '')) {
+ if (keys(%hostdom)) {
+ my %currhosttypes;
+ if (open(my $fh,'<',"$perlvar{'lonTabDir'}/hosttypes.tab")) {
+ while (my $line = <$fh>) {
+ chomp($line);
+ my ($name,$value) = split(/:/,$line);
+ if (($name ne '') && ($value =~ /^(dom|intdom|other)$/)) {
+ $currhosttypes{$name} = $value;
+ }
+ }
+ close($fh);
+ }
+ if (open(my $fh,'>',"$perlvar{'lonTabDir'}/hosttypes.tab")) {
+ my $count = 0;
+ foreach my $lonid (sort(keys(%hostdom))) {
+ my $type = 'other';
+ if ($hostdom{$lonid} eq $dom) {
+ $type = 'dom';
+ } elsif ($intdom{$lonid} eq $internetdom) {
+ $type = 'intdom';
+ }
+ print $fh "$lonid:$type\n";
+ if (exists($currhosttypes{$lonid})) {
+ if ($type ne $currhosttypes{$lonid}) {
+ $changes{$lonid} = 1;
+ }
+ } else {
+ $changes{$lonid} = 1;
+ }
+ $count ++;
+ }
+ close($fh);
+ print "Completed writing host type data for $count hosts.\n";
+ }
+ } else {
+ print "Writing of host types skipped - no hosts found.\n";
+ }
+ } else {
+ print "Writing of host types skipped - could not determine this host's LON-CAPA domain or 'internet' domain.\n";
+ }
+ return %changes;
+}
+
+sub update_revocation_list {
+ my ($result,$changed) = &Apache::lonnet::fetch_crl_pemfile();
+ if ($result eq 'ok') {
+ print "Certificate Revocation List (from CA) updated.\n";
+ } else {
+ print "Certificate Revocation List from (CA) not updated.\n";
+ }
+ return $changed;
+}
+
+sub reset_nosslverify_pids {
+ my ($fh,%sslrem) = @_;
+ &checkon_daemon($fh,'lond',40000,'USR2');
+ my $loncpidfile="$perlvar{'lonDaemons'}/logs/lonc.pid";
+ my $loncppid;
+ if ((-e $loncpidfile) && (open(my $pfh,'<',$loncpidfile))) {
+ $loncppid=<$pfh>;
+ chomp($loncppid);
+ close($pfh);
+ if ($loncppid =~ /^\d+$/) {
+ my %pids_by_host;
+ my $docdir = $perlvar{'lonDocRoot'};
+ if (-d "$docdir/lon-status/loncchld") {
+ if (opendir(my $dh,"$docdir/lon-status/loncchld")) {
+ while (my $file = readdir($dh)) {
+ next if ($file =~ /^\./);
+ if (open(my $fh,'<',"$docdir/lon-status/loncchld/$file")) {
+ my $record = <$fh>;
+ chomp($record);
+ close($fh);
+ my ($remotehost,$authmode) = split(/:/,$record);
+ $pids_by_host{$remotehost}{$authmode}{$file} = 1;
+ }
+ }
+ closedir($dh);
+ if (keys(%pids_by_host)) {
+ foreach my $host (keys(%pids_by_host)) {
+ if ($sslrem{$host}) {
+ if (ref($pids_by_host{$host}) eq 'HASH') {
+ if (ref($pids_by_host{$host}{'insecure'}) eq 'HASH') {
+ if (keys(%{$pids_by_host{$host}{'insecure'}})) {
+ foreach my $pid (keys(%{$pids_by_host{$host}{'insecure'}})) {
+ if (open(PIPE,"ps -o ppid= -p $pid |")) {
+ my $ppid = ;
+ chomp($ppid);
+ close(PIPE);
+ $ppid =~ s/(^\s+|\s+$)//g;
+ if (($ppid == $loncppid) && (kill 0 => $pid)) {
+ kill QUIT => $pid;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return;
+}
+
sub send_mail {
- print "sending mail\n";
- my $emailto="$perlvar{'lonAdmEMail'}";
+ my $defdom = $perlvar{'lonDefDomain'};
+ my $origmail = $perlvar{'lonAdmEMail'};
+ my $emailto = &Apache::loncommon::build_recipient_list(undef,
+ 'lonstatusmail',$defdom,$origmail);
if ($totalcount>2500) {
$emailto.=",$perlvar{'lonSysEMail'}";
}
- my $subj="LON: $perlvar{'lonHostID'} E:$errors W:$warnings N:$notices";
-
- my $result=system("metasend -b -S 4000000 -t $emailto -s '$subj' -f $statusdir/index.html -m text/html >& /dev/null");
- if ($result != 0) {
- $result=system("mail -s '$subj' $emailto < $statusdir/index.html");
+ my $from;
+ my $hostname=`/bin/hostname`;
+ chop($hostname);
+ $hostname=~s/[^\w\.]//g;
+ if ($hostname) {
+ $from = 'www@'.$hostname;
+ }
+ my $subj="LON: $perlvar{'lonHostID'} E:$errors W:$warnings N:$notices";
+ my $loncronmail = "To: $emailto\n".
+ "From: $from\n".
+ "Subject: ".$subj."\n".
+ "Content-type: text/html\; charset=UTF-8\n".
+ "MIME-Version: 1.0\n\n";
+ if (open(my $fh,"<$statusdir/index.html")) {
+ while (<$fh>) {
+ $loncronmail .= $_;
+ }
+ close($fh);
+ } else {
+ $loncronmail .= "Failed to read from http://$hostname/lon-status/index.html\n";
+ }
+ $loncronmail .= "\n\n";
+ if (open(my $mailh, "|/usr/lib/sendmail -oi -t -odb")) {
+ print $mailh $loncronmail;
+ close($mailh);
+ print "Sending mail.\n";
+ } else {
+ print "Sending mail failed.\n";
}
}
sub usage {
print(< /dev/null");
+ system("echo 'Unconfigured machine $hostname.' |".
+ " mail -s '$subj' $emailto > /dev/null");
exit 1;
}
# ----------------------------- Make sure this process is running from user=www
my $wwwid=getpwnam('www');
if ($wwwid!=$<) {
- print("User ID mismatch. This program must be run as user 'www'\n");
+ print("User ID mismatch. This program must be run as user 'www'.\n");
my $emailto="$perlvar{'lonAdmEMail'},$perlvar{'lonSysEMail'}";
my $subj="LON: $perlvar{'lonHostID'} User ID mismatch";
- system("echo 'User ID mismatch. loncron must be run as user www.' |\
- mailto $emailto -s '$subj' > /dev/null");
+ system("echo 'User ID mismatch. loncron must be run as user www.' |".
+ " mail -s '$subj' $emailto > /dev/null");
exit 1;
}
-# ------------------------------------------------------------- Read hosts file
- my $config=IO::File->new("$perlvar{'lonTabDir'}/hosts.tab");
-
- my (%hostname,%hostdom,%hostrole,%spareid);
- while (my $configline=<$config>) {
- next if ($configline =~ /^(\#|\s*\$)/);
- my ($id,$domain,$role,$name)=split(/:/,$configline);
- if ($id && $domain && $role && $name) {
- $name=~s/\s//g;
- $hostname{$id}=$name;
- $hostdom{$id}=$domain;
- $hostrole{$id}=$role;
- }
+# -------------------------------------------- Force reload of host information
+ my $nomemcache;
+ if ($justcheckdaemons) {
+ $nomemcache=1;
+ my $memcachepidfile="$perlvar{'lonDaemons'}/logs/memcached.pid";
+ my $memcachepid;
+ if (-e $memcachepidfile) {
+ my $memfh=IO::File->new($memcachepidfile);
+ $memcachepid=<$memfh>;
+ chomp($memcachepid);
+ if ($memcachepid =~ /^\d+$/ && kill 0 => $memcachepid) {
+ undef($nomemcache);
+ }
+ }
+ }
+ &Apache::lonnet::load_hosts_tab(1,$nomemcache);
+ &Apache::lonnet::load_domain_tab(1,$nomemcache);
+ &Apache::lonnet::get_iphost(1,$nomemcache);
+
+# ----------------------------------------- Force firewall update for lond port
+
+ if ((!$justcheckdaemons) && (!$justreload)) {
+ my $now = time;
+ my $tmpfile = $perlvar{'lonDaemons'}.'/tmp/lciptables_iphost_'.
+ $now.$$.int(rand(10000));
+ if (open(my $fh,">$tmpfile")) {
+ my %iphosts = &Apache::lonnet::get_iphost();
+ foreach my $key (keys(%iphosts)) {
+ print $fh "$key\n";
+ }
+ close($fh);
+ if (&LONCAPA::try_to_lock('/tmp/lock_lciptables')) {
+ my $execpath = $perlvar{'lonDaemons'}.'/lciptables';
+ system("$execpath $tmpfile");
+ unlink('/tmp/lock_lciptables'); # Remove the lock file.
+ }
+ unlink($tmpfile);
+ }
}
- undef $config;
-
-# ------------------------------------------------------ Read spare server file
- $config=IO::File->new("$perlvar{'lonTabDir'}/spare.tab");
-
- while (my $configline=<$config>) {
- chomp($configline);
- if (($configline) && ($configline ne $perlvar{'lonHostID'})) {
- $spareid{$configline}=1;
- }
- }
- undef $config;
# ---------------------------------------------------------------- Start report
@@ -698,36 +1241,53 @@ sub main () {
my $fh;
if (!$justcheckdaemons && !$justcheckconnections && !$justreload) {
- $fh=&start_logging(\%hostdom,\%hostrole,\%hostname,\%spareid);
+ $fh=&start_logging();
&log_machine_info($fh);
&clean_tmp($fh);
&clean_lonIDs($fh);
+ &clean_webDAV_sessionIDs($fh);
&check_httpd_logs($fh);
&rotate_lonnet_logs($fh);
+ &rotate_other_logs($fh);
}
if (!$justcheckconnections && !$justreload) {
+ &checkon_daemon($fh,'lonmemcached',40000);
&checkon_daemon($fh,'lonsql',200000);
if ( &checkon_daemon($fh,'lond',40000,'USR1') eq 'running') {
&checkon_daemon($fh,'lond',40000,'USR2');
}
&checkon_daemon($fh,'lonc',40000,'USR1');
- &checkon_daemon($fh,'lonhttpd',40000);
- &checkon_daemon($fh,'lonmemcached',40000);
&checkon_daemon($fh,'lonmaxima',40000);
+ &checkon_daemon($fh,'lonr',40000);
}
if ($justreload) {
+ &clean_nosslverify($fh);
+ &write_connection_config();
+ &write_hosttypes();
+ &update_revocation_list();
&checkon_daemon($fh,'lond',40000,'USR2');
&checkon_daemon($fh,'lonc',40000,'USR2');
}
if ($justcheckconnections) {
- &test_connections($fh,\%hostname);
+ &test_connections($fh);
}
if (!$justcheckdaemons && !$justcheckconnections && !$justreload) {
- &check_delayed_msg($fh,\%hostname);
- &finish_logging($fh);
+ &check_delayed_msg($fh);
&log_simplestatus();
-
+ &write_loncaparevs();
+ &write_serverhomeIDs();
+ &write_checksums();
+ my %sslrem = &clean_nosslverify($fh);
+ my %conchgs = &write_connection_config();
+ my %hosttypechgs = &write_hosttypes();
+ my $hadcrlchg = &update_revocation_list();
+ if ((keys(%conchgs) > 0) || (keys(%hosttypechgs) > 0) ||
+ $hadcrlchg || (keys(%sslrem) > 0)) {
+ &checkon_daemon($fh,'lond',40000,'USR2');
+ &reset_nosslverify_pids($fh,%sslrem);
+ }
+ &finish_logging($fh);
if ($totalcount>200 && !$noemail) { &send_mail(); }
}
}
@@ -735,10 +1295,3 @@ sub main () {
&main();
1;
-
-
-
-
-
-
-