# $Header: emdb/scripts/unix/DBConsole.pm.template /st_emdbsa_11.2/12 2010/08/21 17:56:48 rpattabh Exp $
#
# Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. 
#
#    NAME
#      DBConsole.pm - Perl Module to provide start, stop, status functionality
#
#    DESCRIPTION
#       This script provides the stop,status,debug functionality for 
#       the emwd and the emctl. Additionally it may hold other
#       states like the start time, its PID, thrashCount etc.
#
#    MODIFIED   (MM/DD/YY)
#      rpattabh  08/20/10  - Bug 10041125: Use ps -aef on Solaris
#      sshastry  02/09/09  - apply mix case fix
#      ashomish  02/04/09  - fix bug 8217579
#      gapadman  11/22/08  - change UNQNAME message
#      ashomish  11/04/08  - fix bug 7422635
#      ashomish  09/30/08  - Remove version hard coding
#      rsamaved  05/21/08  - use ORACLE_UNQNAME instead of DB_UNIQUE_NAME
#      rsamaved  05/08/08  - update version to 11.2
#      swexler   04/08/08  - move functions here
#      dchakumk  03/10/08  - XbranchMerge dchakumk_6752_xbmsrc from
#                            st_emdbsa_11.1
#      swexler   02/18/08  - remove ipv4 flags
#      swexler   02/08/08  - change version
#      swexler   01/31/08  - fix for bad oc4j shutdowns
#      dchakumk  01/07/08  - Merging a2 files from stpl_emdb_main_gen as per
#                            janet
#      ezeng     12/18/07  - Backport ezeng_bug-6396653_gc from main
#      snandarg  09/18/07  - Fixing syntax issue
#      vgoli     09/11/07  - XbranchMerge vgoli_bug-6346876 from main
#      vgoli     08/22/07  - change ps command options for HP-UX
#      misun     08/22/07  - fix the bug 6346686: emctl status dbconsole
#                            reports dbconsole to be not running but em is up.
#      sresrini  08/17/07  - bug 6339100
#      sresrini  08/17/07  - bug 6339100
#      kdas      06/27/07  - XbranchMerge kdas_bug-6042435 from st_emdbsa_11.1
#      misun     06/08/07  - fix the bug 6037461: version number should be
#                            11.1.0.6.0 for db control production.
#      kdas      05/22/07  - hit the logon page for initializing image cache
#      misun     05/21/07  - fix bug 6062223, beta5 :emctl status dbconsole
#                            shows 11.1.0.4.0.
#      vivsharm  04/04/07  - If EM OC4J ADMIN password is defined use that
#      rsamaved  04/03/07  - fix pid parsing
#      misun     02/06/07  - update DB version number to 11.1.0.4.0
#      misun     10/18/06  - update DB version number
#      rsamaved  09/02/06  - fix warning during stop
#      misun     09/06/06  - update DB version number
#      vivsharm  08/21/06  - lrg 2505782
#      misun     08/16/06  - update DB version number
#      vivsharm  07/25/06  - bug 5408027 
#      rdabbott  07/28/06  - fix header
#      vivsharm  04/12/06  - fix stop dbconsole
#      blivshit  05/05/05  - porting fix for RLAL 
#      kduvvuri  07/28/04  - add getVersion. 
#      aaitghez  06/08/04 -  bug 3656322. Cleanup perl warnings 
#      kduvvuri  06/01/04 - add destroy method and setImageCacheInitialized. 
#      rzazueta  12/17/03 - Increase sleep time in debug 
#      rzazueta  12/01/03 - Deprecate password to shutdown DBConsole 
#      dmshah    09/17/03 - Code review changes 
#      dmshah    09/15/03 - Integration testing changes 
#      dmshah    09/11/03 - Check for stack dump during stop 
#      dmshah    09/03/03 - Removing dependency on instantiated port settings 
#      dmshah    07/09/03 - Testing changes
#      dkapoor   07/07/03 - use admin instead of ias_admin
#      szhu      06/20/03 - Workaround for status()
#      vnukal    06/17/03 - adding okToRestart method
#      dmshah    05/08/03 - Obsoleting getProcList
#      dmshah    04/06/03 - dmshah_bug-2849086_mainsa
#      dmshah    04/08/03 - Removing hardcoded pid from stopSAC
#      dmshah    03/14/03 - Adding restart code
#      dmshah    03/13/03 - Adding incThrashCount
#      dmshah    03/11/03 - dmshah_em_watchdog
#      dmshah    03/06/03 - Using signal 0 for process liveness
#      dmshah    03/03/03 - Fixing constructor syntax
#      dmshah    03/03/03 - Testing if..else block
#      dmshah    02/26/03 - Created.
#

