// @(#)root/proofx:$Id$
// Author: Gerardo Ganis  12/12/2005

/*************************************************************************
 * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TXSlave                                                              //
//                                                                      //
// This is the version of TSlave for slave servers based on XRD.        //
// See TSlave for details.                                              //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TXSlave.h"
#include "TProof.h"
#include "TProofServ.h"
#include "TSystem.h"
#include "TEnv.h"
#include "TROOT.h"
#include "TUrl.h"
#include "TMessage.h"
#include "TMonitor.h"
#include "TError.h"
#include "TSysEvtHandler.h"
#include "TVirtualMutex.h"
#include "TThread.h"
#include "TXSocket.h"
#include "TXSocketHandler.h"
#include "Varargs.h"
#include "XProofProtocol.h"

ClassImp(TXSlave)

//______________________________________________________________________________

//---- Hook to the constructor -------------------------------------------------
//---- This is needed to avoid using the plugin manager which may create -------
//---- problems in multi-threaded environments. --------------------------------
TSlave *GetTXSlave(const char *url, const char *ord, Int_t perf,
                     const char *image, TProof *proof, Int_t stype,
                     const char *workdir, const char *msd, Int_t nwk)
{
   return ((TSlave *)(new TXSlave(url, ord, perf, image,
                                    proof, stype, workdir, msd, nwk)));
}

class XSlaveInit {
 public:
   XSlaveInit() {
      TSlave::SetTXSlaveHook(&GetTXSlave);
}};
static XSlaveInit xslave_init;

//______________________________________________________________________________

//---- error handling ----------------------------------------------------------
//---- Needed to avoid blocking on the CINT mutex in printouts -----------------

//______________________________________________________________________________
void TXSlave::DoError(int level, const char *location, const char *fmt, va_list va) const
{
   // Interface to ErrorHandler (protected).

   ::ErrorHandler(level, Form("TXSlave::%s", location), fmt, va);
}

//
// Specific Interrupt signal handler
//
class TXSlaveInterruptHandler : public TSignalHandler {
private:
   TXSocket *fSocket;
public:
   TXSlaveInterruptHandler(TXSocket *s = 0)
      : TSignalHandler(kSigInterrupt, kFALSE), fSocket(s) { }
   Bool_t Notify();
};

//______________________________________________________________________________
Bool_t TXSlaveInterruptHandler::Notify()
{
   // TXSlave interrupt handler.

   Info("Notify","Processing interrupt signal ...");

   // Handle also interrupt condition on socket(s)
   if (fSocket)
      fSocket->SetInterrupt();

   return kTRUE;
}

//______________________________________________________________________________
TXSlave::TXSlave(const char *url, const char *ord, Int_t perf,
               const char *image, TProof *proof, Int_t stype,
               const char *workdir, const char *msd, Int_t nwk) : TSlave()
{
   // Create a PROOF slave object. Called via the TProof ctor.
   fImage = image;
   fProofWorkDir = workdir;
   fWorkDir = workdir;
   fOrdinal = ord;
   fPerfIdx = perf;
   fProof = proof;
   fSlaveType = (ESlaveType)stype;
   fMsd = msd;
   fNWrks = nwk;
   fIntHandler = 0;
   fValid = kFALSE;

   // Instance of the socket input handler to monitor all the XPD sockets
   TXSocketHandler *sh = TXSocketHandler::GetSocketHandler();
   gSystem->AddFileHandler(sh);

   TXSocket::SetLocation((fProof->IsMaster()) ? "master" : "client");

   Init(url, stype);
}

//______________________________________________________________________________
void TXSlave::Init(const char *host, Int_t stype)
{
   // Init a PROOF slave object. Called via the TXSlave ctor.
   // The Init method is technology specific and is overwritten by derived
   // classes.

   // Url string with host, port information; 'host' may contain 'user' information
   // in the usual form 'user@host'

   // Auxilliary url
   TUrl url(host);
   url.SetProtocol(fProof->fUrl.GetProtocol());
   // Check port
   if (url.GetPort() == TUrl("a").GetPort()) {
      // We use 'rootd' service as default.
      Int_t port = gSystem->GetServiceByName("proofd");
      if (port < 0) {
         if (gDebug > 0)
            Info("Init","service 'proofd' not found by GetServiceByName"
                        ": using default IANA assigned tcp port 1093");
         port = 1093;
      } else {
         if (gDebug > 1)
            Info("Init","port from GetServiceByName: %d", port);
      }
      url.SetPort(port);
   }

   // Fill members
   fName = url.GetHostFQDN();
   fPort = url.GetPort(); // We get the right default if the port is not specified
   // Group specification , if any, uses the password field, i.e. user[:group]
   fGroup = url.GetPasswd();

   // The field 'psid' is interpreted as session ID when we are attaching
   // to an existing session (ID passed in the options field of the url) or
   // to our PROOF protocl version when we are creating a new session
   TString opts(url.GetOptions());
   Bool_t attach = (opts.Length() > 0 && opts.IsDigit()) ? kTRUE : kFALSE;
   Int_t psid = (attach) ? opts.Atoi() : kPROOF_Protocol;

   // Add information about our status (Client or Master)
   TString iam;
   Char_t mode = 's';
   TString alias = fProof->GetTitle();
   if (fProof->IsMaster() && stype == kSlave) {
      iam = "Master";
      mode = 's';
      // Send session tag of the closest master to the slaves
      alias.Form("session-%s|ord:%s", fProof->GetName(), fOrdinal.Data());
   } else if (fProof->IsMaster() && stype == kMaster) {
      iam = "Master";
      mode = 'm';
      // Send session tag of the closest master to the slaves
      if (fNWrks > 1) {
         alias.Form("session-%s|ord:%s|plite:%d", fProof->GetName(), fOrdinal.Data(), fNWrks);
         mode = 'L';
      } else {
         alias.Form("session-%s|ord:%s", fProof->GetName(), fOrdinal.Data());
      }
   } else if (!fProof->IsMaster() && stype == kMaster) {
      iam = "Local Client";
      mode = (attach) ? 'A' : 'M';
   } else {
      Error("Init","Impossible PROOF <-> SlaveType Configuration Requested");
      R__ASSERT(0);
   }

   // Add conf file, if required
   if (fProof->fConfFile.Length() > 0 && fNWrks <= 1)
      alias += Form("|cf:%s",fProof->fConfFile.Data());

   // Send over env variables (may not be supported remotely)
   TString envlist;
   if (!fProof->GetManager() ||
        fProof->GetManager()->GetRemoteProtocol() > 1001) {
         // Check if the user forced locally a given authentication protocol:
         // we need to do the same remotely to get the right credentials
         if (gSystem->Getenv("XrdSecPROTOCOL")) {
            TProof::DelEnvVar("XrdSecPROTOCOL");
            TProof::AddEnvVar("XrdSecPROTOCOL", gSystem->Getenv("XrdSecPROTOCOL"));
         }
         const TList *envs = TProof::GetEnvVars();
         if (envs != 0 ) {
            TIter next(envs);
            for (TObject *o = next(); o != 0; o = next()) {
               TNamed *env = dynamic_cast<TNamed*>(o);
               if (env != 0) {
                  if (!envlist.IsNull())
                     envlist += ",";
                  envlist += Form("%s=%s", env->GetName(), env->GetTitle());
               }
            }
         }
   } else {
      if (fProof->GetManager() && TProof::GetEnvVars())
         Info("Init", "** NOT ** sending user envs - RemoteProtocol : %d",
                      fProof->GetManager()->GetRemoteProtocol());
   }

   // Add to the buffer
   if (!envlist.IsNull())
      alias += Form("|envs:%s", envlist.Data());

   // Open connection to a remote XrdPROOF slave server.
   // Login and authentication are dealt with at this level, if required.
   if (!(fSocket = new TXSocket(url.GetUrl(kTRUE), mode, psid,
                                -1, alias, fProof->GetLogLevel(), this))) {
      ParseBuffer(); // For the log path
      Error("Init", "while opening the connection to %s - exit", url.GetUrl(kTRUE));
      return;
   }

   // The socket may not be valid
   if (!(fSocket->IsValid())) {
      // Notify only if verbosity is on: most likely the failure has already been notified
      PDB(kGlobal,1)
         Error("Init", "some severe error occurred while opening "
                       "the connection at %s - exit", url.GetUrl(kTRUE));
      ParseBuffer(); // For the log path
      // Fill some useful info
      R__LOCKGUARD2(gProofMutex);
      fUser = ((TXSocket *)fSocket)->fUser;
      PDB(kGlobal,3) Info("Init","%s: fUser is .... %s", iam.Data(), fUser.Data());
      SafeDelete(fSocket);
      return;
   }

   // Set the ordinal in the title for debugging
   fSocket->SetTitle(fOrdinal);

   // Check if the remote server supports user envs setting
   if (!fProof->GetManager() && !envlist.IsNull() &&
      ((TXSocket *)fSocket)->GetXrdProofdVersion() <= 1001) {
      Info("Init","user envs setting sent but unsupported remotely - RemoteProtocol : %d",
                     ((TXSocket *)fSocket)->GetXrdProofdVersion());
   }

   // Set the reference to TProof
   ((TXSocket *)fSocket)->fReference = fProof;

   // Protocol run by remote PROOF server
   fProtocol = fSocket->GetRemoteProtocol();

   // Set server type
   fProof->fServType = TProofMgr::kXProofd;

   // Set remote session ID
   fProof->fSessionID = ((TXSocket *)fSocket)->GetSessionID();

   // Extract the log file path and, if any, set URL entry point for the default data pool
   ParseBuffer();

   // Remove socket from global TROOT socket list. Only the TProof object,
   // representing all slave sockets, will be added to this list. This will
   // ensure the correct termination of all proof servers in case the
   // root session terminates.
   {
      R__LOCKGUARD2(gROOTMutex);
      gROOT->GetListOfSockets()->Remove(fSocket);
   }

   R__LOCKGUARD2(gProofMutex);

   // Fill some useful info
   fUser = ((TXSocket *)fSocket)->fUser;
   PDB(kGlobal,3) {
      Info("Init","%s: fUser is .... %s", iam.Data(), fUser.Data());
   }

   // Set valid
   fValid = kTRUE;
}

//______________________________________________________________________________
void TXSlave::ParseBuffer()
{
   // Parse fBuffer after a connection attempt

   // Set URL entry point for the default data pool
   TString buffer(((TXSocket *)fSocket)->fBuffer);
   if (!buffer.IsNull()) {
      Ssiz_t ilog = buffer.Index("|log:");
      if (ilog != 0) {
         // Extract the pool URL (on master)
         TString dpu = (ilog != kNPOS) ? buffer(0, ilog) : buffer;
         if (dpu.Length() > 0) fProof->SetDataPoolUrl(dpu);
      }
      if (ilog != kNPOS) {
         // The rest, if any, if the log file path from which we extract the working dir
         buffer.Remove(0, ilog + sizeof("|log:") - 1);
         fWorkDir = buffer;
         if ((ilog = fWorkDir.Last('.')) !=  kNPOS) fWorkDir.Remove(ilog);
         if (gDebug > 2)
            Info("ParseBuffer", "workdir is: %s", fWorkDir.Data());
      } else if (fProtocol > 31) {
         Warning("ParseBuffer", "expected log path not found in received startup buffer!");
      }
   }
   // Done
   return;
}

//______________________________________________________________________________
Int_t TXSlave::SetupServ(Int_t, const char *)
{
   // Init a PROOF slave object. Called via the TXSlave ctor.
   // The Init method is technology specific and is overwritten by derived
   // classes.

   // Get back startup message of proofserv (we are now talking with
   // the real proofserver and not anymore with the proofd front-end)
   Int_t what;
   char buf[512];
   if (fSocket->Recv(buf, sizeof(buf), what) <= 0) {
      Error("SetupServ", "failed to receive slave startup message");
      Close("S");
      SafeDelete(fSocket);
      fValid = kFALSE;
      return -1;
   }

   if (what == kMESS_NOTOK) {
      SafeDelete(fSocket);
      fValid = kFALSE;
      return -1;
   }

   // protocols less than 4 are incompatible
   if (fProtocol < 4) {
      Error("SetupServ", "incompatible PROOF versions (remote version "
                         "must be >= 4, is %d)", fProtocol);
      SafeDelete(fSocket);
      fValid = kFALSE;
      return -1;
   }

   fProof->fProtocol   = fProtocol;   // protocol of last slave on master

   // set some socket options
   fSocket->SetOption(kNoDelay, 1);

   // We are done
   return 0;
}

//______________________________________________________________________________
TXSlave::~TXSlave()
{
   // Destroy slave.

   Close();
}

//______________________________________________________________________________
void TXSlave::Close(Option_t *opt)
{
   // Close slave socket.

   if (fSocket)
      // Closing socket ...
      fSocket->Close(opt);

   SafeDelete(fInput);
   SafeDelete(fSocket);
}

//______________________________________________________________________________
Int_t TXSlave::Ping()
{
   // Ping the remote master or slave servers.
   // Returns 0 if ok, -1 if it did not ping or in case of error

   if (!IsValid()) return -1;

   return (((TXSocket *)fSocket)->Ping(GetOrdinal()) ? 0 : -1);
}

//______________________________________________________________________________
void TXSlave::Touch()
{
   // Touch the client admin file to proof we are alive.

   if (!IsValid()) return;

   ((TXSocket *)fSocket)->RemoteTouch();
   return;
}

//______________________________________________________________________________
void TXSlave::Interrupt(Int_t type)
{
   // Send interrupt to master or slave servers.
   // Returns 0 if ok, -1 in case of error

   if (!IsValid()) return;

   if (type == TProof::kLocalInterrupt) {

      // Deactivate and flush the local socket (we are not - yet - closing
      // the session, so we do less things that in case of an error ...)
      if (fProof) {

         // Attach to the monitor instance, if any
         TMonitor *mon = fProof->fCurrentMonitor;
         if (mon && fSocket && mon->GetListOfActives()->FindObject(fSocket)) {
            // Synchronous collection in TProof
            if (gDebug > 2)
               Info("Interrupt", "%p: deactivating from monitor %p", this, mon);
            mon->DeActivate(fSocket);
         }
      } else {
         Warning("Interrupt", "%p: reference to PROOF missing", this);
      }

      // Post semaphore to wake up anybody waiting; send as many posts as needed
      if (fSocket) {
         R__LOCKGUARD(((TXSocket *)fSocket)->fAMtx);
         TSemaphore *sem = &(((TXSocket *)fSocket)->fASem);
         while (sem->TryWait() != 1)
            sem->Post();
      }
      return;
   }

   ((TXSocket *)fSocket)->SendInterrupt(type);
   Info("Interrupt","Interrupt of type %d sent", type);
}

//______________________________________________________________________________
void TXSlave::StopProcess(Bool_t abort, Int_t timeout)
{
   // Sent stop/abort request to PROOF server. It will be
   // processed asynchronously by a separate thread.
   if (!IsValid()) return;

   ((TXSocket *)fSocket)->SendUrgent(TXSocket::kStopProcess, (Int_t)abort, timeout);
   if (gDebug > 0)
      Info("StopProcess", "Request of type %d sent over", abort);
}

//_____________________________________________________________________________
Int_t TXSlave::GetProofdProtocol(TSocket *s)
{
   // Find out the remote proofd protocol version.
   // Returns -1 in case of error.

   Int_t rproto = -1;

   UInt_t cproto = 0;
   Int_t len = sizeof(cproto);
   memcpy((char *)&cproto,
      Form(" %d", TSocket::GetClientProtocol()),len);
   Int_t ns = s->SendRaw(&cproto, len);
   if (ns != len) {
      ::Error("TXSlave::GetProofdProtocol",
              "sending %d bytes to proofd server [%s:%d]",
              len, (s->GetInetAddress()).GetHostName(), s->GetPort());
      return -1;
   }

   // Get the remote protocol
   Int_t ibuf[2] = {0};
   len = sizeof(ibuf);
   Int_t nr = s->RecvRaw(ibuf, len);
   if (nr != len) {
      ::Error("TXSlave::GetProofdProtocol",
              "reading %d bytes from proofd server [%s:%d]",
              len, (s->GetInetAddress()).GetHostName(), s->GetPort());
      return -1;
   }
   Int_t kind = net2host(ibuf[0]);
   if (kind == kROOTD_PROTOCOL) {
      rproto = net2host(ibuf[1]);
   } else {
      kind = net2host(ibuf[1]);
      if (kind == kROOTD_PROTOCOL) {
         len = sizeof(rproto);
         nr = s->RecvRaw(&rproto, len);
         if (nr != len) {
            ::Error("TXSlave::GetProofdProtocol",
                    "reading %d bytes from proofd server [%s:%d]",
                    len, (s->GetInetAddress()).GetHostName(), s->GetPort());
            return -1;
         }
         rproto = net2host(rproto);
      }
   }
   if (gDebug > 2)
      ::Info("TXSlave::GetProofdProtocol",
             "remote proofd: buf1: %d, buf2: %d rproto: %d",
             net2host(ibuf[0]),net2host(ibuf[1]),rproto);

   // We are done
   return rproto;
}

//______________________________________________________________________________
TObjString *TXSlave::SendCoordinator(Int_t kind, const char *msg, Int_t int2)
{
   // Send message to intermediate coordinator.
   // If any output is due, this is returned as a generic message

   return ((TXSocket *)fSocket)->SendCoordinator(kind, msg, int2);
}

//______________________________________________________________________________
void TXSlave::SetAlias(const char *alias)
{
   // Set an alias for this session. If reconnection is supported, the alias
   // will be communicated to the remote coordinator so that it can be recovered
   // when reconnecting

   // Nothing to do if not in contact with coordinator
   if (!IsValid()) return;

   ((TXSocket *)fSocket)->SendCoordinator(kSessionAlias, alias);

   return;
}

//______________________________________________________________________________
Int_t TXSlave::SendGroupPriority(const char *grp, Int_t priority)
{
   // Communicate to the coordinator the priprity of the group to which the
   // user belongs
   // Return 0 on success

   // Nothing to do if not in contact with coordinator
   if (!IsValid()) return -1;

   ((TXSocket *)fSocket)->SendCoordinator(kGroupProperties, grp, priority);

   return 0;
}

//_____________________________________________________________________________
Bool_t TXSlave::HandleError(const void *in)
{
   // Handle error on the input socket

   XHandleErr_t *herr = in ? (XHandleErr_t *)in : 0;

   // Try reconnection
   if (fSocket && herr && (herr->fOpt == 1)) {

      ((TXSocket *)fSocket)->Reconnect();
      if (fSocket && fSocket->IsValid()) {
         if (gDebug > 0) {
            if (!strcmp(GetOrdinal(), "0")) {
               Printf("Proof: connection to master at %s:%d re-established",
                     GetName(), GetPort());
            } else {
               Printf("Proof: connection to node '%s' at %s:%d re-established",
                     GetOrdinal(), GetName(), GetPort());
            }
         }
         return kFALSE;
      }
   }

   // This seems a real error: notify the interested parties
   Info("HandleError", "%p:%s:%s got called ... fProof: %p, fSocket: %p (valid: %d)",
                       this, fName.Data(), fOrdinal.Data(), fProof, fSocket,
                       (fSocket ? (Int_t)fSocket->IsValid() : -1));

   // Remove interrupt handler (avoid affecting other clients of the underlying physical
   // connection)
   SetInterruptHandler(kFALSE);

   if (fProof) {

      // Remove PROOF signal handler
      if (fProof->fIntHandler)
         fProof->fIntHandler->Remove();

      Info("HandleError", "%p: proof: %p", this, fProof);

      if (fSocket) {
         // This is need to skip contacting the remote server upon close
         ((TXSocket *)fSocket)->SetSessionID(-1);
         // This is need to interrupt possible pickup waiting status
         ((TXSocket *)fSocket)->SetInterrupt();
         // Synchronous collection in TProof: post fatal message; this will
         // mark the worker as bad and update the internal lists accordingly
         ((TXSocket *)fSocket)->PostMsg(kPROOF_FATAL);
      }

      // On masters we notify clients of the problem occured
      if (fProof->IsMaster()) {
         TString msg(Form("Worker '%s-%s' has been removed from the active list",
                          fName.Data(), fOrdinal.Data()));
         TMessage m(kPROOF_MESSAGE);
         m << msg;
         if (gProofServ)
            gProofServ->GetSocket()->Send(m);
         else
            Warning("HandleError", "%p: global reference to TProofServ missing", this);
      }
   } else {
      Warning("HandleError", "%p: reference to PROOF missing", this);
   }

   Printf("TXSlave::HandleError: %p: DONE ... ", this);

   // We are done
   return kTRUE;
}

//_____________________________________________________________________________
Bool_t TXSlave::HandleInput(const void *)
{
   // Handle asynchronous input on the socket

   if (fProof) {

      // Attach to the monitor instance, if any
      TMonitor *mon = fProof->fCurrentMonitor;

      if (gDebug > 2)
         Info("HandleInput", "%p: %s: proof: %p, mon: %p",
                             this, GetOrdinal(), fProof, mon);

      if (mon && mon->IsActive(fSocket)) {
         // Synchronous collection in TProof
         if (gDebug > 2)
            Info("HandleInput","%p: %s: posting monitor %p", this, GetOrdinal(), mon);
         mon->SetReady(fSocket);
      } else {
         // Asynchronous collection in TProof
         if (gDebug > 2) {
            if (mon) {
               Info("HandleInput", "%p: %s: not active in current monitor"
                                   " - calling TProof::CollectInputFrom",
                                   this, GetOrdinal());
            } else {
               Info("HandleInput", "%p: %s: calling TProof::CollectInputFrom",
                                   this, GetOrdinal());
            }
         }
         if (fProof->CollectInputFrom(fSocket) < 0)
            // Something wrong on the line: flush it
            FlushSocket();
      }
   } else {
      Warning("HandleInput", "%p: %s: reference to PROOF missing", this, GetOrdinal());
      return kFALSE;
   }

   // We are done
   return kTRUE;
}

//_____________________________________________________________________________
void TXSlave::SetInterruptHandler(Bool_t on)
{
   // Set/Unset the interrupt handler

   if (gDebug > 1)
      Info("SetInterruptHandler", "enter: %d", on);

   if (on) {
      if (!fIntHandler)
         fIntHandler = new TXSlaveInterruptHandler((TXSocket *)fSocket);
      fIntHandler->Add();
   } else {
      if (fIntHandler)
         fIntHandler->Remove();
   }
}

//_____________________________________________________________________________
void TXSlave::FlushSocket()
{
   // Clean any input on the socket

   if (gDebug > 1)
      Info("FlushSocket", "enter: %p", fSocket);

   if (fSocket)
      TXSocket::fgPipe.Flush(fSocket);
}
 TXSlave.cxx:1
 TXSlave.cxx:2
 TXSlave.cxx:3
 TXSlave.cxx:4
 TXSlave.cxx:5
 TXSlave.cxx:6
 TXSlave.cxx:7
 TXSlave.cxx:8
 TXSlave.cxx:9
 TXSlave.cxx:10
 TXSlave.cxx:11
 TXSlave.cxx:12
 TXSlave.cxx:13
 TXSlave.cxx:14
 TXSlave.cxx:15
 TXSlave.cxx:16
 TXSlave.cxx:17
 TXSlave.cxx:18
 TXSlave.cxx:19
 TXSlave.cxx:20
 TXSlave.cxx:21
 TXSlave.cxx:22
 TXSlave.cxx:23
 TXSlave.cxx:24
 TXSlave.cxx:25
 TXSlave.cxx:26
 TXSlave.cxx:27
 TXSlave.cxx:28
 TXSlave.cxx:29
 TXSlave.cxx:30
 TXSlave.cxx:31
 TXSlave.cxx:32
 TXSlave.cxx:33
 TXSlave.cxx:34
 TXSlave.cxx:35
 TXSlave.cxx:36
 TXSlave.cxx:37
 TXSlave.cxx:38
 TXSlave.cxx:39
 TXSlave.cxx:40
 TXSlave.cxx:41
 TXSlave.cxx:42
 TXSlave.cxx:43
 TXSlave.cxx:44
 TXSlave.cxx:45
 TXSlave.cxx:46
 TXSlave.cxx:47
 TXSlave.cxx:48
 TXSlave.cxx:49
 TXSlave.cxx:50
 TXSlave.cxx:51
 TXSlave.cxx:52
 TXSlave.cxx:53
 TXSlave.cxx:54
 TXSlave.cxx:55
 TXSlave.cxx:56
 TXSlave.cxx:57
 TXSlave.cxx:58
 TXSlave.cxx:59
 TXSlave.cxx:60
 TXSlave.cxx:61
 TXSlave.cxx:62
 TXSlave.cxx:63
 TXSlave.cxx:64
 TXSlave.cxx:65
 TXSlave.cxx:66
 TXSlave.cxx:67
 TXSlave.cxx:68
 TXSlave.cxx:69
 TXSlave.cxx:70
 TXSlave.cxx:71
 TXSlave.cxx:72
 TXSlave.cxx:73
 TXSlave.cxx:74
 TXSlave.cxx:75
 TXSlave.cxx:76
 TXSlave.cxx:77
 TXSlave.cxx:78
 TXSlave.cxx:79
 TXSlave.cxx:80
 TXSlave.cxx:81
 TXSlave.cxx:82
 TXSlave.cxx:83
 TXSlave.cxx:84
 TXSlave.cxx:85
 TXSlave.cxx:86
 TXSlave.cxx:87
 TXSlave.cxx:88
 TXSlave.cxx:89
 TXSlave.cxx:90
 TXSlave.cxx:91
 TXSlave.cxx:92
 TXSlave.cxx:93
 TXSlave.cxx:94
 TXSlave.cxx:95
 TXSlave.cxx:96
 TXSlave.cxx:97
 TXSlave.cxx:98
 TXSlave.cxx:99
 TXSlave.cxx:100
 TXSlave.cxx:101
 TXSlave.cxx:102
 TXSlave.cxx:103
 TXSlave.cxx:104
 TXSlave.cxx:105
 TXSlave.cxx:106
 TXSlave.cxx:107
 TXSlave.cxx:108
 TXSlave.cxx:109
 TXSlave.cxx:110
 TXSlave.cxx:111
 TXSlave.cxx:112
 TXSlave.cxx:113
 TXSlave.cxx:114
 TXSlave.cxx:115
 TXSlave.cxx:116
 TXSlave.cxx:117
 TXSlave.cxx:118
 TXSlave.cxx:119
 TXSlave.cxx:120
 TXSlave.cxx:121
 TXSlave.cxx:122
 TXSlave.cxx:123
 TXSlave.cxx:124
 TXSlave.cxx:125
 TXSlave.cxx:126
 TXSlave.cxx:127
 TXSlave.cxx:128
 TXSlave.cxx:129
 TXSlave.cxx:130
 TXSlave.cxx:131
 TXSlave.cxx:132
 TXSlave.cxx:133
 TXSlave.cxx:134
 TXSlave.cxx:135
 TXSlave.cxx:136
 TXSlave.cxx:137
 TXSlave.cxx:138
 TXSlave.cxx:139
 TXSlave.cxx:140
 TXSlave.cxx:141
 TXSlave.cxx:142
 TXSlave.cxx:143
 TXSlave.cxx:144
 TXSlave.cxx:145
 TXSlave.cxx:146
 TXSlave.cxx:147
 TXSlave.cxx:148
 TXSlave.cxx:149
 TXSlave.cxx:150
 TXSlave.cxx:151
 TXSlave.cxx:152
 TXSlave.cxx:153
 TXSlave.cxx:154
 TXSlave.cxx:155
 TXSlave.cxx:156
 TXSlave.cxx:157
 TXSlave.cxx:158
 TXSlave.cxx:159
 TXSlave.cxx:160
 TXSlave.cxx:161
 TXSlave.cxx:162
 TXSlave.cxx:163
 TXSlave.cxx:164
 TXSlave.cxx:165
 TXSlave.cxx:166
 TXSlave.cxx:167
 TXSlave.cxx:168
 TXSlave.cxx:169
 TXSlave.cxx:170
 TXSlave.cxx:171
 TXSlave.cxx:172
 TXSlave.cxx:173
 TXSlave.cxx:174
 TXSlave.cxx:175
 TXSlave.cxx:176
 TXSlave.cxx:177
 TXSlave.cxx:178
 TXSlave.cxx:179
 TXSlave.cxx:180
 TXSlave.cxx:181
 TXSlave.cxx:182
 TXSlave.cxx:183
 TXSlave.cxx:184
 TXSlave.cxx:185
 TXSlave.cxx:186
 TXSlave.cxx:187
 TXSlave.cxx:188
 TXSlave.cxx:189
 TXSlave.cxx:190
 TXSlave.cxx:191
 TXSlave.cxx:192
 TXSlave.cxx:193
 TXSlave.cxx:194
 TXSlave.cxx:195
 TXSlave.cxx:196
 TXSlave.cxx:197
 TXSlave.cxx:198
 TXSlave.cxx:199
 TXSlave.cxx:200
 TXSlave.cxx:201
 TXSlave.cxx:202
 TXSlave.cxx:203
 TXSlave.cxx:204
 TXSlave.cxx:205
 TXSlave.cxx:206
 TXSlave.cxx:207
 TXSlave.cxx:208
 TXSlave.cxx:209
 TXSlave.cxx:210
 TXSlave.cxx:211
 TXSlave.cxx:212
 TXSlave.cxx:213
 TXSlave.cxx:214
 TXSlave.cxx:215
 TXSlave.cxx:216
 TXSlave.cxx:217
 TXSlave.cxx:218
 TXSlave.cxx:219
 TXSlave.cxx:220
 TXSlave.cxx:221
 TXSlave.cxx:222
 TXSlave.cxx:223
 TXSlave.cxx:224
 TXSlave.cxx:225
 TXSlave.cxx:226
 TXSlave.cxx:227
 TXSlave.cxx:228
 TXSlave.cxx:229
 TXSlave.cxx:230
 TXSlave.cxx:231
 TXSlave.cxx:232
 TXSlave.cxx:233
 TXSlave.cxx:234
 TXSlave.cxx:235
 TXSlave.cxx:236
 TXSlave.cxx:237
 TXSlave.cxx:238
 TXSlave.cxx:239
 TXSlave.cxx:240
 TXSlave.cxx:241
 TXSlave.cxx:242
 TXSlave.cxx:243
 TXSlave.cxx:244
 TXSlave.cxx:245
 TXSlave.cxx:246
 TXSlave.cxx:247
 TXSlave.cxx:248
 TXSlave.cxx:249
 TXSlave.cxx:250
 TXSlave.cxx:251
 TXSlave.cxx:252
 TXSlave.cxx:253
 TXSlave.cxx:254
 TXSlave.cxx:255
 TXSlave.cxx:256
 TXSlave.cxx:257
 TXSlave.cxx:258
 TXSlave.cxx:259
 TXSlave.cxx:260
 TXSlave.cxx:261
 TXSlave.cxx:262
 TXSlave.cxx:263
 TXSlave.cxx:264
 TXSlave.cxx:265
 TXSlave.cxx:266
 TXSlave.cxx:267
 TXSlave.cxx:268
 TXSlave.cxx:269
 TXSlave.cxx:270
 TXSlave.cxx:271
 TXSlave.cxx:272
 TXSlave.cxx:273
 TXSlave.cxx:274
 TXSlave.cxx:275
 TXSlave.cxx:276
 TXSlave.cxx:277
 TXSlave.cxx:278
 TXSlave.cxx:279
 TXSlave.cxx:280
 TXSlave.cxx:281
 TXSlave.cxx:282
 TXSlave.cxx:283
 TXSlave.cxx:284
 TXSlave.cxx:285
 TXSlave.cxx:286
 TXSlave.cxx:287
 TXSlave.cxx:288
 TXSlave.cxx:289
 TXSlave.cxx:290
 TXSlave.cxx:291
 TXSlave.cxx:292
 TXSlave.cxx:293
 TXSlave.cxx:294
 TXSlave.cxx:295
 TXSlave.cxx:296
 TXSlave.cxx:297
 TXSlave.cxx:298
 TXSlave.cxx:299
 TXSlave.cxx:300
 TXSlave.cxx:301
 TXSlave.cxx:302
 TXSlave.cxx:303
 TXSlave.cxx:304
 TXSlave.cxx:305
 TXSlave.cxx:306
 TXSlave.cxx:307
 TXSlave.cxx:308
 TXSlave.cxx:309
 TXSlave.cxx:310
 TXSlave.cxx:311
 TXSlave.cxx:312
 TXSlave.cxx:313
 TXSlave.cxx:314
 TXSlave.cxx:315
 TXSlave.cxx:316
 TXSlave.cxx:317
 TXSlave.cxx:318
 TXSlave.cxx:319
 TXSlave.cxx:320
 TXSlave.cxx:321
 TXSlave.cxx:322
 TXSlave.cxx:323
 TXSlave.cxx:324
 TXSlave.cxx:325
 TXSlave.cxx:326
 TXSlave.cxx:327
 TXSlave.cxx:328
 TXSlave.cxx:329
 TXSlave.cxx:330
 TXSlave.cxx:331
 TXSlave.cxx:332
 TXSlave.cxx:333
 TXSlave.cxx:334
 TXSlave.cxx:335
 TXSlave.cxx:336
 TXSlave.cxx:337
 TXSlave.cxx:338
 TXSlave.cxx:339
 TXSlave.cxx:340
 TXSlave.cxx:341
 TXSlave.cxx:342
 TXSlave.cxx:343
 TXSlave.cxx:344
 TXSlave.cxx:345
 TXSlave.cxx:346
 TXSlave.cxx:347
 TXSlave.cxx:348
 TXSlave.cxx:349
 TXSlave.cxx:350
 TXSlave.cxx:351
 TXSlave.cxx:352
 TXSlave.cxx:353
 TXSlave.cxx:354
 TXSlave.cxx:355
 TXSlave.cxx:356
 TXSlave.cxx:357
 TXSlave.cxx:358
 TXSlave.cxx:359
 TXSlave.cxx:360
 TXSlave.cxx:361
 TXSlave.cxx:362
 TXSlave.cxx:363
 TXSlave.cxx:364
 TXSlave.cxx:365
 TXSlave.cxx:366
 TXSlave.cxx:367
 TXSlave.cxx:368
 TXSlave.cxx:369
 TXSlave.cxx:370
 TXSlave.cxx:371
 TXSlave.cxx:372
 TXSlave.cxx:373
 TXSlave.cxx:374
 TXSlave.cxx:375
 TXSlave.cxx:376
 TXSlave.cxx:377
 TXSlave.cxx:378
 TXSlave.cxx:379
 TXSlave.cxx:380
 TXSlave.cxx:381
 TXSlave.cxx:382
 TXSlave.cxx:383
 TXSlave.cxx:384
 TXSlave.cxx:385
 TXSlave.cxx:386
 TXSlave.cxx:387
 TXSlave.cxx:388
 TXSlave.cxx:389
 TXSlave.cxx:390
 TXSlave.cxx:391
 TXSlave.cxx:392
 TXSlave.cxx:393
 TXSlave.cxx:394
 TXSlave.cxx:395
 TXSlave.cxx:396
 TXSlave.cxx:397
 TXSlave.cxx:398
 TXSlave.cxx:399
 TXSlave.cxx:400
 TXSlave.cxx:401
 TXSlave.cxx:402
 TXSlave.cxx:403
 TXSlave.cxx:404
 TXSlave.cxx:405
 TXSlave.cxx:406
 TXSlave.cxx:407
 TXSlave.cxx:408
 TXSlave.cxx:409
 TXSlave.cxx:410
 TXSlave.cxx:411
 TXSlave.cxx:412
 TXSlave.cxx:413
 TXSlave.cxx:414
 TXSlave.cxx:415
 TXSlave.cxx:416
 TXSlave.cxx:417
 TXSlave.cxx:418
 TXSlave.cxx:419
 TXSlave.cxx:420
 TXSlave.cxx:421
 TXSlave.cxx:422
 TXSlave.cxx:423
 TXSlave.cxx:424
 TXSlave.cxx:425
 TXSlave.cxx:426
 TXSlave.cxx:427
 TXSlave.cxx:428
 TXSlave.cxx:429
 TXSlave.cxx:430
 TXSlave.cxx:431
 TXSlave.cxx:432
 TXSlave.cxx:433
 TXSlave.cxx:434
 TXSlave.cxx:435
 TXSlave.cxx:436
 TXSlave.cxx:437
 TXSlave.cxx:438
 TXSlave.cxx:439
 TXSlave.cxx:440
 TXSlave.cxx:441
 TXSlave.cxx:442
 TXSlave.cxx:443
 TXSlave.cxx:444
 TXSlave.cxx:445
 TXSlave.cxx:446
 TXSlave.cxx:447
 TXSlave.cxx:448
 TXSlave.cxx:449
 TXSlave.cxx:450
 TXSlave.cxx:451
 TXSlave.cxx:452
 TXSlave.cxx:453
 TXSlave.cxx:454
 TXSlave.cxx:455
 TXSlave.cxx:456
 TXSlave.cxx:457
 TXSlave.cxx:458
 TXSlave.cxx:459
 TXSlave.cxx:460
 TXSlave.cxx:461
 TXSlave.cxx:462
 TXSlave.cxx:463
 TXSlave.cxx:464
 TXSlave.cxx:465
 TXSlave.cxx:466
 TXSlave.cxx:467
 TXSlave.cxx:468
 TXSlave.cxx:469
 TXSlave.cxx:470
 TXSlave.cxx:471
 TXSlave.cxx:472
 TXSlave.cxx:473
 TXSlave.cxx:474
 TXSlave.cxx:475
 TXSlave.cxx:476
 TXSlave.cxx:477
 TXSlave.cxx:478
 TXSlave.cxx:479
 TXSlave.cxx:480
 TXSlave.cxx:481
 TXSlave.cxx:482
 TXSlave.cxx:483
 TXSlave.cxx:484
 TXSlave.cxx:485
 TXSlave.cxx:486
 TXSlave.cxx:487
 TXSlave.cxx:488
 TXSlave.cxx:489
 TXSlave.cxx:490
 TXSlave.cxx:491
 TXSlave.cxx:492
 TXSlave.cxx:493
 TXSlave.cxx:494
 TXSlave.cxx:495
 TXSlave.cxx:496
 TXSlave.cxx:497
 TXSlave.cxx:498
 TXSlave.cxx:499
 TXSlave.cxx:500
 TXSlave.cxx:501
 TXSlave.cxx:502
 TXSlave.cxx:503
 TXSlave.cxx:504
 TXSlave.cxx:505
 TXSlave.cxx:506
 TXSlave.cxx:507
 TXSlave.cxx:508
 TXSlave.cxx:509
 TXSlave.cxx:510
 TXSlave.cxx:511
 TXSlave.cxx:512
 TXSlave.cxx:513
 TXSlave.cxx:514
 TXSlave.cxx:515
 TXSlave.cxx:516
 TXSlave.cxx:517
 TXSlave.cxx:518
 TXSlave.cxx:519
 TXSlave.cxx:520
 TXSlave.cxx:521
 TXSlave.cxx:522
 TXSlave.cxx:523
 TXSlave.cxx:524
 TXSlave.cxx:525
 TXSlave.cxx:526
 TXSlave.cxx:527
 TXSlave.cxx:528
 TXSlave.cxx:529
 TXSlave.cxx:530
 TXSlave.cxx:531
 TXSlave.cxx:532
 TXSlave.cxx:533
 TXSlave.cxx:534
 TXSlave.cxx:535
 TXSlave.cxx:536
 TXSlave.cxx:537
 TXSlave.cxx:538
 TXSlave.cxx:539
 TXSlave.cxx:540
 TXSlave.cxx:541
 TXSlave.cxx:542
 TXSlave.cxx:543
 TXSlave.cxx:544
 TXSlave.cxx:545
 TXSlave.cxx:546
 TXSlave.cxx:547
 TXSlave.cxx:548
 TXSlave.cxx:549
 TXSlave.cxx:550
 TXSlave.cxx:551
 TXSlave.cxx:552
 TXSlave.cxx:553
 TXSlave.cxx:554
 TXSlave.cxx:555
 TXSlave.cxx:556
 TXSlave.cxx:557
 TXSlave.cxx:558
 TXSlave.cxx:559
 TXSlave.cxx:560
 TXSlave.cxx:561
 TXSlave.cxx:562
 TXSlave.cxx:563
 TXSlave.cxx:564
 TXSlave.cxx:565
 TXSlave.cxx:566
 TXSlave.cxx:567
 TXSlave.cxx:568
 TXSlave.cxx:569
 TXSlave.cxx:570
 TXSlave.cxx:571
 TXSlave.cxx:572
 TXSlave.cxx:573
 TXSlave.cxx:574
 TXSlave.cxx:575
 TXSlave.cxx:576
 TXSlave.cxx:577
 TXSlave.cxx:578
 TXSlave.cxx:579
 TXSlave.cxx:580
 TXSlave.cxx:581
 TXSlave.cxx:582
 TXSlave.cxx:583
 TXSlave.cxx:584
 TXSlave.cxx:585
 TXSlave.cxx:586
 TXSlave.cxx:587
 TXSlave.cxx:588
 TXSlave.cxx:589
 TXSlave.cxx:590
 TXSlave.cxx:591
 TXSlave.cxx:592
 TXSlave.cxx:593
 TXSlave.cxx:594
 TXSlave.cxx:595
 TXSlave.cxx:596
 TXSlave.cxx:597
 TXSlave.cxx:598
 TXSlave.cxx:599
 TXSlave.cxx:600
 TXSlave.cxx:601
 TXSlave.cxx:602
 TXSlave.cxx:603
 TXSlave.cxx:604
 TXSlave.cxx:605
 TXSlave.cxx:606
 TXSlave.cxx:607
 TXSlave.cxx:608
 TXSlave.cxx:609
 TXSlave.cxx:610
 TXSlave.cxx:611
 TXSlave.cxx:612
 TXSlave.cxx:613
 TXSlave.cxx:614
 TXSlave.cxx:615
 TXSlave.cxx:616
 TXSlave.cxx:617
 TXSlave.cxx:618
 TXSlave.cxx:619
 TXSlave.cxx:620
 TXSlave.cxx:621
 TXSlave.cxx:622
 TXSlave.cxx:623
 TXSlave.cxx:624
 TXSlave.cxx:625
 TXSlave.cxx:626
 TXSlave.cxx:627
 TXSlave.cxx:628
 TXSlave.cxx:629
 TXSlave.cxx:630
 TXSlave.cxx:631
 TXSlave.cxx:632
 TXSlave.cxx:633
 TXSlave.cxx:634
 TXSlave.cxx:635
 TXSlave.cxx:636
 TXSlave.cxx:637
 TXSlave.cxx:638
 TXSlave.cxx:639
 TXSlave.cxx:640
 TXSlave.cxx:641
 TXSlave.cxx:642
 TXSlave.cxx:643
 TXSlave.cxx:644
 TXSlave.cxx:645
 TXSlave.cxx:646
 TXSlave.cxx:647
 TXSlave.cxx:648
 TXSlave.cxx:649
 TXSlave.cxx:650
 TXSlave.cxx:651
 TXSlave.cxx:652
 TXSlave.cxx:653
 TXSlave.cxx:654
 TXSlave.cxx:655
 TXSlave.cxx:656
 TXSlave.cxx:657
 TXSlave.cxx:658
 TXSlave.cxx:659
 TXSlave.cxx:660
 TXSlave.cxx:661
 TXSlave.cxx:662
 TXSlave.cxx:663
 TXSlave.cxx:664
 TXSlave.cxx:665
 TXSlave.cxx:666
 TXSlave.cxx:667
 TXSlave.cxx:668
 TXSlave.cxx:669
 TXSlave.cxx:670
 TXSlave.cxx:671
 TXSlave.cxx:672
 TXSlave.cxx:673
 TXSlave.cxx:674
 TXSlave.cxx:675
 TXSlave.cxx:676
 TXSlave.cxx:677
 TXSlave.cxx:678
 TXSlave.cxx:679
 TXSlave.cxx:680
 TXSlave.cxx:681
 TXSlave.cxx:682
 TXSlave.cxx:683
 TXSlave.cxx:684
 TXSlave.cxx:685
 TXSlave.cxx:686
 TXSlave.cxx:687
 TXSlave.cxx:688
 TXSlave.cxx:689
 TXSlave.cxx:690
 TXSlave.cxx:691
 TXSlave.cxx:692
 TXSlave.cxx:693
 TXSlave.cxx:694
 TXSlave.cxx:695
 TXSlave.cxx:696
 TXSlave.cxx:697
 TXSlave.cxx:698
 TXSlave.cxx:699
 TXSlave.cxx:700
 TXSlave.cxx:701
 TXSlave.cxx:702
 TXSlave.cxx:703
 TXSlave.cxx:704
 TXSlave.cxx:705
 TXSlave.cxx:706
 TXSlave.cxx:707
 TXSlave.cxx:708
 TXSlave.cxx:709