def add_shot(self, shot):
        """
        Add a shot dictionary to :attr:`shots`, applying our survey's :attr:`declination`, and
        optionally averaging and merging with duplicate previous shot.
        """
        if not self.shots or not shot.get('TO', None) or not self.shots[-1].get('TO', None):
            return super(MergingSurvey, self).add_shot(shot)

        from_, to = shot['FROM'], shot['TO']
        prev_shot = self.shots[-1]
        prev_from, prev_to = prev_shot['FROM'], prev_shot['TO']

        if from_ == prev_from and to == prev_to:
            # dupe shot! calculate iterative "running" mean and merge into the previous shot
            total_count = prev_shot.dupe_count + 1

            log.debug('Merging %d shots "%s" <- "%s"', total_count, prev_shot, shot)
            if abs(shot['AZM'] - prev_shot['AZM']) > 2.0:
                log.warning('Merged forward AZM disagreement of %0.1f for "%s" <- "%s"', abs(shot['AZM'] - prev_shot['AZM']), prev_shot, shot)
            if abs(shot['INC'] - prev_shot['INC']) > 2.0:
                log.warning('Merged forward INC disagreement of %0.1f for "%s" <- "%s"', abs(shot['INC'] - prev_shot['INC']), prev_shot, shot)
            if abs(shot['LENGTH'] - prev_shot['LENGTH']) > 1.0:
                log.warning('Merged forward LENGTH disagreement of %0.1f for "%s" <- "%s"', abs(shot['LENGTH'] - prev_shot['LENGTH']), prev_shot, shot)

            avg_length = (prev_shot['LENGTH'] * prev_shot.dupe_count + shot['LENGTH']) / total_count
            avg_azm = (prev_shot['AZM'] * prev_shot.dupe_count + shot['AZM']) / total_count
            avg_inc = (prev_shot['INC'] * prev_shot.dupe_count + shot['INC']) / total_count
            merged_comments = ('%s %s' % (prev_shot.get('COMMENT', '') or '', shot.get('COMMENT', '') or '')).strip() or None

            prev_shot['LENGTH'], prev_shot['AZM'], prev_shot['INC'], prev_shot['COMMENT'] = avg_length, avg_azm, avg_inc, merged_comments
            prev_shot.dupe_count += 1

        elif from_ == prev_to and to == prev_from:
            # backsight! we do the same iterative "running" mean rather than assuming a single forward and single back
            total_count = prev_shot.dupe_count + 1
            inv_azm, inv_inc = self._inverse_azm(shot['AZM']), self._inverse_inc(shot['INC'])

            log.debug('Merging %d backsights "%s" <- "%s"', total_count, prev_shot, shot)
            if abs(inv_azm - prev_shot['AZM']) > 2.0:
                log.warning('Backsight AZM disagreement of %0.1f for "%s" <- "%s"', abs(inv_azm - prev_shot['AZM']), prev_shot, shot)
            if abs(inv_inc - prev_shot['INC']) > 2.0:
                log.warning('Backsight INC disagreement of %0.1f for "%s" <- "%s"', abs(inv_inc - prev_shot['INC']), prev_shot, shot)
            if abs(shot['LENGTH'] - prev_shot['LENGTH']) > 1.0:
                log.warning('Backsight LENGTH disagreement of %0.1f for "%s" <- "%s"', abs(shot['LENGTH'] - prev_shot['LENGTH']), prev_shot, shot)

            avg_length = (prev_shot['LENGTH'] * prev_shot.dupe_count + shot['LENGTH']) / total_count
            avg_azm = (prev_shot['AZM'] * prev_shot.dupe_count + inv_azm) / total_count
            avg_inc = (prev_shot['INC'] * prev_shot.dupe_count + inv_inc) / total_count
            merged_comments = ('%s %s' % (prev_shot.get('COMMENT', '') or '', shot.get('COMMENT', '') or '')).strip() or None

            prev_shot['LENGTH'], prev_shot['AZM'], prev_shot['INC'], prev_shot['COMMENT'] = avg_length, avg_azm, avg_inc, merged_comments
            prev_shot.dupe_count += 1

        else:
            # a new, different shot; no merge
            return super(MergingSurvey, self).add_shot(shot)
Add a shot dictionary to :attr:`shots`, applying our survey's :attr:`declination`, and
        optionally averaging and merging with duplicate previous shot.