<commit_before># these database objects act as a cache for computationally intensive schedule operations
# and are autogenerated.  don't attempt to manipulate them manually.
class ScheduleBlock < ActiveRecord::Base
  belongs_to :schedule
  has_and_belongs_to_many :events
  has_many :scheduled_event_positions, :dependent => :destroy
  has_and_belongs_to_many :tracks, :order => :position
  
  before_save do |block|
    events = block.events
    if events.size > 0
      block.start ||= events[0].start
      block.end ||= events[0].end
      events[1, events.size - 1].each do |event|
        if event.start < block.start
          block.start = event.start
        end
        if event.end > block.end
          block.end = event.end
        end
      end
    end
    block.start = Time.mktime(block.start.year, block.start.month, block.start.day, block.start.hour, 0, 0, 0)
    
    if not block.interval
      block.interval = 30.minutes
      shortest_event_length = block.interval * 4
      
      # calculate last event end and which tracks are used in this block
      block.events.each do |event|
        if shortest_event_length > event.length and event.length > 0
          shortest_event_length = event.length
        end
      end
  
      if shortest_event_length < (block.interval * 4)
        block.interval = shortest_event_length / 4
      end
    end
    
    # ensure that we end on a multiple of interval
    schedlen = ((block.end - block.start) / block.interval).ceil * block.interval
    block.end = block.start + schedlen
  end
  
  def obtain_tracks
    if tracks.size == 0
      events.each do |event|
        event.tracks.each do |track|
          if (not tracks.include?(track)) and (schedule.tracks.include?(track))
            tracks.push(track)
          end
        end
      end
    end
    return tracks.sort {|a, b| a.position <=> b.position}
  end
  
  def obtain_event_positions
    if scheduled_event_positions.size != events.size
      scheduled_event_positions.destroy_all

      usetracks = obtain_tracks
      schedlen = self.end - self.start

      grabbed_columns = {}
      pregrabs = {}
      usetracks.each do |track|
        grabbed_columns[track] = {}
      end

      numcols = usetracks.size
      colsize = ((100.0 - 10.0) / numcols)
      rowheight = (self.interval / (self.end - self.start)) * 100.0
      now = self.start
        
      while now < self.end
        nowevents = []
        while events.size > 0 and events[0].start < (now + interval)
          nowevents.push(events.shift)
        end
      
        colnum = 0
        usetracks.each do |track|
          logger.debug "Formatting track #{track.id} at #{now} with colnum #{colnum}"
        
          # check for expired column grabs
          grabbed_columns[track].reject! { |col, time| time <= now }
        
          trackevents = nowevents.select {|e| e.tracks.include? track}
          eventnum = 0
        
          # pre-grab columns for upcoming events
          trackevents.each do |event|
            events.each do |e|
              if not pregrabs.has_key? e.id
                if e.tracks.include?(track) and e.start > event.start and e.start < event.end
                  pgcolnum = eventnum + 1
                  while grabbed_columns[track].has_key?(pgcolnum)
                    pgcolnum += 1
                  end
                  logger.debug "Event #{e.id} pregrabbing subcolumn #{pgcolnum} until #{e.start}"
                  grabbed_columns[track][pgcolnum] = e.start
                  pregrabs[e.id] = true
                end
              end
            end
          end
        
          # calculate visual dimensions for each event
          eventsize = (colsize - 0.5) / (trackevents.size + grabbed_columns[track].size)          
          trackevents.each do |event|
            if scheduled_event_positions.find_by_event_id(event.id)
              # we already calculated this event
              next
            end
            
            while grabbed_columns[track].has_key?(eventnum)
              eventnum += 1
            end
            
            trackcount = event.tracks.select do |track|
              usetracks.include? track
            end.size
            
            scheduled_event_positions.create(:event => event,
              :left => (colsize * colnum) + (eventsize * eventnum) + 10.0,
              :width => trackcount > 1 ? trackcount * colsize : eventsize,
              :top => ((event.start - self.start) / schedlen) * 100.0,
              :height => ((event.end - event.start) / schedlen) * 100.0,
              :color => trackcount > 1 ? '#ffc' : track.color
              )
          
            grabbed_columns[track][eventnum] = event.end
            logger.debug "Event #{event.id} grabbing subcolumn #{eventnum} until #{event.end}"
            eventnum += 1
          end
        
          colnum += 1
        end
      
        now += self.interval
      end
    end
    
    return scheduled_event_positions
  end