package DBConsole;
use strict;
use EmctlCommon;
use LWP::Simple;
use LWP::UserAgent;
use URI;
use DBConsoleBanner;

$DB_NOHUPFILE=getEMHome("dbconsole") . "/sysman/log/emdb.nohup";
# Nohup file when only the agent is running.
$AGENT_NOHUPFILE=getEMHome("dbconsole") . "/sysman/log/emagent.nohup";
$PID_FILE=getEMHome("dbconsole") . "/emctl.pid";

sub new
{
  my ($class) = @_;
  my $self =
  {
     PID => -1,
     name => undef,
     startTime => -1,
     thrashCount => 0,
     imageCacheInitialized => 0,
     debug => 0,
     emHome => getEMHome("dbconsole"),
     oc4jHome => getOC4JHome("dbconsole"),
     url => getWebUrl(getOC4JHome("dbconsole"), 
                      getEMHome("dbconsole"), "dbconsole"),
     rmiPort => getORMIPort( getOC4JHome("dbconsole") ),
     initialized => 0
  };
  
  bless $self, $class;
  return $self;
}

#
# Initialize 
# Ensure that the values are correct.
#
sub Initialize
{
  my ($self) = shift;
  my ($inPID) = shift;
  my ($inStartTime) = shift;
  my ($debugFlag) = shift;

  $self->{PID} = $inPID;
  $self->{startTime} = $inStartTime;
  $self->{thrashCount} = 0;
  $self->{name} = "DBConsole";
  $self->{initialized} = 1;

  $self->{debug} = $debugFlag if defined($debugFlag);

  if($self->{debug})
  {
    print "The following is set for the DBConsole : \n";
    print "OC4JHome : $self->{oc4jHome} \n";
    print "EMHome : $self->{emHome} \n";
    print "DBConsole URL : $self->{url} \n";
    print "ORMI Port : $self->{rmiPort} \n";
  }

  $self->{initialized} = 1;
  return 1;
}

#
# status
# Checks the PID liveness test first and then uses the appropriate handler
# to check the login Page of the console
#
sub status
{
  my($self) = @_;
  
  if($self->{initialized})
  {
    my $rc;
    $rc = 0xffff & system("$EMDROOT/bin/emdctl status url $self->{url} >$devNull 2>&1");
    $rc >>= 8;

    if( $rc eq 3 )  #DBConsole is UP and running...
    {
      $rc = $STATUS_PROCESS_OK;

      unless($self->{imageCacheInitialized})
      {
        print "## Connected to $self->{url}. Initializing image Cache. \n" if $self->{debug};
        $self->initializeImageCache();
        $self->{imageCacheInitialized} = 1;
      }
    }
    elsif( $rc eq 1 ) # DBConsole process is dead... No Connection by emdctl
    {
      $rc = $STATUS_NO_SUCH_PROCESS;
    }
    elsif( $rc eq 2 ) # DBConsole is hanging ... TIMEOUT from emdctl
    {
       $rc = $STATUS_PROCESS_HANG;
    }
    elsif( $rc eq 6 ) # emdctl internal error... print for debug purposes
    {
       print "## $EMDROOT/bin/emdctl status url $self->{url} returns internal error. \n";
       $rc = $STATUS_PROCESS_UNKNOWN;
    }
    else
    {
       print "## Status URL returned unknown status. Return Code : $rc.\n" if $self->{debug};
       $rc = $STATUS_PROCESS_UNKNOWN; #This should not happen...
    }

    return $rc;
  }
}

