def logfile_entries( logfile )
      lines = File.open( logfile ).map{|l| l}
      entry_indexes = [] # lines that are just a timestamp
      lines.each_with_index do |line, idx|
        next unless first_char_is_num?( line )
        dt = begin
          DateTime.strptime(line.strip, "%m/%d/%Y at %l:%M %p (%Z)")
        rescue ArgumentError
          nil
        end
        next if dt.nil?
        next if idx > 0 && lines[idx-1].strip.present? && !lines[idx-1].strip.starts_with?('Logged by user:')
        entry_indexes << idx
      end
      return nil if entry_indexes.empty?

      # TODO: refactor (shouldn't need to loop over the logfile twice)
      entries = []
      entry_indexes.each_with_index do |entry_idx, entry_indexes_idx|
        end_idx = entry_indexes_idx == (entry_indexes.length - 1) ? (lines.length-1) : (entry_indexes[entry_indexes_idx+1]-1)
        end_idx -= 1 if lines[end_idx].starts_with?('Logged by user:')
        entry_text = lines[entry_idx+1..end_idx].join
        entry_text = lines[entry_idx-1] + entry_text if entry_idx > 0 && lines[entry_idx-1].starts_with?('Logged by user:')
        entries << {:time => DateTime.strptime(lines[entry_idx].strip, "%m/%d/%Y at %l:%M %p (%Z)"), :text => entry_text.strip}
      end
      entries
    end
def logfile_entries( logfile )
      lines = File.open( logfile ).map{|l| l}
      entry_indexes = [] # lines that are just a timestamp
      lines.each_with_index do |line, idx|
        next unless first_char_is_num?( line )
        dt = begin
          DateTime.strptime(line.strip, "%m/%d/%Y at %l:%M %p (%Z)")
        rescue ArgumentError
          nil
        end
        next if dt.nil?
        next if idx > 0 && lines[idx-1].strip.present? && !lines[idx-1].strip.starts_with?('Logged by user:')
        entry_indexes << idx
      end
      return nil if entry_indexes.empty?

      # TODO: refactor (shouldn't need to loop over the logfile twice)
      entries = []
      entry_indexes.each_with_index do |entry_idx, entry_indexes_idx|
        end_idx = entry_indexes_idx == (entry_indexes.length - 1) ? (lines.length-1) : (entry_indexes[entry_indexes_idx+1]-1)
        end_idx -= 1 if lines[end_idx].starts_with?('Logged by user:')
        entry_text = lines[entry_idx+1..end_idx].join
        entry_text = lines[entry_idx-1] + entry_text if entry_idx > 0 && lines[entry_idx-1].starts_with?('Logged by user:')
        entries << {:time => DateTime.strptime(lines[entry_idx].strip, "%m/%d/%Y at %l:%M %p (%Z)"), :text => entry_text.strip}
      end
      entries
    end
Returns an array of hashes containing time and text of each log entry, e.g.,
 [
   [0] {
       :time => Thu, 17 Sep 2015 12:20:00 -0500,
       :text => "Logged by user: (bm25671) John Doe\nSome message was logged"
   },
   [1] {
       :time => Thu, 17 Sep 2015 12:27:00 -0500,
       :text => "Logged by user: (bm25671) Jane Smith\nLorem ipsum..."
   },
   [2] {
       :time => Thu, 17 Sep 2015 13:24:00 -0500,
       :text => "Logged by user: (vr16208) Charlie Williams\nblah blah blah"
   }
 ]

 Returns nil if entries couldn't be parsed (unable to find lines structured DateTime)