@app.route('/moves/<int:id>', methods=['GET'])
def move(id):
    move = Move.query.filter_by(id=id).first_or_404()

    if not move.public and move.user != current_user:
        return app.login_manager.unauthorized()

    samples = move.samples.order_by('time asc').all()
    events = [sample for sample in samples if sample.events]

    filtered_events = []
    pauses = []
    laps = []
    pause_begin = None
    for sample in events:
        assert len(sample.events.keys()) == 1
        if 'pause' in sample.events:
            state = sample.events['pause']['state'].lower() == 'true'
            if state:
                pause_begin = sample
            elif not state and pause_begin:
                pauses.append([pause_begin, sample])
        elif 'lap' in sample.events:
            laps.append(sample)
        else:
            filtered_events.append(sample)

    model = {}
    model['BING_MAPS_API_KEY'] = app.config['BING_MAPS_API_KEY'] if 'BING_MAPS_API_KEY' in app.config else None
    model['move'] = move
    model['samples'] = samples
    model['events'] = filtered_events
    model['pauses'] = pauses
    model['laps'] = laps

    gps_samples = [sample for sample in samples if sample.sample_type and sample.sample_type.startswith('gps-')]
    model['gps_samples'] = gps_samples

    if gps_samples:
        if not move.gps_center_max_distance:
            postprocess_move(move)
            flash(u"got %d GPS samples but no center. recalculated" % len(gps_samples), u'warning')
            db.session.commit()

        gps_center_max_distance = move.gps_center_max_distance

        # empirically determined values
        if gps_center_max_distance < 2000:
            map_zoom_level = 14
        elif gps_center_max_distance < 4000:
            map_zoom_level = 13
        elif gps_center_max_distance < 7500:
            map_zoom_level = 12
        elif gps_center_max_distance < 10000:
            map_zoom_level = 11
        else:
            map_zoom_level = 10

        calculate_distances(model, move.samples)

        model['map_zoom_level'] = map_zoom_level

    if 'swimming' in move.activity:
        swimming_events = [sample for sample in filtered_events if 'swimming' in sample.events]
        model['swimming_events'] = swimming_events

        model['swimming_style_changes'] = [sample for sample in swimming_events if sample.events['swimming']['type'] == 'StyleChange']
        model['swimming_turns'] = [sample for sample in swimming_events if sample.events['swimming']['type'] == 'Turn']

        swimming_strokes = [sample for sample in swimming_events if sample.events['swimming']['type'] == 'Stroke']
        model['swimming_strokes'] = swimming_strokes

        pause_samples = list(itertools.chain.from_iterable(pauses))
        model['swimming_strokes_and_pauses'] = sorted(swimming_strokes + pause_samples, key=lambda sample: sample.time)

        model['swim_pace'] = timedelta(seconds=move.duration.total_seconds() / move.distance)

        if move.stroke_count:
            assert len(model['swimming_strokes']) == move.stroke_count

    # eg. 'Pool swimming' → 'pool_swimming'
    activity_name = move.activity.lower().replace(' ', '_')
    try:
        return render_template("move/%s.html" % activity_name, **model)
    except TemplateNotFound:
        # Fall-back to generic template
        return render_template("move/_move.html", **model)
    except Exception as e:
        if app.debug or app.testing:
            raise e
        else:
            flash(activity_name % "Failed to load move template of activity '%s'.")
            return redirect(url_for('index'))
dataset/ETHPy150Open bwaldvogel/openmoves/openmoves.py/move/swapped operands of `%`