#
# stop
# Stops the Console
#
sub stop
{
  my $self = shift;
  my $password = shift;
        
  if($self->{initialized})
  {
	# changed logic for dbconsole not stopping with kill 0
	my $tries = 5;
	while($tries gt 0)
	{
		unless( (kill 0, $self->{PID}) )
		{
		  #On windows platform [NT 4.0 and Win2k, Perl 5.6's kill is flaky...
		  if($IS_WINDOWS ne "TRUE")
		  {
			 return 0;
		  }
		}
		sleep 1;
		$tries = $tries - 1;
	}

	if($password eq undef)
    {
      print "--- DBConsole internal stop. No OC4J admin passwd hence hard stop. ---\n";
       if ($^O eq "linux")
       {
         my $proc = "";
         my @procs = `/bin/ps uxww | /bin/grep "$ORACLE_HOME/jdk/bin/java" | /bin/grep "DEMSTATE" | /bin/grep -v grep`;
         foreach $proc (@procs)
         {
           my @parts = split ( /\s+/ , $proc );
           kill 9, $parts[1];
         }
       }
       else
       {
         kill 9, $self->{PID};
       }
     
     return 0;
    }
    else
    {
      my($timeInMillis) = time();
      my($pwdfile);
	if(! -d "$FORMFACTOR_BASE/opmn/conf")
	{
		if(! -d "$FORMFACTOR_BASE/opmn")
		{
			mkdir "$FORMFACTOR_BASE/opmn";
			chmod 0755, "$FORMFACTOR_BASE/opmn";
		}
		mkdir "$FORMFACTOR_BASE/opmn/conf";
		chmod 0755, "$FORMFACTOR_BASE/opmn/conf";
	}

      open($pwdfile, "> $FORMFACTOR_FILE");
      print {$pwdfile} $timeInMillis;
      close($pwdfile);

      # redirect stdout/stderr; save old handles
      open(OLDOUT, ">&STDOUT");
      open(OLDERR, ">&STDERR");
      open(STDOUT, ">> $self->{emHome}/sysman/log/stopDBConsole.out");
      open(STDERR, ">> $self->{emHome}/sysman/log/stopDBConsole.out");

      print "\n Stopping DBConsole on ormi port : $self->{rmiPort}. \n";

      my $rc;

      $rc = 0xffff & system("$JAVA_HOME/bin/java -jar ".
                            "-Doracle.home=$FORMFACTOR_BASE -DOPMN=true ".
                            "$ORACLE_HOME/$OC4JLOC"."j2ee/home/admin.jar ".
                            "ormi://localhost:$self->{rmiPort} admin ".
                            "$timeInMillis -shutdown force");

		print "\n\n Shutdown command to OC4J returned :$rc\n";
		$rc >>= 8;
		print "\n\n After right shift by 8 bits return status =$rc\n";

	  # delete the formfactor file now ...
      unlink ($FORMFACTOR_FILE);

      # close file with redirected output, restore old handles
      close(STDOUT);
      close(STDERR);
      open(STDOUT, ">&OLDOUT");
      open(STDERR, ">&OLDERR");

      # scan output file for exceptions, then remove
      open(EMOUT, "stopDBConsole.out");
      while(<EMOUT>)
      {
        if (index($_, "AuthenticationException") >= 0)
        {
          print("Incorrect password provided\n");
          $rc = (1<<8);
          last;
        }
        if (index($_, "ConnectException") >= 0)
        {
          print("Incorrect EM_ADMIN_PORT specified\n");
          $rc = (2<<8);
          last;
        }
        if (index($_, "xception") >= 0)
        {
          print("Exception during shutdown\n");
          $rc = (3<<8);
          last;
        }
      }
      close(EMOUT);
      unlink ("$self->{emHome}/sysman/log/stopDBConsole.out") unless $self->{debug};

      # do not try use kill on windows - it will only kill the parent process
      # and the child java process will remain
      if($rc gt 0 and $IS_WINDOWS ne "TRUE")
	  {
		# If we have not returned yet, means all attemps to kill 0 failed
		print "\nall attemps to stop oc4j failed... now trying to kill 9\n";
		unless( (kill 9, $self->{PID}) )
		{
			#On windows platform [NT 4.0 and Win2k, Perl 5.6's kill is flaky...
			if($IS_WINDOWS ne "TRUE")
			{
				return 0;
			}
		}

	  }
	  print "--- Failed to shutdown DBConsole Gracefully --- \n" if( $rc gt 0 ); # Error during shutdown

		# 5408027 - Even after sure_stop_em reported STOPPED, java process kept running.
		my $psCmd_Linux = "ps auxww"; # this might need porting on other platforms
	        my $osname = `uname -s`;
       		chomp($osname);
        	if($osname eq "HP-UX")
        	{
            		# bug: 6346876, 6391598 for HP-UX platform
            		$psCmd_Linux = "ps -aex"; #This is for HP-UX platform
        	} elsif($osname eq "SunOS" )
		{
		   #bug 6040898  - redundant ps usage messages while stopping dbconsole
		   $psCmd_Linux = "/usr/bin/ps -aef"; #This is for Solaris platform
		}
		else 
		{
		   # 5408027 - Even after sure_stop_em reported STOPPED, java process kept running.
		   $psCmd_Linux = "ps auxww"; # this might need porting on other platforms
		}

		if($IS_WINDOWS ne "TRUE")
		{
			my $DBCONSOLE_STOPPED = "1";
			my $stopStatus = `$psCmd_Linux | grep "$ENV{'ORACLE_HOME'}/jdk/bin/java" | grep "$self->{emHome}" | wc -l`;
			my $trimmed_stopStatus = trim($stopStatus);
			my $status_tries = 5;
			while($status_tries gt 0)
			{
				if ($trimmed_stopStatus eq $DBCONSOLE_STOPPED)
				{
					last; #break out of while
				}
				else
				{
					# no specific reason, just trying 11 secs 
					# on a heavily loaded system this might not be sufficient
					# but if I put in a => while($trimmed_stopStatus ne "1")
					# the risk was that this loop might hang indefinitely - if something was wrong with OC4J
					sleep 11; 
				}
				$stopStatus = `$psCmd_Linux | grep "$ENV{'ORACLE_HOME'}/jdk/bin/java" | grep "$self->{emHome}" | wc -l`;
				$trimmed_stopStatus = trim($stopStatus);
				$status_tries = $status_tries - 1;
			}
			# if still not stopped - ports will not be freed.
			if ($trimmed_stopStatus ne $DBCONSOLE_STOPPED)
			{
				my $java_pid; 
				if($osname eq "SunOS" ){
				my $java_pid_lines = `$psCmd_Linux | grep "$ENV{'ORACLE_HOME'}/jdk/bin/java" | grep "$self->{emHome}" | cut -d " " -f2`;
				my @pid_lines = split(/\n/,$java_pid_lines);
				$java_pid = $pid_lines[0];
				}else{
				my $java_pid_lines = `$psCmd_Linux | grep "$ENV{'ORACLE_HOME'}/jdk/bin/java" | grep "$self->{emHome}"`;
				my @pid_lines = split(/\n/,$java_pid_lines);
				my @pid_line_fields = split(/\s+/,$pid_lines[0]);
				$java_pid = $pid_line_fields[1];
				}
				# I dont like it much, but you've gotta go now, sorry !
				if($java_pid gt 0)
				{
					kill 9, $java_pid;
				}
			}

			my $sts = $self->status();
			if ($sts eq $STATUS_NO_SUCH_PROCESS)
			{
				$rc = 0;
			}
		}
		else #for NT either suggest an equivalent command or let this be
		{
       # This returns a signal of 1 - HANGUP
       # emwd.pl must be updated to assume this is normal
       # or it will start another java process
       system("taskkill /F /T /PID $self->{PID}");
 
		   my $stopStatus = $self->status();
		   if ($stopStatus eq $STATUS_NO_SUCH_PROCESS || $stopStatus eq $STATUS_PROCESS_OK )
			{
				$rc = 0;
				sleep 11;
			}
		}
	  return $rc;
    }
  }
  else
  {
     return 1; # We should never be here...
  }
}

