<commit_before>class Segment
  attr_reader :begin_split, :end_split, :begin_sub_split, :end_sub_split
  delegate :course, to: :begin_split
  delegate :events, :earliest_event_date, :most_recent_event_date, to: :end_split

  def initialize(begin_sub_split, end_sub_split, begin_split = nil, end_split = nil)
    @begin_sub_split = begin_sub_split
    @end_sub_split = end_sub_split
    @begin_split = begin_split || Split.find(begin_sub_split.split_id)
    @end_split = end_split || Split.find(end_sub_split.split_id)
    validate_segment
  end

  def ==(other)
    (begin_sub_split == other.begin_sub_split) && (end_sub_split == other.end_sub_split)
  end

  def eql?(other)
    self == other
  end

  def hash
    [begin_sub_split, end_sub_split].hash
  end

  def name
    within_split? ?
        "Time in #{begin_split.base_name}" :
        [begin_split.base_name, end_split.base_name].join(' to ')
  end

  def distance
    end_split.distance_from_start - begin_split.distance_from_start
  end

  def vert_gain
    end_split.vert_gain_from_start.to_i - begin_split.vert_gain_from_start.to_i
  end

  def vert_loss
    end_split.vert_loss_from_start.to_i - begin_split.vert_loss_from_start.to_i
  end

  def typical_time_by_terrain
    @typical_time_by_terrain ||= (distance * DISTANCE_FACTOR) + (vert_gain * VERT_GAIN_FACTOR)
  end

  def terrain_low_bad
    typical_time_by_terrain / 5
  end

  def terrain_low_questionable
    typical_time_by_terrain / 3.5
  end

  def terrain_high_questionable
    typical_time_by_terrain * 3.5
  end

  def terrain_high_bad
    typical_time_by_terrain * 5
  end

  def limits_by_terrain
    [terrain_low_bad, terrain_low_questionable, terrain_high_questionable, terrain_high_bad]
  end

  def begin_id
    begin_split.id
  end

  def end_id
    end_split.id
  end

  def split_ids
    [begin_id, end_id]
  end

  def begin_bitkey
    begin_sub_split.bitkey
  end

  def end_bitkey
    end_sub_split.bitkey
  end

  def times
    SegmentTimes.new(self).times
  end

  def full_course?
    begin_split.start? && end_split.finish?
  end

  private

  def validate_segment
    raise 'Segment splits must be on same course' if begin_split.course_id != end_split.course_id
    raise 'Segment sub_splits are out of order' if within_split? && (begin_bitkey > end_bitkey)
    raise 'Segment splits are out of order' if begin_split.distance_from_start > end_split.distance_from_start
    raise 'Segment begin sub_split does not reconcile with begin split' if begin_sub_split.split_id != begin_id
    raise 'Segment end sub_split does not reconcile with end split' if end_sub_split.split_id != end_id
  end

  def within_split?
    begin_split == end_split
  end
end<commit_msg>Modify Segment model to lazy evaluate begin_split and end_split.<commit_after>class Segment
  attr_reader :begin_sub_split, :end_sub_split
  delegate :course, to: :begin_split
  delegate :events, :earliest_event_date, :most_recent_event_date, to: :end_split

  def initialize(begin_sub_split, end_sub_split, begin_split = nil, end_split = nil)
    @begin_sub_split = begin_sub_split
    @end_sub_split = end_sub_split
    @arg_begin_split = begin_split
    @arg_end_split = end_split
    validate_segment
  end

  def ==(other)
    (begin_sub_split == other.begin_sub_split) && (end_sub_split == other.end_sub_split)
  end

  def eql?(other)
    self == other
  end

  def hash
    [begin_sub_split, end_sub_split].hash
  end

  def begin_split
    @begin_split ||= arg_begin_split || Split.find(begin_sub_split.split_id)
  end

  def end_split
    @end_split ||= arg_end_split || Split.find(end_sub_split.split_id)
  end

  def name
    within_split? ?
        "Time in #{begin_split.base_name}" :
        [begin_split.base_name, end_split.base_name].join(' to ')
  end

  def distance
    end_split.distance_from_start - begin_split.distance_from_start
  end

  def vert_gain
    end_split.vert_gain_from_start.to_i - begin_split.vert_gain_from_start.to_i
  end

  def vert_loss
    end_split.vert_loss_from_start.to_i - begin_split.vert_loss_from_start.to_i
  end

  def typical_time_by_terrain
    @typical_time_by_terrain ||= (distance * DISTANCE_FACTOR) + (vert_gain * VERT_GAIN_FACTOR)
  end

  def terrain_low_bad
    typical_time_by_terrain / 5
  end

  def terrain_low_questionable
    typical_time_by_terrain / 3.5
  end

  def terrain_high_questionable
    typical_time_by_terrain * 3.5
  end

  def terrain_high_bad
    typical_time_by_terrain * 5
  end

  def limits_by_terrain
    [terrain_low_bad, terrain_low_questionable, terrain_high_questionable, terrain_high_bad]
  end

  def begin_id
    begin_split.id
  end

  def end_id
    end_split.id
  end

  def split_ids
    [begin_id, end_id]
  end

  def begin_bitkey
    begin_sub_split.bitkey
  end

  def end_bitkey
    end_sub_split.bitkey
  end

  def times
    SegmentTimes.new(self).times
  end

  def full_course?
    begin_split.start? && end_split.finish?
  end

  private

  attr_reader :arg_begin_split, :arg_end_split

  def validate_segment
    raise 'Segment splits must be on same course' if arg_begin_split && arg_end_split && (arg_begin_split.course_id != end_split.course_id)
    raise 'Segment sub_splits are out of order' if within_split? && (begin_bitkey > end_bitkey)
    raise 'Segment splits are out of order' if arg_begin_split && arg_end_split && (begin_split.distance_from_start > end_split.distance_from_start)
    raise 'Segment begin sub_split does not reconcile with begin split' if arg_begin_split && (begin_sub_split.split_id != begin_id)
    raise 'Segment end sub_split does not reconcile with end split' if arg_end_split && (end_sub_split.split_id != end_id)
  end

  def within_split?
    begin_sub_split.split_id == end_sub_split.split_id
  end
end
{'fraction_non_alphanumeric': 0.06697900399097692, 'fraction_numerical': 0.002082248828735034, 'mean_word_length': 3.9775474956822108, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, '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': '4699581', 'n_tokens_mistral': 2122, 'n_tokens_neox': 2038, 'n_words': 446}