docs: public void run()
      {
          Object objJobDef = null;
          while (m_bKeepAlive)
          {   // Only loop, if this thread should be kept alive.
              Date earliestDate = null;
              Vector<AutoTask> vJobsToRunLater = null;
              while ((objJobDef = this.getNextJob()) != null)     // Get and remove next job
              { // Until end of jobs
                  if (EMPTY_TIMED_JOBS == objJobDef)
                  {
                      vJobsToRunLater = null; // Clear everything up to this job
                      earliestDate = null;
                  }
                  else if (END_OF_JOBS == objJobDef)
                      m_bKeepAlive = false; // Special - end of Jobs message, quit this thread
                  else
                  {
                      if (objJobDef instanceof AutoTask)
                          if (((AutoTask)objJobDef).getProperties() != null)
                      {
                          Date date = (Date)((AutoTask)objJobDef).getProperties().get(TIME_TO_RUN);
                          if (date != null)
                          {
                              Date now = new Date();
                              if (date.after(now))
                              {   // Don't run this one until later
                                  if ((earliestDate == null)
                                      || (earliestDate.after(date)))
                                          earliestDate = date;
                                  if (vJobsToRunLater == null)
                                      vJobsToRunLater = new Vector<AutoTask>();
                                  this.addJobToRunLater(vJobsToRunLater, (AutoTask)objJobDef);
                                  continue;
                              }
                          }
                      }
                      if (objJobDef instanceof AutoTask)
                          if (((AutoTask)objJobDef).getApplication() == null)
                              ((AutoTask)objJobDef).setApplication(this.getApplication());
                      this.runThread(objJobDef);
                  }
              }
              long lWaitTime = 0;
              if (earliestDate != null)
              {
                  lWaitTime = earliestDate.getTime() - new Date().getTime();
                  if (lWaitTime <= 0)
                      lWaitTime = 1;  // Don't wait (long) there is a task that is ready to go now.
              }
              // No more tasks to process, either stop, or go to sleep
              if (m_bKeepAlive)
              {
                  synchronized(this)
                  {
                      m_bThreadSuspended = true;  // Suspend this puppy
                      try   {
                          while (m_bThreadSuspended)
                          {
                              wait(lWaitTime);     // Wait for notification that I can continue
                              if (lWaitTime != 0)
                              {
                                  m_bThreadSuspended = false;     // I was waiting for the time to expire.
                                  m_vPrivateJobs.addAll(vJobsToRunLater);     // Add all these jobs back
                              }
                          }
                      } catch (InterruptedException ex) {
                          ex.printStackTrace();
                      }
                  }
              }
          }
      }