sub trim()
{
    my($string) = @_;        
    $string =~ s/^\s+//;
    $string =~ s/\s+$//;
    return $string;
}

#
# gatherProcessStatistics
# Gathers process Statistics like Memory size etc
#
sub gatherProcessStatistics
{
  my($self) = @_;
  if($self->{initialized})
  {
  }
}

#
# reInitialize
# Update after a restart, the PID and the start time are changed now
# and needs to be reflected.
# 
sub reInitialize
{
  my($self, $inPID, $inStartTime) = @_;        
  if($self->{initialized})
  {
     $self->{PID} = $inPID;
     $self->{startTime} = $inStartTime;
     $self->{imageCacheInitialized} = 0;
     return 0;
  }
  else
  {
     return 1;
  }
}


#
# getThrashCount
# Returns the number of restarts that has occurred
#
sub getThrashCount
{
  my($self) = @_;
  if($self->{initialized})
  {
     return $self->{thrashCount};
  }
  else
  {
     return -1;
  }
}

#
# setThrashCount
# Reset routine for the setThrashCount
#
sub setThrashCount
{
  my($self, $inThrashCount) = @_;
  if($self->{initialized})
  {
     $self->{thrashCount} = $inThrashCount;
     return 0;
  }
  else
  {
     return 1;
  }
}