end<commit_msg>Cope with events that exist on multiple schedules<commit_after># these database objects act as a cache for computationally intensive schedule operations
# and are autogenerated.  don't attempt to manipulate them manually.
class ScheduleBlock < ActiveRecord::Base
  belongs_to :schedule
  has_and_belongs_to_many :events
  has_many :scheduled_event_positions, :dependent => :destroy
  has_and_belongs_to_many :tracks, :order => :position
  
  before_save do |block|
    events = block.events
    if events.size > 0
      block.start ||= events[0].start
      block.end ||= events[0].end
      events[1, events.size - 1].each do |event|
        if event.start < block.start
          block.start = event.start
        end
        if event.end > block.end
          block.end = event.end
        end
      end
    end
    block.start = Time.mktime(block.start.year, block.start.month, block.start.day, block.start.hour, 0, 0, 0)
    
    if not block.interval
      block.interval = 30.minutes
      shortest_event_length = block.interval * 4
      
      # calculate last event end and which tracks are used in this block
      block.events.each do |event|
        if shortest_event_length > event.length and event.length > 0
          shortest_event_length = event.length
        end
      end
  
      if shortest_event_length < (block.interval * 4)
        block.interval = shortest_event_length / 4
      end
    end
    
    # ensure that we end on a multiple of interval
    schedlen = ((block.end - block.start) / block.interval).ceil * block.interval
    block.end = block.start + schedlen
  end
  
  def obtain_tracks
    if tracks.size == 0
      events.each do |event|
        event.tracks.each do |track|
          if (not tracks.include?(track)) and (schedule.tracks.include?(track))
            tracks.push(track)
          end
        end
      end
    end
    return tracks.sort {|a, b| a.position <=> b.position}
  end
  
  def obtain_event_positions
    if scheduled_event_positions.size != events.size
      scheduled_event_positions.destroy_all

      usetracks = obtain_tracks
      schedlen = self.end - self.start

      grabbed_columns = {}
      pregrabs = {}
      usetracks.each do |track|
        grabbed_columns[track] = {}
      end

      numcols = usetracks.size
      colsize = ((100.0 - 10.0) / numcols)
      now = self.start
        
      while now < self.end
        nowevents = []
        while events.size > 0 and events[0].start < (now + interval)
          nowevents.push(events.shift)
        end
      
        colnum = 0
        usetracks.each do |track|
          logger.debug "Formatting track #{track.id} at #{now} with colnum #{colnum}"
        
          # check for expired column grabs
          grabbed_columns[track].reject! { |col, time| time <= now }
        
          trackevents = nowevents.select {|e| e.tracks.include? track}
          eventnum = 0
        
          # pre-grab columns for upcoming events
          trackevents.each do |event|
            events.each do |e|
              if not pregrabs.has_key? e.id
                if e.tracks.include?(track) and e.start > event.start and e.start < event.end
                  pgcolnum = eventnum + 1
                  while grabbed_columns[track].has_key?(pgcolnum)
                    pgcolnum += 1
                  end
                  logger.debug "Event #{e.id} pregrabbing subcolumn #{pgcolnum} until #{e.start}"
                  grabbed_columns[track][pgcolnum] = e.start
                  pregrabs[e.id] = true
                end
              end
            end
          end
        
          # calculate visual dimensions for each event
          eventsize = (colsize - 0.5) / (trackevents.size + grabbed_columns[track].size)          
          trackevents.each do |event|
            if scheduled_event_positions.find_by_event_id(event.id)
              # we already calculated this event
              next
            end
            
            while grabbed_columns[track].has_key?(eventnum)
              eventnum += 1
            end
            
            trackcount = event.tracks.select do |eventtrack|
              usetracks.include? eventtrack
            end.size
            
            scheduled_event_positions.create(:event => event,
              :left => (colsize * colnum) + (eventsize * eventnum) + 10.0,
              :width => trackcount > 1 ? trackcount * colsize : eventsize,
              :top => ((event.start - self.start) / schedlen) * 100.0,
              :height => ((event.end - event.start) / schedlen) * 100.0,
              :color => trackcount > 1 ? '#ffc' : track.color
              )
          
            grabbed_columns[track][eventnum] = event.end
            logger.debug "Event #{event.id} grabbing subcolumn #{eventnum} until #{event.end}"
            eventnum += 1
          end
        
          colnum += 1
        end
      
        now += self.interval
      end
    end
    
    return scheduled_event_positions
  end
end
{'fraction_non_alphanumeric': 0.09000398247710076, 'fraction_numerical': 0.009557945041816009, 'mean_word_length': 1.7467869838665573, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1333877', 'n_tokens_mistral': 2958, 'n_tokens_neox': 2831, 'n_words': 749}