#
# incThrashCount
# Increments the thrashCount by 1
#
sub incThrashCount
{
  my($self) = @_;
  if($self->{initialized})
  {
     $self->{thrashCount}++;
     return 0;
  }
  else
  {
     return 1;
  }
}

#
# getPID
# Returns the PID for the DBConsole
# 
sub getPID
{
  my($self) = @_;
  if($self->{initialized})
  {
     return $self->{PID};
  }
  else
  {
     return -1;
  }
}

#
# getStartTime
# Returns the start time of the DBConsole
#
sub getStartTime
{
  my($self) = @_;
  if($self->{initialized})
  {
     return $self->{startTime};
  }
  else
  {
     return -1;
  }
}

#
# getName
# Returns the Name
#
sub getName
{
  my($self) = @_;
  if($self->{initialized})
  {
    return $self->{name};
  }
  else
  {
    return undef;
  }
}

#
# debug
# Provides the Debug functionality
#
sub debug
{
  my($self) = @_;
  if($self->{initialized})
  {
     my($tPid) = $self->{PID};

     print "----- Attempting to kill $self->{name} : $tPid -----\n";

     if( kill 0, $tPid)
     {
       print "----- Attempting to dump threads for $tPid ----- \n";
       kill 3, $tPid;
       sleep 10;
       print "----- Attempting to dump threads for $tPid ----- \n";
       kill 3, $tPid;
       sleep 10;
       kill 9, $tPid;
     }

     return 0;
  }
}

#
# debugCore
# DebugCore is called when the monitor detects a core dump
# Parameter : CoreFile
#
sub debugCore
{
  my($self, $debugFile) = @_;        
  if($self->{initialized})
  {
  }
}

sub recycle
{
 return "FALSE";
}

sub okToRestart
{
 return "TRUE";
}


#initializeImageCache
#This subroutine pings the DBConsole, saves the resultant
#html page and then searches and gets the images. The resultant
#effect is that the Server image cache is initialized.

sub initializeImageCache
{
  my $self = shift;

  my($htmlPage) = $self->{emHome}."/sysman/log/logonPage_dbconsole.temp";
  my($rvalue);
  my $imageCacheUrl=$self->{url};
  $imageCacheUrl =~ s/aboutApplication/logon/;
  $imageCacheUrl=$imageCacheUrl."/logon";
  $rvalue = 0xffff & system("$EMDROOT/bin/emdctl status url $imageCacheUrl >$htmlPage 2>&1");
  $rvalue >>= 8;

  if($rvalue eq 3) #HTML page is up... we parse it for image
  {
     open(HTMLFILE, "<$htmlPage");
     while(<HTMLFILE>)
     {
       if(/img src/)
       {
         my(undef, $img) = split /img src="/, $_;
         ($img, undef) = split /" /, $img;
         ($img, undef) = split /">/, $img;
         if( ($img =~ /gif/) or ($img =~ /png/) )
         {
           my($urlTemp, undef) = split /\/em/, $imageCacheUrl;
           $img = $urlTemp.$img;

           $rvalue = 0xffff & system("$EMDROOT/bin/emdctl status url $img >$devNull 2>&1");
           $rvalue >>= 8;

           if($rvalue ne 3)
           {
              print "## Unable to load $img on $imageCacheUrl. Error code returned is $rvalue \n" if $self->{debug};
              last;
           }
         }
       }
     }

     close (HTMLFILE);
  }

  unlink ($htmlPage);
  return $rvalue;
}

sub setImageCacheInitialized
{
;
}

sub getVersion
{
#    print "       Enterprise Manager 11g DB Control Version 11.2.0.0.1\n";
	DBConsoleBanner::printVersion();
}

sub getOracleUniqueName

{
    my($oh,$sid)=@_;
    my  $oracleUnqname = &EmctlCommon::getOracleUniqueName($oh,$sid);
    #print "UNQNAME for $sid is  $oracleUnqname\n";
    if(!defined($oracleUnqname) &&($IS_WINDOWS eq "TRUE")) #for windows ignore case
    {
        #print "Unable to retrieve ORACLE_UNQNAME for $sid, trying with upper/lower case\n";
        if(uc($sid) eq $sid)
        {
              $oracleUnqname = &EmctlCommon::getOracleUniqueName($oh,lc($sid));
        }else {
              $oracleUnqname = &EmctlCommon::getOracleUniqueName($oh,uc($sid));
        }

    }
    return  $oracleUnqname ;


}


sub getOC4JHome 
{
  my ($self)=@_;
  my $oc4jHome = "$ORACLE_HOME/oc4j/j2ee/OC4J_DBConsole";

  # For DBConsole, OC4J HOME is an offset of hostname_<oracle_unqname>
  my $oracleUnqname = &getOracleUniqueName($ENV{ORACLE_HOME},$ENV{ORACLE_SID});

  if($EmctlCommon::HOST_SID_OFFSET_ENABLED eq "host_sid")
  {
    if(!defined($oracleUnqname))
    {
      if(!defined($self))
      {
         print "Environment variable ORACLE_UNQNAME not defined. Please set ORACLE_UNQNAME to database unique name. \n" ;
         exit(1);
       }
     }

    # Grok the current hostname and create the hostname_sid offset to
    # location. We may use a java api here to get the host and domainname.
    my $topDir = &EmctlCommon::getLocalHostName();

    #  for 10.2 dbcontrol, use node name for RAC  
    if(substr($ENV{EMPRODVER},0,4) ne "10.1")
    {
      if (defined($ENV{CRS_HOME}) and ($ENV{CRS_HOME} ne "#CRS_HOME#"))
      {
        # if we are in RAC, use the local node name
        $topDir = &EmctlCommon::getLocalRACNode();

        if ($topDir eq "") {
          print "RAC node name not found, defaulting to local host name\n" if $DEBUG_ENABLED;
          $topDir = &EmctlCommon::getLocalHostName();
        }
      }
    }

    $oc4jHome=$oc4jHome."_".$topDir."_".$oracleUnqname;
  }

#  die "OC4J Configuration issue. $oc4jHome not found. \n" unless( -e "$oc4jHome" );

  print "OC4J HOME ==================  $oc4jHome\n"  if $DEBUG_ENABLED;

  return $oc4jHome;
}


sub getEMHome {
  my($self)=@_;
  my $emHome = $EMDROOT;
  
  # EMSTATE env. var. is set from the script in the em state only bin
  # directory emctl [during NFS installs of state only agents].
  if ( $ENV{EMSTATE} ne "" )
  { 
    $emHome = $ENV{EMSTATE};
  }
  elsif ( $EmctlCommon::HOST_SID_OFFSET_ENABLED eq "host_sid" )
  {
    # For DBConsole, EM HOME is an offset of hostname_<db_unique_name>
    my $oracleUnqname = &getOracleUniqueName($ENV{ORACLE_HOME},$ENV{ORACLE_SID});

    if(!defined($self))
    {
      die "Environment variable ORACLE_UNQNAME not defined. Please define it. \n" unless defined ($oracleUnqname);
    }

    my $topDir = &EmctlCommon::getLocalHostName();

    if (defined($ENV{CRS_HOME}) and ($ENV{CRS_HOME} ne "#CRS_HOME#"))
    {
      # if we are in RAC, use the local node name
      $topDir = &EmctlCommon::getLocalRACNode();

      if ($topDir eq "") {
        print "RAC node name not found, defaulting to local host name\n" if $DEBUG_ENABLED;
        $topDir = &EmctlCommon::getLocalHostName();
      }
    }

    $emHome = $ORACLE_HOME."/".$topDir."_".$oracleUnqname;

    $ENV{EMSTATE}=$emHome; # Promote EMSTATE to the env.
  }
  else
  {
    $emHome = $EMDROOT;
  }

  #EM_TMP_DIR is valid only after a call to getEMHome.
  $EM_TMP_DIR = "$emHome";

  print "EMHOME ==================  $emHome\n"  if $DEBUG_ENABLED;
  return $emHome;
}


sub DESTROY {
    my $self = shift;
}


1;
